Apache Maven Build Guide — Complete Java Project Automation
In this tutorial, you'll learn about Apache Maven Build Guide. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.
Apache Maven is a build automation tool for Java projects that manages dependencies, compiles source code, runs tests, and packages artifacts using declarative XML configuration and a convention-over-configuration philosophy.
What You'll Learn
You'll learn how to configure a Maven POM file, manage dependencies with transitive resolution, execute build lifecycle phases, create multi-module projects, and integrate plugins for testing, packaging, and reporting.
Why Maven Matters
Every Java project needs a build system. Maven enforces a standard project structure and dependency management model that works across thousands of real-world projects. Understanding Maven is essential for Java development, CI/CD pipelines, and enterprise application deployment.
Real-World Use
Maven builds everything from small libraries to the backend services powering Doda Browser — where multi-module Maven projects manage shared libraries, API contracts, and deployable services with consistent versioning across the team.
Prerequisites
- Java 11+ installed
- Basic YAML or XML familiarity
- Maven 3.9+ installed
Step 1: Project Setup and POM Structure
Every Maven project starts with a pom.xml file. This file declares the project coordinates, dependencies, and build configuration.
<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.dodatech</groupId>
<artifactId>hello-maven</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>
</dependencies>
</project>
Expected result: Maven reads this POM, downloads the Gson dependency from Maven Central, and makes it available during compilation.
Step 2: Build Lifecycle and Phases
Maven defines a standard build lifecycle with phases that execute in order. The three main lifecycles are default, clean, and site.
# Compile source code
mvn compile
# Run all tests
mvn test
# Package into JAR
mvn package
# Install into local repository
mvn install
# Full clean build
mvn clean install
# Skip tests during build
mvn package -DskipTests
Expected output: Running mvn clean install produces output showing each phase — resources, compile, test, package, install — with BUILD SUCCESS at the end.
Step 3: Dependency Management
Maven resolves transitive dependencies automatically. If your project depends on Library A, and Library A depends on Library B, Maven downloads both. You can exclude unwanted transitive dependencies using exclusions.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.2.0</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Scope controls when the dependency is available -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>
Expected behavior: Dependencies with scope=test are only available during the test phase and are excluded from the final JAR. Exclusions prevent unwanted transitive libraries from being pulled in.
Step 4: Plugins and Reporting
Maven plugins extend the build lifecycle. The Surefire plugin runs tests, the JAR plugin packages artifacts, and the Shade plugin creates fat JARs with all dependencies bundled.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<includes>
<include>**/*Test.java</include>
</includes>
<reportNameSuffix>unit-tests</reportNameSuffix>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.0</version>
<executions>
<execution>
<phase>package</phase>
<goals><goal>shade</goal></goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Expected behavior: With the Shade plugin, mvn package produces a fat JAR containing your classes plus all runtime dependencies. The Surefire plugin generates an XML test report in target/surefire-reports/.
Step 5: Multi-Module Projects
Real projects split into multiple modules — a shared library, an API module, and a web application. The parent POM lists child modules, and each child inherits common configuration.
<!-- Parent pom.xml -->
<project>
<groupId>com.dodatech</groupId>
<artifactId>myapp-parent</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<modules>
<module>core</module>
<module>api</module>
<module>webapp</module>
</modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.dodatech</groupId>
<artifactId>core</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
<!-- core/pom.xml — inherits from parent -->
<project>
<parent>
<groupId>com.dodatech</groupId>
<artifactId>myapp-parent</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>core</artifactId>
</project>
Expected behavior: Running mvn install from the parent directory builds all modules in reactor order, resolving inter-module dependencies automatically.
Architecture
flowchart LR
subgraph "Maven Build"
POM[pom.xml]
SRC[src/ Directory]
TARGET[target/ Directory]
end
subgraph "Lifecycle Phases"
COMPILE[compile] --> TEST[test]
TEST --> PACKAGE[package]
PACKAGE --> INSTALL[install]
INSTALL --> DEPLOY[deploy]
end
subgraph "External"
CENTRAL[Maven Central]
LOCAL[~/.m2/Repository]
end
POM --> COMPILE
SRC --> COMPILE
COMPILE --> TARGET
CENTRAL -->|download deps| LOCAL
LOCAL --> COMPILE
Common Errors
1. Plugin execution not covered by lifecycle configuration
Maven requires plugin executions to be bound to lifecycle phases. If a plugin goal is not bound to any phase, it won't run. Always specify the <phase> element.
2. Jar hell from conflicting transitive versions
Two dependencies may pull different versions of the same library. Use mvn dependency:tree to visualize the conflict, then add an exclusion or manage the version in dependencyManagement.
3. Non-resolvable parent POM
If a child module's parent POM is not in the local Repository or Maven Central, the build fails. Always run mvn install on the parent first, or use <relativePath> to point to the parent's POM file.
4. Build fails with missing artifact
A dependency might exist but not be reachable due to Repository configuration. Add the required Repository in the POM's <repositories> section.
5. Tests fail with NoClassDefFoundError
A test dependency is missing or has the wrong scope. JUnit and test frameworks should use <scope>test</scope>.
Practice Questions
1. What is the purpose of the jar, war, pom, or ear. A parent POM uses pom packaging. This affects which lifecycle phases and plugins are relevant.
2. How does Maven resolve transitive dependencies? Maven reads the dependency tree recursively. Each dependency's POM lists its own dependencies, and Maven downloads them all, merging versions using a nearest-wins Strategy.
3. What is the difference between mvn package and mvn install?
mvn package produces the artifact in the target/ directory. mvn install does the same plus copies the artifact into the local Maven Repository (~/.m2/Repository) so other local projects can depend on it.
4. Challenge: Create a multi-module project
Build a parent POM with three modules — utils, service, and app. The service module depends on utils, and app depends on service. Verify that building from the parent compiles all three in the correct order.
5. Challenge: Custom archetype Create a Maven archetype that generates a new project with preconfigured dependencies for logging, testing, and JSON Parsing.
FAQ
Next Steps
- Explore Gradle for an alternative build tool with Groovy DSL
- Learn how CI/CD pipelines integrate Maven builds with Jenkins or GitHub Actions
- Automate dependency updates with the Maven Versions plugin
- Try the Docker build strategies tutorial for containerizing Maven artifacts
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro