MIMA goal is creating "MIni MAven", one-shop stop reusable Java 8 library, to use Maven Resolver wherever you are.
MIMA makes you be able to:
- effortlessly reuse Maven Resolver inside and outside of Maven
- if outside Maven, it prepares you the environment obeying Maven user configuration (if asked for)
- supports all the latest Resolver features
Reusing Maven Resolver is hard, especially if you need same thing to work in a library that may be used from within Maven (ie. as part of Mojo) but also from outside of Maven (like part of some CLI).
The purpose of MIMA is to address this issue, and make your library reusable wherever it runs. But let's step back a bit.
Using Maven Resolver as a library was always hard: for start, resolver alone is "incomplete", in a sense that
code in https://github.com/apache/maven-resolver repository does not contain any model classes to work
with. They are provided by Maven itself, when resolver is integrated. Moreover, is incomplete in a sense
that not all components are implemented. Resolver in Maven is "completed" by resolver-provider Maven
module here https://github.com/apache/maven/tree/maven-3.9.x/maven-resolver-provider but even this alone module
is not enough: just check it's dependencies, there are models, builders. And finally, to be able to properly
augment user environment from outside of Maven, obey things as user settings.xml
etc., you even need more.
While some half-solutions did exist so far (most popular was Resolver's ServiceLocator
), these solutions were
never complete: ServiceLocator
never offered "full experience" as compared to Resolver in Sisu, it was missing
the dynamism Sisu offered (for example, it was not extensible). Moreover, ServiceLocator
is deprecated in
latest Resolver releases. Starting with Resolver 1.9.15 it does provides alternative in form of instance supplier.
Still, recent changes in Maven 3.9.x explicitly prevents creation of new RepositorySystem
instances, for
a good reason: if you run within Maven, you have everything "offered on a plate" (just inject it):
you have full environment initialized with user specs and setup. No need to reinvent the wheel.
Maven project never offered one-stop shop solution to use Resolver as a library, as "a whole", a glue that holds things together for most popular use of Resolver: make it usable as it "as in Maven but outside of Maven". MIMA tries to deliver this and go one step beyond: It's goal is to make Resolver easily reusable "as a library", outside of Maven (but still obeying Maven user configuration if needed) but inside of it as well. And to do that in transparent way.
In short, compile and code against context artifact (make it compile
scope in project), this makes
Resolver API available as transitive dependency as well. Next, pick one or more non-conflicting runtime
artifact (make it runtime
scope in project) that will provide implementation(s) at runtime.
"Non-conflicting runtime" means, you should have only one embedded-
and only one standalone-
prefixed runtime
artifact coexisting at classpath, at any time.
Furthermore, as Resolver uses SLF4J for logging, it is your responsibility is to provide a "backend" for logging facade, as MIMA does not pull in any by default.
Complete example of using MIMA in some project intended to be used standalone only:
<dependencies>
...
<!-- context: compile scope -->
<dependency>
<groupId>eu.maveniverse.maven.mima</groupId>
<artifactId>context</artifactId>
<version>${version.mima}</version>
</dependency>
<!-- runtime: runtime scope -->
<dependency>
<groupId>eu.maveniverse.maven.mima.runtime</groupId>
<artifactId>standalone-static</artifactId>
<version>${version.mima}</version>
<scope>runtime</scope>
</dependency>
<!-- logging: runtime scope -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>${version.slf4j}</version>
<scope>runtime</scope>
</dependency>
...
</dependencies>
To demonstrate, an example "demo project" is provided: it contains the "library" artifact, that contains
some business logic that needs Resolver (to calculate classpath for given artifact) and it works as "plain library"
as UTs demonstrate. But, to introduce a twist, this same library is then used as dependency in "library-maven-plugin",
a Maven Plugin that does the same thing by reusing the "library". Here also, Invoker ITs prove that the Mojo works
as expected. The demo
subproject is being tested with Maven 3.9.x and Maven 3.8.x for correct behavior.
MIMA offers several runtime options for several use cases.
To be used when library using MIMA runs within Maven (for example within a Maven Plugin). This runtime has the highest priority.
<dependency>
<groupId>eu.maveniverse.maven.mima.runtime</groupId>
<artifactId>embedded-maven</artifactId>
<version>${version.mima}</version>
<scope>runtime</scope>
</dependency>
To use MIMA from within Maven, this is the only dependency needed. Logging backend is not needed either, it is provided by Maven itself. This runtime activates only when runs within Maven, remains dormant otherwise, and has no transitive dependencies. In case of libraries intended to work in both modes, inside but outside of Maven as well, this dependency may be always present.
To be used when library using MIMA runs standalone. In this case you need to provide backend for SLF4J facade as well.
<dependency>
<groupId>eu.maveniverse.maven.mima.runtime</groupId>
<artifactId>standalone-sisu</artifactId>
<version>${version.mima}</version>
<scope>runtime</scope>
</dependency>
<!-- logging: runtime scope -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>${version.slf4j}</version>
<scope>runtime</scope>
</dependency>
This runtime brings in all dependencies needed for MIMA standalone runtime, and best is to have it in runtine
scope,
is not needed during compile. The runtime uses Eclipse Sisu DI, same engine used
by Maven itself.
This runtime may be used in case you already have an application that is using Sisu for DI as well, like apps using Ollie or alike.
You are also required to provide SLF4J backend.
To be used when library using MIMA runs standalone, and presence of Eclipse Sisu DI (and Google Guice and transitive dependencies like Guava) is unwanted. This runtime has the lowest priority.
<dependency>
<groupId>eu.maveniverse.maven.mima.runtime</groupId>
<artifactId>standalone-static</artifactId>
<version>${version.mima}</version>
<scope>runtime</scope>
</dependency>
<!-- logging: runtime scope -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>${version.slf4j}</version>
<scope>runtime</scope>
</dependency>
This runtime is similar to Resolver's deprecated ServiceLocator
, as it does not use DI but "manually" wires
things up.
You are also required to provide SLF4J backend.
Both standalone runtimes provide -uber
artifacts, that as name implies, are artifacts that contains all the needed
classes shaded (but not relocated) into one JAR and POM modified for dependencies (removed). These artifacts are
added to simplify use of non-trivial transitive dependencies of Resolver.
One big difference exists: -uber
artifacts of standalone runtimes does not include SLF4J API, it is
you (integrator) who should provide binary compatible SLF4J API (baseline is version 1.7.36) and SLF4J backend
at runtime. Required binary compatible SLF4J artifacts at classpath are:
- SLF4J API baseline
- SLF4J jcl-over-slf4j baseline
- SLF4J backend of choice (that is compatible with used SLF4J API)
The jcl-over-slf4j
is required for
Apache HttpClient 4.x logging purposes, as it uses
JCL logging.
When your library executes within Maven, the context you get is actually coming from Maven:
- repositorySystem == provided by Maven
- repositorySystemSession == provided and preconfigured by Maven (w/ all user whistle and bells)
- remoteRepositories == the current project remote repositories
The session and remote repositories (and many other things) can be customized via overrides, but the "with-user-settings" cannot.
When your library runs outside of Maven, the context you get is created "from the scratch", based on initial overrides you provided:
- repositorySystem == provided by (already existing or booted) Sisu DI
- repositorySystemSession == provided by MIMA w/ or w/o user env (see overrides)
- remoteRepositories == "central" or those from overrides
In any case, context is properly set up to support all whistle and bells from latest resolver (working outside of Maven, or from inside of Maven if 3.9.x or later is used with it) like split repository, extensible checksum algorithms, modern transport (and obeys configuration like timeouts or headers, same as Maven would), provided checksums, repository filtering, locking, etc.
MIMA supports all resolver configuration properties from https://maven.apache.org/resolver/configuration.html when runs in standalone mode or embedded in Maven 3.9.x (that provides resolver that supports new features).
Note: overrides are "all or nothing", so for example IF there is a list of remote repositories, they REPLACE current repositories, if any.
- mmr -- adds ability to get Maven models (effective and raw). Use of this extension raises Maven requirement to 3.8.5+!
Buildtime:
- Java LTS (currently 21+)
- Maven 3.9.x
Runtime:
- Java 8+
- Maven 3.8.x+ (if used inside Maven, Maven 3.6.3 is still support but NOT for extensions!)
- Standalone: SLF4J backend (1.7.36 baseline) should be provided.
- Standalone Uber: SLF4J API and backend (1.7.36 baseline) should be provided, and for Apache HttpClient 4.x logging, ideally
jcl-over-slf4j
as well.