This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Documentation

This site are is “work in progress” and will remain as such for a long time. As our time allows.

This section is where the user documentation for our project lives - all the information You need to understand and successfully use our projects.

1 - Overview

Maveniverse projects are here to help and guide you

All the Maveniverse projects were built with well-defined purpose and goal: to help and guide Apache Maven users.

Maveniverse umbrella started as a “laboratory” for fast-paced prototyping and experimenting, but also to host projects that Apache Maven project felt as inadequate to host at project itself.

The idea of Maveniverse is to serve as “skunk works” around Maven with quick turnaround and prototyping, but at the same provide clear passage for projects from Apache Maven to here, but other way around as well (once community deems project as “mature”). Given most of us are Apache Maven committers, or Apache Maven PMC members, we want Apache Maven to prosper.

2 - Contribution Guidelines

How to contribute

We are open for contributions! All our projects are open, feel free to fork them and provide Pull Requests.

3 - MIMA

Use Resolver everywhere!

Maveniverse MIMA is very first project of ours.

A library that allows you to use Maven Resolver wherever you are.

https://github.com/maveniverse/mima

3.1 - What is it?

Where it all started

Maveniverse MIMA (MIni MAven) is a library that makes you able to use Resolver wherever you are, inside or outside of Maven.

4 - Toolbox

Swiss knife in your pocket

Toolbox was started as a “showcase” project of Maveniverse MIMA combined into Mojos and CLI commands, that never stopped growing.

A tool that gives you Swiss Knife for every situation. Toolbox is a Maven Plugin but also a CLI tool (and a Maven 4 mvnsh extension) that provides useful commands.

https://github.com/maveniverse/toolbox

Maven generated plugin documentation

4.1 - What is it?

A showcase of MIMA + Mojo + Picocli that grew

Maveniverse Toolbox serves manifold purpose.

It is a real tool, that gives you Swiss Knife for every situation. Toolbox is a Maven Plugin but also a CLI tool (and a Maven 4 mvnsh extension) that provides useful commands.

Is also a showcase of Maveniverse MIMA.

Finally, is here to educate or help: the shared module is reusable library that can be easily embedded into Mojo or any standalone application.

5 - Nisse

Inject properties to your build

Nisse was a response to “finish” CI Friendly implementation in Maven 3, but turned out to be more.

An extension that makes things right.

https://github.com/maveniverse/nisse

5.1 - What is it?

A small helper for big tasks

Maveniverse Nisse is a suite of extensions and plugins for Maven 3 and Maven 4. In essence, it provides a set of “property sources” that are injected into your build. For Maven 3 it also redoes the “CI Friendly versioning” feature that is in vanilla Maven 3 incomplete.

6 - BOM Builder Maven Plugin

A tool for generating BOMs

A Maven Plugin for BOMs to build according to your own taste.

A plugin that helps you building BOM by your own taste.

https://github.com/maveniverse/bom-builder-maven-plugin

Maven generated plugin documentation

6.1 - What is it?

A tool for building BOMs

The Maveniverse bom-builder-maven-plugin is a Maven Plugin for generating BOMs. The idea is following: you manage your dependencies “as usual”, and then use the plugin to generate BOM or even multiple BOMs as you like them: reactor only or full bill of materials.

7 - Mason

If you dislike XML

A new project that makes POMs written in YAML, JSON, HOCON and TOML possible with all the whistle and bells.

A Maven 4 sugar:

https://github.com/maveniverse/mason

7.1 - What is it?

If you dislike XML

Maveniverse Mason is a Maven 4 extension that allows you to author POMs in YAML, JSON, HOCON and TOML with all the “whistle and bells” (ie. location tracking).

8 - Mímir

The Maven workstation and LAN cache

Maveniverse Mímir started as solution of my own problem: workstation hopping, and a LOT of download when when picking up where I left on.

A Maven 3/4 extension that offers “global cache” on workstation, and shares cache via LAN to other Mimir running nodes.

Mímir is on Github: https://github.com/maveniverse/mimir

8.1 - What is it?

The Maven workstation and LAN cache

Mímir is a Maven 3 and Maven 4 extension that offers global caching on workstations. More precisely, Mímir is a Resolver 1.x and 2.x extension (is a RepositoryConnector) that is loaded via Maven extensions mechanism and extends Resolver.

As you may know, Maven historically uses “local repository” as mixed bag, to store cached artifacts fetched from remote along with locally build and installed artifacts. Hence, your local repository usually contains both kind of artifacts.

