Maven basics

Write program

Maven can best be introduced using a simple Hello World application. Please do the following:

  1. Choose some work directory, say work.

  2. Within work, create folder src/main/java. This is where Maven expects Java sources.

  3. Within work/src/main/java, open org/wearefrank/maven/webapp/example/Main.java. Populate it with the following text:

    package org.wearefrank.maven.webapp.example;
    
    import org.apache.commons.lang3.StringUtils;
    
    /**
     * Although the package name contains "webapp", this is not a webapp yet. It will become so later.
     */
    public class Main {
        public static void main(String[] args) {
            System.out.println(StringUtils.upperCase("Hello World!"));
        }
    }
    

This is a program that should be started from the command line. It simply prints “Hello World!”. To demonstrate Maven, a dependency has been introduced. This program needs Java class org.apache.commons.lang3.StringUtils.

In the next steps, a file pom.xml is added that tells Maven how to compile this program.

  1. Within work, open a file pom.xml. Start it as follows:

    <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>org.wearefrank</groupId>
        <artifactId>mavenWebappExample</artifactId>
        <version>1.0-SNAPSHOT</version>
    </project>
    

The first two lines are the same for every pom.xml file. Next come three lines with tags <groupId>, <artifactId> and <version>. These are collectively referenced as Maven coordinates. The Maven coordinates are the unique identifier of an artifact. Artifacts are the basic building blocks that are combined by Maven during compilation and linking. The three lines identify the artifact that is built by this project. Use the <groupId> as a common name for all artifacts produced by your organization or your team. It is used to distinguish your artifact from artifacts produced by other organizations. The <artifactId> distinguishes your artifact from the ohter artifacts with the same <groupId>. Finally, the <version> is the version of your artifact.

  1. Extend pom.xml as shown:

    <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>org.wearefrank</groupId>
        <artifactId>mavenWebappExample</artifactId>
        <version>1.0-SNAPSHOT</version>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.12.1</version>
                    <configuration>
                        <release>11</release>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </project>
    

    This tells Maven that the compiler, the tool that transforms .java files into .class files, should treat the source code as written for Java 11 (if you are working with another Java version, another version may be needed in the pom.xml). The idea of plugins will be explained later.

  2. Conclude pom.xml by adding a dependency. You add the dependency that references the artifact that holds class org.apache.commons.lang3.StringUtils:

    <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>org.wearefrank</groupId>
        <artifactId>mavenWebappExample</artifactId>
        <version>1.0-SNAPSHOT</version>
    
        <dependencies>
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-lang3</artifactId>
                <version>3.12.0</version>
            </dependency>
        </dependencies>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.12.1</version>
                    <configuration>
                        <release>11</release>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </project>
    

Build program

The program is complete. Start building it as follows:

  1. Open a command prompt and browse to your work directory.

  2. Type mvn clean.

The output should look like this:

$ mvn clean
[INFO] Scanning for projects...
[INFO]
[INFO] -----------------< org.wearefrank:mavenWebappExample >------------------
[INFO] Building mavenWebappExample 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ mavenWebappExample ---
[INFO] Deleting C:\Users\martijn\git\frank-manual\srcSteps\mavenWebapp\v500\target
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.265 s
[INFO] Finished at: 2024-01-29T15:43:19+01:00
[INFO] ------------------------------------------------------------------------

Maven distinguishes build phases. The mvn clean command tells maven to execute build phase clean. Maven delegates everything it does to plugins. By default, Maven executes plugin maven-clean-plugin when it executes phase clean. Maven plugins are artifacts themselves that can be referenced by Maven coordinates. You can change the versions of a plugin by adding a reference to it in your pom.xml. This is what we did to compile for Java version 11. More explanation will be given in a later subsection. Maven plugins are little programs that may have multiple functions. These are named goals. The output says that goal clean of maven-clean-plugin version 2.5 has been executed. This action deleted directory target which probably did not exist at this moment. All output of Maven appears in the target directory, so all output from previous runs of Maven has been removed as was intended.

  1. Within the same command prompt, enter mvn compile to execute build phase compile.

