Build Tools: Maven and Gradle
Build tools automate compilation, testing, packaging, and dependency management. Maven and Gradle are the two dominant build tools in the Java ecosystem.
Maven vs Gradle
| Feature | Maven | Gradle |
|---|---|---|
| Config Format | XML (pom.xml) |
Groovy/Kotlin (build.gradle) |
| Build Speed | Slower | Faster (incremental builds) |
| Learning Curve | Easier (convention) | Steeper (more flexible) |
| Flexibility | Convention over config | Highly customizable |
| IDE Support | Excellent | Excellent |
Maven
Maven uses pom.xml (Project Object Model) for configuration.
Project Structure
my-project/
├── pom.xml
├── src/
│ ├── main/
│ │ ├── java/ # Application source code
│ │ └── resources/ # Config files, properties
│ └── test/
│ ├── java/ # Test source code
│ └── resources/ # Test resources
└── target/ # Compiled output (generated)
Basic pom.xml
<?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>my-app</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- JUnit 5 for testing -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>
<!-- SLF4J for logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.9</version>
</dependency>
</dependencies>
</project>
Common Maven Commands
| Command | Description |
|---|---|
mvn clean |
Delete target directory |
mvn compile |
Compile source code |
mvn test |
Run unit tests |
mvn package |
Create JAR/WAR file |
mvn install |
Install to local repository |
mvn clean install |
Clean, compile, test, and install |
mvn dependency:tree |
Show dependency hierarchy |
Dependency Scopes
<!-- compile (default): Available everywhere -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>32.1.2-jre</version>
</dependency>
<!-- provided: Available at compile, not packaged (e.g., servlet API) -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!-- test: Only for testing -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>
<!-- runtime: Not needed for compilation, only at runtime -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
<scope>runtime</scope>
</dependency>
Gradle
Gradle uses Groovy or Kotlin DSL for configuration.
Basic build.gradle
plugins {
id 'java'
id 'application'
}
group = 'com.example'
version = '1.0.0'
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
repositories {
mavenCentral()
}
dependencies {
// Implementation dependencies
implementation 'com.google.guava:guava:32.1.2-jre'
implementation 'org.slf4j:slf4j-api:2.0.9'
// Test dependencies
testImplementation 'org.junit.jupiter:junit-jupiter:5.10.0'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
application {
mainClass = 'com.example.Main'
}
test {
useJUnitPlatform()
}
Common Gradle Commands
| Command | Description |
|---|---|
./gradlew build |
Compile, test, and package |
./gradlew clean |
Delete build directory |
./gradlew test |
Run unit tests |
./gradlew run |
Run the application |
./gradlew dependencies |
Show dependency tree |
./gradlew tasks |
List available tasks |
Gradle Wrapper: Always use
./gradlew (or gradlew.bat
on Windows) instead of gradle. The wrapper ensures everyone uses the same
Gradle version.
Creating Executable JARs
Maven (with shade plugin)
<build>
<plugins>
<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>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.example.Main</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
Gradle (fat JAR)
jar {
manifest {
attributes 'Main-Class': 'com.example.Main'
}
// Include all dependencies in the JAR
from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
Multi-Module Projects
Maven Parent POM
<!-- parent/pom.xml -->
<project>
<groupId>com.example</groupId>
<artifactId>parent</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<modules>
<module>core</module>
<module>web</module>
<module>api</module>
</modules>
<dependencyManagement>
<dependencies>
<!-- Version managed here, used in children -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>3.1.5</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
Summary
- Maven: Convention-based, XML config, great for standard projects
- Gradle: Flexible, faster builds, Groovy/Kotlin DSL
- Use dependency scopes to control classpath
- Use the Gradle Wrapper for consistent builds
- Shade/Fat JARs bundle dependencies for deployment
- Multi-module projects share configuration via parent
Enjoying these tutorials?