Gradle
Build Tool
Gradle
Overview
Gradle is a powerful build automation tool primarily focused on the Java ecosystem. Developed by Hans Dockter and Adam Murdoch in 2008, Gradle was designed to overcome the limitations of Apache Ant and Apache Maven. Gradle uses Groovy DSL or Kotlin DSL to write build scripts, supporting both declarative configuration and imperative logic. With advanced optimization features like incremental builds, build caching, and parallel execution, Gradle achieves fast builds even for large-scale projects. As the standard build tool for Android development, Gradle now supports multi-language development including Java, Kotlin, Scala, C++, Swift, and more.
Details
Key Features
- DSL-based Configuration: Flexible build scripts using Groovy or Kotlin DSL
- High-Performance Builds: Optimization through incremental builds, build caching, and parallel execution
- Dependency Management: Powerful dependency resolution and conflict handling
- Multi-Project Support: Support for large-scale multi-module projects
- Plugin Ecosystem: Rich community plugins and official plugins
- IDE Integration: Excellent support in IntelliJ IDEA, Eclipse, and Android Studio
- Multi-Language Support: Java, Kotlin, Scala, C++, Swift, JavaScript, and more
Architecture
Task-based execution engine, DAG (Directed Acyclic Graph) dependency management, acceleration through Gradle daemon, separation of configuration and execution phases.
Ecosystem
Gradle Plugin Portal, Android Gradle Plugin, Spring Boot Gradle Plugin, Kotlin Gradle Plugin, rich third-party plugin ecosystem.
Pros and Cons
Pros
- High Performance: Acceleration through incremental builds and caching
- Flexibility: Support for both imperative logic and declarative configuration
- Kotlin DSL: Type-safe build script creation
- Android Standard: De facto standard for Android development
- Extensibility: High extensibility through plugins
- Multi-Language Support: Support for languages beyond Java
- Modern Architecture: Latest build system design
Cons
- Learning Curve: Understanding DSL and Gradle concepts required
- Complexity: Configuration becomes complex in large projects
- Memory Usage: Consumes more memory than Maven
- Build Script Debugging: DSL debugging can be challenging
- Version Compatibility: Compatibility issues between Gradle versions
- Cold Start Time: Initial startup time for first runs
Reference Links
- Gradle Official Site
- Gradle User Guide
- Gradle DSL Reference
- Gradle Plugin Portal
- Gradle GitHub Repository
- Gradle Getting Started
Usage Examples
Installation and Project Setup
# Check Gradle installation
gradle --version
# Create new Gradle project
gradle init
# Project type selection (interactive)
# 1: basic
# 2: application
# 3: library
# 4: Gradle plugin
# Manual project creation
mkdir my-gradle-project
cd my-gradle-project
# Generate Gradle Wrapper
gradle wrapper
# Build using Wrapper (recommended)
./gradlew build
./gradlew test
./gradlew clean
./gradlew tasks --all # List available tasks
# Display build information
./gradlew projects
./gradlew dependencies
./gradlew properties
Basic build.gradle (Groovy DSL)
plugins {
id 'java'
id 'application'
}
// Project information
group = 'com.example'
version = '1.0.0'
// Java configuration
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
// Application configuration
application {
mainClass = 'com.example.Main'
}
// Repository configuration
repositories {
mavenCentral()
mavenLocal()
google()
gradlePluginPortal()
}
// Dependencies
dependencies {
// Compile-time dependencies
implementation 'org.apache.commons:commons-lang3:3.12.0'
implementation 'com.google.guava:guava:31.1-jre'
implementation 'org.slf4j:slf4j-api:2.0.6'
// Runtime dependencies
runtimeOnly 'ch.qos.logback:logback-classic:1.4.6'
// Test dependencies
testImplementation 'org.junit.jupiter:junit-jupiter:5.9.2'
testImplementation 'org.mockito:mockito-core:5.1.1'
testImplementation 'org.assertj:assertj-core:3.24.2'
// Annotation processor
annotationProcessor 'org.projectlombok:lombok:1.18.26'
compileOnly 'org.projectlombok:lombok:1.18.26'
}
// Test configuration
test {
useJUnitPlatform()
testLogging {
events "passed", "skipped", "failed"
exceptionFormat "full"
}
// Test coverage
finalizedBy jacocoTestReport
}
// JaCoCo configuration
jacoco {
toolVersion = "0.8.8"
}
jacocoTestReport {
dependsOn test
reports {
xml.required = true
html.required = true
}
}
// JAR configuration
jar {
manifest {
attributes(
'Implementation-Title': project.name,
'Implementation-Version': project.version,
'Main-Class': application.mainClass
)
}
// Create Fat JAR
from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
// Custom task
task copyDocs(type: Copy) {
description = 'Copy documentation files'
group = 'documentation'
from 'src/docs'
into 'build/docs'
include '**/*.md'
}
// Process property files
processResources {
expand(project.properties)
}
build.gradle.kts (Kotlin DSL)
plugins {
java
application
id("org.springframework.boot") version "3.1.0"
id("io.spring.dependency-management") version "1.1.0"
id("org.jetbrains.kotlin.jvm") version "1.8.21"
id("org.jetbrains.kotlin.plugin.spring") version "1.8.21"
}
group = "com.example"
version = "1.0.0"
java {
sourceCompatibility = JavaVersion.VERSION_17
}
application {
mainClass.set("com.example.ApplicationKt")
}
repositories {
mavenCentral()
}
dependencies {
// Spring Boot
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-security")
implementation("org.springframework.boot:spring-boot-starter-validation")
// Kotlin
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
// Database
runtimeOnly("com.h2database:h2")
runtimeOnly("org.postgresql:postgresql")
// Testing
testImplementation("org.springframework.boot:spring-boot-starter-test") {
exclude(group = "org.junit.vintage", module = "junit-vintage-engine")
}
testImplementation("org.springframework.security:spring-security-test")
testImplementation("io.kotest:kotest-runner-junit5:5.5.5")
testImplementation("io.kotest:kotest-assertions-core:5.5.5")
testImplementation("io.mockk:mockk:1.13.4")
}
tasks {
test {
useJUnitPlatform()
}
withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
kotlinOptions {
freeCompilerArgs = listOf("-Xjsr305=strict")
jvmTarget = "17"
}
}
bootJar {
archiveFileName.set("${project.name}-${project.version}.jar")
}
register<Copy>("generateConfig") {
description = "Generate configuration files"
group = "build setup"
from("src/main/templates")
into("src/main/resources")
expand(project.properties)
filteringCharset = "UTF-8"
}
}
// Development task
tasks.register("dev") {
description = "Start development server"
group = "application"
dependsOn("bootRun")
doFirst {
println("Starting development server...")
}
}
Multi-Project Configuration
// settings.gradle
rootProject.name = 'multi-project-example'
include 'core'
include 'web'
include 'data'
include 'common'
// Define project structure
project(':core').projectDir = file('modules/core')
project(':web').projectDir = file('modules/web')
project(':data').projectDir = file('modules/data')
project(':common').projectDir = file('modules/common')
// Root project build.gradle
plugins {
id 'java'
id 'org.springframework.boot' version '3.1.0' apply false
id 'io.spring.dependency-management' version '1.1.0' apply false
}
// Apply to all projects
allprojects {
group = 'com.example.multiproject'
version = '1.0.0'
repositories {
mavenCentral()
}
}
// Apply to subprojects only
subprojects {
apply plugin: 'java'
apply plugin: 'io.spring.dependency-management'
java {
sourceCompatibility = JavaVersion.VERSION_17
}
dependencies {
// Common dependencies
implementation 'org.slf4j:slf4j-api'
testImplementation 'org.junit.jupiter:junit-jupiter'
}
test {
useJUnitPlatform()
}
}
// Inter-project dependencies
project(':web') {
apply plugin: 'org.springframework.boot'
dependencies {
implementation project(':core')
implementation project(':data')
implementation project(':common')
implementation 'org.springframework.boot:spring-boot-starter-web'
}
}
project(':core') {
dependencies {
implementation project(':common')
implementation project(':data')
}
}
project(':data') {
dependencies {
implementation project(':common')
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
}
}
project(':common') {
dependencies {
implementation 'org.apache.commons:commons-lang3'
}
}
Custom Plugins and Tasks
// Custom task class
class CustomBuildTask extends DefaultTask {
@Input
String inputMessage = "Default message"
@OutputFile
File outputFile
@TaskAction
void execute() {
println "Executing custom build task: ${inputMessage}"
if (!outputFile.parentFile.exists()) {
outputFile.parentFile.mkdirs()
}
outputFile.text = """
Build executed at: ${new Date()}
Message: ${inputMessage}
Project: ${project.name}
Version: ${project.version}
"""
logger.lifecycle("Custom build completed: ${outputFile.absolutePath}")
}
}
// Custom plugin
class CustomBuildPlugin implements Plugin<Project> {
void apply(Project project) {
// Add extension
project.extensions.create('customBuild', CustomBuildExtension)
// Add custom task
project.tasks.register('customBuild', CustomBuildTask) {
description = 'Execute custom build task'
group = 'custom'
inputMessage = project.customBuild.message
outputFile = new File(project.buildDir, 'custom/build-info.txt')
}
// Set dependency on existing task
project.tasks.named('build') {
dependsOn 'customBuild'
}
}
}
// Extension class
class CustomBuildExtension {
String message = "Hello from custom plugin"
boolean enabled = true
List<String> environments = ['dev', 'test', 'prod']
}
// Apply plugin
apply plugin: CustomBuildPlugin
// Plugin configuration
customBuild {
message = "Custom build for ${project.name}"
enabled = true
environments = ['development', 'staging', 'production']
}
// Generate tasks for multiple environments
customBuild.environments.each { env ->
tasks.register("deploy${env.capitalize()}", Copy) {
description = "Deploy to ${env} environment"
group = 'deployment'
from 'build/libs'
into "deploy/${env}"
include '*.jar'
doLast {
println "Deployed to ${env} environment"
}
}
}
Advanced Configuration and Build Optimization
// gradle.properties
# Build optimization
org.gradle.daemon=true
org.gradle.parallel=true
org.gradle.caching=true
org.gradle.configureondemand=true
# JVM settings
org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=1g -XX:+UseG1GC
# Kotlin settings
kotlin.code.style=official
kotlin.incremental=true
kotlin.daemon.jvm.options=-Xmx2g
// Advanced build.gradle configuration
plugins {
id 'java'
id 'jacoco'
id 'checkstyle'
id 'com.github.spotbugs' version '5.0.13'
id 'org.sonarqube' version '4.0.0.2929'
}
// Build cache configuration
buildCache {
local {
enabled = true
}
remote(HttpBuildCache) {
url = 'https://example.com/build-cache/'
enabled = true
push = true
credentials {
username = findProperty('buildCacheUsername')
password = findProperty('buildCachePassword')
}
}
}
// Code quality configuration
checkstyle {
toolVersion = '10.7.0'
configFile = file("${rootDir}/config/checkstyle/checkstyle.xml")
ignoreFailures = false
}
spotbugs {
toolVersion = '4.7.3'
effort = 'max'
reportLevel = 'low'
excludeFilter = file("${rootDir}/config/spotbugs/exclude.xml")
}
jacoco {
toolVersion = '0.8.8'
}
jacocoTestReport {
reports {
xml.required = true
html.required = true
csv.required = false
}
afterEvaluate {
classDirectories.setFrom(files(classDirectories.files.collect {
fileTree(dir: it, exclude: [
'**/Application.class',
'**/config/**',
'**/dto/**',
'**/entity/**'
])
}))
}
}
// SonarQube configuration
sonarqube {
properties {
property 'sonar.projectKey', 'my-project'
property 'sonar.projectName', 'My Project'
property 'sonar.host.url', 'https://sonarcloud.io'
property 'sonar.organization', 'my-org'
property 'sonar.java.coveragePlugin', 'jacoco'
property 'sonar.coverage.jacoco.xmlReportPaths', 'build/reports/jacoco/test/jacocoTestReport.xml'
property 'sonar.junit.reportPaths', 'build/test-results/test'
}
}
// Environment-specific profiles
gradle.taskGraph.whenReady { taskGraph ->
if (taskGraph.hasTask(':bootRun')) {
// Development environment configuration
bootRun {
environment 'SPRING_PROFILES_ACTIVE', 'development'
environment 'DEBUG', 'true'
}
}
}
// Conditional task execution
if (project.hasProperty('env') && project.env == 'production') {
jar {
exclude '**/application-dev.yml'
exclude '**/logback-spring.xml'
}
}
// Using Gradle Version Catalogs (Gradle 7.0+)
dependencyResolutionManagement {
versionCatalogs {
libs {
library('spring-boot-starter-web', 'org.springframework.boot', 'spring-boot-starter-web').version('3.1.0')
library('junit-jupiter', 'org.junit.jupiter', 'junit-jupiter').version('5.9.2')
bundle('testing', ['junit-jupiter', 'mockito-core', 'assertj-core'])
}
}
}
dependencies {
implementation libs.spring.boot.starter.web
testImplementation libs.bundles.testing
}
Profiles and Task Control
# Environment-specific execution
./gradlew build -Penv=production
./gradlew bootRun -Pspring.profiles.active=dev
# Parallel task execution
./gradlew test jacocoTestReport --parallel
# Cache control
./gradlew build --build-cache
./gradlew clean --build-cache
# Verbose logging
./gradlew build --info
./gradlew build --debug
# Execute specific tasks only
./gradlew :web:test
./gradlew compileJava compileTestJava
# Quality checks
./gradlew check
./gradlew sonarqube
# Project information
./gradlew dependencies --configuration compileClasspath
./gradlew dependencyInsight --dependency org.springframework.boot
./gradlew projects
./gradlew tasks --group build
# Performance analysis
./gradlew build --profile
./gradlew build --scan
# Continue on failure
./gradlew build --continue
# Offline execution
./gradlew build --offline