Introduction

Maven is more than just a build tool—it’s a complete project management framework that enforces a standard structure, manages dependencies, and automates the build lifecycle. In this lecture, we’ll explore how to set up a proper Maven project, understand the pom.xml file, and configure plugins for building, testing, and reporting.

infoThis lecture assumes you’ve completed the previous lectures on setting up Java and learning Java basics. Make sure Maven is installed before proceeding.

Why Use Maven?

Before diving into the structure, let’s understand what Maven solves:

Problems Maven Solves
  • Dependency Management: Automatically downloads and manages external libraries
  • Standard Project Structure: Everyone follows the same conventions
  • Build Automation: Consistent compilation, testing, and packaging
  • Plugin Ecosystem: Extends functionality without writing custom scripts
  • Multi-Module Projects: Manages complex projects with multiple components

Maven Standard Directory Structure

Maven follows a convention-over-configuration philosophy. Here’s the standard structure:

my-project/
├── pom.xml                          # Project Object Model (configuration)
├── src/
│   ├── main/
│   │   ├── java/                    # Java source code
│   │   │   └── com/example/app/
│   │   │       ├── Main.java
│   │   │       ├── model/
│   │   │       │   └── Note.java
│   │   │       └── service/
│   │   │           └── NoteService.java
│   │   ├── resources/               # Configuration files, properties
│   │   │   ├── application.properties
│   │   │   └── logback.xml
│   │   └── webapp/                  # Web resources (for web apps)
│   │       ├── WEB-INF/
│   │       └── index.html
│   └── test/
│       ├── java/                    # Test source code
│       │   └── com/example/app/
│       │       ├── NoteTest.java
│       │       └── NoteServiceTest.java
│       └── resources/               # Test resources
│           └── test.properties
├── target/                          # Build output (generated)
│   ├── classes/                     # Compiled classes
│   ├── test-classes/                # Compiled test classes
│   ├── my-project-1.0.0.jar         # Packaged JAR file
│   └── surefire-reports/            # Test reports
└── README.md                        # Project documentation

errorNever commit the ‘target/’ directory to version control! It contains generated files that should be rebuilt. Add it to your .gitignore file.

Directory Purpose

Directory Purpose
src/main/java Production Java source files
src/main/resources Production configuration files
src/test/java Test source files
src/test/resources Test configuration files
target Compiled output and packages (auto-generated)

Creating a Maven Project

Maven provides archetypes (project templates) for quick starts:

mvn archetype:generate \
    -DgroupId=com.example \
    -DartifactId=notes-app \
    -DarchetypeArtifactId=maven-archetype-quickstart \
    -DarchetypeVersion=1.4 \
    -DinteractiveMode=false

Parameters explained:

Method 2: Manual Creation

Create Project Directory

mkdir notes-app
cd notes-app

Create Directory Structure

mkdir -p src/main/java/notes_app
mkdir -p src/main/resources
mkdir -p src/test/java/notes_app
mkdir -p src/test/resources

Create pom.xml

Create a pom.xml file in the project root (we’ll cover this next).

Understanding pom.xml

The pom.xml (Project Object Model) is Maven’s configuration file. Let’s build one from scratch, explaining each section.

Basic Project Information

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

    <!-- Project Coordinates -->
    <groupId>com.example</groupId>
    <artifactId>notes-app</artifactId>
    <version>1.0.0</version>
    <packaging>jar</packaging>

    <!-- Project Metadata -->
    <name>Notes App</name>
    <description>A simple note management application</description>
Project Coordinates (GAV)
  • groupId: Unique identifier for your organization (e.g., com.example, org.apache)
  • artifactId: Project name/identifier (e.g., notes-app, commons-lang)
  • version: Project version (e.g., 1.0.0, 2.1-SNAPSHOT)
  • packaging: Output format (jar, war, pom)

Properties

Properties define reusable values and project settings:

    <properties>
        <!-- Java version -->
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        
        <!-- Character encoding -->
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        
        <!-- Dependency versions -->
        <junit.version>5.8.2</junit.version>
    </properties>