Mímir alleviates this, by introducing a new workstation wide read-through cache (by default in ~/.mimir/local) and placing hardlinks in Maven local repository pointing to Mímir cache entries. This implies several important things:

  • you have separated pure cache, unlike existing local repository, that is a mixed bag on your disk.
  • because of hardlinks, ideally you have only one copy of any cached artifact on your disk (as opposed to as many, as many local repositories you use).
  • is more compatible than “split local repository” as it is in reality “invisible” for Maven and Maven Mojos.

Also some consequences are:

  • you can easily adhere to “best practices” and delete your local repository often, as you still have it all locally (in Mímir caches). You will not lose you precious time by waiting to populate local repository.
  • backup or caching (like in CI case) is simple also: instead of tip-toeing and doing trickery with your local repository, just store and restore Mímir caches instead, you may forget local repository.

Advanced features of Mímir is LAN-wide cache sharing, so if you hop from workstation to workstation on same LAN, you don’t need to pull everything again, as your build will get it from the workstation that already has it. Nowadays with Gigabit LANs combined with modern WiFi networks, doing this is usually faster, than going to Maven Central.

8.2 - Why would I use it?

The Maven workstation and LAN cache

In short: you want to use it for proper local repository maintenance, but it also helps with disk space usage as well, and real workstation wide caching, irrelevant of how many local repositories you use.

Finally, if you workstation-hop a lot (like I do) on same LAN, it makes pretty much sense to pick up on the new workstation where you left off on old workstation.

On CI-like setups it also simplifies caching between jobs, as all you need is to store Mímir cache after job finishes, and on subsequent job runs just restore it.

8.3 - How to use it?

The Maven workstation and LAN cache

Simplest way to use Mímir is with Maven 4, it supports user wide extensions. Just create ~/.m2/extensions.xml with following content (adjust Mímir version as needed):

<?xml version="1.0" encoding="UTF-8"?>
<extensions>
    <extension>
        <groupId>eu.maveniverse.maven.mimir</groupId>
        <artifactId>extension3</artifactId>
        <version>${mimirVersion}</version>
    </extension>
</extensions>

You can add it to your (parent) POM as well, as build extension:

    <extensions>
      <extension>
        <groupId>eu.maveniverse.maven.mimir</groupId>
        <artifactId>extension3</artifactId>
        <version>${mimirVersion}</version>
      </extension>
    </extensions>

Using it with Maven 3 is also possible and completely fine and compatible, but there you will need to set up per-project extensions in .mvn/extensions.xml file instead of one user-wide one.

One extra step is needed, in case you have non-trivial networking (like Docker, Tailscale or alike): you need to “help” a bit to JGroups, to figure out which networking interface belongs to your LAN. To achieve that, you need to create ~/.mimir/daemon.properties file with following content (use your LAN IP address):

mimir.jgroups.interface=match-address\:192.168.1.*

This will help JGroups to properly bind to interface that is used on your LAN.

With these, you are fully set up. Now just go and fire up a Maven or Maven Daemon build.

8.4 - Use case: Maven CI

The Maven workstation and LAN cache

TBD: explain how is Mímir used in Maven GH CI

9 - Njord (Njörðr)

Local staging, Artifact publishing and more!

Njord is an attempt to bring simple “publishing” (new term, is not “deploying with a twist”) to Maven 3 and Maven 4 with some extras like “local staging”.

Maveniverse Njörðr is a tool that makes possible “local staging” (as you may know from MRM), repository operations and publishing repositories.

https://github.com/maveniverse/njord

Maven generated plugin documentation

9.1 - What is it?

Publish where you want (and more)!

Njord is a Maven 3 and Maven 4 extension that offers local staging, repository operations and repository publishing. More precisely, Njord is a Resolver 1.x and 2.x extension (is RepositoryConnector) that is loaded via Maven extensions mechanism and extends Resolver. Njord does not mingle with your build at all.

Njord supports “templates”, that define repository properties. Based on template a repository (“artifact store” in Njord lingo) is created. And those repositories can be merged, redeployed, dropped, validated or published (and more coming). Also, based on chosen template, Resolver is configured to deploy mandatory checksums for you. On the other hand, mandatory signatures are NOT generated, it is you who must provide them as part of your build.

In short, Njord keeps things “as before” (as without it): user never had to worry about checksums (Resolver did generate them always), while the signatures are usually provided by a plugin enabled in “release profile”. Njord goes step forward, and IF user selects any “SCA” template
(“SCA” stands for “Stronger Checksum Algorithms”, see Resolver Checksums) it will configure Resolver, and it will implicitly generate required stronger checksums without any user intervention required.

