Post Thumbnail

Comprehensive Step-by-Step Guide on How to Upload Open Source Java Library to Maven Central

1. Overview

This article is a comprehensive guide on how to deploy a Java library to Maven Central, so everyone can use it by including the dependency in their project(s).

It goes without saying that there has to be a Java library for it to be uploaded. Hence, the first thing is creating a Java library that’s unique, of quality code standard and will be beneficial to the developer community.

In summary, to upload a shiny new Java library to Maven Central, we’ll have to reserve our Group ID, provide the required details in the project’s pom.xml, sign the generated artefacts with GnuPG and, finally, deploy to Sonatype’s Nexus Repository Manager.

2. Reserve a Group ID

Whenever we want to add a new dependency to a Maven project, we add the following entry to the <dependencies> section of a pom.xml file:

1
2
3
4
5
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-api</artifactId>
    <version>5.9.0</version>
</dependency>

The <groupId> and <artifactId> constitute the library’s namespace, also known as coordinate.

The <groupId> is a globally unique identifier, usually derived from reversing the domain name of the developer.

The reason for using a reversed domain name is because a domain name is unique, globally, by itself and connected to a single person or an organization.

If you do not have a domain name, you can use your GitHub username as the <groupId> in the following format: com.github.YourGitHubUserName. For example, consider the javafaker library:

1
2
3
4
5
<dependency>
    <groupId>com.github.javafaker</groupId>
    <artifactId>javafaker</artifactId>
    <version>1.0.2</version>
</dependency>

The <artifactId> is the chosen name for the project. There can be different artifact IDs belonging to a single group ID.

Now, that we’ve learnt about the coordinates, let’s proceed to reserve one for our project on Sonatype.

Let’s create an account on Sonatype JIRA instance here and then log in to create a new project ticket.

Take note of the username/password used here. We will reference it in subsequence sections.

Clicking on the create button at the top of the website will load a modal. Fill in the following details on that modal:

NOTE: In the modal for creating a new project ticket, ensure the Project field is set to Community Support - Open Source Project Repository Hosting (OSSRH) and the Issue Type is New Project.

The creation of the new ticket project will trigger the creation of repositories on Sonatype’s OSS Repository Hosting (OSSRH) that’ll be synced to Maven Central after deploying the artefacts.

It’s important not to deploy until there’s an email confirmation that the issue created has been resolved. If there’s any problem along the line, we can always comment on the issue to get help and/or explanation.

3. Update Project POM

Now that we’ve successfully registered our Group ID, the next thing to do is update the project’s pom.xml with the necessary information.

Let’s start by providing the project’s name, description and URL as well as the coordinates and packaging information:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<groupId>com.smattme</groupId>
<artifactId>mysql-backup4j</artifactId>
<version>1.0.1</version>
<packaging>jar</packaging>

<name>${project.groupId}:${project.artifactId}</name>
<description>
    This is a simple library for backing up mysql databases and sending to emails, cloud storage and so on.
    It also provide a method for programmatically, importing SQL queries generated during the export process,
</description>
<url>https://github.com/SeunMatt/mysql-backup4j</url>

Up next is the license and developers information. In this case, we’ll be using an MIT license. If any other license is used, all that’s needed is a corresponding URL to such license. If it’s an open-source license, there’s a good chance it’s going to be available on opensource.org:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<licenses>
    <license>
        <name>MIT License</name>
        <url>http://www.opensource.org/licenses/mit-license.php</url>
    </license>
</licenses>

<developers>
    <developer>
        <name>Seun Matt</name>
        <email>[email protected]</email>
        <organization>SmattMe</organization>
        <organizationUrl>https://smattme.com</organizationUrl>
    </developer>
</developers>

Another important piece of information required is the source code management (SCM) details:

1
2
3
4
5
<scm>
    <connection>scm:git:git://github.com/SeunMatt/mysql-backup4j.git</connection>
    <developerConnection>scm:git:ssh://github.com:SeunMatt/mysql-backup4j.git</developerConnection>
    <url>https://github.com/SeunMatt/mysql-backup4j/tree/master</url>
</scm>

In this case, the project is hosted on GitHub, thus the reason for the supplied values. Example configurations for other SCMs can be found here

4. Distribution and Plugins Configuration

In this step, we’ll be configuring our project for deployment to the OSSRH using the Apache Maven Plugin. The plugin requires that we add a distributionManagement section to our pom.xml:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<distributionManagement>
    <snapshotRepository>
        <id>ossrh</id>
        <url>https://oss.sonatype.org/content/repositories/snapshots</url>
    </snapshotRepository>
    <repository>
        <id>ossrh</id>
        <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
    </repository>
</distributionManagement>

We need to provide access token credentials for the <snapshotRepository> and <repository>. First, we need to login to https://oss.sonatype.org/ using the same username and password from step one.

Upon logging in, click on your username, located at the top-right corner of the page to navigate to the profile page.

On the profile page, click the Summary drop-down and select User Token. Finally, click the Access User Token to see the username and password to use.

Copy the User Token credentials, navigate to your ~/.m2/settings.xml file and add a new entry for the ossrh server:

1
2
3
4
5
6
7
8
9
<settings>
  <servers>
    <server>
      <id>ossrh</id>
      <username>your-token-username</username>
      <password>your-token-password</password>
    </server>
  </servers>