Common properties:

infoDefine version numbers as properties! This makes it easy to update versions in one place.

Dependencies

Dependencies are external libraries your project needs:

    <dependencies>
        <!-- JUnit 5 for testing -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
        
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
        
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

Dependency Scopes

Scope Description Available In
compile Default, available everywhere Main code, tests, runtime
test Only for testing Test code only
provided Provided by container (e.g., servlet API) Compile & test, not packaged
runtime Not needed for compilation Runtime & tests only

Finding Dependencies

Search for dependencies on Maven Central:

  1. Search for the library name
  2. Copy the Maven dependency block
  3. Paste into your pom.xml

Example: Adding Apache Commons Lang:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.12.0</version>
</dependency>

Build Configuration

The build section configures plugins that perform specific tasks:

    <build>
        <plugins>
            <!-- Compiler Plugin -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>11</source>
                    <target>11</target>
                </configuration>
            </plugin>
            
            <!-- Surefire Plugin (for running tests) -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.22.2</version>
            </plugin>
            
            <!-- JaCoCo Plugin (for code coverage) -->
            <plugin>
                <groupId>org.jacoco</groupId>
                <artifactId>jacoco-maven-plugin</artifactId>
                <version>0.8.10</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>prepare-agent</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>report</id>
                        <phase>test</phase>
                        <goals>
                            <goal>report</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>check</id>
                        <goals>
                            <goal>check</goal>
                        </goals>
                        <configuration>
                            <rules>
                                <rule>
                                    <element>BUNDLE</element>
                                    <limits>
                                        <limit>
                                            <counter>LINE</counter>
                                            <value>COVEREDRATIO</value>
                                            <minimum>0.60</minimum>
                                        </limit>
                                    </limits>
                                </rule>
                            </rules>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

Essential Maven Plugins

1. Maven Compiler Plugin

Compiles Java source code.

Configuration options:

<configuration>
    <source>11</source>               <!-- Source Java version -->
    <target>11</target>                <!-- Target bytecode version -->
    <encoding>UTF-8</encoding>         <!-- Source file encoding -->
    <compilerArgs>
        <arg>-parameters</arg>         <!-- Keep parameter names in bytecode -->
    </compilerArgs>
</configuration>

2. Maven Surefire Plugin

Runs unit tests during the build.

Features:

Configuration example:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.22.2</version>
    <configuration>
        <includes>
            <include>**/*Test.java</include>
            <include>**/*Tests.java</include>
        </includes>
    </configuration>
</plugin>

3. JaCoCo Plugin

Generates code coverage reports.

What it does:

Key configuration:

<configuration>
    <rules>
        <rule>
            <element>BUNDLE</element>
            <limits>
                <limit>
                    <counter>LINE</counter>
                    <value>COVEREDRATIO</value>
                    <minimum>0.60</minimum>  <!-- 60% minimum coverage -->
                </limit>
            </limits>
        </rule>
    </rules>
</configuration>

View coverage report:

mvn test
open target/site/jacoco/index.html

4. Maven JAR Plugin

Creates JAR files with additional configuration:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <version>3.2.0</version>
    <configuration>
        <archive>
            <manifest>
                <mainClass>notes_app.Main</mainClass>
                <addClasspath>true</addClasspath>
            </manifest>
        </archive>
    </configuration>
</plugin>

5. Maven Shade Plugin

Creates an “uber JAR” with all dependencies included:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>3.2.4</version>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
            <configuration>
                <transformers>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                        <mainClass>notes_app.Main</mainClass>
                    </transformer>
                </transformers>
            </configuration>
        </execution>
    </executions>
</plugin>

Maven Build Lifecycle

Maven has three built-in lifecycles, each with phases:

Default Lifecycle (Build)

Phase Description
validate Validate project structure
compile Compile source code
test Run unit tests
package Create JAR/WAR file
verify Run integration tests
install Install to local repository
deploy Deploy to remote repository