For now, templates supported out of the box are:

NameModeMandatory ChecksumsMandatoryRedeploy allowed?
releaseRELEASESHA-1, MD5GPG (Sigstore optional)no
release-scaRELEASESHA-512, SHA-256, SHA-1, MD5GPG (Sigstore optional)no
release-redeployRELEASESHA-1, MD5GPG (Sigstore optional)yes
release-redeploy-scaRELEASESHA-512, SHA-256, SHA-1, MD5GPG (Sigstore optional)yes
snapshotSNAPSHOTSHA-1, MD5GPG (Sigstore optional)no
snapshot-scaSNAPSHOTSHA-512, SHA-256, SHA-1, MD5GPG (Sigstore optional)no

The njord: URI

Njord can be considered also as new transport for Maven. It defines the njord: URI prefix and supports several forms:

  • njord: URI is a shorthand for njord:release-sca (default template), see below.
  • njord:<TEMPLATE> is equivalent to njord:template:<TEMPLATE>, see below.
  • njord:template:<TEMPLATE> URI when deployed to, will create new store using given template.
  • njord:store:<STORE> URI when deployed to, will try to deploy to given store that already must exist (will not be created).

Similarly, to use Njord URIs in cases like maven-deploy-plugin parameter for alternate deployment repository, the format accepts id::uri formatted string, so Njord URIs looks like id::njord: or id::njord:template:release-sca with one important detail: the id repository ID is there only to fulfil syntactical requirements, is unused otherwise. Store name will be determined at the moment of creation.

Example URIs:

  • njord: - means “use default template and create a new store” that is release-sca.
  • njord:snapshot - means “use template by name snapshot and create a new store”.
  • njord:store:release-00001 - means “select existing store release-00001 and use that”.

Basically by setting up your POM with distribution release repository using URL njord: and snapshot repository using URL njord:snapshot you are ready to use Njord. But, Njord is not intrusive, you can still use it by doing nothing in your project and just deploying with -DaltDeploymentRepository=id::njord: as well.

Hints:

9.2 - Using it

Using Njord!

Short explanation how to use Njord. It is totally non-invasive, but still you can integrate it as well with your project. To prove it, there is example at end of this page.

There is only one required thing: the extension must be loaded when publishing. Still, the extension is non-invasive, and remains fully dormant, does not interfere with your build at all, merely defines the njord: transport.

Setting it up

Maveniverse Njord is a suite of Maven (core or build; works both ways) extension and a Maven Plugin. You should keep the versions of extension and plugin aligned. Simplest way to achieve this is to:

  • create a property like version.njord in your parent POM carrying Njord version.
  • adding a build/pluginManagement section with Njord plugin and version property.
  • adding a build/extensions section wirh Njord extension and version property.

Depending on your needs, Njord can be defined in parent POMs but can also be “sideloaded” as user or project extension, maybe even only when you are about to publish (so not all the time).

If you want to add Njord to your parent POM, the recommended way is this:

  <properties>
    <version.njord>VERSION</version.njord>
  </properties>

  <build>
    <extensions>
      <extension>
        <groupId>eu.maveniverse.maven.njord</groupId>
        <artifactId>extension3</artifactId>
        <version>${version.njord}</version>
      </extension>
    </extensions>
    <pluginManagement>
      <plugins>
        <plugin>
          <groupId>eu.maveniverse.maven.plugins</groupId>
          <artifactId>njord</artifactId>
          <version>${version.njord}</version>
        </plugin>
      </plugins>
    </pluginManagement>

Alternatively, with Maven 3 create project-wide, or with Maven 4+ create user-wide ~/.m2/extensions.xml like this:

<?xml version="1.0" encoding="UTF-8"?>
<extensions>
    <extension>
        <groupId>eu.maveniverse.maven.njord</groupId>
        <artifactId>extension3</artifactId>
        <version>${currentVersion}</version>
    </extension>
</extensions>

It is recommended (but not mandatory) to add this stanza to your settings.xml as well if you don’t have it already (to not type whole G of plugin):

  <pluginGroups>
    <pluginGroup>eu.maveniverse.maven.plugins</pluginGroup>
  </pluginGroups>

Next, set up authentication. Different publishers require different server, for example the recommended entry for Sonatype Central Portal publishing service is following stanza in your settings.xml (assuming you enabled snapshots on your namespace, and you wish directly to deploy to it, not locally stage them):

  <servers>
    <server>
      <id>sonatype-central-portal</id>
      <username>$TOKEN1</username>
      <password>$TOKEN2</password>
      <configuration>
        <njord.publisher>sonatype-cp</njord.publisher>
        <njord.releaseUrl>njord:template:release-sca</njord.releaseUrl>
      </configuration>
    </server>
  </servers>

