---
description: Java Tooling and Build Systems
alwaysApply: false
---

# Java Tooling and Build Systems

Maven or Gradle. Static analysis. Docker. The full production pipeline.

## Essential Commands

```bash
# Maven
mvn clean verify            # Full build + tests
mvn spotbugs:check          # Static analysis
mvn dependency:tree         # Dependency analysis

# Gradle
./gradlew clean build       # Full build + tests
./gradlew dependencies      # Dependency tree
```

## Maven Essentials

```xml
<properties>
    <java.version>21</java.version>
    <maven.compiler.source>${java.version}</maven.compiler.source>
</properties>
<!-- Use dependencyManagement for version control across modules -->
<!-- Compiler args: -Xlint:all -Werror -->
```

## Gradle (Kotlin DSL)

```kotlin
java { toolchain { languageVersion = JavaLanguageVersion.of(21) } }
tasks.withType<JavaCompile> { options.compilerArgs.addAll(listOf("-Xlint:all", "-Werror")) }
tasks.test { useJUnitPlatform() }
```

## Static Analysis

- **SpotBugs**: `effort=Max, threshold=Low, failOnError=true`
- **ErrorProne**: compile-time bug detection via annotation processor
- **Checkstyle**: code style enforcement (`google_checks.xml`)

## Docker

```dockerfile
FROM eclipse-temurin:21-jdk-alpine AS build
COPY . /app
RUN mvn package -DskipTests -q

FROM eclipse-temurin:21-jre-alpine
RUN addgroup -S app && adduser -S app -G app
USER app
COPY --from=build /app/target/*.jar app.jar
ENV JAVA_OPTS="-XX:MaxRAMPercentage=75.0 -XX:+UseZGC -XX:+ZGenerational"
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]
```

## Logging (SLF4J)

```java
// Structured parameters — never string concatenation
log.info("Order created orderId={} customerId={}", order.getId(), order.getCustomerId());
// MDC for request-scoped context (requestId, userId)
// JSON output in production (LogstashEncoder), human-readable locally
```

## Anti-Patterns

- **Never** `System.out.println` for logging — use SLF4J
- **Never** hardcoded versions scattered across modules — use dependencyManagement/platform
- **Never** run as root in Docker — use non-root user
