Expert Java Spring Boot development with SOLID principles, layered architecture (Controller→Service→Repository), DTOs, JPA best practices, and comprehensive error handling
An expert Java Spring Boot development assistant that enforces clean architecture, SOLID principles, and industry best practices for building robust REST APIs with proper layering and error handling.
Guides development of Java Spring Boot 3 applications with Maven and Java 17, emphasizing:
Always adhere to:
Break down tasks into smallest units and approach problems step-by-step.
**RestController Layer:**
**Service Layer:**
**Repository Layer:**
```java
@Entity
@Data // from Lombok (unless specified otherwise)
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotEmpty
private String email;
@Size(min = 3, max = 50)
private String username;
@OneToMany(fetch = FetchType.LAZY) // Always use LAZY unless specified
private List<Post> posts;
}
```
**Requirements:**
```java
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
@Query("SELECT u FROM User u WHERE u.email = :email")
Optional<User> findByEmail(@Param("email") String email);
@EntityGraph(attributePaths = {"posts"})
@Query("SELECT u FROM User u WHERE u.id = :id")
Optional<User> findByIdWithPosts(@Param("id") Long id);
// Multi-join queries return DTOs
@Query("SELECT new com.example.dto.UserSummaryDTO(u.id, u.username, COUNT(p)) " +
"FROM User u LEFT JOIN u.posts p WHERE u.id = :id GROUP BY u.id, u.username")
Optional<UserSummaryDTO> getUserSummary(@Param("id") Long id);
}
```
**Requirements:**
```java
// Interface
public interface UserService {
UserDTO getUserById(Long id);
UserDTO createUser(CreateUserDTO dto);
}
// Implementation
@Service
public class UserServiceImpl implements UserService {
@Autowired // without constructor (unless specified otherwise)
private UserRepository userRepository;
@Override
public UserDTO getUserById(Long id) {
User user = userRepository.findById(id)
.orElseThrow(() -> new IllegalArgumentException("User not found"));
return mapToDTO(user);
}
@Override
@Transactional
public UserDTO createUser(CreateUserDTO dto) {
// Multi-step database operations use @Transactional
User user = new User();
user.setEmail(dto.email());
user.setUsername(dto.username());
User saved = userRepository.save(user);
return mapToDTO(saved);
}
private UserDTO mapToDTO(User user) {
return new UserDTO(user.getId(), user.getUsername(), user.getEmail());
}
}
```
**Requirements:**
```java
public record CreateUserDTO(String email, String username) {
// Compact canonical constructor for validation
public CreateUserDTO {
if (email == null || email.isBlank()) {
throw new IllegalArgumentException("Email cannot be blank");
}
if (username == null || username.length() < 3) {
throw new IllegalArgumentException("Username must be at least 3 characters");
}
}
}
public record UserDTO(Long id, String username, String email) {}
```
**Requirements:**
```java
@RestController
@RequestMapping("/api/users") // Class-level route
public class UserController {
@Autowired // without constructor (unless specified otherwise)
private UserService userService;
@GetMapping("/{id}") // Resource-based paths, no verbs
public ResponseEntity<ApiResponse<UserDTO>> getUser(@PathVariable Long id) {
try {
UserDTO user = userService.getUserById(id);
ApiResponse<UserDTO> response = new ApiResponse<>("SUCCESS", "User retrieved", user);
return ResponseEntity.ok(response);
} catch (IllegalArgumentException ex) {
throw ex; // Let GlobalExceptionHandler handle it
}
}
@PostMapping // No verb in path
public ResponseEntity<ApiResponse<UserDTO>> createUser(@RequestBody CreateUserDTO dto) {
try {
UserDTO user = userService.createUser(dto);
ApiResponse<UserDTO> response = new ApiResponse<>("SUCCESS", "User created", user);
return ResponseEntity.status(HttpStatus.CREATED).body(response);
} catch (IllegalArgumentException ex) {
throw ex;
}
}
}
```
**Requirements:**
**ApiResponse.java:**
```java
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ApiResponse<T> {
private String result; // "SUCCESS" or "ERROR"
private String message; // success or error message
private T data; // return object from service, if successful
}
```
**GlobalExceptionHandler.java:**
```java
@RestControllerAdvice
public class GlobalExceptionHandler {
public static ResponseEntity<ApiResponse<?>> errorResponseEntity(String message, HttpStatus status) {
ApiResponse<?> response = new ApiResponse<>("ERROR", message, null);
return new ResponseEntity<>(response, status);
}
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<ApiResponse<?>> handleIllegalArgumentException(IllegalArgumentException ex) {
return errorResponseEntity(ex.getMessage(), HttpStatus.BAD_REQUEST);
}
// Add more exception handlers as needed
}
```
1. **Define Entity** - Create entity class with proper annotations and relationships
2. **Create Repository** - Extend JpaRepository, add custom queries with `@EntityGraph`
3. **Define DTOs** - Create record types with validation in compact constructors
4. **Create Service Interface** - Define method signatures
5. **Implement ServiceImpl** - Business logic using Repository methods, return DTOs
6. **Create RestController** - Handle requests/responses, use try-catch, return ApiResponse
7. **Test** - Verify each layer independently
When asked to "Create a user management API":
1. Create `User` entity with validation annotations
2. Create `UserRepository` extending JpaRepository
3. Create `UserDTO` and `CreateUserDTO` records with validation
4. Create `UserService` interface and `UserServiceImpl`
5. Create `UserController` with CRUD endpoints
6. Ensure GlobalExceptionHandler and ApiResponse are in place
Leave a review
No reviews yet. Be the first to review this skill!
# Download SKILL.md from killerskills.ai/api/skills/java-spring-boot-senior-developer/raw