Supported publishers are:

Publisher (publisher ID)server.idWhat is needed
Sonatype Central Portal (sonatype-cp)-Obtain tokens for publishing by following this documentation.
Sonatype OSS on https://oss.sonatype.org/ (sonatype-oss)-Obtain tokens for publishing by following this documentation and using OSS instance.
Sonatype S01 on https://s01.oss.sonatype.org/ (sonatype-s01)-As above but using S01 instance.
Apache RAO on https://repository.apache.org/ (apache-rao)apache.releases.httpsAs above but using RAO instance.

Make sure your settings.xml contains token associated with proper server.id corresponding to you publishing service you want to use.

In case you are about to publish a project you cannot alter distribution management for some reason, and assuming Central Portal publishing is enabled for it, just add this stanza in your settings.xml:

     <server>
       <id>the-project-releases</id>
       <configuration>
         <njord.serviceRedirect>sonatype-central-portal</njord.serviceRedirect>
       </configuration>
     </server>

This basically redirects the server “the-project-release” (in POM that you are unable to change) to your defined sonatype-central-portal entry.

That’s all! No project change needed at all.

Using it

Next, let’s see an example of Apache Maven project (I used maven-gpg-plugin):

  1. For example’s sake, I took last release of plugin (hence am simulating release deploy): git checkout maven-gpg-plugin-3.2.7
  2. Deploy it (locally stage): mvn -P apache-release deploy -DaltDeploymentRepository=id::njord: (The id is really unused, is there just to fulfil deploy plugin syntax requirement. The URL njord: will use “default” store template that is RELEASE. You can target other templates by using, and is equivalent of this njord:release. You can stage locally snapshots as well with URL njord:snapshot. Finally, you can target existing store with njord:store:storename-xxx).
  3. Check staged store names: mvn njord:list
  4. Optionally, check locally staged content: mvn njord:list-content -Dstore=release-xxx (use store name from above)
  5. Optionally, validate locally staged content: mvn njord:validate -Ddetails -Dstore=release-xxx (use store name from above)
  6. Publish it to ASF: mvn njord:publish -Dstore=release-xxx -Dtarget=apache-rao (use store name from above)
  7. From now on, the repository is staged on RAO, so you can close it, vote, and on vote pass, release it. All the usual fluff as before.
  8. Drop locally staged store: mvn njord:drop -Dstor=release-xxx (use store name from above)

Check out Maven generated plugin documentation for more mojos.

9.3 - Configuring it

Using Njord!

Njord uses existing Maven infrastructure to get the configuration, still a bit more explanation is needed for some bits.

For start, user interacts with Njord via njord: URI using vanilla Maven plugins like maven-deploy-plugin is, and also using njord-maven-plugin Mojos. All the mojos does not require projects to be run (and are also aggregator Mojos). Still, IF Mojos are invoked with Maven Project present (ie in a checkout where POM is present, and Maven loads it) the Project will be used as “extra contextual source” for some operations.

Njord basedir

By default, Njord uses ~/.njord directory (in user home) directory as basedir. All the stores (locally staged artifacts) are here. This directory may also contain a plain Java properties file njord.properties to define some workstation-wide Njord configuration (usually not needed). The file full path is ~/.njord/njord.properties.

Njord properties

Njord applies following “precedence” rule to calculate effective (configuration) properties:

  • Maven system properties
  • Njord system-wide properties (sourced from ~/.njord/njord.properties)
  • Maven project properties (if present)
  • Maven user properties

This implies, that if you want to define for example njord.dryRun property, you can achieve it in multiple ways: it is possible even to have it in (effective) Project properties set by some profile. But be warned: in this example case, the property will be defined ONLY if you invoke Njord Mojos in this very same project using very same active profiles! Basic Maven stuff.

Of course, the recommended way to set this very property from example is Maven user property like mvn -Dnjord.dryRun ....

Project

Njord Mojos does not require project, and they can be invoked without any. But, in that case all the “heuristics” will be unavailable, and you will need to provide all the required input to Mojos explicitly. For example, assuming you have locally staged myproject-00001, you can still publish it by explicitly configuring publish mojo from a directory where no project exists:

$ mvn njord:publish -Dstore=myproject=00001 -Dpublisher=sonatype-cp

Naturally, your user wide settings.xml should be configured for this: authentication tokens should be set for server sonatype-cp.

