/spring-boot-patterns
Spring Boot best practices and patterns. Use when creating controllers, services, repositories, or when user asks about Spring Boot architecture, REST APIs, exception handling, or JPA patterns.
$ npx -y skills add decebals/claude-code-java --skill spring-boot-patterns --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/spring-boot-patterns
Context preview
The summary Claude sees to decide when to auto-load this skill.
Spring Boot best practices and patterns. Use when creating controllers, services, repositories, or when user asks about Spring Boot architecture, REST APIs, exception handling, or JPA patterns.
SKILL.md
spring-boot-patterns.SKILL.mdname: spring-boot-patterns
description: Spring Boot best practices and patterns. Use when creating controllers, services, repositories, or when user asks about Spring Boot architecture, REST APIs, exception handling, or JPA patterns.
Spring Boot Patterns Skill
Best practices and patterns for Spring Boot applications.
When to Use
- User says "create controller" / "add service" / "Spring Boot help"
- Reviewing Spring Boot code
- Setting up new Spring Boot project structure
Project Structure
src/main/java/com/example/myapp/
├── MyAppApplication.java # @SpringBootApplication
├── config/ # Configuration classes
│ ├── SecurityConfig.java
│ └── WebConfig.java
├── controller/ # REST controllers
│ └── UserController.java
├── service/ # Business logic
│ ├── UserService.java
│ └── impl/
│ └── UserServiceImpl.java
├── repository/ # Data access
│ └── UserRepository.java
├── model/ # Entities
│ └── User.java
├── dto/ # Data transfer objects
│ ├── request/
│ │ └── CreateUserRequest.java
│ └── response/
│ └── UserResponse.java
├── exception/ # Custom exceptions
│ ├── ResourceNotFoundException.java
│ └── GlobalExceptionHandler.java
└── util/ # Utilities
└── DateUtils.java---
Controller Patterns
REST Controller Template
@RestController
@RequestMapping("/api/v1/users")
@RequiredArgsConstructor // Lombok for constructor injection
public class UserController {
private final UserService userService;
@GetMapping
public ResponseEntity<List<UserResponse>> getAll() {
return ResponseEntity.ok(userService.findAll());
}
@GetMapping("/{id}")
public ResponseEntity<UserResponse> getById(@PathVariable Long id) {
return ResponseEntity.ok(userService.findById(id));
}
@PostMapping
public ResponseEntity<UserResponse> create(
@Valid @RequestBody CreateUserRequest request) {
UserResponse created = userService.create(request);
URI location = ServletUriComponentsBuilder.fromCurrentRequest()
.path("/{id}")
.buildAndExpand(created.getId())
.toUri();
return ResponseEntity.created(location).body(created);
}
@PutMapping("/{id}")
public ResponseEntity<UserResponse> update(
@PathVariable Long id,
@Valid @RequestBody UpdateUserRequest request) {
return ResponseEntity.ok(userService.update(id, request));
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> delete(@PathVariable Long id) {
userService.delete(id);
return ResponseEntity.noContent().build();
}
}Controller Best Practices
| Practice | Example | |----------|---------| | Versioned API | `/api/v1/users` | | Plural nouns | `/users` not `/user` | | HTTP methods | GET=read, POST=create, PUT=update, DELETE=delete | | Status codes | 200=OK, 201=Created, 204=NoContent, 404=NotFound | | Validation | `@Valid` on request body |
❌ Anti-patterns
// ❌ Business logic in controller
@PostMapping
public User create(@RequestBody User user) {
user.setCreatedAt(LocalDateTime.now()); // Logic belongs in service
return userRepository.save(user); // Direct repo access
}
// ❌ Returning entity directly (exposes internals)
@GetMapping("/{id}")
public User getById(@PathVariable Long id) {
return userRepository.findById(id).get();
}---
Service Patterns
Service Interface + Implementation
// Interface
public interface UserService {
List<UserResponse> findAll();
UserResponse findById(Long id);
UserResponse create(CreateUserRequest request);
UserResponse update(Long id, UpdateUserRequest request);
void delete(Long id);
}
// Implementation
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true) // Default read-only
public class UserServiceImpl implements UserService {
private final UserRepository userRepository;
private final UserMapper userMapper;
@Override
public List<UserResponse> findAll() {
return userRepository.findAll().stream()
.map(userMapper::toResponse)
.toList();
}
@Override
public UserResponse findById(Long id) {
return userRepository.findById(id)
.map(userMapper::toResponse)
.orElseThrow(() -> new ResourceNotFoundException("User", id));
}
@Override
@Transactional // Write transaction
public UserResponse create(CreateUserRequest request) {
User user = userMapper.toEntity(request);
User saved = userRepository.save(user);
return userMapper.toResponse(saved);
}
@Override
@Transactional
public void delete(Long id) {
if (!userRepository.existsById(id)) {
throw new ResourceNotFoundException("User", id);
}
userRepository.deleteById(id);
}
}Service Best Practices
- Interface + Impl for testability
- `@Transactional(readOnly = true)` at class level
- `@Transactional` for write methods
- Throw domain exceptions, not generic ones
- Use mappers (MapStruct) for entity ↔ DTO conversion
---
Repository Patterns
JPA Repository
public interface UserRepository extends JpaRepository<User, Long> {
// Derived query
Optional<User> findByEmail(String email);
List<User> findByActiveTrue();
// Custom query
@Query("SELECT u FROM User u WHERE u.department.id = :deptId")
List<User> findByDepartmentId(@Param("deptId") Long departmentId);
// Native query (use sparingly)
@Query(value = "SELECT * FROM users WHERE created_at > :date",
nativeQuery = true)
List<User> findRecentUsers(@Param("date") LocalDate date);
// Exists check (more efficient than findBy)
boolean existsByEmail(SRead more
name: spring-boot-patterns description: Spring Boot best practices and patterns. Use when creating controllers, services, repositories, or when user asks about Spring Boot architecture, REST APIs, exception handling, or JPA patterns.
Spring Boot Patterns Skill
Best practices and patterns for Spring Boot applications.
When to Use
- User says "create controller" / "add service" / "Spring Boot help"
- Reviewing Spring Boot code
- Setting up new Spring Boot project structure
Project Structure
src/main/java/com/example/myapp/
├── MyAppApplication.java # @SpringBootApplication
├── config/ # Configuration classes
│ ├── SecurityConfig.java
│ └── WebConfig.java
├── controller/ # REST controllers
│ └── UserController.java
├── service/ # Business logic
│ ├── UserService.java
│ └── impl/
│ └── UserServiceImpl.java
├── repository/ # Data access
│ └── UserRepository.java
├── model/ # Entities
│ └── User.java
├── dto/ # Data transfer objects
│ ├── request/
│ │ └── CreateUserRequest.java
│ └── response/
│ └── UserResponse.java
├── exception/ # Custom exceptions
│ ├── ResourceNotFoundException.java
│ └── GlobalExceptionHandler.java
└── util/ # Utilities
└── DateUtils.java---
Controller Patterns
REST Controller Template
@RestController
@RequestMapping("/api/v1/users")
@RequiredArgsConstructor // Lombok for constructor injection
public class UserController {
private final UserService userService;
@GetMapping
public ResponseEntity<List<UserResponse>> getAll() {
return ResponseEntity.ok(userService.findAll());
}
@GetMapping("/{id}")
public ResponseEntity<UserResponse> getById(@PathVariable Long id) {
return ResponseEntity.ok(userService.findById(id));
}
@PostMapping
public ResponseEntity<UserResponse> create(
@Valid @RequestBody CreateUserRequest request) {
UserResponse created = userService.create(request);
URI location = ServletUriComponentsBuilder.fromCurrentRequest()
.path("/{id}")
.buildAndExpand(created.getId())
.toUri();
return ResponseEntity.created(location).body(created);
}
@PutMapping("/{id}")
public ResponseEntity<UserResponse> update(
@PathVariable Long id,
@Valid @RequestBody UpdateUserRequest request) {
return ResponseEntity.ok(userService.update(id, request));
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> delete(@PathVariable Long id) {
userService.delete(id);
return ResponseEntity.noContent().build();
}
}Controller Best Practices
| Practice | Example | |----------|---------| | Versioned API | `/api/v1/users` | | Plural nouns | `/users` not `/user` | | HTTP methods | GET=read, POST=create, PUT=update, DELETE=delete | | Status codes | 200=OK, 201=Created, 204=NoContent, 404=NotFound | | Validation | `@Valid` on request body |
❌ Anti-patterns
// ❌ Business logic in controller
@PostMapping
public User create(@RequestBody User user) {
user.setCreatedAt(LocalDateTime.now()); // Logic belongs in service
return userRepository.save(user); // Direct repo access
}
// ❌ Returning entity directly (exposes internals)
@GetMapping("/{id}")
public User getById(@PathVariable Long id) {
return userRepository.findById(id).get();
}---
Service Patterns
Service Interface + Implementation
// Interface
public interface UserService {
List<UserResponse> findAll();
UserResponse findById(Long id);
UserResponse create(CreateUserRequest request);
UserResponse update(Long id, UpdateUserRequest request);
void delete(Long id);
}
// Implementation
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true) // Default read-only
public class UserServiceImpl implements UserService {
private final UserRepository userRepository;
private final UserMapper userMapper;
@Override
public List<UserResponse> findAll() {
return userRepository.findAll().stream()
.map(userMapper::toResponse)
.toList();
}
@Override
public UserResponse findById(Long id) {
return userRepository.findById(id)
.map(userMapper::toResponse)
.orElseThrow(() -> new ResourceNotFoundException("User", id));
}
@Override
@Transactional // Write transaction
public UserResponse create(CreateUserRequest request) {
User user = userMapper.toEntity(request);
User saved = userRepository.save(user);
return userMapper.toResponse(saved);
}
@Override
@Transactional
public void delete(Long id) {
if (!userRepository.existsById(id)) {
throw new ResourceNotFoundException("User", id);
}
userRepository.deleteById(id);
}
}Service Best Practices
- Interface + Impl for testability
- `@Transactional(readOnly = true)` at class level
- `@Transactional` for write methods
- Throw domain exceptions, not generic ones
- Use mappers (MapStruct) for entity ↔ DTO conversion
---
Repository Patterns
JPA Repository
public interface UserRepository extends JpaRepository<User, Long> {
// Derived query
Optional<User> findByEmail(String email);
List<User> findByActiveTrue();
// Custom query
@Query("SELECT u FROM User u WHERE u.department.id = :deptId")
List<User> findByDepartmentId(@Param("deptId") Long departmentId);
// Native query (use sparingly)
@Query(value = "SELECT * FROM users WHERE created_at > :date",
nativeQuery = true)
List<User> findRecentUsers(@Param("date") LocalDate date);
// Exists check (more efficient than findBy)
boolean existsByEmail(SReusable AI development infrastructure for Java projects, optimized for Claude Code This project is not affiliated with Anthropic.
Other skills on claude-code-java.
- /api-contract-review
Review REST API contracts for HTTP semantics, versioning, backward compatibility, and response consistency. Use when user asks "review API", "check endpoints", "REST review", or before releasing API changes.
Open skill - /architecture-review
Analyze Java project architecture at macro level - package structure, module boundaries, dependency direction, and layering. Use when user asks "review architecture", "check structure", "package organization", or when evaluating if a codebase follows clean architecture
Open skill - /changelog-generator
Generate changelogs from git commits. Use when user says "generate changelog", "update changelog", "what changed since last release", or before preparing a new release.
Open skill - /clean-code
Clean Code principles (DRY, KISS, YAGNI), naming conventions, function design, and refactoring. Use when user says "clean this code", "refactor", "improve readability", or when reviewing code quality.
Open skill - /concurrency-review
Review Java concurrency code for thread safety, race conditions, deadlocks, and modern patterns (Virtual Threads, CompletableFuture, @Async). Use when user asks "check thread safety", "concurrency review", "async code review", or when reviewing multi-threaded code.
Open skill - /design-patterns
Common design patterns with Java examples (Factory, Builder, Strategy, Observer, Decorator, etc.). Use when user asks "implement pattern", "use factory", "strategy pattern", or when designing extensible components.
Open skill

