Gradle

Build ToolJavaKotlinDSLDependency ManagementProject ManagementGroovyDSLKotlinDSL

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

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