When project is present, it implies several things:

First, “prefix” is known (top level project artifactId), in this example case, it would be myproject. When prefix is known, Njord will use simple heuristics, and will implicitly use last (newest) store prefixed with this prefix (so if you have myproject-00001 and myproject-00002 the latter would be selected).

Second, if project is present, and if distributionManagement is configured (usually is for projects being deployed), then Njord can deduce the publisher using the server.id from POM and the server configuration present in your settings.xml.

9.4 - Migrating projects

Using Njord!

Here will try to explain required steps to migrate your project to Njord. Assuming Maven basic knowledge, and some experience about existing publishing to Central, using phased out services like Sonatype OSS or Sonatype S01 are. Also, assuming you do have a project already, set up and probably published used via these legacy services.

Setup your namespace on Sonatype portal

Not much to say here, just follow the guide. Do not forget to enable SNAPSHOTS for namespace, if you intend to use them.

Edit your settings.xml and add your tokens to it. One of the main goals of Njord is to prevent copy-pasta happening in your Maven Settings. Users publishing one namespace may not experience this, but users publishing multiple namespaces are currently forced to copy-paste their auth tokens, as each project usually “invent” their own distribution management server IDs (exception is ASF, where ASF parent POM contains “well known” server ID).

Hence, Njord recommend to name and store your tokens only once in your Maven Settings (this example is for Sonatype Central Portal):

    <server>
      <id>sonatype-central-portal</id>
      <username>$TOKEN1</username>
      <password>$TOKEN2</password>
    </server>

Next, we will add a bit of Njord configuration: what publisher we want to use with this server, and what templates. Edit the server entry above to contain something like this:

    <server>
      <id>sonatype-central-portal</id>
      <username>$TOKEN1</username>
      <password>$TOKEN2</password>
      <configuration>
        <!-- Sonatype Central Portal publisher -->
        <njord.publisher>sonatype-cp</njord.publisher>
        <!-- Releases are staged locally (if omitted, would go directly to URL as per POM) -->
        <njord.releaseUrl>njord:template:release-sca</njord.releaseUrl>
        <!-- Only if you want snapshots locally staged (if omitted, would go directly to URL as per POM) -->
        <njord.snapshotUrl>njord:template:snapshot-sca</njord.snapshotUrl>
      </configuration>
    </server>

One more nit, for simplicity sake:

  <pluginGroups>
    <pluginGroup>eu.maveniverse.maven.plugins</pluginGroup>
  </pluginGroups>

To not have to type plugin G on each invocation (this is not mandatory, but makes life easier).

And that’s it! Your settings.xml now contains auth for Sonatype Central Portal, and also tells Njord which publisher to use with this server (it is sonatype-cp), and which templates to use.

Note: if you want to use Central Portal Snapshots feature, then don’t forget to first enable these on Portal Web UI. Next, in that case you can remove the njord.snapshotUrl element, and enjoy “direct deploy” (so Njord does not meddle, or stage snapshots). Maven will go directly for Central Portal Snapshot endpoint. Any service that supports SNAPSHOT deploy and accepts maven-deploy-plugin deploy requests may be left without njord.snapshotUrl configuration as in that case that good old deploy plugin can do the job as well, no Njord needed.

Setup your project

As your project was already published to Central, the POM may contain distribution management like this:

  <distributionManagement>
    <snapshotRepository>
      <id>myproject-snapshots</id>
      <name>My Project Snapshots</name>
      <url>https://oss.sonatype.org/content/repositories/snapshots/</url>
    </snapshotRepository>
    <repository>
      <id>myproject-releases</id>
      <name>My Project Releases</name>
      <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
    </repository>
  </distributionManagement>

You do not have to change anything!. But, it is worth to change it. For start, the URLs for releases here are “fake”, and some tools like SBOM engines cannot use them as intended, as the URL is not “where artifacts are published”, it is “service used to publish” instead. It is recommended to change this POM section into something like this:

  <distributionManagement>
    <snapshotRepository>
      <id>sonatype-central-portal</id>
      <name>My Project Snapshots</name>
      <url>https://central.sonatype.com/repository/maven-snapshots</url>
    </snapshotRepository>
    <repository>
      <id>sonatype-central-portal</id>
      <name>My Project Releases</name>
      <url>https://repo.maven.apache.org/maven2</url>
    </repository>
</distributionManagement>

Yes, you see it right: POM now says the truth: “we publish to Central” and “we use Sonatype Central Portal” service. Also, there is no need to distinguish server for “release” and “snapshot”.

