This tutorial describes the usage and the core concepts of using Maven for building Java applications.

1. What is Apache Maven?

Apache Maven is an powerful build tool primary for Java software projects. It is implemented in Java which makes it platform-independent.

Build tools performs the compilation, testing, packaging and deployment of the final product. The advantages of performing these steps automatically instead of a human performing these steps is that the build is reproducible, faster and less error prone.

Maven can also perform related activities, e.g., create web sites, upload build results or generate reports.

Maven also supports the creation of the initial folder structure for applications to make it easy to get started.

The key features of Maven are:

  • Convention over configuration: avoid as much configuration as possible, by choosing real world default values and supplying project templates (archtypes).

  • Dependency management: support the definition and usage of dependencies to other libraries and projects. During the build, the Maven build system resolves the dependencies and it also builds the dependent projects if needed.

  • Extensible via plug-ins: The Maven build system is extensible via plug-ins, which allows to keep the Maven core small. The Maven core does for example not know how to compile Java source code, this is handled by the compiler plug-in.

The dependencies can be sourced from the local file system, from the Internet or public repositories. Maven Central is an open repository for Java libraries, which is used by default to search for required libraries. The local repository is found in the .m2/repository folder of the user’s home directory, Maven uses this directory to cache downloaded artifacts.

2. How to use this Maven tutorial

This tutorial covers the core concepts of the Maven build tool.

If you do not care about understanding the underlying technology, just ensure you installed the command line tooling and jump to Maven examples.

You may want to primary use an IDE for Maven. Modern IDEs contain great support for Maven, e.g. the Eclipse IDE support. This tutorial covers the command line usage and a deeper understanding of Maven itself, if you more interested in using the Maven tooling from the IDE, please see the Maven with Eclipse tutorial.

3. Installing Maven

To run a Maven build from the command line / terminal, you need to install the Maven command line tooling. To test if you have Maven already installed, type the following command into your command line:

mvn -version

If you see output which includes Apache Maven you already have Maven installed and can skip this section.

3.1. Requirements

You need to have a Java SDK installed and and set the JAVA_HOME environment variable to point to a valid Java SDK.

Downloading and installing Maven on Windows and Mac

For a manual installation you can download Maven from the Maven Download page. Extract the downloaded distribution to a selected folder on your computer and add the M2_HOME environment pointing to this directory. Add M2_HOME/bin to your path variable.

See Official Maven installation for a detailed installation guide.

Downloading and installing Maven on Ubuntu

For Linux most distributions include Maven into their main repositories. On Ubuntu you can use the following command on the command line to install it.

sudo apt-get install mvn
# if that does not work, try
sudo apt-get install maven

3.2. Validate installation

To validate that Maven was correctly installed, open a console and use the following command:

mvn -version

You should receive as output feedback which version of Maven you have installed. It also includes the used Java version.

Maven home: /home/vogella/.sdkman/candidates/maven/current
Java version: 21, vendor: Eclipse Adoptium, runtime: /home/vogella/.sdkman/candidates/java/21-tem
Default locale: en_US, platform encoding: UTF-8
OS name: "linux", version: "6.2.0-36-generic", arch: "amd64", family: "unix"

3.3. Optional: Code completion for bash shells

The bash shell is the default shell on Linux.

See https://github.com/juven/maven-bash-completion for a bash shell extension for the command line to have code completion for Maven commands. This should also work with the git bash von Windows.

3.4. Proxy settings

To configure you proxy, add a file named .m2/settings.xml to your user home with the proxy settings, similar to the following:

<settings>
  <proxies>
   <proxy>
      <id>example-proxy</id>
      <active>true</active>
      <protocol>http</protocol>
      <host>proxy.example.com</host>
      <port>8080</port>
      <username>proxyuser</username>
      <password>somepassword</password>
      <nonProxyHosts>www.google.com|*.example.com</nonProxyHosts>
    </proxy>
  </proxies>
</settings>

User and password is only required if you proxy request base authentication.

4. Core concepts of Maven

By default, the configuration of a Maven project is done via at least one pom.xml configuration file. This name pom file is derived from the term Project Object Model.

Maven uses a declarative style of describing the build, i.e., you describe what should be build not how it is build. This allows Maven to use default for performing the build steps.

The pom file defines:

  • identifiers for the project to be build

  • properties relevant for build configuration

  • plugins which provide functionality for the build via a build section.

  • library and project dependencies via the dependencies section

Each project has its own pom file. You can configure Maven to build one project or multiple projects. A multi project typically defines a pom file in the root of the directory and lists the individual projects in a modules section.

The result of a build is called artifact and can be, for example, an executable JAR file or zip file.

A minimal pom file for a single project is listed in following snippet. This project does not define any properties, dependencies nor any additional plugins.

<?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>                    (1)

  <groupId>com.vogella.maven.first</groupId>            (2)
  <artifactId>com.vogella.maven.first</artifactId>      (3)
  <version>1.0-SNAPSHOT</version>                       (4)

  <name>com.vogella.maven.first</name>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>11</maven.compiler.source>   (5)
    <maven.compiler.target>11</maven.compiler.target>   (5)
  </properties>

