All skills
jeffallan avatar

/java-architect

@efebc44
by jeffallanjeffallan/claude-skills12k stars
1,127

Use when building, configuring, or debugging enterprise Java applications with Spring Boot 3.x, microservices, or reactive programming. Invoke to implement WebFlux endpoints, optimize JPA queries and database performance, configure Spring Security with OAuth2/JWT, or resolve authentication issues and async processing challenges in cloud-native Spring applications.

Use this Skill: https://skilld.dev/gh/jeffallan/claude-skills/java-architect

This session only. Nothing lands on disk.

referencesjpa-optimization.md

≈2.7k tokens on demand. Your agent reads this file only when SKILL.md points to it.

JPA Optimization

Optimized Entity Design

package com.example.domain.model;

import jakarta.persistence.*;
import lombok.*;
import org.hibernate.annotations.BatchSize;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import java.time.Instant;
import java.util.ArrayList;
import java.util.List;

@Entity
@Table(
    name = "users",
    indexes = {
        @Index(name = "idx_email", columnList = "email"),
        @Index(name = "idx_created_at", columnList = "created_at")
    }
)
@EntityListeners(AuditingEntityListener.class)
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false, unique = true, length = 100)
    private String email;

    @Column(nullable = false, length = 50)
    private String username;

    @Column(nullable = false)
    private Boolean active = true;

    @OneToMany(
        mappedBy = "user",
        cascade = CascadeType.ALL,
        orphanRemoval = true,
        fetch = FetchType.LAZY
    )
    @BatchSize(size = 25)
    @Builder.Default
    private List<Order> orders = new ArrayList<>();

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "department_id")
    private Department department;

    @CreatedDate
    @Column(nullable = false, updatable = false)
    private Instant createdAt;

    @LastModifiedDate
    private Instant updatedAt;

    @Version
    private Long version;

    // Helper methods
    public void addOrder(Order order) {
        orders.add(order);
        order.setUser(this);
    }

    public void removeOrder(Order order) {
        orders.remove(order);
        order.setUser(null);
    }
}

Repository with Custom Queries

package com.example.domain.repository;

import com.example.domain.model.User;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.repository.query.Param;

import java.time.Instant;
import java.util.List;
import java.util.Optional;

public interface UserRepository extends JpaRepository<User, Long> {

    // N+1 prevention with EntityGraph
    @EntityGraph(attributePaths = {"orders", "department"})
    @Query("SELECT u FROM User u WHERE u.id = :id")
    Optional<User> findByIdWithOrders(@Param("id") Long id);

    // Projection for read-only queries
    @Query("""
        SELECT new com.example.application.dto.UserSummary(
            u.id, u.email, u.username, COUNT(o)
        )
        FROM User u
        LEFT JOIN u.orders o
        WHERE u.active = true
        GROUP BY u.id, u.email, u.username
        """)
    List<UserSummary> findActiveUsersSummary();

    // Fetch join to avoid N+1
    @Query("""
        SELECT DISTINCT u FROM User u
        LEFT JOIN FETCH u.orders
        WHERE u.department.id = :deptId
        """)
    List<User> findByDepartmentWithOrders(@Param("deptId") Long deptId);

    // Pagination with count query optimization
    @Query(
        value = "SELECT u FROM User u WHERE u.active = true",
        countQuery = "SELECT COUNT(u) FROM User u WHERE u.active = true"
    )
    Page<User> findActiveUsers(Pageable pageable);

    // Batch update
    @Modifying
    @Query("UPDATE User u SET u.active = false WHERE u.createdAt < :date")
    int deactivateOldUsers(@Param("date") Instant date);

    // Native query for complex operations
    @Query(
        value = """
            SELECT u.* FROM users u
            WHERE u.id IN (
                SELECT DISTINCT o.user_id
                FROM orders o
                WHERE o.total > :amount
            )
            """,
        nativeQuery = true
    )
    List<User> findUsersWithLargeOrders(@Param("amount") Double amount);
}

DTO Projections

package com.example.application.dto;