Finally, IF you have some existing plugin that did the job before, just remove, and undo all the hoops and loops that the plugin or tool required (like adding some properties, profiles, whatnot).

And you are done!

Extension

Finally, you need to make sure that Njord extension is loaded as extension. Ideally as POM project/build/extensions:

    <properties>
      <version.njord>VERSION</version.njord>
    </properties>

    <build>
    <extensions>
      <extension>
        <groupId>eu.maveniverse.maven.njord</groupId>
        <artifactId>extension3</artifactId>
        <version>${version.njord}</version>
      </extension>
    </extensions>
    <pluginManagement>
      <plugins>
        <plugin>
          <groupId>eu.maveniverse.maven.plugins</groupId>
          <artifactId>njord</artifactId>
          <version>${version.njord}</version>
        </plugin>
      </plugins>
    </pluginManagement>

But you can do it as core extension, in .mvn/extensions.xml or Maven 4 user wide ~/.m2/extensions.xml:

<?xml version="1.0" encoding="UTF-8"?>
<extensions>
    <extension>
        <groupId>eu.maveniverse.maven.njord</groupId>
        <artifactId>extension3</artifactId>
        <version>VERSION</version>
    </extension>
</extensions>

Summary

To get summary, invoke mvn njord:status.

Note: this line above will work for you as-is IF you added pluginGroup to your settings.xml.

It will tell you all publishing related information about your project, even is the auth present or not (ie you may have a typo in server.id in POM or your settings.xml).

With this setup as above, one should see output like this (example is from BOM builder plugin), with added right hand “annotated explanations”:

[cstamas@angeleyes bom-builder-maven-plugin (master)]$ mvn njord:status
[INFO] Scanning for projects...
[INFO] Njord 0.6.0 session created
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO] 
[INFO] eu.maveniverse.maven.bom-builder:bom-builder                       [pom]
[INFO] eu.maveniverse.maven.plugins:bom-builder3                 [maven-plugin]
[INFO] eu.maveniverse.maven.bom-builder:it3                               [pom]
[INFO] 
[INFO] ------------< eu.maveniverse.maven.bom-builder:bom-builder >------------
[INFO] Building eu.maveniverse.maven.bom-builder:bom-builder 1.1.1-SNAPSHOT [1/3]
[INFO]   from pom.xml
[INFO] --------------------------------[ pom ]---------------------------------
[INFO] 
[INFO] --- njord:0.6.0:status (default-cli) @ bom-builder ---
[INFO] Project deployment:
[INFO]   Store prefix: bom-builder  <------------------------------------------------ store prefix, build-builder-00001, etc
[INFO] * Release
[INFO]   Repository Id: sonatype-central-portal
[INFO]   Repository Auth: Present  <------------------------------------------------- auth is present
[INFO]   POM URL: https://repo.maven.apache.org/maven2/  <--------------------------- POM "truth", once published, artifacts are here
[INFO]   Effective URL: njord:template:release-sca  <-------------------------------- The Njord URL we use when deploy releases
[INFO] - release-sca  <-------------------------------------------------------------- The template we set, detailed
[INFO]     Default prefix: 'bom-builder'
[INFO]     Allow redeploy: false
[INFO]     Checksum Factories: [SHA-512, SHA-256, SHA-1, MD5]
[INFO]     Omit checksums for: [.asc, .sigstore, .sigstore.json]
[INFO] * Snapshot
[INFO]   Repository Id: sonatype-central-portal
[INFO]   Repository Auth: Present
[INFO]   POM URL: https://central.sonatype.com/repository/maven-snapshots/  <-------- Snapshots do not use Njord, mvn deploy deploys directly Portal
[INFO] 
[INFO] No candidate artifact stores found  <----------------------------------------- Nothing has been locally staged yet
[INFO] 
[INFO] Project publishing:
[INFO] - 'sonatype-cp' -> Publishes to Sonatype Central Portal  <-------------------- The publishing service we set, detailed
[INFO]   Checksums:
[INFO]     Mandatory: SHA-1, MD5
[INFO]     Supported: SHA-512, SHA-256
[INFO]   Signatures:
[INFO]     Mandatory: GPG
[INFO]     Supported: Sigstore
[INFO]   Published artifacts will be available from:
[INFO]     RELEASES:  central @ https://repo.maven.apache.org/maven2/
[INFO]     SNAPSHOTS: sonatype-central-portal @ https://central.sonatype.com/repository/maven-snapshots
[INFO]   Service endpoints:
[INFO]     RELEASES:  sonatype-central-portal @ https://central.sonatype.com/api/v1/publisher/upload
[INFO]     SNAPSHOTS: sonatype-central-portal @ https://central.sonatype.com/repository/maven-snapshots
[INFO] 
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary for eu.maveniverse.maven.bom-builder:bom-builder 1.1.1-SNAPSHOT:
[INFO] 
[INFO] eu.maveniverse.maven.bom-builder:bom-builder ....... SUCCESS [  0.037 s]
[INFO] eu.maveniverse.maven.plugins:bom-builder3 .......... SKIPPED
[INFO] eu.maveniverse.maven.bom-builder:it3 ............... SKIPPED
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.329 s
[INFO] Finished at: 2025-05-24T22:49:03+02:00
[INFO] ------------------------------------------------------------------------
[INFO] Njord session closed
[cstamas@angeleyes bom-builder-maven-plugin (master)]$ 