</project>
1 4.0.0 is the latest version of the pom file structure, usable for Maven 2.x or 3.x
2 Unique identifier of the organization or the project
3 Name of the project which is built
4 Defines the currently version of the project
5 Set Java compiler level for the Java project

The groupId, artifactId and version attributes are further explained in the next section. For a full reference of possible entries in the pom file, see Maven pom reference.

4.1. Project identifiers via the group, artifact and version (GAV)

A Maven project uses the groupId, artifactId, version (also knows as GAV) and the packaging property to uniquely identify a Maven component. These attributes are explained in the following table.

Table 1. Coordinate attributes
Name Description

groupId

Defines a unique base name of the organization or group that created the project. This is normally a reverse domain name or the name of an open source project. For the generation of new projects, the groupId also defines the package of the main class.

artifactId

Defines the unique name of the project within the groupId. If you generate a new project via Maven this is also used as root folder for the project.

version

This defines the version of the project. If a new version of the project is build, this version should change so that consumers can see that a different version is used.

packaging

Defines the packaging method. This could be e.g. a jar, war or ear file. If the packaging type is pom, Maven does not create anything for this project, it is just meta-data.

For example, you can use the GAV to specific which exact version of a library you want ot use.

The full Maven coordinates are often written in the following format: groupId:artifactId:packaging:version.

4.2. Parent pom and effective pom

Each pom file inherits from a parent (super) pom. If no explicit parent pom is defined it inherits from the base pom of Maven.

Maven always executes against an effective pom. This is a combination of settings from this project’s pom.xml, all parent pom, a super-pom defined within Maven, user-defined settings, and active profiles.

To see the effective pom, use the following command:

mvn help:effective-pom

4.3. Dependencies

4.3.1. Maven repositories and dependency resolution

A repository is a collection of libraries and project artifacts stored in a directory structure similar to the Maven coordinates of the project.

During the initial phase of a build Maven validates, if you have the specified version of all required artifact dependencies and Maven plug-ins. If required, it retrieves them from a Maven repository.

If necessary, Maven downloads these artifacts and plug-ins into a local repository. The default local repository is located in the home directory of the user in the .m2/repository folder. If an artifact or a plug-in is available in the local repository, Maven uses it for the build to avoid unnecessary network traffic.

