home / skills / kousen / claude-code-training / spring-boot-skill

spring-boot-skill skill

/skills-and-plugins/spring-boot-skill

This skill generates Spring Boot components following modern Java best practices and team conventions to ensure clean, scalable code.

npx playbooks add skill kousen/claude-code-training --skill spring-boot-skill

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
6.2 KB
---
name: Spring Boot Best Practices
description: Generate Spring Boot components following modern Java best practices and team conventions
---

# Spring Boot Code Generation Guidelines

When generating or reviewing Spring Boot code, follow these best practices:

## Dependency Injection

- **Use constructor injection**, never field injection with @Autowired
- Mark injected fields as `private final`
- Let Lombok's `@RequiredArgsConstructor` generate constructors when appropriate

```java
// Good
@Service
@RequiredArgsConstructor
public class UserService {
    private final UserRepository userRepository;
    private final EmailService emailService;
}

// Avoid
@Service
public class UserService {
    @Autowired
    private UserRepository userRepository; // Field injection - avoid
}
```

## Package Structure

Follow standard Spring Boot layering:
```
com.example.project/
├── controller/       # REST endpoints, @RestController
├── service/          # Business logic, @Service
├── repository/       # Data access, extends JpaRepository
├── model/            # JPA entities, @Entity
├── dto/              # Data transfer objects
├── config/           # Configuration classes, @Configuration
└── exception/        # Custom exceptions and @ControllerAdvice
```

## REST Controllers

- Use proper HTTP methods (GET, POST, PUT, DELETE, PATCH)
- Return `ResponseEntity<T>` for explicit status codes
- Use `@Valid` for request body validation
- Include API versioning in paths (e.g., `/api/v1/users`)

```java
@RestController
@RequestMapping("/api/v1/users")
@RequiredArgsConstructor
public class UserController {
    private final UserService userService;

    @GetMapping("/{id}")
    public ResponseEntity<UserDto> getUser(@PathVariable Long id) {
        return userService.findById(id)
            .map(ResponseEntity::ok)
            .orElse(ResponseEntity.notFound().build());
    }

    @PostMapping
    public ResponseEntity<UserDto> createUser(@Valid @RequestBody CreateUserRequest request) {
        UserDto created = userService.create(request);
        return ResponseEntity.status(HttpStatus.CREATED).body(created);
    }
}
```

## Service Layer

- Keep services focused on business logic
- Use `Optional<T>` for potentially absent results
- Throw custom exceptions for business rule violations
- Add `@Transactional` where needed

```java
@Service
@RequiredArgsConstructor
public class UserService {
    private final UserRepository userRepository;

    public Optional<User> findById(Long id) {
        return userRepository.findById(id);
    }

    @Transactional
    public User create(CreateUserRequest request) {
        if (userRepository.existsByEmail(request.getEmail())) {
            throw new UserAlreadyExistsException(request.getEmail());
        }
        User user = new User(request.getName(), request.getEmail());
        return userRepository.save(user);
    }
}
```

## JPA Entities

- Use `@Entity` and `@Table` annotations
- Include `@Id` with generation strategy
- Use Lombok annotations: `@Data`, `@NoArgsConstructor`, `@AllArgsConstructor`
- Include proper relationships with `@OneToMany`, `@ManyToOne`, etc.

```java
@Entity
@Table(name = "users")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String name;

    @Column(nullable = false, unique = true)
    private String email;

    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
    private List<Order> orders = new ArrayList<>();
}
```

## Testing Requirements

For every component generated:

1. **Controller Tests** - Use `@WebMvcTest` and MockMvc
2. **Service Tests** - Use `@ExtendWith(MockitoExtension.class)` with mocks
3. **Repository Tests** - Use `@DataJpaTest` with test database
4. **Integration Tests** - Use `@SpringBootTest` for end-to-end scenarios

```java
@WebMvcTest(UserController.class)
class UserControllerTest {
    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private UserService userService;

    @Test
    void getUser_WhenExists_ReturnsUser() throws Exception {
        // Arrange
        UserDto user = new UserDto(1L, "John Doe", "[email protected]");
        when(userService.findById(1L)).thenReturn(Optional.of(user));

        // Act & Assert
        mockMvc.perform(get("/api/v1/users/1"))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.name").value("John Doe"));
    }
}
```

