Maven Plugins — Compiler, Surefire, Shade, and More
Plugins are the engine of Maven. Every action — compile, test, package — is performed by a plugin. Understanding plugins gives you full control over your build.
How Plugins Work
Plugins provide goals that bind to lifecycle phases:
Phase Plugin Goal
────────────── ──────────────────── ──────────────
compile maven-compiler-plugin compiler:compile
test maven-surefire-plugin surefire:test
package maven-jar-plugin jar:jar
You configure plugins in <build><plugins>:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<!-- plugin-specific config -->
</configuration>
</plugin>
</plugins>
</build>
Compiler Plugin — Java Version
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<release>21</release> <!-- Java 21 -->
</configuration>
</plugin>
Or via properties (simpler):
<properties>
<maven.compiler.release>21</maven.compiler.release>
</properties>
<release>is preferred over<source>+<target>— it also sets--releasefor API compatibility checking.
Surefire Plugin — Running Tests
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.5</version>
<configuration>
<includes>
<include>**/*Test.java</include>
<include>**/*Tests.java</include>
</includes>
<excludes>
<exclude>**/*IntegrationTest.java</exclude>
</excludes>
</configuration>
</plugin>
mvn test
# Runs: UserServiceTest.java, OrderTests.java
# Skips: UserIntegrationTest.java
Failsafe Plugin — Integration Tests
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.2.5</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
mvn verify
# Runs *IT.java and *IntegrationTest.java files
Shade Plugin — Uber/Fat JAR
Packages your app + all dependencies into a single JAR:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.6.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation=
"org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.myapp.App</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
mvn clean package
java -jar target/my-project-1.0.0.jar
Spring Boot Maven Plugin
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>3.3.0</version>
</plugin>
# Package as executable JAR
mvn clean package
java -jar target/my-app-1.0.0.jar
# Run directly
mvn spring-boot:run
Exec Maven Plugin — Run Java Classes
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<mainClass>com.myapp.App</mainClass>
</configuration>
</plugin>
mvn exec:java
JaCoCo Plugin — Code Coverage
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.12</version>
<executions>
<execution>
<goals><goal>prepare-agent</goal></goals>
</execution>
<execution>
<id>report</id>
<phase>test</phase>
<goals><goal>report</goal></goals>
</execution>
</executions>
</plugin>
mvn clean test
# Report: target/site/jacoco/index.html
Plugin Management
<pluginManagement> defines plugin versions in parent POM — children inherit without specifying version:
<!-- Parent POM -->
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<release>21</release>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
<!-- Child POM — no version needed -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<!-- version and config inherited from parent -->
</plugin>
</plugins>
</build>
Useful Plugins Summary
| Plugin | Purpose | Command |
|---|---|---|
maven-compiler-plugin |
Java version | (automatic) |
maven-surefire-plugin |
Unit tests | mvn test |
maven-failsafe-plugin |
Integration tests | mvn verify |
maven-shade-plugin |
Fat JAR | mvn package |
spring-boot-maven-plugin |
Spring Boot JAR/run | mvn spring-boot:run |
exec-maven-plugin |
Run main class | mvn exec:java |
jacoco-maven-plugin |
Code coverage | mvn test |
maven-enforcer-plugin |
Enforce rules (Java version, etc.) | mvn verify |
versions-maven-plugin |
Check for outdated deps | mvn versions:display-dependency-updates |
Common Mistakes
| Mistake | Fix |
|---|---|
| Wrong Surefire version (can’t find JUnit 5) | Use Surefire 3.x for JUnit 5 |
Plugin in <pluginManagement> but not <plugins> |
<pluginManagement> only declares — child must also add to <plugins> |
| Shade plugin + Spring Boot plugin | Use one or the other, not both |
Missing <executions> for JaCoCo |
JaCoCo needs prepare-agent execution |
Key Takeaways
- Plugins do all the work — compile, test, package are all plugin goals.
- Compiler plugin sets Java version; Surefire runs tests; Shade creates fat JARs.
<pluginManagement>centralizes plugin config in parent POMs.- Spring Boot plugin creates executable JARs with embedded server.
- Use
versions:display-dependency-updatesto find outdated dependencies.
What’s Next?
Next: Gradle Introduction — the alternative build tool with Groovy/Kotlin DSL, faster builds, and the Gradle wrapper.