Common Maven Commands

# Clean (delete target directory)
mvn clean

# Compile source code
mvn compile

# Run tests
mvn test

# Package into JAR
mvn package

# Skip tests while packaging
mvn package -DskipTests

# Install to local repository
mvn install

# Run a specific phase (includes all previous phases)
mvn clean install

# Run the application
mvn exec:java -Dexec.mainClass="notes_app.Main"

Creating the Notes App Project

Let’s create a complete Maven project for a notes application:

Create Project Structure

mkdir -p notes-app/src/main/java/notes_app
mkdir -p notes-app/src/test/java/notes_app
cd notes-app

Create pom.xml

Use the complete pom.xml example from earlier in this lecture.

Create Java Classes

Create src/main/java/notes_app/Note.java, NoteService.java, and Main.java with the implementation from your project.

Build the Project

mvn clean compile

Run the Application

mvn exec:java -Dexec.mainClass="notes_app.Main"

Package Management

Java Packages

Packages organize classes into namespaces:

package notes_app;  // Package declaration (must be first line)

import java.util.List;  // Import from Java standard library
import java.time.LocalDateTime;

public class Note {
    // Class implementation
}

Package naming conventions:

Directory Structure Matches Packages

src/main/java/
└── com/
    └── example/
        └── project/
            ├── Main.java                    (package com.example.project)
            ├── model/
            │   └── Note.java                (package com.example.project.model)
            └── service/
                └── NoteService.java         (package com.example.project.service)

Best Practices

1. Use Properties for Versions

<properties>
    <junit.version>5.8.2</junit.version>
    <jackson.version>2.13.0</jackson.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter</artifactId>
        <version>${junit.version}</version>
        <scope>test</scope>
    </dependency>
</dependencies>

2. Add .gitignore

# Maven
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties

# IDE
.idea/
*.iml
.vscode/
.classpath
.project
.settings/

# OS
.DS_Store
Thumbs.db

3. Use Semantic Versioning

Format: MAJOR.MINOR.PATCH

4. Document Dependencies

Add comments explaining why dependencies are needed:

<!-- JUnit 5 - Modern testing framework with assertions and annotations -->
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>${junit.version}</version>
    <scope>test</scope>
</dependency>

5. Keep Dependencies Updated

Check for updates:

mvn versions:display-dependency-updates

Troubleshooting

“Package does not exist”

Problem: Import statements can’t find classes.

Solution:

  1. Verify directory structure matches package names
  2. Run mvn clean compile
  3. Refresh your IDE project

“Cannot find symbol”

Problem: Classes aren’t compiled or in wrong location.

Solution:

  1. Ensure files are in src/main/java/ (not src/)
  2. Package declaration matches directory structure
  3. Run mvn clean compile

Dependency Not Found

Problem: Maven can’t download a dependency.

Solution:

  1. Check spelling in pom.xml
  2. Verify version exists on Maven Central
  3. Delete local repository cache: rm -rf ~/.m2/repository/com/example/dependency-name
  4. Run mvn clean install -U (force update)

Summary

You’ve learned how to structure and configure professional Java projects using Maven!

Key takeaways:

What’s Next?

In the next lecture, we’ll cover:

  1. Unit Testing with JUnit 5 - Writing effective tests
  2. Test-Driven Development - Writing tests first
  3. Assertions and Test Lifecycle - JUnit features
  4. Code Coverage - Measuring test effectiveness with JaCoCo

Quick Reference

# Create project
mvn archetype:generate -DgroupId=com.example -DartifactId=my-app

# Build commands
mvn clean           # Delete target/
mvn compile         # Compile source
mvn test            # Run tests
mvn package         # Create JAR
mvn install         # Install to local repo

# Run application
mvn exec:java -Dexec.mainClass="com.example.Main"

# Check for updates
mvn versions:display-dependency-updates

infoUnderstanding Maven’s conventions saves countless hours of configuration. Follow the standard structure, and Maven handles the rest!