</settings>

If the settings.xml file does not exist, create one in that same ~/.m2 directory.

Note that the <id> has the same value as that of the <snapshotRepository> and <repository> configured above. This is crucial for the Maven plugins to locate the right credentials in subsequent steps.

The next step to add some Maven plugins: source-code, Javadoc, nexus staging and the GPG plugins. Each of these plugins will be placed within the <plugins> tag that’s inside the <build> tag in the pom.xml.

Deploying a library to OSSRH requires that the source code and JavaDoc of the library be deployed as well. Hence, we’ll add the Maven plugins to achieve that seamlessly:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-javadoc-plugin</artifactId>
    <version>3.0.0</version>
    <executions>
        <execution>
            <id>attach-javadocs</id>
            <goals>
                <goal>jar</goal>
            </goals>
        </execution>
    </executions>
</plugin>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-source-plugin</artifactId>
    <version>3.0.1</version>
    <executions>
        <execution>
            <id>attach-sources</id>
            <goals>
                <goal>jar</goal>
            </goals>
        </execution>
    </executions>
</plugin>

The latest version of the Javadoc and Source code plugins can be found here and here respectively.

Another requirement we need to satisfy is the signing of our artefacts with a GPG/PGP program. For that, we have to install GnuPG on our system.

After installation, we should ensure the bin folder of the GnuPG installation is in the system path and run gpg --version to verify the installation. Note that on some systems gpg2 --version will be used.

Let’s generate a key pair for our system by running the follow command and following the prompts:

1
gpg --gen-key

We can list the keys that are available using:

1
gpg --list-keys

It’s important to follow this guide to ensure the primary key generated is used to sign our files.

Let’s get back to our pom.xml file and add the Maven plugin for the GnuPG program so our files can be automatically signed with the default key we generate during program build:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-gpg-plugin</artifactId>
    <version>1.6</version>
    <executions>
        <execution>
            <id>sign-artifacts</id>
            <phase>verify</phase>
            <goals>
                <goal>sign</goal>
            </goals>
        </execution>
    </executions>
</plugin>

The latest version for the Maven GPG plugin can be found here.

While generating our key pair, we provided a passphrase for it; that passphrase is going to be configured in our .m2/settings.xml file. We can also specify the executable for our GnuPG program - either gpg or gpg2.

Therefore, in the settings.xml file, we’ll add a <profiles> section just after the closing tag for </servers>:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<profiles>
    <profile>
      <id>ossrh</id>
      <activation>
        <activeByDefault>true</activeByDefault>
      </activation>
      <properties>
        <gpg.executable>gpg</gpg.executable>
        <gpg.passphrase>pass-phrase</gpg.passphrase>
      </properties>
    </profile>
  </profiles>

To wrap it all up, we’ll add the Nexus Staging Maven plugin to our pom.xml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<plugin>
    <groupId>org.sonatype.plugins</groupId>
    <artifactId>nexus-staging-maven-plugin</artifactId>
    <version>1.6.8</version>
    <extensions>true</extensions>
    <configuration>
        <serverId>ossrh</serverId>
        <nexusUrl>https://oss.sonatype.org/</nexusUrl>
        <autoReleaseAfterClose>false</autoReleaseAfterClose>
    </configuration>
</plugin>

The latest version of the plugin can be found here. Take note of the <serverId>ossrh</serverId>; You’ll notice the same value ossrh is used in the settings.xml file.

This is important for the plugin to be able to locate the credentials we configured in the <servers> section of settings.xml.

One final note in this section, keep the GPG keys and the passphrase in a safe place. It will always be required for future updates.

Step Four: OSS Deployment

This is the final step. It’s recommended to do some pre-launch checks, so that we do not release a buggy library.

Once the checks are complete, the first step in the deployment is to run the following command:

1
mvn clean deploy

If everything goes well, we’ll see, among the console outputs, the staging repository ID created for the project like this:

1
* Created staging repository with ID "comsmattme-1001".

NOTE: comsmattme is the Group ID we’ve been using in this article as an example.

Let’s log in to https://oss.sonatype.org with the same credentials for the JIRA account created in step one to inspect the artefacts we’ve deployed to staging.

After login, we’ll click on Staging Repositories on the left side menu under the Build Promotion sub-menu. Using the search bar at the top right of the page, we’ll search for the staging repository ID created e.g. comsmattme-1001 in this case.

We should be able to see and inspect the artefacts that were uploaded by the nexus staging Maven plugin. If satisfied with everything, then we can do a release by running this Maven command:

1
mvn nexus-staging:release

Once the release command is executed successfully, it may take up to 2 hours or more for the library to show up on Maven Central.

To search for our library on Maven Central, we’ll supply the following query to the search box: g:com.smattme a:mysql-backup4j where g is the group ID and a is the artefact ID.

5. Conclusion

In this comprehensive article, we’ve walked through the process of deploying our Java library to Maven Central. The complete pom.xml for the example project used in this article can be found here and the settings.xml can be found here as well.

Happy coding!

Seun Matt

Results-driven Engineer, dedicated to building elite teams that consistently achieve business objectives and drive profitability. With over 9 years of experience, spannning different facets of the FinTech space; including digital lending, consumer payment, collections and payment gateway using Java/Spring Boot technologies, PHP and Ruby on Rails