## Documentation

- Add comprehensive JavaDoc for public methods
- Include `@param`, `@return`, and `@throws` tags
- Document business rules and assumptions
- Use OpenAPI/Swagger annotations for REST endpoints

```java
/**
 * Creates a new user in the system.
 *
 * @param request the user creation request containing name and email
 * @return the created user with generated ID
 * @throws UserAlreadyExistsException if a user with the email already exists
 */
@Transactional
public User create(CreateUserRequest request) {
    // implementation
}
```

## Error Handling

- Create custom exceptions extending RuntimeException
- Use `@ControllerAdvice` for global exception handling
- Return proper HTTP status codes with error details

```java
@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(UserNotFoundException.class)
    public ResponseEntity<ErrorResponse> handleUserNotFound(UserNotFoundException ex) {
        ErrorResponse error = new ErrorResponse(
            HttpStatus.NOT_FOUND.value(),
            ex.getMessage()
        );
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
    }
}
```

## Configuration

- Use `application.yml` over `application.properties`
- Externalize configuration values
- Use Spring profiles for environment-specific config

```yaml
spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/mydb
    username: ${DB_USERNAME}
    password: ${DB_PASSWORD}
  jpa:
    hibernate:
      ddl-auto: validate
    show-sql: false
```

## When This Skill Activates

This skill automatically activates when:
- Generating Spring Boot controllers, services, or repositories
- Creating JPA entities or DTOs
- Writing Spring Boot tests
- Reviewing existing Spring Boot code
- Questions about Spring Boot best practices

Overview

This skill generates Spring Boot components and enforces modern Java and team conventions for readable, testable, and maintainable applications. It produces controllers, services, repositories, entities, DTOs, configuration, and tests following established layering and dependency-injection patterns. Use it to speed development while keeping code consistent with common enterprise practices.

How this skill works

The skill inspects requested component types (controllers, services, repositories, entities, DTOs, configs, and tests) and outputs code that follows constructor injection, clear package structure, REST conventions, JPA mapping patterns, and standardized error handling. It also generates matching tests (unit, slice, repository, and integration) and adds JavaDoc and OpenAPI annotations when appropriate. Configuration and environment concerns are externalized to YAML and Spring profiles.

When to use it

  • Scaffolding new Spring Boot REST endpoints and related service/repository layers
  • Creating JPA entities and DTOs with correct relationships and constraints
  • Adding tests: controller (MockMvc), service (Mockito), repository (DataJpaTest), integration (SpringBootTest)
  • Reviewing or refactoring existing Spring Boot code to match best practices
  • Generating configuration files and profile-aware application.yml

Best practices

  • Always use constructor injection and mark dependencies private final; prefer Lombok @RequiredArgsConstructor where helpful
  • Follow layered package layout: controller, service, repository, model, dto, config, exception
  • Return ResponseEntity<T> from controllers, use @Valid on request bodies, and version APIs (/api/v1/...)
  • Keep services focused on business rules, use Optional<T>, and annotate transactional boundaries
  • Model JPA entities with proper annotations, relationships, and column constraints; avoid bidirectional cycles without care
  • Ship comprehensive tests for each component type and use profiles + externalized config in application.yml

Example use cases

  • Generate a versioned REST controller, service implementation, repository interface, DTOs, and entity for a new resource
  • Refactor a controller from field injection to constructor injection and add proper ResponseEntity usage
  • Create repository and DataJpaTest for new domain objects with sample test data
  • Produce controller and service tests: @WebMvcTest with MockMvc and Mockito-based unit tests
  • Add global exception handling with @ControllerAdvice and consistent error response payloads

FAQ

Should I use Lombok for everything?

Use Lombok to reduce boilerplate (constructors, getters/setters) but keep explicit code where clarity or framework constraints require it.

When do I add @Transactional?

Annotate service methods that perform one or more write operations or require atomicity; prefer method-level over class-level when possible.