AGENTS.java.md — Java
Additive to ../AGENTS.md. Applies to every .java file. Spring Boot rules are
in AGENTS.spring.md.
Build and check
./gradlew spotlessCheck test # Gradle
./mvnw -B -ntp spotless:check verify # Maven
Formatting is Spotless (google-java-format). Run spotlessApply before you push.
Java rules
- Records for data carriers. Sealed interfaces for closed hierarchies, and on
Java 21+ an exhaustive pattern-matching
switchover them. varonly when the type is obvious from the right-hand side.- No
nullfrom public methods. ReturnOptional<T>for a value that may be absent and an empty collection for “none”. NeverOptionalas a field or parameter. - Immutable by default:
finalfields,List.copyOf/Map.copyOffor collections you hand out. - No swallowed exceptions. Wrap checked exceptions in an unchecked domain
exception with the cause attached. An empty
catchneeds a comment saying why. - No
System.out,System.errorprintStackTrace()outsidemainand tests. Log with SLF4J placeholders (log.info("user {}", id)), not concatenation. - Strong-typed identifiers (a record wrapping the value), same reasoning as Kotlin and Swift.
- No
new Thread(…)and no staticExecutorService. Inject anExecutor, or use virtual threads on Java 21+. @SuppressWarningsneeds a trailing comment explaining why.
Build rules
- Gradle: dependencies in
gradle/libs.versions.toml, same as Kotlin. - Maven: versions live in the parent
<dependencyManagement>or an imported BOM. Modulepom.xmlfiles declare no<version>for managed dependencies. - No new build plugin without Platform review.
Testing
- JUnit 5 and AssertJ. Mock only at boundaries you do not own.
- Testcontainers for the real database, not an in-memory stand-in.
- A bug fix lands with a test that fails before the fix.
Anti-patterns seen in this repo
- Static utility classes holding mutable state.
catch (Exception e) { log.error(…) }and carry on, in a path that should fail.