// Interface-based projection
public interface UserProjection {
    Long getId();
    String getEmail();
    String getUsername();
    DepartmentProjection getDepartment();

    interface DepartmentProjection {
        String getName();
    }
}

// Class-based projection (constructor expression)
public record UserSummary(
    Long id,
    String email,
    String username,
    Long orderCount
) {}

// Dynamic projection
public interface UserRepository extends JpaRepository<User, Long> {
    <T> List<T> findByActive(boolean active, Class<T> type);
}

// Usage
List<UserProjection> users = userRepository.findByActive(true, UserProjection.class);

Query Optimization Patterns

package com.example.application.service;

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class UserQueryService {

    private final UserRepository userRepository;
    private final EntityManager entityManager;

    // Batch fetching
    public List<User> findUsersWithOrders(List<Long> userIds) {
        return entityManager.createQuery("""
            SELECT DISTINCT u FROM User u
            LEFT JOIN FETCH u.orders
            WHERE u.id IN :ids
            """, User.class)
            .setParameter("ids", userIds)
            .setHint("hibernate.default_batch_fetch_size", 25)
            .getResultList();
    }

    // Pagination with total count
    public Page<UserSummary> findUsersPaged(Pageable pageable) {
        List<UserSummary> users = entityManager.createQuery("""
            SELECT new com.example.application.dto.UserSummary(
                u.id, u.email, u.username, COUNT(o)
            )
            FROM User u
            LEFT JOIN u.orders o
            GROUP BY u.id, u.email, u.username
            """, UserSummary.class)
            .setFirstResult((int) pageable.getOffset())
            .setMaxResults(pageable.getPageSize())
            .getResultList();

        Long total = entityManager.createQuery(
            "SELECT COUNT(DISTINCT u) FROM User u",
            Long.class
        ).getSingleResult();

        return new PageImpl<>(users, pageable, total);
    }

    // Stream large datasets
    @Transactional(readOnly = true)
    public void processLargeDataset() {
        try (Stream<User> stream = userRepository.streamByActiveTrue()) {
            stream
                .filter(user -> user.getOrders().size() > 10)
                .forEach(this::processUser);
        }
    }

    // Criteria API for dynamic queries
    public List<User> findUsersByCriteria(UserSearchCriteria criteria) {
        CriteriaBuilder cb = entityManager.getCriteriaBuilder();
        CriteriaQuery<User> query = cb.createQuery(User.class);
        Root<User> user = query.from(User.class);

        List<Predicate> predicates = new ArrayList<>();

        if (criteria.email() != null) {
            predicates.add(cb.like(user.get("email"), "%" + criteria.email() + "%"));
        }
        if (criteria.active() != null) {
            predicates.add(cb.equal(user.get("active"), criteria.active()));
        }
        if (criteria.createdAfter() != null) {
            predicates.add(cb.greaterThan(user.get("createdAt"), criteria.createdAfter()));
        }

        query.where(predicates.toArray(new Predicate[0]));
        return entityManager.createQuery(query).getResultList();
    }
}

Batch Operations

@Service
@RequiredArgsConstructor
public class UserBatchService {

    private final UserRepository userRepository;
    private final EntityManager entityManager;

    @Transactional
    public void batchInsert(List<User> users) {
        int batchSize = 50;
        for (int i = 0; i < users.size(); i++) {
            entityManager.persist(users.get(i));
            if (i % batchSize == 0 && i > 0) {
                entityManager.flush();
                entityManager.clear();
            }
        }
        entityManager.flush();
        entityManager.clear();
    }

    @Transactional
    public void batchUpdate(List<User> users) {
        int batchSize = 50;
        for (int i = 0; i < users.size(); i++) {
            entityManager.merge(users.get(i));
            if (i % batchSize == 0 && i > 0) {
                entityManager.flush();
                entityManager.clear();
            }
        }
        entityManager.flush();
        entityManager.clear();
    }
}

Second-Level Cache Configuration

