When a Java developer hears Maven they probably think of the popular build tool. But there’s another side to Maven: a vital repository system serving up dependencies needed to build Java applications.
In this article you’ll discover why the Maven repository system is so important and how to use it effectively in your own project.
In today’s world of cheap cloud storage a repository might not sound like anything special, but the Maven repository format was designed pre-AWS to store all kinds of libraries loved by Java developers. And it’s still in use today.
These libraries are stored as jar file artifacts, and can be pulled as dependencies into:
- Maven builds
- Gradle builds
- SBT builds
- and even Ant builds
Whatever your choice of build tool, the code from the library becomes available from within your application code so you don’t have to reinvent the wheel.
The Before Maven period
History can roughly be divided into two periods. There is the painful pre-2004 Before Maven period and the mostly happy post-2004 After Maven period.
Before Maven most Java engineers were using the Ant build tool, and storing any required libraries in the version control system.
Yes, every single library and transitive dependency was downloaded and stored in the project along with the source code! 😲
Better dependency handling with Maven
When Jason van Zyl built Maven, part of the Apache Software Foundation, he included a ground-breaking new system for downloading artifacts from a remote repository.
On the opposite side Maven also included a way to publish to a repository in a custom format. This format made it easy for consumers to fetch any transitive dependencies.
The first Maven repository is what’s known today as Maven Central. It’s a community-lead repository that anyone’s free to publish artifacts to.
By pulling dependencies from a central location you not only save on version control storage space, but it also means dependencies can be managed more effectively from your build tool.
To understand how all this works, let’s get into some implementation details of the Maven repository system.
The Maven repository format
To build an application using the Maven build tool requires a pom.xml file (stands for Project Object Model). It contains an essential group id, artifact id, and version, known as the coordinates of the project.
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.tomgregory</groupId>
<artifactId>maven-demo</artifactId>
<version>1.0-SNAPSHOT</version>
...
</project>
When the Maven build tool builds a project, generates a jar file, and publishes it to a remote Maven repository, the coordinates are used to calculate the jar file URL.
For example, here’s how the URL looks for the Apache commons-lang3 artifact within the Maven Central repository.
https://repo1.maven.org/maven2/org/apache/commons/commons-lang3/3.12.0/commons-lang3-3.12.0.jar
It consists of a:
- repository prefix https://repo1.maven.org/maven2
- group id org/apache/commons
- artifact id commons-lang3
- version 3.12.0
- file name commons-lang3-3.12.0.jar
If we browse the directory containing the jar file, we see other files have also been published.
For example, there’s the commons-lang3-3.12.0.pom XML file which importantly contains a list of dependencies of this artifact.
That means when a build tool downloads this artifact, it can also download transitive dependencies at the same time. We’ll get into that shortly with a worked example in Maven and Gradle.
Now that you understand the Maven repository format, let’s learn about Maven Central in more detail.
Maven Central: the home of open source Java
Maven Central is a repository hosted at https://repo1.maven.org/maven2 containing over 8 million artifacts.
The maven2 in the URL refers to Maven version 2 released in 2005. Even though version 3 of the Maven build tool was released in 2010, it still uses the repository version 2. If you think this is a confusing naming convention, I completely agree!
But the other confusing thing is that the Maven Central repository is actually operated by a company called Sonatype. You might know them just from the strange name or from their popular repository tool Nexus, which stores private artifacts in the Maven repository format.
Searching artifacts in Maven Central
If you go to https://search.maven.org you can search for any library you like, see all available versions, see the transitive dependencies of a particular version, and view the directory structure as seen earlier.
An alternative way to search Maven artifacts is at https://mvnrepository.com.
This is a search engine which not only indexes Maven Central, but other repositories too. If we search for the same artifact here we get similar information, but I think it’s easier to browse transitive dependencies through this site.
The site also gives you the actual code needed to depend on an artifact in a variety of build tools.
Let’s see how this looks for Maven and Gradle.
Add a dependency in Maven
So with Maven I can copy the XML snippet provided by mvnrepository.com and paste it into my pom.xml file.
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
...
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.6.4</version>
</dependency>
</dependencies>
</project>
When I run mvn package
to build this project, Maven will:
- download the artifact from Maven Central if it doesn’t already exist locally
- download any transitive dependencies of the artifact
- add the artifacts to the Java compile classpath
Within the IDE my code now has access to code from the spring-boot-starter-web library, and its dependencies. Nice!
Add a dependency in Gradle
For Gradle, it’s just a one line code snippet, which I paste into the Gradle build script.
plugins {
id 'java'
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web:2.6.4'
}
Running ./gradlew build
also causes the artifact and its transitive dependencies to be downloaded and added to the compile classpath.
Your personal private Maven repository
But what happens when you don’t want anyone else seeing your precious code in your published artifact?
Well, you need to use a private repository. There are several options, including:
- Sonartype’s Nexus
- Artifactory
- AWS CodeArtifact
CodeArtifact is my favourite. It’s a fully managed AWS service, so you can just click a button to create a repository and start publishing to it.
CodeArtifact provides instructions for publishing to and depending on your private repository in a variety of build tools, including Maven and Gradle.
Here’s how to setup publishing in Gradle’s Groovy build script.
...
publishing {
publications {
mavenJava(MavenPublication) {
groupId = '<groupId>'
artifactId = '<artifactId>'
version = '<version>'
from components.java
}
}
repositories {
maven {
url '<your-private-repo-url>'
credentials {
username "aws"
password System.env.CODEARTIFACT\_AUTH\_TOKEN
}
}
}
}
With this in place, when I run ./gradlew publish
I end up with an artifact in my private repository using the Maven format.
That artifact can then be used in whatever Java projects I like by referencing the private repository in the Gradle build script.
...
repositories {
maven {
url '<your-private-repo-url>'
credentials {
username "aws"
password System.env.CODEARTIFACT\_AUTH\_TOKEN
}
}
}
Then adding an appropriate dependency.
...
dependencies {
implementation '<groupId>:<artifactId>:<version>'
}
Final thoughts
That was an overview of the Maven repository system. I hope you can now see Maven as more than just a build tool.
As mentioned, Maven repositories are essential for building Java projects with Gradle. If you want to get started with Gradle or just understand the fundamentals, check out this awesome course. 👇
Stop reading Gradle articles like these
This article helps you fix a specific problem, but it doesn't teach you the Gradle fundamentals you need to actually help your team succeed.
Instead, follow a step-by-step process that makes getting started with Gradle easy.