Publish it!

With this setup, you just perform mvn deploy as you did before. If your checkout is snapshot, you will deploy to Central Portal Snapshots. If your checkout is a release, it will be locally staged once Maven finishes.

To publish, just use mvn njord:publish, or just do mvn deploy -Dnjord.autoPublish.

Once Maven returns, your project is being validated at https://central.sonatype.com/publishing

Check out Maven generated plugin documentation for more mojos.

What if don’t want (or cannot) change the POM?

In this case Njord can still be used, but the “inconvenience” is that you need to hand over all info to Njord.

The maven user settings change is mandatory, you need to have tokens set in your settings.xml.

The presence of Njord extension is mandatory as well, You can load it as user-wide extension (~/m2/extensions.xml) if you use Maven 4 or you can create (or edit if exists) project .mvn/extensions.xml.

Below I assume you work with a release checkout (ie you checked out a tag, also the “release profile” in this example follow ASF convention):

$ mvn -P apache-release deploy \                                                     1)
         -DaltDeploymentRepository=id::njord: \                                      2)
         -Dnjord.autoPublish \                                                       3)
         -Dnjord.publisher=sonatype-cp \                                             4)
         -Dnjord.publisher.sonatype-cp.releaseRepositoryId=sonatype-central-portal   5)

So what happens here? We invoke “deploy for release” (1), but using “alternate deployment repository” (2), that will create an artifact store from default template. Note that id::url form is standard format accepted by maven-deploy-plugin but the id is in fact unused, as store ID will be known only after it is created. At session end (3) the created store with deployed artifacts will be published, using specified publisher service (4) and auth material from specified server (5) in user settings.xml.

10 - Zippy

Small extension for ZIP files

Zippy is small extension for simpler working with ZIP files.

Makes living with ZIPs simpler.

https://github.com/maveniverse/zippy

10.1 - What is it?

Embrace ZIPs

By Java spec, classpath may contain JARs, ZIPs and directories (with .class files). Maven is “not conformant” in this respect, as while it adds JAR dependencies to classpath, ZIPs are not added.

Zippy helps here.

Zippy extension provides:

  • Dependency type zip-classpath, similar to type=zip, but ZIP declared with this type is added to classpath.
  • Dependency type zip, that by default makes Maven behave same as before. But, IF you define Java System Property maveniverse.zippy.zip.classpath=true, then all dependencies of type=zip will be added to classpath. Not recommended for new projects, this is more like a hack.
  • Packaging zip, where one can create POM with <packaging>zip</packaging> and unfiltered (and filtered if configured as usual) resources from project will be just zipped up as main artifact.

To use it, just add following bits to your project .mvn/extensions.xml:

<?xml version="1.0" encoding="UTF-8"?>
<extensions>
    <extension>
        <groupId>eu.maveniverse.maven.zippy</groupId>
        <artifactId>extension3</artifactId>
        <version>${version.zippy}</version>
    </extension>
</extensions>

Naturally, this extension applies locally to project only, so it will modify ZIP file handling in situ only.

You can still produce libraries and JARs for downstream consumption that expect same behaviour, but then your consumers must use Zippy as well.

11 - Heimdall (Heimdallr)

Filtering at next level!

Heimdall enhances Maven Remote Repository Filtering (RRF) feature tremendously. The RRF feature is present in Apache Maven since 3.9.0 release.

Maveniverse Heimdall hooks into Resolver and enhances filtering the remote repositories.

Sources: https://github.com/maveniverse/heimdall

The main differences from “vanilla” RRF are:

  • Prefix files does not have to be checked in with sources, is automatically discovered, fetched and cached for you
  • Group files got enhancements, and are much more expressive and powerful.

