Claude Code for Java — Spring Boot, Maven & Gradle Guide
Claude Code is highly effective for Java development when configured to understand your build tool, Spring Boot version, and enterprise coding conventions. This guide covers the CLAUDE.md template, automated test hooks for Maven and Gradle, Spring Boot workflow patterns, JUnit 5 testing, and microservice architecture prompts.
Java Spring Boot CLAUDE.md Template
# Project: [Your Service Name]
## Stack
- Java 21 (LTS) — use records, sealed classes, pattern matching, virtual threads
- Build: Maven 3.9 (or Gradle 8.x — specify)
- Spring Boot 3.3
- Spring Data JPA + Hibernate 6
- Spring Security 6
- Database: PostgreSQL 16 via JDBC (or MySQL — specify)
- Testing: JUnit 5, Mockito, AssertJ, @SpringBootTest, Testcontainers
## Commands
```bash
mvn test # run all tests
mvn test -pl module-name # run specific module
mvn verify # compile + test + integration tests
mvn spring-boot:run # start local server
./mvnw checkstyle:check # lint check
mvn dependency:tree # view dependency graph
```
# For Gradle:
# ./gradlew test
# ./gradlew bootRun
# ./gradlew check
## Conventions
- Dependency injection: constructor injection only (no @Autowired on fields)
- Use Java records for DTOs and value objects
- Exceptions: custom exceptions extend RuntimeException, handled in @ControllerAdvice
- Transactions: @Transactional at service layer, not repository
- Validation: Bean Validation (@Valid, @NotNull, @Size) on request DTOs
- Lombok: not used (Java records replace most use cases)
- Package structure: feature-based, not layer-based
## Project structure
- src/main/java/com/company/service/
- [feature]/
- [Feature]Controller.java — REST endpoints
- [Feature]Service.java — business logic
- [Feature]Repository.java — Spring Data JPA
- [Feature]Request.java — request DTOs (records)
- [Feature]Response.java — response DTOs (records)
- [Feature]Entity.java — JPA entities
- src/test/java/... — mirrors main structure
Automated Test Hooks
Maven hook
// .claude/settings.json
{
"allowedTools": ["Edit", "Write", "Bash", "Read", "Glob", "Grep"],
"hooks": [
{
"event": "PostToolUse",
"matcher": "Edit|Write",
"hooks": [{
"type": "command",
"command": "cd $PROJECT_ROOT && mvn test -q 2>&1 | tail -40"
}]
}
]
}
Maven test output is verbose. The
-q (quiet) flag suppresses download logs. Pipe through tail -40 to show only the test results. For faster feedback during active development, use mvn test -pl [module] -q to run only the changed module.Gradle hook
{
"event": "PostToolUse",
"matcher": "Edit|Write",
"hooks": [{
"type": "command",
"command": "cd $PROJECT_ROOT && ./gradlew test --quiet 2>&1 | tail -40"
}]
}
Teaching Claude Java Conventions
| Pattern | CLAUDE.md instruction |
|---|---|
| DTOs | "Use Java records for all DTOs and value objects — no Lombok" |
| DI style | "Constructor injection only; no @Autowired on fields" |
| Exceptions | "Custom exceptions extend RuntimeException; handle all in @ControllerAdvice" |
| Validation | "Use @Valid on @RequestBody; validate at controller boundary, not service" |
| Transactions | "@Transactional at service layer only; repositories are always in a transaction" |
| Null safety | "Use Optional |
Spring Boot Workflow Prompts
Add a REST endpoint
claude "add a PATCH /api/v1/orders/{id}/status endpoint.
Controller: OrderController.java
Service method: OrderService.updateStatus(UUID id, OrderStatus status)
Repository: OrderRepository extends JpaRepository
Request DTO: UpdateOrderStatusRequest (Java record with @NotNull OrderStatus newStatus)
Response DTO: OrderResponse (Java record)
@ControllerAdvice handles OrderNotFoundException → 404
Write @WebMvcTest for the controller and Mockito unit test for the service."
Add Spring Data JPA repository query
claude "add a query to find all orders by customerId and status, created after a given date.
Use Spring Data JPA @Query with JPQL (not native SQL).
Method in OrderRepository: findByCustomerIdAndStatusAndCreatedAtAfter(...)
Add pagination: return Page<Order> with Pageable parameter.
Write @DataJpaTest using an in-memory H2 database."
Spring Security — add JWT authentication
claude "add JWT authentication to the Spring Security config.
- JwtAuthenticationFilter extends OncePerRequestFilter
- Extract Bearer token from Authorization header
- Validate using jjwt 0.12 (already in pom.xml)
- Load user via UserDetailsService
- Public endpoints: POST /api/v1/auth/login, POST /api/v1/auth/register
- All others require authentication
- Don't use deprecated WebSecurityConfigurerAdapter (use SecurityFilterChain bean)"
JUnit 5 Testing Patterns
Controller test (@WebMvcTest)
claude "write a @WebMvcTest for OrderController covering:
- POST /api/v1/orders → 201 Created with order body
- POST /api/v1/orders with invalid body → 400 Bad Request with field errors
- GET /api/v1/orders/{id} not found → 404
- PATCH /api/v1/orders/{id}/status → 200 OK
Use MockMvc, @MockBean for OrderService, AssertJ for response assertions."
Service unit test (Mockito)
claude "write Mockito unit tests for OrderService:
@ExtendWith(MockitoExtension.class)
@Mock OrderRepository, @Mock PaymentClient, @Mock EventPublisher
Test createOrder: happy path, duplicate order (should throw OrderExistsException),
payment failure (should throw PaymentException and NOT save order).
Use AssertJ assertThat() for all assertions. No Spring context needed."
Integration test with Testcontainers
claude "add a Testcontainers integration test for the order creation flow.
@SpringBootTest(webEnvironment = RANDOM_PORT)
@Testcontainers — PostgreSQL container via @Container.
Use TestRestTemplate to POST /api/v1/orders.
Assert: 201 response, order exists in DB, event published to RabbitMQ (also containerized).
Extend a shared AbstractIntegrationTest base class that starts the containers once."
Microservice Architecture Patterns
Multi-module Maven project setup
# Root CLAUDE.md for a multi-module project:
## Modules
- api/ — REST controllers, DTOs, OpenAPI spec
- domain/ — entities, domain services, repository interfaces
- infrastructure/ — JPA implementations, external clients, event publishers
- application/ — use cases, orchestration
- boot/ — Spring Boot application class, config, main
## Inter-module rules
- domain/ has zero Spring dependencies (pure Java)
- api/ depends on application/ only; never domain/ directly
- Run all tests: mvn test (root)
- Run single module: mvn test -pl domain/
5 Tips for Java + Claude Code
- Paste your
pom.xmldependencies section (orbuild.gradledependencies block) into CLAUDE.md. Claude will use the exact library versions you have and won't generate code for APIs that don't exist in your version. - Tell Claude your Java version explicitly. Java 21 supports records, sealed classes, pattern matching in switch, and virtual threads. Without knowing the version, Claude defaults to Java 11 idioms and misses these improvements.
- For JPA entities, specify your ID generation strategy in CLAUDE.md: "Use UUID primary keys generated by the application (@UuidGenerator), not database sequences." Claude will follow this consistently across all generated entities.
- For generated code (MapStruct mappers, jOOQ classes, OpenAPI client stubs), add a "Never edit these directories" section to CLAUDE.md. Claude will regenerate via the plugin instead of editing the generated source directly.
- Use
claude "run mvn test and fix all failing tests"as a recovery prompt when you have accumulated test debt. Claude will read all failures and fix them systematically, one at a time.