Maven uses a default remote repository location (http://repo1.maven.org/maven2) from which it downloads the core Maven plugins and dependencies. You can configure Maven to use more repositories and replace the default one.

Every project can define dependencies using the unique identifier (GAV) of the library it requires.

<dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
 </dependencies>

During a build, the Maven system tries to resolve the dependencies of the modules which are build. To resolve dependencies, Maven uses the following sources in the given order:

  • Projects which are included in the same Maven run (the so called Maven reactor)

  • Local repository

  • Maven central repository

Maven supports direct and transitive dependencies. Direct dependencies are the ones that are explicitly included in the pom file of the project. Transitive dependencies are dependencies required by our direct dependencies.

Maven handles direct and transitive dependencies.

For this, you specify in the pom file the external libraries your project depends on using their GAV (groupId, artifactId and version) then Maven downloads them, puts them in your local Maven repository and make them available for the project build. The transitive dependencies of the required libraries are also made available.

The following listing shows a pom file with a dependency to JUnit5.

<?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.vogella.maven.first</groupId>
  <artifactId>com.vogella.maven.first</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>com.vogella.maven.first</name>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
  </properties>

  (1)
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.22.2</version>
      </plugin>
      <plugin>
        <artifactId>maven-failsafe-plugin</artifactId>
        <version>2.22.2</version>
      </plugin>
    </plugins>
  </build>

  (2)
  <dependencies>
    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-api</artifactId>
      <version>5.7.2</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-engine</artifactId>
      <version>5.7.2</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

</project>
1 This build section is required as starting with version 2.22.0, Maven Surefire and Maven Failsafe provide native support for executing tests on the JUnit Platform.
2 This defines dependencies for the software tests (via the scope attribute) to JUnit5 (also known as JUnit Jupiter)

Maven will download the defined dependencies and their transitive dependencies from the Maven central repository and add them to the users local Maven repository. If the dependencies are already found in your local repository, Maven will use these and download them again.

You can also define an (external of a Maven repository) location for a library.

<dependency>
  <groupId>mylib</groupId>
  <artifactId>mylib</artifactId>
  <scope>system</scope>   (1)
  <version>1.0</version>
  <systemPath>${basedir}\libs\mylibrary.jar</systemPath>
</dependency>
1 Requires that the library is defined via a system path

You can also define snapshot dependencies. These are libraries which can constantly under development. Maven downloads these snapshots on every build, even if a matching version is already available in the local repository.

<version>1.0-SNAPSHOT</version>

4.3.2. Excluding transitive dependencies

Sometimes your dependencies have conflicting transitive dependencies. For example library A requires library C in version 1.0.0 and library B requires it in version 1.1.0. To use library C in version 1.0.0 you can exclude C from the dependencies of A.

Lets for example B is the com.vogella.example artifactId.

<dependency>
  <groupId>com.vogella.group</groupId>
  <artifactId>com.vogella.example</artifactId>
  <version>1.0</version>
  <scope>compile</scope>
  <exclusions>
    <exclusion>
      <groupId>c.groupId</groupId>
      <artifactId>c.artifactId</artifactId>
    </exclusion>
  </exclusions>
</dependency>

5. Maven plug-ins, goals and the life cycle

5.1. Maven life cycle

Maven builds follows a specified life cycle. The build life cycle is divided into build phases The build phases are divided into build goals.

Maven has three default life cycle phases:

  • default (cannot be executed)

  • clean

  • site

You can execute a full life cycle via command like clean or site. You can also execute build phases like verify or single goals like dependency:copy-dependencies.

The following lists gives an overview of the important Maven life cycle phases:

Build phase Description

validate

checks if the project is correct and all information is available

compile

compiles the source code into binary artifacts

test

executes the tests

package

takes the compiled code and package it, for example into a JAR file

integration-test

takes the packaged result and executes additional tests, which require the packaging

verify

performs checks if the package is valid

install

install the result of the package phase into the local Maven repository

deploy

deploys the package to a target, i.e. remote repository

If you execute a build phase, all build phases before that build phase are executed in the above sequence. All relevant goals are executed during this process.

A goal is relevant for a phase, if the Maven plug-in or the pom binds this goal to the corresponding life cycle phase.

5.2. Plugins and goals

Maven plugins provide the functionalities which are used in the Maven build.

Each Maven plugins provides one or more goals. A goal is a “unit of work” in Maven. It is possible to execute goals independently or as part of a larger chain of goals.

Goals can define parameters, which may have default values. The goals are executed based on the information found in the pom of the project, e.g., the compiler:compile goal checks the pom for relevant parameters. Goals can be attached to a life cycle phase.

5.3. Packages and goal bindings

Each packaging contains a list of bindings for goals to a particular life cycle phase. For example, the jar packaging binds the following goals to the life cycle phases.

Table 2. Packaging goal
Life cycle phase Goal binding

process-resources

resources:resources

compile

compiler:compile

process-test-resources

resources:testResources

test-compile

compiler:testCompile

test

surefire:test

package

jar:jar

install

install:install

deploy

deploy:deploy

5.4. Adding goals to life cycle phases

You can add goals to life cycle phases by configuring more Maven plug-ins and adding them to a life cycle in your pom file. You need to specify which goal should be executed. If the plug-in does not specify the default life cycle it should run, you must also specify the life cycle phase it should run.

<plugin>
   <groupId>com.vogella.example</groupId>
   <artifactId>vogella-some-maven-plugin</artifactId>
   <version>1.0</version>
   <executions>
     <execution>
       <phase>verify</phase>
       <goals>
         <goal>checklinks</goal>
       </goals>
     </execution>
   </executions>
 </plugin>

6. Maven and version control systems

Maven generates its output into the target folder of each project. This build output should not get included into your version control system.

Add this directory to your ignore resources. For example, if you use Git as version control system, add the "target/" entry to your .gitignore file in the root of each project.

7. Running a Maven build via the command line

To build a Maven project via the command line, you use the mvn command from the command line. The command must be executed in the directory which contains the relevant pom file.

You pass the build life cycle, phase or goal as parameter to this command.

Maven reads the pom file and resolves the dependencies of the project. Maven validates if the dependencies are available in a local repository and if they are available these are used.

If the dependency is not available in the build reactor or the local repo, Maven downloads the depended artifacts from the central repository or the specified ones into the local repository.

Maven executes all life cycle phases until the specified one.

For example the mvn clean install command triggers the jar packaging. This includes compiling the sources, executing the tests and packaging the compiled files in a JAR file. As last step the install phase installs the resulting artifact into the local repository, so it can be used as dependencies by other Maven builds.

Maven creates the build result in the target folder.

mvn install (1)
1 compile, build and install the build result

To ensure that the build target is removed before a new build, add the clean target.

mvn clean install

If you have a multi project build, you can also instruct Maven to perform a parallel build.

mvn clean install -T4 (1)
1 -T4 defines that 4 processes are available

By default, Maven checks online if the dependencies have been changed. If you want to use your local repository, you can use the -o to tell Maven to work offline.

mvn -o clean install

7.1. Dealing with build failure

If you are running a complex multi-module project build, you can define how the Maven build system should react to errors in one module.

  • -fae, --fail-at-end - fails the build after all modules are build; allow all non-impacted builds to continue

  • -ff, --fail-fast - Stop at first module build failure

  • -fn, --fail-never - NEVER fail the build, regardless of module build result

The -fn and -fae options are useful to verify builds that are running within a continuous integration tool like Jenkins and to see all errors in the build.

7.2. Scaffolding a project with Maven

Maven supports project scaffolding, based on project templates (called archtype). This is provided by the archetype plug-in. Maven provides archetypes for almost anything, from a simple Java application to a complex web application.

The goal of this scaffolding is to allow a fast start into the Maven world. It provides the "standardized" folder structure of software projects.

You can create a project by executing the generation goal on the archetype plugin via the following command: mvn archetype:generate.

mvn archetype:generate This starts the generation process in the interactive mode and asks you for several settings.

8. Maven Wrapper

You can provide a script which downloads automatically the correct version of Maven so that users of the Maven command line do not have to download and install it themself. This functionality is provided by the Maven wrapper.

The wrapper will be provided in the next standard Maven release (either 3.7.0 or 4.0.0).

8.1. Creating a Maven Wrapper

Create a Maven Wrapper for a project with the latest available Maven version.

cd {your-project}
mvn -N io.takari:maven:wrapper

You can create a Maven Wrapper for a project with a specified Maven version by using the maven property.

cd {your-project}
mvn -N io.takari:maven:wrapper -Dmaven=3.6.3

The wrapper goal creates the following files:

  • mvnw (shell script for unix systems)

  • mvnw.cmd (batch file for windows)

  • .mvn/wrapper/maven-wrapper.jar (Maven Wrapper JAR)

  • .mvn/wrapper/maven-wrapper.properties (Maven Wrapper properties)

The Maven Wrapper files can be added to your version control system (vcs), for example your Git repo.

The -N, --non-recursive command line option specifies that only the project in the current directory is built without building it’s submodules. So the Maven Wrapper will only be applied for the main project and not in every submodule.

8.2. Using the Maven Wrapper

To run the Maven Wrapper the mvnw for Linux / Mac systems or mvnw.bat for Windows systems can be used.

UNIX:

./mvnw clean package

WINDOWS:

mvnw.cmd clean package

9. Exercise: Create and build a Java project with Maven

In this exercise you create a Java project with the Maven command line tooling and build this project. You use the scaffolding functionality of Maven to create a Java project.

9.1. Project generation

Create a separate folder for this exercise.

To avoid the interactive mode, all required properties are passed directly to the command. Otherwise Maven asks for all the required parameters. Enter the following into one line in the command shell(the backslash masks the line breaks).

mvn archetype:generate -DgroupId=com.vogella.maven.first \
-DartifactId=com.vogella.maven.first   \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DarchetypeVersion=1.4 \
-DinteractiveMode=false

With this command Maven generates a Java project based on a pre-defined template.

If this is the first time you execute this goal, Maven has to download the required plug-ins and artifacts for the project generation from the Maven central repository. Therefore, the first run is longer than consecutive runs. It also produces additional output compared to a second run.

You have generated a whole Maven project structure with Java source code.

9.2. Review generated project

Validate that Maven generated a project on your file system similar to the following structure.

.
└── com.vogella.maven.first
    ├── pom.xml
    └── src
        ├── main
        │   └── java
        │       └── com
        │           └── vogella
        │               └── maven
        │                   └── first
        │                       └── App.java
        └── test
            └── java
                └── com
                    └── vogella
                        └── maven
                            └── first
                                └── AppTest.java

Maven created a App.java class in the ./src/main/ folder, which is just a simple "Hello World" program. It also created an example test class in ./src/test/. In the root folder there is a pom.xml file.

9.3. Update your Java version to Java 11

Open the pom.xml file and update your compiler settings to use Java 11.

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
  </properties>

9.4. Compile your sources

Now you want to compile your Java sources. For this switch on the command line into our projects root directory and trigger the following Maven command.

mvn compile

The output should be similar to the following.

[INFO] Scanning for projects...
[INFO]
[INFO] ----------< com.vogella.maven.first:com.vogella.maven.first >-----------
[INFO] Building com.vogella.maven.first 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
Downloading from central: https://repo.maven.apache.org/maven2/junit/junit/4.11/junit-4.11.pom
Downloaded from central: https://repo.maven.apache.org/maven2/junit/junit/4.11/junit-4.11.pom (2.3 kB at 7.1 kB/s)
[INFO]
[INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ com.vogella.maven.first ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /home/vogella/temp/com.vogella.maven.first/src/main/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.0:compile (default-compile) @ com.vogella.maven.first ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /home/vogella/temp/com.vogella.maven.first/target/classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.731 s
[INFO] Finished at: 2021-01-25T12:49:07+01:00
[INFO] ------------------------------------------------------------------------

Maven now runs through all life cycle phases, which were needed by the compile phase. It resolves the dependencies, loads the JUnit artifact and built the sources. It also executes the JUnit test.

9.5. Create a JAR file

Now you want to create an executable JAR file out of our project. The package goal creates a deployable JAR file.

To ensure previous build artifacts are removed, you can use the clean goal.

mvn clean package

9.6. Validate

Afterwards you can run the packed program.

java -cp target/com.vogella.maven.first-1.0-SNAPSHOT.jar com.vogella.maven.first.App

The output should be Hello World! on the command line.

9.7. Running the test

Instead of running a full build with packaging, it is also possible to just run the test phases of the Maven life cycle.

mvn test

Your output should include the output of your test similar to the following.

[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.vogella.maven.first.AppTest
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.031 s - in com.vogella.maven.first.AppTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.678 s
[INFO] Finished at: 2021-01-25T12:52:42+01:00
[INFO] ------------------------------------------------------------------------

9.8. Remove all build results / Clean the project

To remove all build artifacts (tge ./target/ folder), use the clean command.

mvn clean

9.9. Update your dependencies to use JUnit 5

Change your pom file to use JUnit Jupitur.

<?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.vogella.maven.first</groupId>
  <artifactId>com.vogella.maven.first</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>com.vogella.maven.first</name>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
  </properties>

  (1)
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.22.2</version>
      </plugin>
      <plugin>
        <artifactId>maven-failsafe-plugin</artifactId>
        <version>2.22.2</version>
      </plugin>
    </plugins>
  </build>

  (2)
  <dependencies>
    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-api</artifactId>
      <version>5.7.2</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-engine</artifactId>
      <version>5.7.2</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

Run your build, it should fail, as you unit test is not using an older JUnit version.

Change your unit test to the following.

package com.vogella.maven.first;

import static org.junit.jupiter.api.Assertions.assertTrue;

import org.junit.jupiter.api.Test;

class MyFirstJUnitJupiterTests {

    @Test
    void addition() {
        assertTrue(true);
    }
}

Run mvn verify again and validate that your project compiles and that all test are successfully.

9.10. Specify the main class in the MANIFEST

Currently you have to specify the main class in the jar if you want to run your app. Test this by switching to the target folder and typing:

 java -cp com.vogella.maven.first-1.0-SNAPSHOT.jar com.vogella.maven.first.App

We would like to add the main application to the MANIFEST.MF. For this add the following to the pom file.

    <build>
        <plugins>
            <!-- all the existing build entries-->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.2.0</version>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>com.vogella.maven.first.App</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>

Run the Maven build again with mvn clean verify.

9.11. Verify

Afterwards you can start your application directly.

java -jar com.vogella.maven.first-1.0-SNAPSHOT.jar

This should print "Hello World!" to the console.

A jar file is a zip file, open this zip file with your preferred tool and check that the /META-INF/MANIFEST.MF contains an entry for the main class.

10. Multi module projects

Maven supports building multiple projects. A multi module project (aggregator) is defined by a parent POM referencing one or more projects.

This aggregator can contain also the build configuration or include another parent POM to get this configuration.

<?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.vogella</groupId>
  <artifactId>com.vogella.parent</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>pom</packaging>

  <name>com.vogella.parent</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.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>


  <modules>
    <module>com.vogella.maven.api</module>
    <module>com.vogella.maven.consumer</module>
  </modules>
</project>

The packaging type of such a POM is pom, as such a project will not result in any build output.

The individual pom can point to the parent pom to inherit its configuration.

<?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>

  <parent>
    <groupId>com.vogella</groupId>
    <artifactId>com.vogella.parent</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>

  <groupId>com.vogella</groupId>
  <artifactId>com.vogella.maven.api</artifactId>
  <version>1.0-SNAPSHOT</version>

</project>

11. Exercise: Creating a multi project Maven project

In this exercise you create two projects and build them in one multi project build.

11.1. Create two projects

Create two projects in the same directory:

mvn archetype:generate -DgroupId=com.vogella \
-DartifactId=com.vogella.maven.api   \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DarchetypeVersion=1.4 \
-DinteractiveMode=false
mvn archetype:generate -DgroupId=com.vogella \
-DartifactId=com.vogella.maven.consumer   \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DarchetypeVersion=1.4 \
-DinteractiveMode=false

This creates two sub-directories.

11.2. Create parent pom

Create the following pom in the main directory.

<?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.vogella</groupId>
  <artifactId>com.vogella.parent</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>pom</packaging>

  <name>com.vogella.parent</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.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
  </properties>

  <modules>
    <module>com.vogella.maven.api</module>
    <module>com.vogella.maven.consumer</module>
  </modules>
</project>

11.3. Update individual poms

Define the parent relationship in the poms of the projects so that they can also inherit the configuration of the parent.

For com.vogella.maven.api

<?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>

  <parent>
    <groupId>com.vogella</groupId>
    <artifactId>com.vogella.parent</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>

  <groupId>com.vogella</groupId>
  <artifactId>com.vogella.maven.api</artifactId>
  <version>1.0-SNAPSHOT</version>

</project>

For com.vogella.maven.consumer

<?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>

  <parent>
    <groupId>com.vogella</groupId>
    <artifactId>com.vogella.parent</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>

  <groupId>com.vogella</groupId>
  <artifactId>com.vogella.maven.consumer</artifactId>
  <version>1.0-SNAPSHOT</version>

</project>

Also update the parent pom to contain the common configuration.

<?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.vogella</groupId>
  <artifactId>com.vogella.parent</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>pom</packaging>

  <name>com.vogella.parent</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.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
  </dependencies>


  <modules>
    <module>com.vogella.maven.api</module>
    <module>com.vogella.maven.consumer</module>
  </modules>
</project>

11.4. Verify the build

Use mvn clean verify to run the build. It should be successfully.

11.5. Update JUNit dependencies and code

Update your JUnit dependencies and your unit test to JUnit 5.

Show Solution
  (1)
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.22.2</version>
      </plugin>
      <plugin>
        <artifactId>maven-failsafe-plugin</artifactId>
        <version>2.22.2</version>
      </plugin>
    </plugins>
  </build>

  (2)
  <dependencies>
    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-api</artifactId>
      <version>5.7.2</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-engine</artifactId>
      <version>5.7.2</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

The following listings contain the adjusted tests.

package com.vogella.maven.api;

import static org.junit.jupiter.api.Assertions.assertTrue;

import org.junit.jupiter.api.Test;

/**
 * Unit test for simple App.
 */
public class AppTest
{
    @Test
    public void shouldAnIswerWithTrue()
    {
        App app = new App();
        assertTrue( true );
    }
}
package com.vogella.maven.consumer;

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()
    {
        System.out.println("THIS IS A TEST");
        assertTrue( true );
    }
}

12. Define project dependencies

12.1. Define API

In your api project, define the following class:

package com.vogella.maven.api;

public interface TaskService {

}

12.2. Define usage

Defining project dependencies is the same as defining library dependencies.

Add a dependency to the api project in the pom of the consumer project.

 <dependencies>
    <dependency>
        <groupId>com.vogella</groupId>
        <artifactId>com.vogella.maven.api</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
  </dependencies>

Now you can modify the App in your consumer project to use this API.

package com.vogella.maven.consumer;

import com.vogella.maven.api.TaskService;

public class App
{
    public static void main( String[] args )
    {
        System.out.println( "Hello World!" );
        TaskService taskService;
    }
}

12.3. Verify

Run you build with:

mvn clean verify

This works as the build contains both modules.

12.4. Install Maven modules into local Maven repository

Now try to build the com.vogella.maven.consumer alone by switching into the directory the mvn clean verify command. This fails, as the com.vogella.maven.api project is not available in your local .m2 repo and not part of the build (Maven reactor).

Switch back to the parent directory and use mvn clean install to build and install the modules into your local repo.

Now you can also build com.vogella.maven.consumer, the com.vogella.maven.api module is source from your local Maven repository.

12.5. Create one executable JAR

Maven provides multiple options to create one big JAR. Lets use the maven-assembly-plugin.

Add the following to the pom file of your com.vogella.maven.consumer

<build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                        <configuration>
                            <archive>
                                <manifest>
                                    <mainClass>
                                        com.vogella.maven.consumer.App
                                    </mainClass>
                                </manifest>
                            </archive>
                            <descriptorRefs>
                                <descriptorRef>jar-with-dependencies</descriptorRef>
                            </descriptorRefs>
                        </configuration>
                    </execution>
                </executions>
                </plugin>
        </plugins>
    </build>

13. Optional: Adding an unrelated project to the build

The com.vogella.maven.first project you created earlier does not depend on anything from the other two projects. You can keep its independent build configuration but maybe you want to build if for convenience with the same build. To do this, add it as child module to your build and re-run the build. Ensure it is also build.

Maintaining the build configuration can become a maintenance burden, so you may want to add the parent relationship to re-use a common build configuration.

14. Exercise: Add Maven wrapper to your project

14.1. Create the wrapper

For your multi project, create a Maven wrapper.

mvn -N io.takari:maven:wrapper

14.2. Verify the wrapper

Use mvnw (Linux / Mac) or mvnw.cmd (Windows) depending on your platform to run the clean verify command.

Now everyone can run your build, without installing Maven.

15. Using profiles and properties in Maven

15.1. Using profiles

Maven supports the usage of profiles to define different configurations. If you start Maven, you can instruct it to use a certain profile. For this you specify the -P parameter followed directly (without whitespace) by the profile, e.g. -PyourProfile.

<profiles>
 <profile>
  <id>dev</id>
   <activation>
           <activeByDefault>true</activeByDefault>
        </activation>
  <properties>
    <db.location>URL_to_dev_system</db.location>
    <logo.image>companylogo.png</logo.image>
  </properties>
 </profile>
  <profile>
    <id>production</id>
        <properties>
            <db.location>URL_to_prod_system</db.location>
            <logo.image>companylogo2.png</logo.image>
        </properties>
    </profile>
 </profiles>

15.2. Using properties

You can specify properties in your build files. You can override them via the command line with the -D parameter followed directly (without whitespace) by its value. See the next chapter for an example.

15.3. Example for properties: Skipping the tests in a Maven build

You can specify via a property that your tests should be skipped during the build. This property (among with several others for demo purposes) is defined in the following snippet.

<properties>
    <skipTests>true</skipTests>
    <maven.build.timestamp.format>yyyyMMdd-HHmm</maven.build.timestamp.format>
    <buildTimestamp>${maven.build.timestamp}</buildTimestamp>
    <buildId>${buildType}${buildTimestamp}</buildId>
</properties>

How to override these parameters via the command line is demonstrated by the following listing.

mvn clean install -DskipTests=false

15.4. Useful properties

Table 3. Useful properties
Property Description

skipTests

true or false, specifies if tests should be executed or not

showWarnings

true or false, defines if the Maven build shows the compiler warnings

16. Maven settings

Maven allows to define settings on a global, user and project level. The common case is to define on a user level, settings like a proxy server or passwords to upload build artifacts to a server.

You can view the file locations in the Eclipse IDE via Windows  Preferences  Maven  User settings.

Maven settings

The user settings file is located in the .m2 folder of the users home.

The following settings.xml file defines a proxy server. If this snippet is located in the .m2 folder of the users home, Maven uses this proxy.

<settings>
 <proxies>
  <proxy>
   <active>true</active>
   <protocol>http</protocol>
   <host>proxy</host>
   <port>8080</port>
   <username>your_user</username>
   <password>your_password</password>
   <nonProxyHosts>www.google.com|*.test.com</nonProxyHosts>
  </proxy>
 </proxies>
</settings>

17. Useful Maven parameters

The following table lists useful Maven parameters.

Table 4. Maven build parameters
Parameter Description

--log-file log.txt

Maven build output is written to the specified file

--debug

Outputs more information during the build process

18. Exercise: Excluding certain tests

18.1. Run Maven build without tests

Sometimes your tests run too long or are flacky so you want to build your software without runnig the tests. Use the -DskipTests=true on the command line to skip tests.

Check in the log output that the tests are skipped.

[INFO] Tests are skipped.

For testing, add skipTests as parameter to your build.

    <properties>
        <!-- more properties..-->
        <skipTests>true</skipTests>
    </properties>

Run your tests without the skipTests parameter and ensure that they still not executed.

Test again with -DskipTests=false and check that you can override the default configuration via the command line.

After this test, remove the property again from your pom file.

18.2. Use profiles

To practise the usage of profiles, define a profile which skips tests

    <profiles>
        <profile>
            <id>dev</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <properties>
                <!-- potential properties here-->
            </properties>
        </profile>
        <profile>
            <id>notests</id>
            <properties>
                <skipTests>true</skipTests>
            </properties>
        </profile>
    </profiles>

Run your Maven build with mvn clean verify -Pnotests and validate that no tests are executed.

18.3. Tag a few tests

Tag a few tests with JUnit 5 as slow.

package com.vogella;

import static org.junit.jupiter.api.Assertions.assertTrue;

import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;

/**
 * Unit test for simple App.
 */
public class AppTest
{
    @Test
    @Tag("slow")
    public void shouldAnswerWithTrue()
    {
        System.out.println("THIS IS A TEST");
        assertTrue( true );
    }
}

18.4. Exclude tagged tests

<plugin>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.22.2</version>
    <configuration>
        <includes>
            <include>**/Test*.java</include>
            <include>**/*Test.java</include>
            <include>**/*Tests.java</include>
            <include>**/*TestCase.java</include>
        </includes>
        <!-- use groups to define included tags, use comma to separate -->
        <excludedGroups>slow</excludedGroups>
    </configuration>
</plugin>

Run the build and ensure the tagged test is not executed.

If you configure this for the multi project build ensure you modify the correct test. In the exercises it was optional to align the build configuration for the first project you created, so in case you have not updated the pom of com.vogella.maven.first the parent pom setting may not apply for this projet.

18.5. Exclude on the command line

mvn clean verify -DexcludedGroups="slow"

18.6. Define a profile

Add a profile named fast to run all tests.

Define a new property named excludedtests which contain the excluded tags. Override in in your profile.

You can refer to a property named name via ${name}.

19. Creating a unit test report with Maven

Maven can generate HTML test reports for unit test. This allows to review the test results after the build and to identify easily the test failures.

The Maven unit test reports are generated by the Maven Surefire plugin. To generate them, you can execute the following command:

mvn surefire-report:report

The generated unit test report is located in the target/site directory of the project.

To generate an aggregated test report for a multi-project Maven build, use the following:

mvn surefire-report:report -Daggregate=true

20. Exercise: Generate an HTML test report

20.1. Create a test report for your single Maven project

In your com.vogella.maven.first project run the following command.

mvn surefire-report:report

20.2. Validate generated report

Open the generated com.vogella.maven.first/target/site/surefire-report.html and review the file.

It looks a bit boring as it is not styled. This is because the report goal only creates the test reports and not default reports.

20.3. Trying running the site phase.

Try running the mvn site command.

The site target may fail with an error, as some plugins have errors in their latest version. In this case fix the plugins used for creating the reports in your pom file.

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-site-plugin</artifactId>
  <version>3.7.1</version>
</plugin>
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-project-info-reports-plugin</artifactId>
  <version>3.0.0</version>
</plugin>

Re-run the build and validate that the site is generated.

Open the index.xml and check the content. Go back to your project pom and add a description.

<description>This is a description</description>

Re-run the site generate and check that the generated HTML contans the new description.

Have a short look at the additional customization you can for your description: https://maven.apache.org/plugins/maven-site-plugin/examples/sitedescriptor.html

20.4. Bind the test generation to the test goal

Currently the test reports a only generated if you execute the site goal. You can also bind goals to other phases and goals.

Add the following to your build configuration. Now, if you run mvn clean test the test reports are generated also. The report-only goal only generates the test reports without re-running tests (which are already running due to the test phase).

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-report-plugin</artifactId>
                <version>2.6</version>
                <executions>
                    <execution>
                        <phase>test</phase>
                        <goals>
                            <goal>report-only</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

21. Exercise: Setting up a Git repository and Github build actions

In this exercise you create a new Github repository for your Maven build. Afterwards you configure Github actions to validate every commit and every pull request automatically on Github.

21.1. Create new Github repository

Create a new public Github repository. Clone it to your local machine with your preferred method.

21.2. Add your projects to your Github repo

If you are using the Git command line, move your projects into the Git repository. If you are using the Eclipse IDE, you can add these projects with the Team  Share Project…​ menu entry.

21.3. Create a .gitignore file

Create a new .gitignore file in the top level directory of your repository. Ignore at least all /target folders in this file. The following .gitignore ignores all target folder and some potential Eclipse metadata.

target/
**.class
.metadata
release.properties

Ensure that target is not listed with the git status command.

21.4. Commit and push

Add and commit all files.

git stage . # older git versions: git add .
git commit -m "Initial commit"
git push --set-upstream origin master

21.5. Setup build validation

To verify each commit and pull request on Github create the following file maven.yaml in the .github/workflows directory.

name: Maven build for Java 11 and Java 15 on Ubuntu/ MacOS and Windows

on:
  push:
  pull_request:

jobs:
  build:
    name: "Build (JDK-${{ matrix.java }}, ${{ matrix.os }})"
    strategy:
      fail-fast: false
      matrix:
        os: [ ubuntu-latest, macOS-latest, windows-latest ]
        java: [11, 15 ]
    runs-on: ${{ matrix.os }}
    steps:
      - name: 'Checkout'
        uses: actions/checkout@v2

      - name: 'Set up JDK'
        uses: actions/setup-java@v1
        with:
          java-version: ${{ matrix.java }}

      - name: Cache Maven Dependencies
        uses: actions/cache@v2
        with:
          path: ~/.m2/repository
          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
          restore-keys: |
            ${{ runner.os }}-maven-
      - name: Build and test with Maven using xvfb
        uses: GabrielBB/xvfb-action@v1
        with:
          run: |
            mvn clean verify

State, commit and push this file.

21.6. Check that your workflow works

Switch to Github and select Actions on your repository. You should see that your verification has been triggered or already completed.

maven githubactions10

Wait until the build verification has completed and review some of the details.

maven githubactions20
maven githubactions30

22. Useful Maven tips and plug-ins

22.1. Checking and updating versions

Maven can check dependencies for newer version and update your pom files to use these new versions:

  • mvn versions:display-dependency-updates - show if updates for library are available

  • mvn versions:use-releases - Update snapshot version to use the current release

  • mvn versions:use-next-releases - Update snapshot version to use next release

  • mvn versions:use-latest-releases - Update pom to use latest versions

22.2. Capturing all folder as modules

Maven requires an entry in the top-level project. You can use a Linux command line and awk to generate such entries.

ls -l|  grep '^d'  | awk '{ print "<module>"$9"</module>" }'

22.3. Show the dependency tree

Maven provides a plugin, which can be used to visualize a dependency tree to either the console or an output file.

# Show dependencies inside the console
mvn dependency:tree -Dverbose
# Write dependency to a file
mvn dependency:tree -Dverbose -DoutputFile=/home/simon/maven-dependencies
<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.vogella</groupId>
    <artifactId>com.vogella.maven.dependencies</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>

    <dependencies>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.10</version>
        </dependency>
    </dependencies>

</project>

The output of the mvn dependency:tree -Dverbose command can for example look like the following.

Dependency tree of slf4j-log4j12

22.4. Show all goals of a certain plug-in

You can see all goals of a certain plug-in. The standard Maven plug-ins are listed on the Maven Plugin Site.

For example, the following shows all goals of the site plug-in.

mvn help:describe -e -Dplugin=site

22.5. Versions plugin

The display-dependency-updates goal of the Versions Maven Plugin can be used to determine, if there are newer versions of a dependency available.

For example, running mvn versions:display-dependency-updates for a project might result in the following output.

The display-dependency-updates goal of the versions maven plugin

22.6. Execute a Java program with Maven

If you want to execute a program you can use the exec-maven-plugin. This is demonstrated in the following pom.xml file. To trigger this use the exec:java target in maven.

<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.vogella.build.maven.intro</groupId>
    <artifactId>com.vogella.build.maven.intro</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>mavenintroduction</name>
    <build>
        <sourceDirectory>src</sourceDirectory>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.3</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.2.1</version>
                <configuration>
                    <mainClass>com.vogella.build.maven.intro.Main</mainClass>
                </configuration>
            </plugin>
        </plugins>

    </build>
</project>

Output of Maven

23. Maven vs. other build tools

23.1. Maven vs. Ant

Ant uses an imperative style of declaring the actions the Ant build should do. You specify the commands Ant should perform and the sequence in which they should happen. Ant has no dependency management tools per default, you have to use other tools like Ivy or handle the download of the dependencies manually.

Ant projects also do not follow a standard project layout.

Maven uses a declarative style which defines what to build not how to build. If uses a default layout for projects and provides build in support for dependency management.

Ant build files tend to be unique for the project while Maven build files tend to follow a similar structure therefore maintenace of Maven build files are typically easier.

23.2. Maven vs. Gradle

Gradle provides the same functionality as Maven but uses a concise syntax. Gradle supports also a declarative and imperative style in addition to Mavens declarative approach.

The Maven build tool is older and maintained by a group of volunteers, which the Gradle build is driven by a venture capital founded company.

24. Common Maven tasks

24.1. Setting the Java Version in Maven

To configure Maven to compile for a certain Java release you can use properties in your pom file.

    <properties>
        <maven.compiler.target>11</maven.compiler.target>
        <maven.compiler.source>11</maven.compiler.source>
    </properties>

In a full build file this would look like the following:

<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">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.vogella</groupId>
    <artifactId>com.vogella.xml.jaxb.maven</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <maven.compiler.target>11</maven.compiler.target>
        <maven.compiler.source>11</maven.compiler.source>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-impl</artifactId>
            <version>2.3.3</version>
        </dependency>
    </dependencies>
</project>

25. Apache Maven resources