From Source to JAR - Part 2

The first part of our series covered the basics of compiling Java code and creating executable JAR files. In this second part, we’ll explain how Maven works.

This article will cover Maven’s basic principles and functions. We’ll examine Maven’s Project Object Model (POM) and build lifecycle phases. The next article will explore Gradle, with its flexible and faster approach using Groovy or Kotlin scripts.

Maven Overview

Maven is a powerful tool for automating the build process, especially for Java projects. It simplifies building by using standard structures and lifecycle phases, making the process more predictable and manageable. Maven relies on simple configurations to create a consistent build system across different projects, using the Project Object Model (POM) file (pom.xml) to standardize and consolidate project details.

  • Example of a 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>

  <groupId>org.alvesfc</groupId>
  <artifactId>mavenSample</artifactId>
  <version>1.0-SNAPSHOT</version>

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

</project>

This example defines a simple Java project with a dependency on JUnit for testing and configures the Maven Compiler Plugin to compile Java code with Java 17.

  • Key Elements of a POM File:

    • groupId: Identifies the project’s group or organization.
    • artifactId: Specifies the project’s unique name.
    • version: Indicates the project’s version number.
    • properties: Contains project-specific configurations and settings.
      • maven.compiler.source: Specifies the Java version for source code.
      • maven.compiler.target: Specifies the Java version for compiled code.
      • project.build.sourceEncoding: Specifies the character encoding for source files.

Maven Build Lifecycle Phases

Maven’s build lifecycle is a well-structured process with clearly defined phases to ensure that your Java project is built,tested, packaged, and ready for deployment.

Here’s a breakdown of the essential lifecycle phases and their purposes:

  • Clean : Deletes all files from the previous build to start fresh for the next build.

  • Validate : Make sure all project information is available before starting the build. Check for necessary files, and validate project structure and configuration. For example, verify required directories, files, and pom.xml formatting.

  • Compile: Compiling source code involves converting it into bytecode for the Java Virtual Machine (JVM) to execute. This is achieved by running the javac command to compile .java files into .class files.

  • Test : Run tests on the compiled source code to confirm correct behavior. This involves executing unit tests using a framework like JUnit. Tests should not rely on code packaging or deployment. For example, run tests located in src/test/java and create test reports.

  • Package: Packages the code into distributable formats like JAR, WAR, or EAR by assembling the compiled code and resources into an archive. For example, it creates a JAR file (my-app-1.0.jar) in the target directory using the compiled classes and resources.

  • Verify: Runs extra checks on integration test results to ensure quality criteria are met. This involves validating packaging, running integration tests, and checking code quality. For example, running integration tests that rely on the packaged code and ensuring smooth integration with other components.

  • Install: The command “install” copies the package, such as a JAR file, into the local Maven repository. This makes the package available for use in other projects on the local machine. For example, placing the JAR file into the .m2/repository directory allows other local projects to use it as a dependency.

  • Deploy: Deploy the final package to a remote repository for sharing. This involves sending the finished code to a remote repository where other developers can access and use it. For example, upload the JAR file to a remote Maven repository like Nexus or Artifactory.

Installing Maven via Package Managers

  1. Linux:
  • Debian-based systems (e.g., Ubuntu):

    sudo apt update
    sudo apt install maven
    
  1. macOS:

    brew install maven
    

After installation, verify it by running:

mvn -version

Creating a Maven Project

To create a new Maven project, use the following command:

mvn archetype:generate -DgroupId=org.alvesfc -DartifactId=mavenSample -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

Explanation of the command:

  • mvn archetype:generate: This is the Maven command to generate a new project from an archetype. An archetype is a project templating toolkit.

  • -DgroupId=org.alvesfc: This sets the groupId for the new project. The groupId is a unique base package name for the project, typically using your organization’s domain name in reverse. In this case, it’s set to org.alvesfc.

  • -DartifactId=mavenSample: This sets the artifactId for the new project. The artifactId is the name of the jar without version. It’s used along with the groupId to uniquely identify the project artifact in the repository. Here, it’s set to mavenSample.

  • -DarchetypeArtifactId=maven-archetype-quickstart: This specifies the archetype to use to generate the project. The maven-archetype-quickstart is a basic archetype which creates a simple Java application with a main method and a JUnit test case.

  • -DinteractiveMode=false: This flag is used to skip the interactive mode in the archetype generation process. If set to true, Maven would prompt you to confirm the values for groupId, artifactId, and other parameters. By setting it to false, it uses the provided values without asking for confirmation.

When you run the command above, a folder named mavenSample will be created with the following structure:

mavenSample
├── pom.xml
└── src
    ├── main
    │   └── java
    │       └── org
    │           └── alvesfc
    │               └── App.java
    └── test
        └── java
            └── org
                └── alvesfc
                    └── AppTest.java

Executing Maven Build Phases

To build the project, go to the project directory and use the mvn command followed by the desired build phase.

For example, to compile the project, run:

mvn compile

You can execute the entire Maven build lifecycle by specifying a goal that triggers the last phase you want to execute.

For example, to run the full build lifecycle up to the install phase, use:

mvn install

This command will run through all the build lifecycle phases, including validate, compile, test, package, verify and install. The install phase copies the packaged JAR file to the local Maven repository.

Skipping Phases:

If you want to skip a particular phase, you can use the -Dskip flag followed by the phase name.

For example, to skip the test phase, run:

mvn install -DskipTests

Conclusion

Understanding Maven basics is essential for Java developers as it simplifies building and managing Java applications. The pom.xml file standardizes the process, making it easier to maintain and automate. In the next part, we’ll explore Gradle, another build tool that offers enhanced flexibility and speed through Groovy or Kotlin scripts, helping you choose the most suitable tool for your development needs.

References

Posts in this series