First Project Build
This article demonstrates the very first build with Apache Maven. In this article, we will use command prompt to create our simple Maven project and then use mvn
command to build it.
You can watch the entire demo in this video.
Pre-requisite
You need to have Apache Maven already installed on your system. If you don’t have Maven installed, you can install it by following steps from our previous articles:
You can also watch the videos here.
Creating a Simple Maven Project
In this article, we will create the Maven project from the command prompt using the mvn
command. This basic project scaffolding is done using the maven-archetype-plugin. This plugin the one that is used by the IDEs under the hood to create the Project.
The archetype plugin has a numerous template projects to chose from and also from various sources. If you type simple mvn archetype:generate
, you will be presented with 3500+ various project templates. You can use the filter option to limit the search and chose, but in most cases, it is preferable to use an IDE.
The Archetype plugin works in interactive and non-interactive mode. In the interactive mode, you need to select the project template from which the project should be created and then you need to provide the maven coordinates.
If you already know the archetype, it is advisable to use the non-interactive mode. This is the approach which we will use in this article.
So, fire up a new Terminal window, and run the following command:
mvn archetype:generate \
-DinteractiveMode=false \
-DarchetypeGroupId=org.apache.maven.archetypes \
-DarchetypeArtifactId=maven-archetype-simple \
-DarchetypeVersion=1.5
-DgroupId=io.thedevjournal.maven \
-DartifactId=first-maven-build \
-Dversion=1.0
Info
If you are running this for the very first time, then Maven will download the plugin jars from the Maven central, and you will see those in your console. Don’t worry, these will be just downloaded just once and occasionally when there is a new update to the plugin that is being executed.
The command is a long one, so let us dissect it one at a time.
archetype:generate
This is a goal of archetype plugin that is responsible for generating for the project. Maven’s plugin execution follows this convention plugin:goal
to execute the various executions goals provided by the plugin. A full list of archetype plugin’s goals are listed here.
Because, we need to create a project from a template, we use the generate
goal.
Info
Maven Lifecycle Goals are discussed in this article.
-DinteractiveMode=false
Property arguments to Maven are provided using -D
prefix. In our case, we are providing a property interactiveMode
which is used by archetype plugin. This tells the archetype plugin that it should not prompt the user for any mandatory value that is not provided. It will instead error out mentioning which value was missing.
In the interactive mode, Maven will use the values that you have provided and if any value is missing, it will ask you to provide them on the prompt.
Since, we are providing all the mandatory values as property arguments, we are disabling the interactive mode by interactiveMode=false
.
-DarchetypeGroupId=org.apache.maven.archetypes
This property tells the Archetype plugin to select the groupId
of the archetype that need to be used to create the project. There can be multiple organizations or teams that are creating their own archetypes, and they could clash. The archetypeGroupId
provides the ability to avoid such collisions.
For example, if you type mvn archetype:generate
, and when the plugin is asking you to provide the archetype id or filter option, type maven-archetype-simple
. You will see that there are three archetypes that define the same artifact id. Here is the output.
-> mvn archetype:generate
...
...
3523: remote -> za.co.absa.hyperdrive:component-archetype_2.12 (-)
Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): 2216: maven-archetype-simple
Choose archetype:
1: remote -> com.haoxuer.maven.archetype:maven-archetype-simple (a simple maven archetype)
2: remote -> fr.ebruno.maven.archetypes:maven-archetype-simple (An archetype which contains a simple Maven project.)
3: remote -> org.apache.maven.archetypes:maven-archetype-simple (An archetype which contains a simple Maven project.)
As you can see, the first archetype has archetypeGroupId=com.haoxuer.maven.archetype
, second one has archetypeGroupId=fr.ebruno.maven.archetypes
, and third archetypeGroupId=org.apache.maven.archetypes
. To allow archetype plugin to chose precisely which of this needs to be used, you should specify archetypeGroupId
.
Info
If you don’t specify archetypeGroupId
and there are multiple archetypes, the archetype plugin will use the first one from the list.
-DarchetypeArtifactId=maven-archetype-simple
archetypeArtifactId
tells which project template to be used to create the project. In our case, we will be using maven-archetype-simple
to create our project from.
-DarchetypeVersion=1.5
Even if you have provided archetypeGroupId
and archetypeArtifactId
, it is possible that there are multiple versions. If that is the case, you need to specify the version of the artifact id, which should be used to generate the project. In our case, we will be using Version 1.5
of maven-archetype-simple
to generate our project.
Info
If you don’t specify archetypeVersion
and there are multiple versions, the archetype plugin will use the oldest available version.
-DgroupId=io.thedevjournal.maven.firstbuild
, -DartifactId=first-build
and -Dversion=1.0
groupId, artifactId
and version
together combine to indicate your project’s co-ordinate. Maven co-ordinates is the backbone of the Dependency Management. Just like a GPS Co-ordinate allow you to locate a specific place on a Globe, similarly, a project co-ordinate allows Maven to locate the project in the dependency tree of the root project.
Info
Maven co-ordinates are discussed in great details in this article.
What is inside the generated Project?
Now that the project is created, let us see the files that have been created. A quick run of tree
command shows the following output.
-> tree .
.
├── pom.xml
└── src
├── main
│ └── java
│ └── io
│ └── devjournal
│ └── maven
│ └── firstbuild
│ └── App.java
└── test
└── java
└── io
└── devjournal
└── maven
└── firstbuild
└── AppTest.java
App.java
is a very simple java program printing Hello World!
, and AppTest.java
is a JUnit test class file.
Below are the contents of these files.
package io.devjournal.maven.firstbuild;
/**
* Hello world!
*/
public class App {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
package io.devjournal.maven.firstbuild;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
/**
* Unit test for simple App.
*/
public class AppTest {
/**
* Rigorous Test :-)
*/
@Test
public void shouldAnswerWithTrue() {
assertTrue(true);
}
}
pom.xml
The project object model file, pom.xml
contains the project, its dependencies and details of how to build the project. A detailed explanation of different sections of the POM is covered in this article, but high-level sections are discussed in individual tabs.
<!-- Project's Co-ordinates as provided in the mvn archetype:generate command -->
<groupId>io.devjournal.maven</groupId>
<artifactId>first-maven-build</artifactId>
<version>1.0</version>
<!-- Name of the Project and URL(you should adjust this as indicated) -->
<name>first-maven-build</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<!-- Encoding of Files in the Project -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- Java Compiler Version -->
<maven.compiler.release>17</maven.compiler.release>
</properties>
<!-- Manages dependency versions -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>5.11.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- Dependency 1 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<!-- Dependency 2 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<!-- How to Build the Project -->
<build>
<!-- Which Build Plugins to Use -->
<pluginManagement>
<plugins>
<!-- Build Plugin 1 - maven-clean-plugin-->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.4.0</version>
</plugin>
<!-- Build Plugin 2 - maven-resources-plugin-->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.3.1</version>
</plugin>
<!-- More plugins here -->
</plugins>
</pluginManagement>
</build>
<?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>io.devjournal.maven</groupId>
<artifactId>first-maven-build</artifactId>
<version>1.0</version>
<name>first-maven-build</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.release>17</maven.compiler.release>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>5.11.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<!-- Optionally: parameterized tests support -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.4.0</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.3.1</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.3.0</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.4.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>3.1.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>3.1.2</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.12.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.6.1</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
Building the Project
It has been too much theory. Let us build this project.
Maven build contains of different lifecycle phases, and depending on your requirements, you specify the goals to execute. A typical Maven build consists of two goals - clean package
.
clean
tells Maven to delete the files created from previous builds, while package
tells Maven to compile, test, and package the project.
Info
Maven Lifecycle Phases are discussed in detail in this article.
Here is the output when you run mvn clean package
.
-> mvn clean package
[INFO] Scanning for projects...
[INFO]
[INFO] ---------------< io.devjournal.maven:first-maven-build >----------------
[INFO] Building first-maven-build 1.0
[INFO] from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- clean:3.4.0:clean (default-clean) @ first-maven-build ---
[INFO] Deleting /home/thedevjournal/git/mastering-maven/first-maven-build/target
[INFO]
[INFO] --- resources:3.3.1:resources (default-resources) @ first-maven-build ---
[INFO] skip non existing resourceDirectory /home/thedevjournal/git/mastering-maven/first-maven-build/src/main/resources
[INFO]
[INFO] --- compiler:3.13.0:compile (default-compile) @ first-maven-build ---
[INFO] Recompiling the module because of changed source code.
[INFO] Compiling 1 source file with javac [debug release 17] to target/classes
[INFO]
[INFO] --- resources:3.3.1:testResources (default-testResources) @ first-maven-build ---
[INFO] skip non existing resourceDirectory /home/thedevjournal/git/mastering-maven/first-maven-build/src/test/resources
[INFO]
[INFO] --- compiler:3.13.0:testCompile (default-testCompile) @ first-maven-build ---
[INFO] Recompiling the module because of changed dependency.
[INFO] Compiling 1 source file with javac [debug release 17] to target/test-classes
[INFO]
[INFO] --- surefire:3.3.0:test (default-test) @ first-maven-build ---
[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider
[INFO]
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running io.devjournal.maven.firstbuild.AppTest
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.033 s -- in io.devjournal.maven.firstbuild.AppTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO]
[INFO] --- jar:3.4.2:jar (default-jar) @ first-maven-build ---
[INFO] Building jar: /home/thedevjournal/git/mastering-maven/first-maven-build/target/first-maven-build-1.0.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.511 s
[INFO] Finished at: 2025-02-02T20:10:27+05:30
[INFO] ------------------------------------------------------------------------
Info
If you are running mvn clean package
for the very first time, you will see Maven download a lot of plugin jar files, just like the archetype plugin execution earlier. Every time, there is a new plugin that Maven executes, or an existing plugin for which there is a new updated, Maven will download the new jar files for the first time.
And with that, your first Maven build is complete.