From ccfg-java
This skill should be used when creating or editing pom.xml, build.gradle.kts, managing Java dependencies, configuring Maven/Gradle plugins, or organizing multi-module projects.
npx claudepluginhub jsamuelsen11/claude-config --plugin ccfg-javaThis skill uses the workspace's default tool permissions.
This skill defines comprehensive build conventions for Java projects, covering Gradle Kotlin DSL,
Master Maven and Gradle - build configuration, dependencies, plugins, CI/CD
Provides Gradle build patterns for Android apps using Version Catalogs, convention plugins, build optimization, and multi-module setups. Useful for modern Android project configuration.
Configures Maven plugins like compiler, surefire, jar, resources; sets up executions, plugin management, and custom configurations in pom.xml for Java builds.
Share bugs, ideas, or general feedback.
This skill defines comprehensive build conventions for Java projects, covering Gradle Kotlin DSL, Maven POM configuration, dependency management, plugins, multi-module layouts, and build performance.
Use build.gradle.kts (Kotlin DSL) for type safety, IDE auto-completion, and refactoring support.
// CORRECT: build.gradle.kts (Kotlin DSL)
plugins {
java
id("org.springframework.boot") version "3.3.0"
id("io.spring.dependency-management") version "1.1.5"
}
group = "com.example"
version = "1.0.0"
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
repositories {
mavenCentral()
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
runtimeOnly("org.postgresql:postgresql")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}
tasks.withType<Test> {
useJUnitPlatform()
}
// WRONG: build.gradle (Groovy DSL) for new projects
plugins {
id 'java'
id 'org.springframework.boot' version '3.3.0'
}
// Less type safety, worse IDE support
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
}
A comprehensive build file for a Spring Boot application.
// CORRECT: Complete build.gradle.kts for Spring Boot
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import org.gradle.api.tasks.testing.logging.TestLogEvent
plugins {
java
jacoco
id("org.springframework.boot") version "3.3.0"
id("io.spring.dependency-management") version "1.1.5"
id("com.diffplug.spotless") version "6.25.0"
}
group = "com.example"
version = "1.0.0"
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
repositories {
mavenCentral()
}
dependencies {
// Spring Boot starters
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-validation")
implementation("org.springframework.boot:spring-boot-starter-actuator")
// Database
runtimeOnly("org.postgresql:postgresql")
runtimeOnly("org.flywaydb:flyway-core")
// Testing
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.testcontainers:junit-jupiter")
testImplementation("org.testcontainers:postgresql")
testImplementation("org.assertj:assertj-core")
// Development only
developmentOnly("org.springframework.boot:spring-boot-devtools")
annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")
}
tasks.withType<Test> {
useJUnitPlatform()
testLogging {
events(TestLogEvent.PASSED, TestLogEvent.SKIPPED, TestLogEvent.FAILED)
exceptionFormat = TestExceptionFormat.FULL
showStandardStreams = false
}
}
tasks.jacocoTestReport {
dependsOn(tasks.test)
reports {
xml.required = true
html.required = true
}
}
tasks.jacocoTestCoverageVerification {
violationRules {
rule {
limit {
counter = "LINE"
value = "COVEREDRATIO"
minimum = "0.90".toBigDecimal()
}
}
}
}
spotless {
java {
googleJavaFormat("1.22.0")
removeUnusedImports()
trimTrailingWhitespace()
endWithNewline()
}
}
tasks.check {
dependsOn(tasks.jacocoTestCoverageVerification)
}
Import Bills of Materials (BOMs) to align dependency versions consistently.
// CORRECT: BOM imports with platform() in Gradle
dependencies {
implementation(platform("org.springframework.boot:spring-boot-dependencies:3.3.0"))
implementation(platform("org.testcontainers:testcontainers-bom:1.19.7"))
implementation(platform("software.amazon.awssdk:bom:2.25.0"))
// No version needed when managed by BOM
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("software.amazon.awssdk:s3")
implementation("software.amazon.awssdk:dynamodb")
testImplementation("org.testcontainers:postgresql")
testImplementation("org.testcontainers:kafka")
}
// WRONG: Specifying versions already managed by a BOM
dependencies {
implementation(platform("org.springframework.boot:spring-boot-dependencies:3.3.0"))
// Version is redundant and can cause conflicts
implementation("org.springframework.boot:spring-boot-starter-web:3.3.0")
}
Use dependencyManagement to import BOMs in Maven.
<!-- CORRECT: BOM import in Maven pom.xml -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>3.3.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-bom</artifactId>
<version>1.19.7</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- No version needed -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Choose the right dependency configuration for each dependency.
// CORRECT: Proper dependency scopes in Gradle
dependencies {
// api: exposes dependency to consumers (use sparingly, only in libraries)
api("com.google.guava:guava:33.1.0-jre")
// implementation: internal dependency, not leaked to consumers (default choice)
implementation("com.fasterxml.jackson.core:jackson-databind")
implementation("org.slf4j:slf4j-api")
// runtimeOnly: needed at runtime but not at compile time
runtimeOnly("org.postgresql:postgresql")
runtimeOnly("ch.qos.logback:logback-classic")
// compileOnly: needed at compile time only (e.g., annotations)
compileOnly("org.projectlombok:lombok")
annotationProcessor("org.projectlombok:lombok")
// testImplementation: test compile and runtime
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.assertj:assertj-core")
// testRuntimeOnly: test runtime only
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}
// WRONG: Using implementation when api or runtimeOnly is correct
dependencies {
// This leaks PostgreSQL driver to consumers (should be runtimeOnly)
implementation("org.postgresql:postgresql")
// This hides a public API type from consumers (should be api)
implementation("com.google.guava:guava:33.1.0-jre")
// If your public API returns a Guava type, consumers can't compile
}
Use correct Maven scopes for dependencies.
<!-- CORRECT: Maven dependency scopes -->
<dependencies>
<!-- compile (default): available everywhere -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- runtime: not needed for compilation -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<!-- provided: supplied by the container -->
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<!-- test: only for testing -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Use the Spotless plugin with google-java-format for consistent code formatting.
// CORRECT: Spotless configuration in build.gradle.kts
plugins {
id("com.diffplug.spotless") version "6.25.0"
}
spotless {
java {
googleJavaFormat("1.22.0")
removeUnusedImports()
trimTrailingWhitespace()
endWithNewline()
targetExclude("build/**")
}
kotlinGradle {
ktlint("1.2.1")
}
}
// Run formatting check before build
tasks.check {
dependsOn(tasks.named("spotlessCheck"))
}
# Apply formatting
./gradlew spotlessApply
# Check formatting (CI)
./gradlew spotlessCheck
Configure Spotless via the Maven plugin.
<!-- CORRECT: Spotless Maven plugin -->
<plugin>
<groupId>com.diffplug.spotless</groupId>
<artifactId>spotless-maven-plugin</artifactId>
<version>2.43.0</version>
<configuration>
<java>
<googleJavaFormat>
<version>1.22.0</version>
<style>GOOGLE</style>
</googleJavaFormat>
<removeUnusedImports />
<trimTrailingWhitespace />
<endWithNewline />
</java>
</configuration>
<executions>
<execution>
<goals>
<goal>check</goal>
</goals>
<phase>verify</phase>
</execution>
</executions>
</plugin>
Use Checkstyle for enforcing coding standards.
// CORRECT: Checkstyle in build.gradle.kts
plugins {
id("checkstyle")
}
checkstyle {
toolVersion = "10.15.0"
configFile = file("config/checkstyle/checkstyle.xml")
isIgnoreFailures = false
maxWarnings = 0
}
tasks.withType<Checkstyle> {
reports {
xml.required = true
html.required = true
}
}
<!-- config/checkstyle/checkstyle.xml (Google checks) -->
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
"https://checkstyle.org/dtds/configuration_1_3.dtd">
<module name="Checker">
<module name="TreeWalker">
<module name="GoogleStyle"/>
</module>
</module>
Use SpotBugs for finding potential bugs through static analysis.
// CORRECT: SpotBugs in build.gradle.kts
plugins {
id("com.github.spotbugs") version "6.0.9"
}
spotbugs {
toolVersion = "4.8.4"
effort = com.github.spotbugs.snom.Effort.MAX
reportLevel = com.github.spotbugs.snom.Confidence.MEDIUM
}
tasks.withType<com.github.spotbugs.snom.SpotBugsTask> {
reports.create("html") {
required = true
}
reports.create("xml") {
required = false
}
}
Use JaCoCo for code coverage measurement and enforcement.
// CORRECT: JaCoCo in build.gradle.kts
plugins {
jacoco
}
jacoco {
toolVersion = "0.8.11"
}
tasks.jacocoTestReport {
dependsOn(tasks.test)
reports {
xml.required = true
html.required = true
csv.required = false
}
classDirectories.setFrom(files(classDirectories.files.map {
fileTree(it) {
exclude(
"**/config/**",
"**/dto/**",
"**/*Application*",
"**/*Config*",
"**/*Properties*"
)
}
}))
}
tasks.jacocoTestCoverageVerification {
violationRules {
rule {
limit {
counter = "LINE"
value = "COVEREDRATIO"
minimum = "0.90".toBigDecimal()
}
limit {
counter = "BRANCH"
value = "COVEREDRATIO"
minimum = "0.80".toBigDecimal()
}
}
}
}
tasks.check {
dependsOn(tasks.jacocoTestCoverageVerification)
}
Use convention plugins in buildSrc for shared configuration in multi-module Gradle projects.
my-project/
buildSrc/
build.gradle.kts
src/main/kotlin/
java-conventions.gradle.kts
spring-conventions.gradle.kts
app/
build.gradle.kts
domain/
build.gradle.kts
infrastructure/
build.gradle.kts
settings.gradle.kts
build.gradle.kts
// buildSrc/build.gradle.kts
plugins {
`kotlin-dsl`
}
repositories {
gradlePluginPortal()
}
dependencies {
implementation("org.springframework.boot:spring-boot-gradle-plugin:3.3.0")
implementation("io.spring.gradle:dependency-management-plugin:1.1.5")
implementation("com.diffplug.spotless:spotless-plugin-gradle:6.25.0")
}
// buildSrc/src/main/kotlin/java-conventions.gradle.kts
plugins {
java
jacoco
id("com.diffplug.spotless")
}
group = "com.example"
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
repositories {
mavenCentral()
}
dependencies {
testImplementation("org.junit.jupiter:junit-jupiter")
testImplementation("org.assertj:assertj-core")
testImplementation("org.mockito:mockito-junit-jupiter")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}
tasks.withType<Test> {
useJUnitPlatform()
}
spotless {
java {
googleJavaFormat("1.22.0")
removeUnusedImports()
}
}
// buildSrc/src/main/kotlin/spring-conventions.gradle.kts
plugins {
id("java-conventions")
id("org.springframework.boot")
id("io.spring.dependency-management")
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}
// app/build.gradle.kts
plugins {
id("spring-conventions")
}
dependencies {
implementation(project(":domain"))
implementation(project(":infrastructure"))
implementation("org.springframework.boot:spring-boot-starter-web")
}
// domain/build.gradle.kts
plugins {
id("java-conventions")
}
// Domain module has no Spring dependency
// infrastructure/build.gradle.kts
plugins {
id("spring-conventions")
}
dependencies {
implementation(project(":domain"))
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
runtimeOnly("org.postgresql:postgresql")
}
// settings.gradle.kts
rootProject.name = "my-project"
include("app", "domain", "infrastructure")
Use a parent POM for shared configuration in Maven multi-module projects.
<!-- Parent 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
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.0</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>my-project</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>app</module>
<module>domain</module>
<module>infrastructure</module>
</modules>
<properties>
<java.version>21</java.version>
<testcontainers.version>1.19.7</testcontainers.version>
<assertj.version>3.25.3</assertj.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-bom</artifactId>
<version>${testcontainers.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>domain</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>infrastructure</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>com.diffplug.spotless</groupId>
<artifactId>spotless-maven-plugin</artifactId>
<version>2.43.0</version>
<configuration>
<java>
<googleJavaFormat>
<version>1.22.0</version>
</googleJavaFormat>
</java>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.11</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
<!-- app/pom.xml (child module) -->
<?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
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.example</groupId>
<artifactId>my-project</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>app</artifactId>
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>domain</artifactId>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>infrastructure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Use Gradle version catalogs for centralized dependency version management.
# gradle/libs.versions.toml
[versions]
spring-boot = "3.3.0"
spring-dependency-management = "1.1.5"
testcontainers = "1.19.7"
assertj = "3.25.3"
mockito = "5.11.0"
spotless = "6.25.0"
spotbugs = "6.0.9"
jacoco = "0.8.11"
postgresql = "42.7.3"
flyway = "10.11.0"
jackson = "2.17.0"
[libraries]
spring-boot-starter-web = { module = "org.springframework.boot:spring-boot-starter-web" }
spring-boot-starter-data-jpa = { module = "org.springframework.boot:spring-boot-starter-data-jpa" }
spring-boot-starter-validation = { module = "org.springframework.boot:spring-boot-starter-validation" }
spring-boot-starter-actuator = { module = "org.springframework.boot:spring-boot-starter-actuator" }
spring-boot-starter-test = { module = "org.springframework.boot:spring-boot-starter-test" }
spring-boot-devtools = { module = "org.springframework.boot:spring-boot-devtools" }
spring-boot-configuration-processor = { module = "org.springframework.boot:spring-boot-configuration-processor" }
postgresql = { module = "org.postgresql:postgresql", version.ref = "postgresql" }
flyway-core = { module = "org.flywaydb:flyway-core", version.ref = "flyway" }
testcontainers-bom = { module = "org.testcontainers:testcontainers-bom", version.ref = "testcontainers" }
testcontainers-junit-jupiter = { module = "org.testcontainers:junit-jupiter" }
testcontainers-postgresql = { module = "org.testcontainers:postgresql" }
assertj-core = { module = "org.assertj:assertj-core", version.ref = "assertj" }
mockito-junit-jupiter = { module = "org.mockito:mockito-junit-jupiter", version.ref = "mockito" }
[bundles]
spring-web = [
"spring-boot-starter-web",
"spring-boot-starter-validation",
"spring-boot-starter-actuator",
]
testing = [
"spring-boot-starter-test",
"assertj-core",
"mockito-junit-jupiter",
]
testcontainers = [
"testcontainers-junit-jupiter",
"testcontainers-postgresql",
]
[plugins]
spring-boot = { id = "org.springframework.boot", version.ref = "spring-boot" }
spring-dependency-management = { id = "io.spring.dependency-management", version.ref = "spring-dependency-management" }
spotless = { id = "com.diffplug.spotless", version.ref = "spotless" }
spotbugs = { id = "com.github.spotbugs", version.ref = "spotbugs" }
// build.gradle.kts using version catalog
plugins {
java
alias(libs.plugins.spring.boot)
alias(libs.plugins.spring.dependency.management)
alias(libs.plugins.spotless)
}
dependencies {
implementation(libs.bundles.spring.web)
implementation(libs.spring.boot.starter.data.jpa)
runtimeOnly(libs.postgresql)
runtimeOnly(libs.flyway.core)
testImplementation(platform(libs.testcontainers.bom))
testImplementation(libs.bundles.testing)
testImplementation(libs.bundles.testcontainers)
developmentOnly(libs.spring.boot.devtools)
annotationProcessor(libs.spring.boot.configuration.processor)
}
// WRONG: Hardcoded versions in build.gradle.kts when catalog exists
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web:3.3.0") // Use catalog
testImplementation("org.assertj:assertj-core:3.25.3") // Use catalog
}
Commit the Gradle wrapper to version control for reproducible builds.
# Generate Gradle wrapper
gradle wrapper --gradle-version 8.7
# Files to commit
# gradlew (Unix script)
# gradlew.bat (Windows script)
# gradle/wrapper/gradle-wrapper.jar
# gradle/wrapper/gradle-wrapper.properties
# .gitignore for Gradle projects
.gradle/
build/
!gradle/wrapper/gradle-wrapper.jar
!gradle/wrapper/gradle-wrapper.properties
# CORRECT: Use wrapper for all commands
./gradlew build
./gradlew test
./gradlew bootRun
# WRONG: Using system Gradle directly
gradle build # May use different version
Commit the Maven wrapper for reproducible builds.
# Generate Maven wrapper
mvn wrapper:wrapper -Dmaven=3.9.6
# Files to commit
# mvnw (Unix script)
# mvnw.cmd (Windows script)
# .mvn/wrapper/maven-wrapper.jar
# .mvn/wrapper/maven-wrapper.properties
# CORRECT: Use wrapper for all commands
./mvnw clean install
./mvnw test
./mvnw spring-boot:run
# WRONG: Using system Maven directly
mvn clean install # May use different version
Set up publishing for Maven Central via Sonatype OSSRH.
// CORRECT: Publishing configuration in build.gradle.kts
plugins {
`maven-publish`
signing
}
java {
withJavadocJar()
withSourcesJar()
}
publishing {
publications {
create<MavenPublication>("mavenJava") {
from(components["java"])
pom {
name = "My Library"
description = "A description of my library"
url = "https://github.com/username/my-library"
licenses {
license {
name = "The Apache License, Version 2.0"
url = "https://www.apache.org/licenses/LICENSE-2.0.txt"
}
}
developers {
developer {
id = "username"
name = "Developer Name"
email = "dev@example.com"
}
}
scm {
connection = "scm:git:git://github.com/username/my-library.git"
developerConnection = "scm:git:ssh://github.com:username/my-library.git"
url = "https://github.com/username/my-library"
}
}
}
}
repositories {
maven {
name = "OSSRH"
url = uri("https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/")
credentials {
username = findProperty("ossrhUsername") as String? ?: ""
password = findProperty("ossrhPassword") as String? ?: ""
}
}
}
}
signing {
sign(publishing.publications["mavenJava"])
}
Configure Maven Central publishing in pom.xml.
<!-- CORRECT: Distribution management in pom.xml -->
<distributionManagement>
<snapshotRepository>
<id>ossrh</id>
<url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>
</snapshotRepository>
<repository>
<id>ossrh</id>
<url>https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
</distributionManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.3.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.6.3</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>3.2.2</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Enable build caching for faster incremental builds.
# gradle.properties
org.gradle.caching=true
org.gradle.parallel=true
org.gradle.daemon=true
org.gradle.jvmargs=-Xmx2g -XX:+UseParallelGC
org.gradle.configureondemand=true
// settings.gradle.kts - enable local build cache
buildCache {
local {
isEnabled = true
directory = File(rootDir, ".gradle/build-cache")
removeUnusedEntriesAfterDays = 30
}
}
# WRONG: gradle.properties without performance tuning
# (missing all performance flags)
Configure Maven for parallel builds.
# CORRECT: Parallel Maven builds
./mvnw -T 1C clean install # 1 thread per CPU core
./mvnw -T 4 clean install # 4 threads
./mvnw -T 1C -pl app -am install # Build specific module with dependencies
# CORRECT: Skip tests for faster builds during development
./mvnw -DskipTests clean package # Skip test execution
./mvnw -Dmaven.test.skip clean package # Skip compilation and execution
<!-- .mvn/maven.config for default options -->
-T 1C
--no-transfer-progress
Configure proper inputs and outputs to avoid unnecessary work.
// CORRECT: Custom task with proper inputs/outputs for caching
tasks.register<Exec>("generateOpenApi") {
inputs.file("src/main/resources/openapi.yaml")
outputs.dir("build/generated/openapi")
commandLine("./gradlew", "openApiGenerate")
}
// WRONG: Task always runs because no inputs/outputs defined
tasks.register<Exec>("generateOpenApi") {
commandLine("./gradlew", "openApiGenerate") // Runs every time
}
A comprehensive pom.xml for a Spring Boot application.
<?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
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.0</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>my-service</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>my-service</name>
<description>My Spring Boot Service</description>
<properties>
<java.version>21</java.version>
<testcontainers.version>1.19.7</testcontainers.version>
<spotless.version>2.43.0</spotless.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-bom</artifactId>
<version>${testcontainers.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- Spring Boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- Database -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
<!-- Testing -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>com.diffplug.spotless</groupId>
<artifactId>spotless-maven-plugin</artifactId>
<version>${spotless.version}</version>
<configuration>
<java>
<googleJavaFormat>
<version>1.22.0</version>
</googleJavaFormat>
<removeUnusedImports />
</java>
</configuration>
<executions>
<execution>
<goals>
<goal>check</goal>
</goals>
<phase>verify</phase>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.11</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>verify</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
<execution>
<id>check</id>
<phase>verify</phase>
<goals>
<goal>check</goal>
</goals>
<configuration>
<rules>
<rule>
<element>BUNDLE</element>
<limits>
<limit>
<counter>LINE</counter>
<value>COVEREDRATIO</value>
<minimum>0.90</minimum>
</limit>
</limits>
</rule>
</rules>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
When contributing to existing repositories, follow their established build tool and conventions.
# Discover build conventions
ls build.gradle.kts build.gradle pom.xml 2>/dev/null # Build tool
cat gradle/libs.versions.toml 2>/dev/null # Version catalog
cat gradle.properties 2>/dev/null # Build properties
ls buildSrc/ 2>/dev/null # Convention plugins
cat .mvn/maven.config 2>/dev/null # Maven defaults
# Before making changes:
# - Check if project uses Maven or Gradle
# - Check Gradle DSL: Kotlin (.kts) or Groovy
# - Look for version catalogs (libs.versions.toml)
# - Look for convention plugins (buildSrc/)
# - Check for Spotless/Checkstyle configuration
# - Verify Java version in build configuration
# - Follow the established dependency declaration style
This skill ensures consistent, performant, and maintainable build configurations across Java projects using Maven or Gradle. Apply these conventions for reproducible builds, proper dependency management, and enforced code quality standards.