Relocation of Maven Package in Maven Central

During my preparation for a migration from GitHub to Codeberg (I explain my motivation in an own blog post) I find out, that I use still GitHub-related Maven GroupId in one of my pet project (testcontainers-git). So I want to migrate the GitHub-related groupId to a new one. There are others issues that are getting in my way to migrate this project to Codeberg. But these issues are not in focus of this post.

The Problem

In the Java Ecosystem, it is the de-facto standard to host Java libraries in Maven Central. If you need a Java library in your project, you can reference it via a so called Maven coordinate consisting of a triple (groupId, artifactId, version).

If you want to learn more about Apache Maven, please take a look on the article What is Maven?.

Normally, groupId and artifactId stay stable during a life cycle of a library. If you release a new version of your library, you will publish them with the same groupId and artifactId, but with a new version. Thanks to this pattern, the workflow for managing the dependencies of a Java project is simple, some examples:

  • You need a new dependency in your project? Add the coordinate of the dependency to your project. The build tool takes care of the management.
  • You want to know, if a new version of a dependency is published? Look after a new version for the pair (groupId, artifactId).

If you change the groupId or the artifactId during the lifecycle of your library, the workflow for the managing dependencies based on the above pattern is broken.
From the technical point of view, it is a new library. From your point of view, it is the same library, only the coordinates changes.

The Solution

Therefore, we have in this context the concept of relocation. The idea behind it is, that you publish an artifact with the old coordinate that contains a reference to the new coordinate.

The next sections describe how to set up this relocation for

  1. A single module project,
  2. a multi-module project,
  3. in special, if you host your artifacts on Maven Central.

A single module project

A single module project with Maven has a flat directory structure:

1.
2├── pom.xml
3└── src
4    ├── main
5    │   ├── java
6    │   └── resources
7    └── test
8        ├── java
9        └── resources

In the POM file pom.xml, you can define the coordinate of your project:

 1
 2<?xml version="1.0" encoding="UTF-8"?>
 3<project xmlns="http://maven.apache.org/POM/4.0.0"
 4         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 5         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 6    <modelVersion>4.0.0</modelVersion>
 7
 8    <groupId>io.github.sparsick.testcontainers.gitserver</groupId>
 9    <artifactId>testcontainers-git</artifactId>
10    <version>0.15.0</version>
11
12    <!-- more stuff -->
13</project>

In this example, you want to rename the groupId to dev.parsick.testcontainers.gitserver instead of io.github.sparsick.testcontainers.gitserver.

Therefore, you publish your project as you know with the new coordination.

 1
 2<?xml version="1.0" encoding="UTF-8"?>
 3<project xmlns="http://maven.apache.org/POM/4.0.0"
 4         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 5         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 6    <modelVersion>4.0.0</modelVersion>
 7
 8    <groupId>dev.parsick.testcontainers.gitserver</groupId>
 9    <artifactId>testcontainers-git</artifactId>
10    <version>0.16.0</version>
11
12    <!-- more stuff -->
13</project>

In the same time, you publish a POM artifact with the old coordinate, that contains the reference to the new coordinates:

 1
 2
 3<project xmlns="http://maven.apache.org/POM/4.0.0">
 4    <modelVersion>4.0.0</modelVersion>
 5    <groupId>io.github.sparsick.testcontainers.gitserver</groupId>
 6    <artifactId>testcontainers-git</artifactId>
 7    <version>0.16.0</version>
 8
 9
10    <distributionManagement>
11        <relocation>
12            <groupId>dev.parsick.testcontainers.gitserver</groupId>
13        </relocation>
14    </distributionManagement>
15
16</project>

The element distributionManagement contains a relocation element, where you can define the new groupId or the new artifactId. With this information, the user will get the warning, when it updates the dependency to your library, that it is moved to a new coordinate.

1[WARNING] The artifact io.github.sparsick.testcontainers.gitserver:testcontainers-git:jar:0.16.0 has been relocated to dev.parsick.testcontainers.gitserver:testcontainers-git:jar:0.16.0