spring:
  jpa:
    properties:
      hibernate:
        cache:
          use_second_level_cache: true
          use_query_cache: true
          region:
            factory_class: org.hibernate.cache.jcache.JCacheRegionFactory
        javax:
          cache:
            provider: org.ehcache.jsr107.EhcacheCachingProvider
            uri: classpath:ehcache.xml
<!-- ehcache.xml -->
<config xmlns="http://www.ehcache.org/v3">
    <cache alias="users">
        <key-type>java.lang.Long</key-type>
        <value-type>com.example.domain.model.User</value-type>
        <expiry>
            <ttl unit="minutes">10</ttl>
        </expiry>
        <resources>
            <heap unit="entries">1000</heap>
        </resources>
    </cache>
</config>

Performance Monitoring

@Component
@Aspect
@Slf4j
public class QueryPerformanceAspect {

    @Around("@annotation(org.springframework.data.jpa.repository.Query)")
    public Object logQueryPerformance(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        try {
            return joinPoint.proceed();
        } finally {
            long duration = System.currentTimeMillis() - start;
            if (duration > 1000) {
                log.warn("Slow query detected: {} took {}ms",
                    joinPoint.getSignature(), duration);
            }
        }
    }
}

Quick Reference

Pattern Use Case
@EntityGraph Prevent N+1 queries
JOIN FETCH Eager fetch associations
DTO Projection Read-only queries
@BatchSize Batch fetch collections
@Query with pagination Large datasets
@Modifying Bulk updates/deletes
Criteria API Dynamic queries
Second-level cache Frequently accessed data
Stream API Process large results
readOnly = true Optimization hint

Source: SKILL.md on GitHub

1 alert16d5 checks · Risk CRITICAL
  • Gen Agent Trust Hub16d

    This skill is flagged by automated scanners due to malicious reputation associated with its documentation URL and the main instruction file. It also facilitates the execution of shell commands through build tools, which can be misused if the skill processes untrusted project files.

  • Socket16d

    No alerts

  • Snyk16d

    Risk: LOW · No issues

  • Runlayer6mo

    1/6 files flagged

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at efebc44. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 months ago.

Steadyupdated 5 months ago
Other metadata
metadata
{
  "author": "https://github.com/Jeffallan",
  "version": "1.1.0",
  "domain": "language",
  "triggers": "Spring Boot, Java, microservices, Spring Cloud, JPA, Hibernate, WebFlux, reactive, Java Enterprise",
  "role": "architect",
  "scope": "implementation",
  "output-format": "code",
  "related-skills": "fullstack-guardian, api-designer, devops-engineer, database-optimizer"
}
  • java
  • spring-boot
  • microservices
  • webflux
  • jpa
  • hibernate
  • spring-security
  • oauth2
  • jwt
  • reactive

README badge

README badge for jeffallan/claude-skills/java-architect

Builds and debugs enterprise Java applications with Spring Boot 3.x, microservices, and reactive programming using WebFlux and Project Reactor. Covers domain-driven design, JPA query optimization, Spring Security with OAuth2/JWT, and cloud-native deployment patterns with Java 21 LTS.

Generated from the current SKILL.md.

Does this skill cover Spring Boot 2.x or only 3.x?
Only Spring Boot 3.x. The skill is specifically focused on Spring Boot 3.x with Java 21 LTS and will not guide you on 2.x patterns or deprecated APIs.
Can this skill help with reactive applications?
Yes. It includes guidance on Spring WebFlux, Project Reactor, and R2DBC, with explicit constraints against blocking code in reactive contexts.
What testing frameworks does this skill assume?
JUnit 5, TestContainers, and Mockito. The skill enforces 85%+ code coverage via Maven or Gradle verification before completion.
Does this skill handle security configuration?
Yes. It covers Spring Security, OAuth2, JWT configuration, and method-level security, with a reference guide and post-implementation verification steps for filter chain correctness.
Will this skill help optimize database performance?
Yes. It includes JPA query optimization, N+1 prevention with JOIN FETCH, query projections, and Hibernate SQL log analysis as part of the data layer workflow.

Generated from the current SKILL.md. These answers refresh after source changes.