Maven / Gradle
Maven build tool: pom.xml, lifecycle, profiles, plugins, dependency management, and the patterns that scale.
Java — Maven essentials
EXAMPLE
# ===== Create a project =====
mvn archetype:generate \
-DgroupId=com.example -DartifactId=myapp \
-DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
cd myapp
# ===== pom.xml structure =====
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>myapp</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.release>21</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.2</version>
</plugin>
</plugins>
</build>
</project>
# ===== Lifecycle =====
mvn validate # check pom + project sanity
mvn compile # compile main sources
mvn test # compile + run unit tests
mvn package # compile + test + package (jar/war)
mvn verify # package + integration tests
mvn install # verify + install into local repo
mvn deploy # install + push to remote repo
# Skip tests (use sparingly):
mvn package -DskipTests
mvn package -Dmaven.test.skip=true # also skips compile
# ===== Common plugins =====
# maven-compiler-plugin compile sources
# maven-surefire-plugin unit tests
# maven-failsafe-plugin integration tests (run during verify)
# maven-shade-plugin uber-jar with deps included
# spring-boot-maven-plugin Spring Boot fat-jar / native-image
# jacoco-maven-plugin test coverage
# spotless-maven-plugin formatter / linter
# ===== Dependency management =====
# Scope:
# - compile (default) on classpath always
# - provided available at compile but provided by runtime (servlet API)
# - runtime not at compile; at runtime (e.g. JDBC driver)
# - test only for test phases
# - system / import special
# Exclude transitive:
<dependency>
<groupId>com.foo</groupId>
<artifactId>bar</artifactId>
<version>1.0</version>
<exclusions>
<exclusion>
<groupId>com.baz</groupId>
<artifactId>old-thing</artifactId>
</exclusion>
</exclusions>
</dependency>
# ===== Profiles =====
<profiles>
<profile>
<id>prod</id>
<properties>
<env>production</env>
</properties>
</profile>
</profiles>
mvn package -Pprod
# ===== Multi-module =====
# Parent pom with packaging=pom listing <modules>.
# Child poms inherit + override.
# ===== Useful commands =====
mvn dependency:tree # see resolved deps
mvn dependency:analyze # find unused / undeclared deps
mvn versions:display-dependency-updates # check for newer versions
mvn help:effective-pom # see inherited + merged pom
# ===== Patterns =====
# - properties for version pinning; single source of truth
# - dependencyManagement block for multi-module version control
# - Spring Boot / Quarkus parents take care of most plugin config
# - Use a build wrapper (mvnw) so teammates use the same Maven version
# ===== Pitfalls =====
# - Skipping tests in CI to ship faster -> regressions
# - SNAPSHOT versions in production -> non-reproducible
# - Multi-module without dependencyManagement -> version drift
# - Manual phase invocation (mvn surefire:test) instead of mvn test
Why it matters
Maven: pom.xml describes the project, lifecycle phases orchestrate the build, plugins do the work. Pin versions in properties, use dependencyManagement for multi-module, lean on Surefire / Failsafe for tests, and ship mvnw. Boring + predictable is the entire point.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Discussion
Loading…