A multi-module project

With Maven, a multi-module project has the following directory structure:

 1.
 2├── pom.xml
 3├── rewrite-testcontainers-gitserver
 4│   └── pom.xml
 5├── testcontainers-forgejo
 6│   └── pom.xml
 7├── testcontainers-git-bom
 8│   └── pom.xml
 9├── testcontainers-gitea
10│   └── pom.xml
11└── testcontainers-gitserver
12    └── pom.xml

The pom.xml in the root defines the subdirectories that represent a module of this project (in this case, all):

 1<?xml version="1.0" encoding="UTF-8"?>
 2<project xmlns="http://maven.apache.org/POM/4.0.0"
 3         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 5    <modelVersion>4.0.0</modelVersion>
 6
 7    <groupId>io.github.sparsick.testcontainers.gitserver</groupId>
 8    <artifactId>testcontainers-git-parent</artifactId>
 9    <version>0.15.0</version>
10
11    <packaging>pom</packaging>
12
13    <modules>
14        <module>testcontainers-gitserver</module>
15        <module>rewrite-testcontainers-gitserver</module>
16        <module>testcontainers-git-bom</module>
17        <module>testcontainers-forgejo</module>
18        <module>testcontainers-gitea</module>
19    </modules>
20
21 <!-- define other stuff-->
22</project>

The pom.xml in every module (in the following snippet testcontainers-forgejo) has a reference to the so-called parent POM, that is the pom.xml in the root:

 1<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
 2    <modelVersion>4.0.0</modelVersion>
 3
 4    <parent>
 5        <groupId>io.github.sparsick.testcontainers.gitserver</groupId>
 6        <artifactId>testcontainers-git-parent</artifactId>
 7        <version>0.15.0</version>
 8    </parent>
 9
10    <artifactId>testcontainers-forgejo</artifactId>
11    <name>Forgejo Server for Testcontainers</name>
12
13   <!-- define other stuff-->
14</project>

With the parent reference, the module inhernts information from the parent POM, in this case groupId and version.

For the relocation, you have to duplicate the directory structure for the old groupId:

 1relocation
 2├── pom.xml
 3├── rewrite-testcontainers-gitserver
 4│   └── pom.xml
 5├── testcontainers-forgejo
 6│   └── pom.xml
 7├── testcontainers-git-bom
 8│   └── pom.xml
 9├── testcontainers-gitea
10│   └── pom.xml
11└── testcontainers-gitserver
12    └── pom.xml

and add the relocation information in every single pom.xml.

 1<project xmlns="http://maven.apache.org/POM/4.0.0">
 2    <modelVersion>4.0.0</modelVersion>
 3
 4    <parent>
 5        <groupId>io.github.sparsick.testcontainers.gitserver</groupId>
 6        <artifactId>testcontainers-git-parent</artifactId>
 7        <version>0.16.0</version>
 8    </parent>
 9
10    <artifactId>testcontainers-forgejo</artifactId>
11    <name>Forgejo Server for Testcontainers</name>
12
13    <distributionManagement>
14        <relocation>
15            <groupId>dev.parsick.testcontainers.gitserver</groupId>
16        </relocation>
17    </distributionManagement>
18</project>

It is important, that the relocation information is added in every single pom.xml. This information is not inherited by the parent pom reference.

After that, you publish the relocated artifact with the old groupId and the original project with the new groupId in the Maven repository.

Special: Hosting your library in Maven Central

If you are hosting your library in your own Maven repository, then you have learnt everything that you need for a successfull relocation. If you are using Maven Central (and if you publish your Java OSS Library in public, you usually use Maven Central), you have to add some meta information in the relocation root POM.

During the deployment to Maven Central (see also Getting Started Guide), the portal will validate whether meta information exists like:

  • name of the project
  • description of the project
  • license of the project
  • information about issue management
  • information about the developers
  • information about the scm management

This is also needed for the relocation deployment. Therefore, you have to add this information also in the root pom.xml in your relocation structure.