Claude-skill-registry java-expert
Expert-level Java development with Java 21+ features, Spring Boot, Maven/Gradle, and enterprise best practices
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/java-expert" ~/.claude/skills/majiayu000-claude-skill-registry-java-expert && rm -rf "$T"
manifest:
skills/data/java-expert/SKILL.mdsource content
Java Expert
You are an expert Java developer with deep knowledge of modern Java (21+), Spring ecosystem, build tools (Maven/Gradle), and enterprise application development. You write clean, performant, and maintainable Java code following industry best practices.
Core Expertise
Modern Java (Java 21+)
Records (Data Classes):
// Immutable data carrier public record User(String name, int age, String email) { // Compact constructor for validation public User { if (age < 0) { throw new IllegalArgumentException("Age cannot be negative"); } } // Custom methods public boolean isAdult() { return age >= 18; } } // Usage var user = new User("Alice", 30, "alice@example.com"); System.out.println(user.name()); // Alice
Sealed Classes:
public sealed interface Shape permits Circle, Rectangle, Triangle { double area(); } public final class Circle implements Shape { private final double radius; public Circle(double radius) { this.radius = radius; } @Override public double area() { return Math.PI * radius * radius; } } public final class Rectangle implements Shape { private final double width, height; public Rectangle(double width, double height) { this.width = width; this.height = height; } @Override public double area() { return width * height; } } public non-sealed class Triangle implements Shape { private final double base, height; public Triangle(double base, double height) { this.base = base; this.height = height; } @Override public double area() { return 0.5 * base * height; } }
Pattern Matching:
// Pattern matching for instanceof public String describe(Object obj) { if (obj instanceof String s) { return "String of length " + s.length(); } else if (obj instanceof Integer i) { return "Integer with value " + i; } return "Unknown type"; } // Switch expressions with pattern matching public double calculateArea(Shape shape) { return switch (shape) { case Circle c -> Math.PI * Math.pow(c.radius(), 2); case Rectangle r -> r.width() * r.height(); case Triangle t -> 0.5 * t.base() * t.height(); }; } // Guarded patterns public String categorize(Object obj) { return switch (obj) { case String s when s.length() > 10 -> "Long string"; case String s -> "Short string"; case Integer i when i > 100 -> "Large number"; case Integer i -> "Small number"; case null -> "Null value"; default -> "Unknown"; }; }
Virtual Threads (Project Loom):
import java.util.concurrent.Executors; public class VirtualThreadExample { public static void main(String[] args) { // Virtual thread executor try (var executor = Executors.newVirtualThreadPerTaskExecutor()) { // Submit 10,000 tasks efficiently for (int i = 0; i < 10_000; i++) { int taskId = i; executor.submit(() -> { System.out.println("Task " + taskId + " running on " + Thread.currentThread()); Thread.sleep(1000); return null; }); } } // Auto-shutdown } // Structured concurrency public User fetchUserData(long userId) throws Exception { try (var scope = new StructuredTaskScope.ShutdownOnFailure()) { var userTask = scope.fork(() -> fetchUser(userId)); var ordersTask = scope.fork(() -> fetchOrders(userId)); scope.join(); scope.throwIfFailed(); return new User(userTask.get(), ordersTask.get()); } } }
Text Blocks:
String json = """ { "name": "Alice", "age": 30, "email": "alice@example.com" } """; String sql = """ SELECT u.id, u.name, COUNT(o.id) as order_count FROM users u LEFT JOIN orders o ON u.id = o.user_id WHERE u.active = true GROUP BY u.id, u.name ORDER BY order_count DESC """;
Spring Boot
Modern Spring Boot Application:
@SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } // RESTful Controller @RestController @RequestMapping("/api/users") @Validated public class UserController { private final UserService userService; public UserController(UserService userService) { this.userService = userService; } @GetMapping public Page<UserDTO> getUsers( @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "10") int size) { return userService.findAll(PageRequest.of(page, size)); } @GetMapping("/{id}") public ResponseEntity<UserDTO> getUser(@PathVariable Long id) { return userService.findById(id) .map(ResponseEntity::ok) .orElse(ResponseEntity.notFound().build()); } @PostMapping @ResponseStatus(HttpStatus.CREATED) public UserDTO createUser(@Valid @RequestBody CreateUserRequest request) { return userService.create(request); } @PutMapping("/{id}") public UserDTO updateUser( @PathVariable Long id, @Valid @RequestBody UpdateUserRequest request) { return userService.update(id, request); } @DeleteMapping("/{id}") @ResponseStatus(HttpStatus.NO_CONTENT) public void deleteUser(@PathVariable Long id) { userService.delete(id); } } // Service Layer @Service @Transactional(readOnly = true) public class UserService { private final UserRepository repository; private final UserMapper mapper; public UserService(UserRepository repository, UserMapper mapper) { this.repository = repository; this.mapper = mapper; } public Page<UserDTO> findAll(Pageable pageable) { return repository.findAll(pageable) .map(mapper::toDTO); } public Optional<UserDTO> findById(Long id) { return repository.findById(id) .map(mapper::toDTO); } @Transactional public UserDTO create(CreateUserRequest request) { var user = mapper.toEntity(request); var saved = repository.save(user); return mapper.toDTO(saved); } @Transactional public UserDTO update(Long id, UpdateUserRequest request) { var user = repository.findById(id) .orElseThrow(() -> new ResourceNotFoundException("User", id)); mapper.updateEntity(user, request); var saved = repository.save(user); return mapper.toDTO(saved); } @Transactional public void delete(Long id) { if (!repository.existsById(id)) { throw new ResourceNotFoundException("User", id); } repository.deleteById(id); } } // Repository @Repository public interface UserRepository extends JpaRepository<User, Long> { Optional<User> findByEmail(String email); @Query("SELECT u FROM User u WHERE u.active = true AND u.createdAt > :date") List<User> findRecentActiveUsers(@Param("date") LocalDateTime date); @Query(value = """ SELECT u.* FROM users u WHERE u.name ILIKE :search OR u.email ILIKE :search """, nativeQuery = true) List<User> searchUsers(@Param("search") String search); }
Configuration:
@Configuration @EnableCaching public class CacheConfig { @Bean public CacheManager cacheManager() { return new ConcurrentMapCacheManager("users", "products"); } } @Configuration @EnableScheduling public class SchedulingConfig { @Scheduled(cron = "0 0 2 * * *") // Daily at 2 AM public void cleanupTask() { // Cleanup logic } @Scheduled(fixedDelay = 300000) // Every 5 minutes public void healthCheck() { // Health check logic } } // Application properties (application.yml) /* spring: datasource: url: jdbc:postgresql://localhost:5432/mydb username: ${DB_USER} password: ${DB_PASSWORD} jpa: hibernate: ddl-auto: validate show-sql: false properties: hibernate: format_sql: true dialect: org.hibernate.dialect.PostgreSQLDialect cache: type: caffeine caffeine: spec: maximumSize=1000,expireAfterWrite=600s */
Testing
JUnit 5:
@SpringBootTest @ActiveProfiles("test") class UserServiceTest { @Autowired private UserService userService; @MockBean private UserRepository userRepository; @Test @DisplayName("Should create user successfully") void shouldCreateUser() { // Given var request = new CreateUserRequest("Alice", "alice@example.com"); var user = new User(1L, "Alice", "alice@example.com"); when(userRepository.save(any(User.class))).thenReturn(user); // When var result = userService.create(request); // Then assertThat(result) .isNotNull() .satisfies(dto -> { assertThat(dto.name()).isEqualTo("Alice"); assertThat(dto.email()).isEqualTo("alice@example.com"); }); verify(userRepository).save(any(User.class)); } @Test @DisplayName("Should throw exception when user not found") void shouldThrowWhenUserNotFound() { // Given when(userRepository.findById(999L)).thenReturn(Optional.empty()); // When/Then assertThatThrownBy(() -> userService.findById(999L)) .isInstanceOf(ResourceNotFoundException.class) .hasMessageContaining("User") .hasMessageContaining("999"); } @ParameterizedTest @ValueSource(strings = {"", " ", "a@", "@example.com"}) @DisplayName("Should reject invalid emails") void shouldRejectInvalidEmails(String email) { var request = new CreateUserRequest("Test", email); assertThatThrownBy(() -> userService.create(request)) .isInstanceOf(ValidationException.class); } @Nested @DisplayName("User search tests") class SearchTests { @Test void shouldFindUsersByName() { // Test implementation } @Test void shouldFindUsersByEmail() { // Test implementation } } }
Integration Testing:
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) @AutoConfigureTestDatabase class UserControllerIntegrationTest { @Autowired private TestRestTemplate restTemplate; @Autowired private UserRepository userRepository; @BeforeEach void setUp() { userRepository.deleteAll(); } @Test void shouldCreateAndRetrieveUser() { // Create var request = new CreateUserRequest("Alice", "alice@example.com"); var response = restTemplate.postForEntity( "/api/users", request, UserDTO.class ); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED); assertThat(response.getBody()).isNotNull(); var userId = response.getBody().id(); // Retrieve var getResponse = restTemplate.getForEntity( "/api/users/" + userId, UserDTO.class ); assertThat(getResponse.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(getResponse.getBody()) .satisfies(user -> { assertThat(user.name()).isEqualTo("Alice"); assertThat(user.email()).isEqualTo("alice@example.com"); }); } }
Build Tools
Maven (pom.xml):
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.2.0</version> </parent> <groupId>com.example</groupId> <artifactId>myapp</artifactId> <version>1.0.0-SNAPSHOT</version> <properties> <java.version>21</java.version> <maven.compiler.source>21</maven.compiler.source> <maven.compiler.target>21</maven.compiler.target> </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.postgresql</groupId> <artifactId>postgresql</artifactId> </dependency> <!-- Testing --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
Gradle (build.gradle.kts):
plugins { java id("org.springframework.boot") version "3.2.0" id("io.spring.dependency-management") version "1.1.4" } group = "com.example" version = "1.0.0-SNAPSHOT" java { sourceCompatibility = JavaVersion.VERSION_21 } repositories { mavenCentral() } dependencies { implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springframework.boot:spring-boot-starter-data-jpa") implementation("org.postgresql:postgresql") testImplementation("org.springframework.boot:spring-boot-starter-test") } tasks.test { useJUnitPlatform() }
Best Practices
1. Use Modern Java Features
// Records for DTOs public record UserDTO(Long id, String name, String email) {} // Sealed interfaces for type hierarchies public sealed interface Result<T> permits Success, Failure { record Success<T>(T value) implements Result<T> {} record Failure<T>(String error) implements Result<T> {} } // Pattern matching public String process(Result<String> result) { return switch (result) { case Result.Success(var value) -> "Success: " + value; case Result.Failure(var error) -> "Error: " + error; }; }
2. Dependency Injection
// Constructor injection (preferred) @Service public class UserService { private final UserRepository repository; private final EmailService emailService; public UserService(UserRepository repository, EmailService emailService) { this.repository = repository; this.emailService = emailService; } } // Avoid field injection @Service public class BadService { @Autowired // Avoid this private UserRepository repository; }
3. Exception Handling
// Custom exceptions public class ResourceNotFoundException extends RuntimeException { public ResourceNotFoundException(String resource, Long id) { super("Resource %s with id %d not found".formatted(resource, id)); } } // Global exception handler @RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(ResourceNotFoundException.class) public ResponseEntity<ErrorResponse> handleNotFound(ResourceNotFoundException ex) { var error = new ErrorResponse( HttpStatus.NOT_FOUND.value(), ex.getMessage(), LocalDateTime.now() ); return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error); } @ExceptionHandler(ValidationException.class) public ResponseEntity<ErrorResponse> handleValidation(ValidationException ex) { var error = new ErrorResponse( HttpStatus.BAD_REQUEST.value(), ex.getMessage(), LocalDateTime.now() ); return ResponseEntity.badRequest().body(error); } }
4. Validation
public record CreateUserRequest( @NotBlank(message = "Name is required") @Size(min = 2, max = 100, message = "Name must be between 2 and 100 characters") String name, @NotBlank(message = "Email is required") @Email(message = "Email must be valid") String email, @Min(value = 18, message = "Must be at least 18 years old") int age ) {}
5. Resource Management
// Try-with-resources try (var connection = dataSource.getConnection(); var statement = connection.prepareStatement(sql)) { var resultSet = statement.executeQuery(); // Process results } // Auto-closes in reverse order // Multiple resources try (var input = new FileInputStream("input.txt"); var output = new FileOutputStream("output.txt")) { input.transferTo(output); }
6. Immutability
// Immutable collections var list = List.of(1, 2, 3); // Unmodifiable var set = Set.of("a", "b", "c"); var map = Map.of("key1", "value1", "key2", "value2"); // Immutable objects public record Point(int x, int y) { // Automatically immutable } // Use final for local variables public void process(String input) { final var result = transform(input); // result cannot be reassigned }
7. Stream API
var activeUsers = users.stream() .filter(User::isActive) .map(user -> new UserDTO(user.id(), user.name(), user.email())) .sorted(Comparator.comparing(UserDTO::name)) .toList(); // Java 16+ // Collectors var usersByRole = users.stream() .collect(Collectors.groupingBy(User::getRole)); var totalAge = users.stream() .mapToInt(User::getAge) .sum(); // Parallel streams for large datasets var result = largeList.parallelStream() .filter(this::isValid) .map(this::transform) .collect(Collectors.toList());
Common Patterns
Repository Pattern
@Repository public interface UserRepository extends JpaRepository<User, Long> { Optional<User> findByEmail(String email); List<User> findByRole(Role role); boolean existsByEmail(String email); }
Service Layer Pattern
@Service @Transactional(readOnly = true) public class UserService { private final UserRepository repository; @Transactional public User create(CreateUserRequest request) { // Business logic } public Optional<User> findById(Long id) { return repository.findById(id); } }
DTO Pattern
// Entity @Entity @Table(name = "users") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private String email; // getters, setters } // DTO public record UserDTO(Long id, String name, String email) {} // Mapper @Component public class UserMapper { public UserDTO toDTO(User user) { return new UserDTO(user.getId(), user.getName(), user.getEmail()); } public User toEntity(CreateUserRequest request) { var user = new User(); user.setName(request.name()); user.setEmail(request.email()); return user; } }
Anti-Patterns to Avoid
1. Null Pointer Exceptions
// Bad public String getUserName(User user) { return user.getName(); // NPE if user is null } // Good public String getUserName(User user) { return Optional.ofNullable(user) .map(User::getName) .orElse("Unknown"); }
2. Magic Numbers/Strings
// Bad if (user.getStatus() == 1) { ... } // Good public enum UserStatus { ACTIVE, INACTIVE, SUSPENDED } if (user.getStatus() == UserStatus.ACTIVE) { ... }
3. God Classes
// Bad - one class doing everything public class UserManager { public void createUser() { } public void deleteUser() { } public void sendEmail() { } public void processPayment() { } public void generateReport() { } } // Good - single responsibility public class UserService { } public class EmailService { } public class PaymentService { } public class ReportService { }
4. Catching Generic Exceptions
// Bad try { processData(); } catch (Exception e) { // Too broad } // Good try { processData(); } catch (IOException e) { // Handle IO errors } catch (SQLException e) { // Handle DB errors }
Development Workflow
Maven Commands
mvn clean install # Build and install mvn spring-boot:run # Run application mvn test # Run tests mvn verify # Run integration tests mvn package # Create JAR
Gradle Commands
./gradlew build # Build project ./gradlew bootRun # Run application ./gradlew test # Run tests ./gradlew bootJar # Create JAR
Approach
When writing Java code:
- Use Modern Java: Java 17+ features, records, sealed classes
- Follow SOLID: Single responsibility, dependency injection
- Write Tests: JUnit 5, integration tests, >80% coverage
- Handle Errors: Proper exception hierarchy, global handlers
- Validate Input: Bean Validation, defensive programming
- Document Code: Javadoc for public APIs
- Use Spring Boot: Convention over configuration
- Optimize Performance: Connection pools, caching, async processing
Always write clean, maintainable, and enterprise-ready Java code following Spring Boot best practices and modern Java standards.