.claude/skills/java-expert/SKILL.md
Java and Spring Boot expert including REST APIs, JPA, and microservices
npx skillsauth add oimiragieo/agent-studio java-expertInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Virtual Threads (Project Loom)
Executors.newVirtualThreadPerTaskExecutor() for thread pools// Enable virtual threads in Spring Boot 3.2+
// application.properties
spring.threads.virtual.enabled=true
// Or programmatically
@Bean
public TomcatProtocolHandlerCustomizer<?> protocolHandlerVirtualThreadExecutorCustomizer() {
return protocolHandler -> {
protocolHandler.setExecutor(Executors.newVirtualThreadPerTaskExecutor());
};
}
// Using virtual threads directly
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
executor.submit(() -> {
// I/O-bound task
Thread.sleep(1000);
return "result";
});
}
Pattern Matching
// Pattern matching for switch
String result = switch (obj) {
case String s -> "String: " + s;
case Integer i -> "Integer: " + i;
case Long l -> "Long: " + l;
case null -> "null";
default -> "Unknown";
};
// Record patterns
record Point(int x, int y) {}
if (obj instanceof Point(int x, int y)) {
System.out.println("x: " + x + ", y: " + y);
}
Records
public record UserDTO(String name, String email, LocalDate birthDate) {
// Compact constructor for validation
public UserDTO {
if (name == null || name.isBlank()) {
throw new IllegalArgumentException("Name cannot be blank");
}
}
}
Sealed Classes
public sealed interface Result<T> permits Success, Failure {
record Success<T>(T value) implements Result<T> {}
record Failure<T>(String error) implements Result<T> {}
}
Framework Setup:
Project Structure (Layered Architecture):
src/main/java/com/example/app/
├── controller/ # REST endpoints (RestController)
├── service/ # Business logic (Service)
│ └── impl/ # Service implementations
├── repository/ # Data access (Repository)
├── model/
│ ├── entity/ # JPA entities
│ └── dto/ # Data Transfer Objects
├── config/ # Configuration classes
├── exception/ # Custom exceptions and handlers
└── util/ # Utility classes
Controller Layer (RestController):
@RestController
@RequestMapping("/api/users")
@RequiredArgsConstructor
public class UserController {
private final UserService userService;
@GetMapping("/{id}")
public ResponseEntity<UserDTO> getUser(@PathVariable Long id) {
UserDTO user = userService.findById(id);
return ResponseEntity.ok(user);
}
@PostMapping
public ResponseEntity<UserDTO> createUser(@Valid @RequestBody CreateUserDTO dto) {
UserDTO created = userService.create(dto);
return ResponseEntity.status(HttpStatus.CREATED).body(created);
}
}
Service Layer:
@Service@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class UserServiceImpl implements UserService {
private final UserRepository userRepository;
private final ModelMapper modelMapper;
@Override
public UserDTO findById(Long id) {
User user = userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException(id));
return modelMapper.map(user, UserDTO.class);
}
@Override
@Transactional
public UserDTO create(CreateUserDTO dto) {
User user = modelMapper.map(dto, User.class);
User saved = userRepository.save(user);
return modelMapper.map(saved, UserDTO.class);
}
}
Repository Layer (Spring Data JPA):
JpaRepository<Entity, ID>@Query for complex queries@Repository
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByEmail(String email);
@Query("SELECT u FROM User u WHERE u.createdAt > :date")
List<User> findRecentUsers(@Param("date") LocalDateTime date);
// Projection for performance
@Query("SELECT new com.example.dto.UserSummaryDTO(u.id, u.name, u.email) FROM User u")
List<UserSummaryDTO> findAllSummaries();
}
Entity Design:
@Entity and @Table annotations@Id with generation strategy@Column for constraints and mappingsequals() and hashCode() based on business key@Entity
@Table(name = "users")
@Getter @Setter
@NoArgsConstructor
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
private String email;
@Column(nullable = false)
private String name;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Order> orders = new ArrayList<>();
@CreatedDate
@Column(nullable = false, updatable = false)
private LocalDateTime createdAt;
@LastModifiedDate
private LocalDateTime updatedAt;
}
Performance Optimization:
@EntityGraph or JOIN FETCH to prevent N+1 queries@Query("SELECT u FROM User u JOIN FETCH u.orders WHERE u.id = :id")
Optional<User> findByIdWithOrders(@Param("id") Long id);
// Pagination
Page<User> findAll(Pageable pageable);
Unit Testing Services:
@ExtendWith(MockitoExtension.class)
class UserServiceImplTest {
@Mock
private UserRepository userRepository;
@Mock
private ModelMapper modelMapper;
@InjectMocks
private UserServiceImpl userService;
@Test
void findById_WhenUserExists_ReturnsUserDTO() {
// Given
Long userId = 1L;
User user = new User();
user.setId(userId);
UserDTO expectedDTO = new UserDTO();
when(userRepository.findById(userId)).thenReturn(Optional.of(user));
when(modelMapper.map(user, UserDTO.class)).thenReturn(expectedDTO);
// When
UserDTO result = userService.findById(userId);
// Then
assertNotNull(result);
verify(userRepository).findById(userId);
verify(modelMapper).map(user, UserDTO.class);
}
}
Integration Testing (Spring Boot Test):
@SpringBootTest
@AutoConfigureMockMvc
@Transactional
class UserControllerIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private ObjectMapper objectMapper;
@Test
void createUser_WithValidData_ReturnsCreated() throws Exception {
CreateUserDTO dto = new CreateUserDTO("John Doe", "[email protected]");
mockMvc.perform(post("/api/users")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(dto)))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.name").value("John Doe"));
}
}
Maven (pom.xml):
<properties>
<java.version>21</java.version>
<spring-boot.version>3.2.0</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
</dependencies>
Gradle (build.gradle):
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.0'
id 'io.spring.dependency-management' version '1.1.4'
}
java {
sourceCompatibility = JavaVersion.VERSION_21
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-validation'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
Global Exception Handler:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(UserNotFoundException.class)
public ResponseEntity<ErrorResponse> handleUserNotFound(UserNotFoundException ex) {
ErrorResponse error = new ErrorResponse(
"USER_NOT_FOUND",
ex.getMessage(),
LocalDateTime.now()
);
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleValidation(MethodArgumentNotValidException ex) {
Map<String, String> errors = ex.getBindingResult()
.getFieldErrors()
.stream()
.collect(Collectors.toMap(
FieldError::getField,
FieldError::getDefaultMessage
));
ErrorResponse error = new ErrorResponse(
"VALIDATION_ERROR",
"Invalid input",
errors,
LocalDateTime.now()
);
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
}
}
Logging (SLF4J + Logback):
@Slf4j
@Service
public class UserServiceImpl implements UserService {
public UserDTO findById(Long id) {
log.debug("Finding user with id: {}", id);
try {
User user = userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException(id));
log.info("User found: {}", user.getEmail());
return modelMapper.map(user, UserDTO.class);
} catch (UserNotFoundException ex) {
log.error("User not found with id: {}", id, ex);
throw ex;
}
}
}
Actuator for Monitoring:
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
endpoint:
health:
show-details: always
</instructions>
<examples>
Example usage:
```
User: "Review this code for java best practices"
Agent: [Analyzes code against consolidated guidelines and provides specific feedback]
```
</examples>
@Autowired — field injection hides dependencies, makes testing harder, and creates partially-initialized objects that crash at runtime if the context isn't fully loaded.Optional.get() without a preceding isPresent() check or orElse()/orElseThrow() — unconditional get() throws NoSuchElementException on empty optionals, silently defeating Optional's entire purpose.@Transactional boundaries explicitly — calling a transactional method from within the same class bypasses the proxy and runs without a transaction, causing silent data inconsistency.@Async without a configured TaskExecutor — Spring's default @Async executor uses a single-thread pool; concurrent async calls queue up and defeat parallelism.@ControllerAdvice with specific exception types for error handling — catching Exception globally hides root causes; specific exception handlers produce correct HTTP status codes and meaningful error responses.| Anti-Pattern | Why It Fails | Correct Approach |
| ------------------------------------------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| Field injection with @Autowired | Hidden dependencies; untestable without Spring context; null in unit tests | Constructor injection; all required dependencies declared as final fields |
| Optional.get() without check | NoSuchElementException at runtime; defeats Optional's null-safety contract | Use orElseThrow(), orElse(), or map()/flatMap() chains |
| @Transactional on same-class method calls | Spring proxy bypassed; method runs outside transaction; data integrity lost | Move transactional methods to a separate service bean; inject and call from outside |
| Default @Async thread pool | Single-thread pool queues all tasks; async calls run sequentially | Configure ThreadPoolTaskExecutor with pool size, queue, and rejection policy |
| Global @ExceptionHandler(Exception.class) | Swallows specific exceptions; all errors return same generic 500 response | Map specific exception types to HTTP status codes; use @ResponseStatus annotations |
This expert skill consolidates 1 individual skills:
Before starting:
cat .claude/context/memory/learnings.md
After completing: Record any new patterns or exceptions discovered.
ASSUME INTERRUPTION: Your context may reset. If it's not in memory, it didn't happen.
tools
Comprehensive biosignal processing toolkit for analyzing physiological data including ECG, EEG, EDA, RSP, PPG, EMG, and EOG signals. Use this skill when processing cardiovascular signals, brain activity, electrodermal responses, respiratory patterns, muscle activity, or eye movements. Applicable for heart rate variability analysis, event-related potentials, complexity measures, autonomic nervous system assessment, psychophysiology research, and multi-modal physiological signal integration.
tools
Comprehensive toolkit for creating, analyzing, and visualizing complex networks and graphs in Python. Use when working with network/graph data structures, analyzing relationships between entities, computing graph algorithms (shortest paths, centrality, clustering), detecting communities, generating synthetic networks, or visualizing network topologies. Applicable to social networks, biological networks, transportation systems, citation networks, and any domain involving pairwise relationships.
data-ai
Molecular featurization for ML (100+ featurizers). ECFP, MACCS, descriptors, pretrained models (ChemBERTa), convert SMILES to features, for QSAR and molecular ML.
development
Run Python code in the cloud with serverless containers, GPUs, and autoscaling. Use when deploying ML models, running batch processing jobs, scheduling compute-intensive tasks, or serving APIs that require GPU acceleration or dynamic scaling.