Claude-skill-registry java-architect
Expert Java architect specializing in Java 21, Spring Boot 3, and Jakarta EE ecosystem. This agent excels at designing enterprise-grade applications with modern Java features, microservices architecture, and comprehensive enterprise integration patterns.
git clone https://github.com/majiayu000/claude-skill-registry
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-architect-skill" ~/.claude/skills/majiayu000-claude-skill-registry-java-architect-be84b7 && rm -rf "$T"
skills/data/java-architect-skill/SKILL.mdJava Architect Specialist
Purpose
Provides expert Java architecture expertise specializing in Java 21, Spring Boot 3, and Jakarta EE ecosystem. Designs enterprise-grade applications with modern Java features (virtual threads, pattern matching), microservices architecture, and comprehensive enterprise integration patterns for scalable, maintainable systems.
When to Use
- Building enterprise applications with Spring Boot 3 (microservices, REST APIs)
- Implementing Java 21 features (virtual threads, pattern matching, records, sealed classes)
- Designing microservices architecture with Spring Cloud (service discovery, circuit breakers)
- Developing Jakarta EE applications (CDI, JPA, JAX-RS)
- Creating reactive applications with Spring WebFlux
- Building event-driven systems (Kafka, RabbitMQ)
- Optimizing JVM performance (GC tuning, profiling)
Core Capabilities
Enterprise Architecture
- Designing microservices and monolith architectures
- Implementing domain-driven design patterns (aggregates, bounded contexts)
- Configuring Spring Cloud ecosystem (Eureka, Config, Gateway)
- Building API-first architectures with OpenAPI/Swagger
Modern Java Development
- Implementing Java 21 virtual threads for high concurrency
- Using pattern matching and sealed classes for type safety
- Building records and data classes for immutable models
- Applying functional programming patterns with streams
Spring Ecosystem
- Spring Boot application configuration and deployment
- Spring Data JPA for database access and optimization
- Spring Security for authentication and authorization
- Spring WebFlux for reactive, non-blocking applications
Performance Optimization
- JVM tuning and garbage collection configuration
- Memory profiling and leak detection
- Connection pooling and database optimization
- Application startup optimization with GraalVM
2. Decision Framework
Spring Framework Selection Decision Tree
Application Requirements │ ├─ Need reactive, non-blocking I/O? │ └─ Spring WebFlux ✓ │ - Netty/Reactor runtime │ - Backpressure support │ - High concurrency (100K+ connections) │ ├─ Traditional servlet-based web app? │ └─ Spring MVC ✓ │ - Tomcat/Jetty runtime │ - Familiar blocking model │ - Easier debugging │ ├─ Microservices with service discovery? │ └─ Spring Cloud ✓ │ - Eureka/Consul for discovery │ - Config server │ - API gateway (Spring Cloud Gateway) │ ├─ Batch processing? │ └─ Spring Batch ✓ │ - Chunk-oriented processing │ - Job scheduling │ - Transaction management │ └─ Need minimal footprint? └─ Spring Boot with GraalVM Native Image ✓ - AOT compilation - Fast startup (<100ms) - Low memory (<50MB)
JPA vs JDBC Decision Matrix
| Factor | Use JPA/Hibernate | Use JDBC (Spring JdbcTemplate) |
|---|---|---|
| Complexity | Complex domain models with relationships | Simple queries, reporting |
| Performance | OLTP with caching (2nd-level cache) | OLAP, bulk operations |
| Type safety | Criteria API, type-safe queries | Plain SQL with RowMapper |
| Maintenance | Schema evolution with migrations | Direct SQL control |
| Learning curve | Steeper (lazy loading, cascades) | Simpler, explicit |
| N+1 queries | Risk (needs @EntityGraph, fetch joins) | Explicit control |
Example decision: E-commerce order system with relationships → JPA (Order → OrderItems → Products)
Example decision: Analytics dashboard with aggregations → JDBC (complex SQL, performance-critical)
Virtual Threads (Project Loom) Decision Path
Concurrency Requirements │ ├─ High thread count (>1000 threads)? │ └─ Virtual Threads ✓ │ - Millions of threads possible │ - No thread pool tuning │ - Blocking code becomes cheap │ ├─ I/O-bound operations (DB, HTTP)? │ └─ Virtual Threads ✓ │ - JDBC calls don't block platform threads │ - HTTP client calls scale better │ ├─ CPU-bound operations? │ └─ Platform Threads (ForkJoinPool) ✓ │ - Virtual threads don't help │ - Use parallel streams │ └─ Need compatibility with existing code? └─ Virtual Threads ✓ - Drop-in replacement for Thread - No code changes required
Red Flags → Escalate to Oracle
| Observation | Why Escalate | Example |
|---|---|---|
| JPA N+1 queries causing 1000+ DB calls | Complex lazy loading issue | "Single page load triggers 500 SELECT queries" |
| Circular dependency in Spring beans | Architectural design problem | "BeanCurrentlyInCreationException during startup" |
| Memory leak despite GC tuning | Complex object retention | "Heap grows to max despite Full GC, heap dump shows mysterious retention" |
| Distributed transaction spanning multiple microservices | SAGA pattern or compensating transactions | "Need ACID across Order, Payment, Inventory services" |
| Reactive stream backpressure overload | Complex reactive pipeline | "Flux overproducing, downstream can't keep up" |
Workflow 2: Event-Driven Microservice with Kafka
Scenario: Implement event sourcing for order service
Step 1: Configure Spring Kafka
// Configuration/KafkaConfig.java @Configuration @EnableKafka public class KafkaConfig { @Value("${spring.kafka.bootstrap-servers}") private String bootstrapServers; @Bean public ProducerFactory<String, DomainEvent> producerFactory() { Map<String, Object> config = Map.of( ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers, ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class, ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class, ProducerConfig.ACKS_CONFIG, "all", ProducerConfig.RETRIES_CONFIG, 3, ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG, true ); return new DefaultKafkaProducerFactory<>(config); } @Bean public KafkaTemplate<String, DomainEvent> kafkaTemplate() { return new KafkaTemplate<>(producerFactory()); } @Bean public ConsumerFactory<String, DomainEvent> consumerFactory() { Map<String, Object> config = Map.of( ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers, ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class, ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, JsonDeserializer.class, ConsumerConfig.GROUP_ID_CONFIG, "order-service", ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest", ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false, JsonDeserializer.TRUSTED_PACKAGES, "com.example.order.domain.events" ); return new DefaultKafkaConsumerFactory<>(config); } }
Step 2: Define domain events
// Domain/Events/DomainEvent.java public sealed interface DomainEvent permits OrderCreated, OrderItemAdded, OrderProcessingStarted, OrderCompleted, OrderCancelled { UUID aggregateId(); LocalDateTime occurredAt(); long version(); } public record OrderCreated( UUID aggregateId, UUID customerId, LocalDateTime occurredAt, long version ) implements DomainEvent {} public record OrderItemAdded( UUID aggregateId, UUID productId, int quantity, BigDecimal unitPrice, LocalDateTime occurredAt, long version ) implements DomainEvent {} public record OrderCompleted( UUID aggregateId, BigDecimal totalAmount, LocalDateTime occurredAt, long version ) implements DomainEvent {}
Step 3: Event publisher
// Infrastructure/EventPublisher.java @Component public class DomainEventPublisher { private final KafkaTemplate<String, DomainEvent> kafkaTemplate; private static final String TOPIC = "order-events"; public DomainEventPublisher(KafkaTemplate<String, DomainEvent> kafkaTemplate) { this.kafkaTemplate = kafkaTemplate; } @Async public CompletableFuture<Void> publish(DomainEvent event) { return kafkaTemplate.send(TOPIC, event.aggregateId().toString(), event) .thenAccept(result -> { var metadata = result.getRecordMetadata(); log.info("Published event: {} to partition {} offset {}", event.getClass().getSimpleName(), metadata.partition(), metadata.offset()); }) .exceptionally(ex -> { log.error("Failed to publish event: {}", event, ex); return null; }); } }
Step 4: Event consumer
// Infrastructure/OrderEventConsumer.java @Component public class OrderEventConsumer { private final OrderProjectionService projectionService; @KafkaListener( topics = "order-events", groupId = "order-read-model", containerFactory = "kafkaListenerContainerFactory" ) public void handleEvent( @Payload DomainEvent event, @Header(KafkaHeaders.RECEIVED_PARTITION) int partition, @Header(KafkaHeaders.OFFSET) long offset ) { log.info("Received event: {} from partition {} offset {}", event.getClass().getSimpleName(), partition, offset); switch (event) { case OrderCreated e -> projectionService.handleOrderCreated(e); case OrderItemAdded e -> projectionService.handleOrderItemAdded(e); case OrderCompleted e -> projectionService.handleOrderCompleted(e); case OrderCancelled e -> projectionService.handleOrderCancelled(e); default -> log.warn("Unknown event type: {}", event); } } }
Expected outcome:
- Event-driven architecture with Kafka
- Type-safe event handling (sealed interfaces, pattern matching)
- Async event publishing with CompletableFuture
- Idempotent event processing
4. Patterns & Templates
Pattern 1: Repository Pattern with Specifications
Use case: Type-safe dynamic queries
// Specification for dynamic filtering public class OrderSpecifications { public static Specification<Order> hasCustomerId(CustomerId customerId) { return (root, query, cb) -> cb.equal(root.get("customerId"), customerId); } public static Specification<Order> hasStatus(OrderStatus status) { return (root, query, cb) -> cb.equal(root.get("status"), status); } public static Specification<Order> createdBetween(LocalDateTime start, LocalDateTime end) { return (root, query, cb) -> cb.between(root.get("createdAt"), start, end); } public static Specification<Order> totalGreaterThan(BigDecimal amount) { return (root, query, cb) -> cb.greaterThan(root.get("totalAmount"), amount); } } // Usage: Combine specifications Specification<Order> spec = Specification .where(hasCustomerId(customerId)) .and(hasStatus(new OrderStatus.Pending())) .and(createdBetween(startDate, endDate)); List<Order> orders = orderRepository.findAll(spec);
Pattern 3: CQRS with Separate Read/Write Models
Use case: Optimize reads independently from writes
// Write model (domain entity) @Entity public class Order { // Rich behavior, complex relationships public void addItem(Product product, int quantity) { ... } public void complete() { ... } } // Read model (denormalized projection) @Entity @Table(name = "order_summary") @Immutable public class OrderSummary { @Id private UUID orderId; private UUID customerId; private String customerName; private int itemCount; private BigDecimal totalAmount; private String status; private LocalDateTime createdAt; // Getters only (no setters, immutable) } // Read repository (optimized queries) public interface OrderSummaryRepository extends JpaRepository<OrderSummary, UUID> { @Query(""" SELECT os FROM OrderSummary os WHERE os.customerId = :customerId ORDER BY os.createdAt DESC """) List<OrderSummary> findByCustomerId(@Param("customerId") UUID customerId); }
❌ Anti-Pattern: LazyInitializationException
What it looks like:
@Service @Transactional public class OrderService { public Order findById(OrderId id) { return orderRepository.findById(id).orElseThrow(); } } @RestController public class OrderController { @GetMapping("/orders/{id}") public OrderDto getOrder(@PathVariable UUID id) { Order order = orderService.findById(new OrderId(id)); // Transaction already closed! var items = order.getItems(); // LazyInitializationException! return new OrderDto(order, items); } }
Why it fails:
- Lazy loading outside transaction: Hibernate proxy can't load data
- N+1 queries: Even if transaction open, lazy loads trigger multiple queries
Correct approach:
// Option 1: Eager fetch with @EntityGraph @Repository public interface OrderRepository extends JpaRepository<Order, OrderId> { @EntityGraph(attributePaths = {"items", "items.product"}) Optional<Order> findById(OrderId id); } // Option 2: DTO projection (no lazy loading) @Query(""" SELECT new com.example.dto.OrderDto( o.id, o.customerId, o.totalAmount, COUNT(i.id), o.status, o.createdAt ) FROM Order o LEFT JOIN o.items i WHERE o.id = :id GROUP BY o.id, o.customerId, o.totalAmount, o.status, o.createdAt """) Optional<OrderDto> findOrderDtoById(@Param("id") OrderId id); // Option 3: Open Session in View (not recommended for APIs) spring.jpa.open-in-view: false // Disable to catch lazy loading issues early
6. Integration Patterns
backend-developer:
- Handoff: Backend-developer defines business logic → java-architect implements with Spring Boot patterns
- Collaboration: REST API design, database schema, authentication/authorization
- Tools: Spring Boot, Spring Security, Spring Data JPA, Jackson
- Example: Backend defines order workflow → java-architect implements with DDD aggregates and domain events
database-optimizer:
- Handoff: Java-architect identifies slow JPA queries → database-optimizer creates indexes
- Collaboration: Query optimization, connection pooling, transaction tuning
- Tools: Hibernate statistics, JPA Criteria API, native queries
- Example: N+1 query problem → database-optimizer adds composite index on foreign keys
devops-engineer:
- Handoff: Java-architect builds Spring Boot app → devops-engineer containerizes with Docker
- Collaboration: Health checks, metrics (Actuator), graceful shutdown
- Tools: Spring Boot Actuator, Micrometer, Docker multi-stage builds
- Example: Java-architect exposes /actuator/health → devops-engineer configures Kubernetes liveness probe
kubernetes-specialist:
- Handoff: Java-architect builds microservice → kubernetes-specialist deploys to K8s
- Collaboration: Readiness probes, resource limits, rolling updates
- Tools: Spring Cloud Kubernetes, ConfigMaps, Secrets
- Example: Java-architect uses @ConfigurationProperties → kubernetes-specialist provides ConfigMap
graphql-architect:
- Handoff: Java-architect provides domain model → graphql-architect exposes as GraphQL API
- Collaboration: Schema design, N+1 prevention with DataLoader
- Tools: Spring GraphQL, GraphQL Java, DataLoader
- Example: Order aggregate → GraphQL type with resolvers and subscriptions