Just by loading the extension, prefix filter will auto-activate itself and will fetch and cache (according Maven update policies) the prefix files for you. This immediately means that remote repositories that offer prefix files (like Central, ASF forge, Eclipse forge, etc) will not be asked by your build to deliver files they don’t have, this is “win-win” for both parties: your build is faster (no need to wait for HTTP 404s) and target repo is relieved of sending 404s for stuff not there.

If you configure group filters as well, you can fully control which Maven Artifact groupIDs are allowed (or not) to come from given remote repository, making your build even faster by making Maven knowledgeable where to get stuff from.

The IT included is based on “oldie” RRF demo, but Heimdall will of course happily work with “vanilla” RRF as well.

Note: using Resolver filters (thet need to be explicitly enabled) along with Heimdall is not recommended.

11.1 - How to use it?

Filtering at next level!

Simplest way to use Heimdall is using it as build extension: Just create a file .mvn/extensions.xml in your project (or add it if you already have this file):

<?xml version="1.0" encoding="UTF-8"?>
<extensions>
    <extension>
        <groupId>eu.maveniverse.maven.heimdall</groupId>
        <artifactId>extension3</artifactId>
        <version>${heimdallVersion}</version>
    </extension>
</extensions>

With this one step, you are fully set up and protected from generating 404s on remote repositories if they publish prefix files (those not publishing will be used “as before”). Now just go and fire up a Maven or Maven Daemon build.

When you added this extension, prefix filter will auto activate and pull/cache prefix files it founds, and will use them (functionality from this point on is equal to the Apache Maven RRF, with difference that you do not have to check in potentially huge prefixes file to your source).

Prefix filtering

Prefix filtering does not require much user intervention: it makes use of remote repository published prefix files.

Examples of those are:

When Heimdall discovers these files, it will pull them and cache (applying all the Maven caching policies) and use them for their origin repositories.

In short, “prefix file” contains path prefix entries per one line. Those are NOT Maven coordinates! Prefix files can be 2, 3 or more path segments deep (usually are 2).

Maven will never ask a remote repository with prefix file for an artifact known to not be there.

For example, take Eclipse Tycho repository above: its prefix file contains one notable entry: org/eclipse. This tells Maven that the repo has artifacts which path starts with org/eclipse/.... Having this information, Maven will never go and reach Tycho repository in relation of any org.apache artifact, for example.

Prefix file is not about “it is 100% here” type of information, in fact, it is the opposite: it is telling “it is 100% not here”. By not having artifact layout path segments listed here, repository states “do not bother coming to me”.

Maven groupId filtering

If you’re using other remote repositories, not only Maven Central, this may come very handy!

While prefix filtering is about paths, group ID filtering is about Maven group IDs.

You can “fine-tune” group filtering per project level, or globally (user wide). To tune group filtering on project level, few steps more is needed. First, tell Heimdall where the group filter file configurations are:

Create .mvn/maven.config (or add to, if already exist) following entry:

-Dheimdall.groupId.basedir=${session.rootDirectory}/.mvn/rrf/

This will make Heimdall to look for group filter configurations in this repository (it is top level .mvn/rrf). Next, create filter rules/configurations. You build may contain other remote repository definitions, or even more, your dependency may pull in POM that defines one, making Maven “wander off”. To figure out all remote repositories in play on your build, run this command:

$ mvn toolbox:list-repositories

This will list all the repositories considered to pull dependencies. Now that you know the list of repositories, you can simply prepare filters as well: each file has path like this:

.mvn/rrf/groupId-${repositoryId}.txt

If the file is matched with remote repository ID, it is loaded up and used. For repositories not having matched file, no groupId filtering happens.

Contents of the file list Maven groupIDs with some extra information, examples below (numbering should NOT be in file, is just for reference):

com.atlassian         (1)
=com.atlassian        (2)
!com.atlassian.foo    (3)
!=com.atlassian.foo   (4)

Legend:

  • First line means: allow groupId com.atlassian and all below (so, com.atlassian.foo as well etc).
  • Second line means: allow groupIdcom.atlassian exactly and only and nothing below.
  • Third line means: disallow groupId com.atlassian.foo and all below.
  • Fourth line means: disallow groupId com.atlassian.foo exactly and only.

12 - DOMTrip

The lossless XML editing library for Java

Round-trip editing is a programmatic changing/editing an XML document, like for example a Maven POM is, while preserving all the formatting of the original document.

Maveniverse DOMTrip is in works.

Sources: https://github.com/maveniverse/domtrip

Site: https://maveniverse.github.io/domtrip/