Skip to content
Development
Skill

/java-patterns

Java: Spring Boot, CompletableFuture, records, sealed types, JPA/Hibernate, virtual threads. Triggers: Java, Spring, JPA, Hibernate, Maven, Gradle, virtual thread, sealed class.

From plugin
ai-toolkit
161111 skills44 agents
Install
$ npx -y skills add softspark/ai-toolkit --skill java-patterns --agent claude-code

How 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/java-patterns

Context preview

The summary Claude sees to decide when to auto-load this skill.

Java: Spring Boot, CompletableFuture, records, sealed types, JPA/Hibernate, virtual threads. Triggers: Java, Spring, JPA, Hibernate, Maven, Gradle, virtual thread, sealed class.

SKILL.md

java-patterns.SKILL.md
name: java-patterns
description: "Java: Spring Boot, CompletableFuture, records, sealed types, JPA/Hibernate, virtual threads. Triggers: Java, Spring, JPA, Hibernate, Maven, Gradle, virtual thread, sealed class."
effort: medium
user-invocable: false
allowed-tools: Read

Java Patterns Skill

Project Structure

Maven / Gradle Standard Layout

my-app/
├── pom.xml (or build.gradle.kts + settings.gradle.kts)
├── src/
│   ├── main/
│   │   ├── java/com/example/myapp/
│   │   │   ├── MyApplication.java
│   │   │   ├── config/
│   │   │   ├── controller/
│   │   │   ├── service/
│   │   │   ├── repository/
│   │   │   ├── model/
│   │   │   │   ├── entity/
│   │   │   │   └── dto/
│   │   │   └── exception/
│   │   └── resources/
│   │       ├── application.yml
│   │       └── db/migration/
│   └── test/
│       ├── java/com/example/myapp/
│       └── resources/application-test.yml
└── target/ (or build/)

Multi-Module

parent/
├── pom.xml              (packaging=pom)
├── common/              (shared utilities)
├── domain/              (entities, business rules)
├── api/                 (REST controllers, DTOs)
└── app/                 (Spring Boot main, wiring)

---

Idioms / Code Style

Records (Java 16+)

public record UserDto(Long id, String name, String email) {
    public UserDto {  // compact constructor for validation
        Objects.requireNonNull(name, "name must not be null");
        Objects.requireNonNull(email, "email must not be null");
    }
}

Sealed Classes (Java 17+)

public sealed interface Shape permits Circle, Rectangle, Triangle {
    double area();
}
public record Circle(double radius) implements Shape {
    public double area() { return Math.PI * radius * radius; }
}
public record Rectangle(double w, double h) implements Shape {
    public double area() { return w * h; }
}
public record Triangle(double base, double height) implements Shape {
    public double area() { return 0.5 * base * height; }
}

Switch Expressions (Java 14+)

String describe(Shape shape) {
    return switch (shape) {
        case Circle c    -> "Circle r=" + c.radius();
        case Rectangle r -> "Rect %sx%s".formatted(r.w(), r.h());
        case Triangle t  -> "Triangle base=" + t.base();
    };
}
// Guard patterns (Java 21+)
String classify(Shape shape) {
    return switch (shape) {
        case Circle c when c.radius() > 100 -> "large circle";
        case Circle c                        -> "small circle";
        case Rectangle r                     -> "rectangle";
        case Triangle t                      -> "triangle";
    };
}

var, Streams, Optional

// var -- use when RHS makes type obvious
var users = new ArrayList<User>();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
// Avoid: var result = service.process(data); -- type unclear

// Streams
List<String> names = users.stream()
    .filter(User::isActive)
    .map(User::name)
    .sorted()
    .toList();  // Java 16+, unmodifiable

Map<Department, List<User>> byDept = users.stream()
    .collect(Collectors.groupingBy(User::department));

// Optional -- return type only, never as field or parameter
String city = findByEmail(email)
    .map(User::address)
    .map(Address::city)
    .orElse("Unknown");
// Never call .get() without guard -- use orElse/orElseThrow

// Text blocks (Java 15+)
String json = """
    {"name": "%s", "email": "%s"}
    """.formatted(name, email);

---

Error Handling

| Type | When | Examples | |------|------|---------| | Checked | Recoverable I/O the caller must handle | IOException, SQLException | | Unchecked | Programming errors, business rule violations | IllegalArgumentException, custom domain exceptions |

Custom Exception Hierarchy

public abstract class DomainException extends RuntimeException {
    private final String errorCode;
    protected DomainException(String errorCode, String message) {
        super(message);
        this.errorCode = errorCode;
    }
    public String errorCode() { return errorCode; }
}

public class EntityNotFoundException extends DomainException {
    public EntityNotFoundException(String entity, Object id) {
        super("NOT_FOUND", "%s with id %s not found".formatted(entity, id));
    }
}

Try-With-Resources

try (var conn = dataSource.getConnection();
     var stmt = conn.prepareStatement(sql);
     var rs = stmt.executeQuery()) {
    while (rs.next()) { results.add(mapRow(rs)); }
}

Global Handler (Spring)

@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(EntityNotFoundException.class)
    public ResponseEntity<ErrorResponse> handleNotFound(EntityNotFoundException ex) {
        return ResponseEntity.status(404).body(new ErrorResponse(ex.errorCode(), ex.getMessage()));
    }
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<ErrorResponse> handleValidation(MethodArgumentNotValidException ex) {
        var errors = ex.getBindingResult().getFieldErrors().stream()
            .map(e -> e.getField() + ": " + e.getDefaultMessage()).toList();
        return ResponseEntity.badRequest().body(new ErrorResponse("VALIDATION_ERROR", errors.toString()));
    }
    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleGeneric(Exception ex) {
        log.error("Unhandled exception", ex);
        return ResponseEntity.internalServerError()
            .body(new ErrorResponse("INTERNAL_ERROR", "An unexpected error occurred"));
    }
}
public record ErrorResponse(String code, String message) {}

---

Testing Patterns

JUnit 5 + Mockito + AssertJ

@DisplayName("UserService")
class UserServiceTest {
    private UserRepository repository;
    private UserService service;

    @BeforeEach
    void setUp() {
        repository = mock(UserRepository.class);
        service = new UserService(repository);
    }
Read more
Ships withai-toolkit

Professional-grade AI coding toolkit with multi-platform support. Machine-enforced safety, 109 skills, 44 agents, expanded lifecycle hooks, persona presets, experimental opt-in plugin packs, and benchmark tooling — works with Claude Code, Claude Chat/Cowork,

Get the whole plugin