The output should look as follows:

$ mvn compile
[INFO] Scanning for projects...
[INFO]
[INFO] -----------------< org.wearefrank:mavenWebappExample >------------------
[INFO] Building mavenWebappExample 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ mavenWebappExample ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory C:\Users\martijn\git\frank-manual\srcSteps\mavenWebapp\v500\src\main\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.12.1:compile (default-compile) @ mavenWebappExample ---
[INFO] Recompiling the module because of changed source code.
[WARNING] File encoding has not been set, using platform encoding windows-1252, i.e. build is platform dependent!
[INFO] Compiling 1 source file with javac [debug release 11] to target\classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.002 s
[INFO] Finished at: 2024-01-29T16:40:54+01:00
[INFO] ------------------------------------------------------------------------

Build phase compile is part of the default life cycle. All preceding phases, like process-resources, of the default life cycle are executed as well. Phase process-resources is linked to plugin maven-resources-plugin and its goal resources. Phase compile executes goal compile of plugin maven-compiler-plugin.

  1. Check what files have been produced. Enter command tree.

The output should look like this:

C:\Users\martijn\frank-manual\srcSteps\mavenWebapp\v500>tree
Folder PATH listing
Volume serial number is D8AD-6F85
C:.
├───src
│   └───main
│       └───java
│           └───org
│               └───frankframework
│                   └───maven
│                       └───webapp
│                           └───example
└───target
    ├───classes
    │   └───org
    │       └───frankframework
    │           └───maven
    │               └───webapp
    │                   └───example
    ├───generated-sources
    │   └───annotations
    └───maven-status
        └───maven-compiler-plugin
            └───compile
                └───default-compile

C:\Users\martijn\frank-manual\srcSteps\mavenWebapp\v500>

All generated files appear in the target directory. Within that directory, there is a directory classes. This directory holds everything that this artifact will put on the classpath when the linked application executes. There is a path org/wearefrank/maven/webapp/example. This path resembles the path to file Main.java. The directory holds file Main.class, the byte code produced by compiling source file Main.java (not shown).

  1. Assemble the artifact of this project, which has <groupId> org.ibissource, <artifactId> mavenWebappExample and <version> 1.0-SNAPSHOT. Do so by entering mvn install.

  2. Check that you have file mavenWebappExample-1.0-SNAPSHOT.jar. This is a ZIP file that holds all data that this artifact should put on the classpath.

  3. Check that your home directory has a folder named .m2. Check that this folder contains directory repository\org\wearefrank\mavenWebappExample\1.0-SNAPSHOT.

  4. Check that that directory contains the same JAR file: mavenWebappExample-1.0-SNAPSHOT.jar.

Maven has stored the artifact in the local repository on your computer. If you would build some other project that references org.wearefrank:mavenWebappExample:1.0-SNAPSHOT as a dependency, then the corresponding directory in the .m2 folder would be accessed.

  1. Check that your .m2 folder has directory repository\org\apache\commons\commons-lang3\3.12.0.

Maven has downloaded the artifact that was referenced as <dependency>. Please note that this version does not end with SNAPSHOT. Version numbers that end with SNAPSHOT are development versions that will change. Versions without SNAPSHOT are expected not to change anymore. Anytime that such an artifact is used, the data should be the same.

Conclusion

Maven is a tool that automates compiling and linking Java programs. It distinguishes build phases like clean, process-resources, compile and install that each belong to a lifecycle. When Maven executes a phase, it automatically executes the preceding phases of the lifecycle first. Maven delegates its work to plugins, little programs that can have multiple functions that are named goals. Each phase is linked to plugin goals, which appear in the console output when Maven executes. If your Maven build fails or if you have to update the build process, you probably need information about specific Maven plugins. Maven plugins are usually documented quite well on the internet. Maven plugins and dependencies in your pom.xml are Maven artifacts. Each artifact is referenced by three Maven coordinates: the group id, the artifact id and the version. Maven can download artifacts automatically and stores them in a central repository on your computer.

In the next subsection, you will use Maven to execute the Java program you wrote.