Smithery Logo
MCPsSkillsDocsPricing
Login
Smithery Logo

Accelerating the Agent Economy

Resources

DocumentationPrivacy PolicySystem Status

Company

PricingAboutBlog

Connect

© 2026 Smithery. All rights reserved.

    kivo360

    moai-lang-java

    kivo360/moai-lang-java
    Coding
    1

    About

    SKILL.md

    Install

    Install via Skills CLI

    or add to your agent
    • Claude Code
      Claude Code
    • Codex
      Codex
    • OpenClaw
      OpenClaw
    • Cursor
      Cursor
    • Amp
      Amp
    • GitHub Copilot
      GitHub Copilot
    • Gemini CLI
      Gemini CLI
    • Kilo Code
      Kilo Code
    • Junie
      Junie
    • Replit
      Replit
    • Windsurf
      Windsurf
    • Cline
      Cline
    • Continue
      Continue
    • OpenCode
      OpenCode
    • OpenHands
      OpenHands
    • Roo Code
      Roo Code
    • Augment
      Augment
    • Goose
      Goose
    • Trae
      Trae
    • Zencoder
      Zencoder
    • Antigravity
      Antigravity
    ├─
    ├─
    └─

    About

    Java best practices with Spring ecosystem, enterprise backend development, and JVM optimization for 2025

    SKILL.md

    Java Development Mastery

    Modern Java Development with 2025 Best Practices

    Comprehensive Java development guidance covering enterprise backend applications, Spring ecosystem integration, and production-ready development using the latest JVM features and frameworks.

    What It Does

    • Backend API Development: Spring Boot, Spring Framework applications with modern reactive patterns
    • Database Integration: Spring Data JPA, Hibernate, JDBC with query optimization
    • API Development: REST, GraphQL, and gRPC services with Spring Security
    • Testing & Quality: JUnit 5, Mockito, TestContainers with integration tests
    • Performance Optimization: JVM tuning, reactive programming, caching patterns
    • Production Deployment: Docker, Kubernetes, CI/CD, monitoring with Spring Actuator
    • Security Best Practices: Spring Security, input validation, dependency scanning
    • Code Quality: Checkstyle, SpotBugs, pre-commit hooks, static analysis

    When to Use

    Perfect Scenarios

    • Building REST APIs and microservices
    • Developing enterprise applications and services
    • Creating database-driven applications with JPA/Hibernate
    • Integrating with enterprise systems and messaging
    • Automating backend workflows with Spring Batch
    • Deploying scalable server applications on JVM
    • Enterprise application development with Spring

    Common Triggers

    • "Create Java backend API"
    • "Set up Spring Boot project"
    • "Optimize Java performance"
    • "Test Java application"
    • "Deploy Spring Boot application"
    • "Java best practices"
    • "Spring Boot microservice"

    Tool Version Matrix (2025-11-06)

    Core Java

    • Java: 23 (current) / 21 (LTS) / 17 (LTS)
    • Package Managers: Maven 3.9.x, Gradle 8.8
    • Build Tools: Maven Wrapper, Gradle Wrapper
    • JVM: OpenJDK, Oracle JDK, Amazon Corretto

    Web Frameworks

    • Spring Boot: 3.3.x - Production-ready applications
    • Spring Framework: 6.2.x - Core application framework
    • Spring Security: 6.4.x - Authentication and authorization
    • Spring Data: 3.3.x - Database access layer
    • Micronaut: 4.7.x - Reactive microservices framework
    • Quarkus: 3.17.x - Cloud-native Java framework

    Testing Tools

    • JUnit: 5.11.x - Primary testing framework
    • Mockito: 5.15.x - Mocking framework
    • TestContainers: 1.20.x - Integration testing with containers
    • AssertJ: 3.26.x - Fluent assertions library
    • Jacoco: 0.8.x - Code coverage analysis

    Code Quality

    • Checkstyle: 10.20.x - Code style checking
    • SpotBugs: 4.8.x - Static analysis
    • PMD: 7.7.x - Code quality analysis
    • Error Prone: 2.36.x - Google's error detection

    Database Tools

    • Hibernate: 6.6.x - ORM framework
    • Flyway: 10.20.x - Database migrations
    • Liquibase: 4.29.x - Database schema management
    • H2: 2.3.x - In-memory database for testing

    Ecosystem Overview

    Package Management

    # Maven project creation
    mvn archetype:generate -DgroupId=com.example -DartifactId=my-app -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
    
    # Gradle project creation (modern approach)
    gradle init --type java-application --dsl kotlin --test-framework junit-jupiter --package com.example
    
    # Dependency management
    # Maven (pom.xml)
    # Gradle (build.gradle.kts)
    ./mvnw spring-boot:run
    ./gradlew bootRun
    

    Project Structure (2025 Best Practice)

    my-java-project/
    ├── build.gradle.kts          # Gradle build configuration (Kotlin DSL)
    ├── settings.gradle.kts       # Gradle settings
    ├── gradlew                   # Gradle wrapper
    ├── gradlew.bat               # Windows Gradle wrapper
    ├── src/
    │   ├── main/
    │   │   ├── java/com/example/
    │   │   │   ├── Application.java      # Main application class
    │   │   │   ├── controller/           # REST controllers
    │   │   │   ├── service/              # Business logic
    │   │   │   ├── repository/           # Data access layer
    │   │   │   ├── model/                # Domain models
    │   │   │   ├── config/               # Configuration classes
    │   │   │   └── exception/            # Custom exceptions
    │   │   └── resources/
    │   │       ├── application.yml       # Application configuration
    │   │       ├── application-dev.yml   # Development profile
    │   │       └── application-prod.yml  # Production profile
    │   └── test/
    │       └── java/com/example/
    │           ├── unit/                 # Unit tests
    │           ├── integration/          # Integration tests
    │           └── testutil/             # Test utilities
    ├── .github/
    │   └── workflows/                    # CI/CD pipelines
    ├── Dockerfile
    ├── docker-compose.yml                # Development environment
    ├── README.md
    └── .gitignore
    

    Modern Development Patterns

    Modern Java Features (Java 21+)

    import java.util.List;
    import java.util.Optional;
    import java.util.concurrent.CompletableFuture;
    import java.util.stream.Stream;
    import java.util.function.Predicate;
    import java.util.record.Record;
    
    // Records (immutable data carriers)
    public record User(Long id, String username, String email) {
        // Compact constructor for validation
        public User {
            if (username == null || username.isBlank()) {
                throw new IllegalArgumentException("Username cannot be null or blank");
            }
        }
    }
    
    // Pattern Matching for instanceof
    public void processUser(Object obj) {
        if (obj instanceof User(String username, String email)) {
            System.out.println("User: " + username + ", Email: " + email);
        }
    }
    
    // Sealed classes for domain modeling
    public sealed interface Payment permits CreditCardPayment, PayPalPayment {
        BigDecimal getAmount();
    }
    
    public final record CreditCardPayment(BigDecimal amount, String cardNumber) implements Payment {}
    public final record PayPalPayment(BigDecimal amount, String email) implements Payment {}
    
    // Switch expressions with pattern matching
    public String processPayment(Payment payment) {
        return switch (payment) {
            case CreditCardPayment(var amount, var card) -> 
                "Processing credit card payment of " + amount;
            case PayPalPayment(var amount, var email) -> 
                "Processing PayPal payment of " + amount + " for " + email;
        };
    }
    
    // Virtual Threads (Project Loom)
    import java.util.concurrent.Executors;
    
    public class VirtualThreadExample {
        public static void main(String[] args) {
            try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
                // Create thousands of virtual threads
                List<CompletableFuture<String>> futures = IntStream.range(0, 10_000)
                    .mapToObj(i -> CompletableFuture.supplyAsync(() -> {
                        // Simulate I/O-bound operation
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                        }
                        return "Task " + i + " completed";
                    }, executor))
                    .toList();
                
                // Wait for all to complete
                CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
            }
        }
    }
    
    // Scoped Values (Structured concurrency)
    import java.util.concurrent.ScopedValue;
    
    public final class Context {
        private static final ScopedValue<String> USER_ID = ScopedValue.newInstance();
        
        public static void main(String[] args) {
            // Bind value in a structured scope
            ScopedValue.where(USER_ID, "user123").run(() -> {
                // All code in this scope can access USER_ID.get()
                processRequest();
                handleData();
            });
        }
    }
    

    Spring Boot Reactive Patterns

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.annotation.Bean;
    import org.springframework.web.reactive.function.server.RouterFunction;
    import org.springframework.web.reactive.function.server.ServerResponse;
    import org.springframework.web.reactive.function.server.RouterFunctions;
    import reactor.core.publisher.Flux;
    import reactor.core.publisher.Mono;
    import org.springframework.web.reactive.function.server.ServerRequest;
    
    @SpringBootApplication
    public class ReactiveApplication {
        
        @Bean
        public RouterFunction<ServerResponse> userRoutes(UserHandler userHandler) {
            return RouterFunctions.route()
                .GET("/api/users", userHandler::getAllUsers)
                .GET("/api/users/{id}", userHandler::getUserById)
                .POST("/api/users", userHandler::createUser)
                .PUT("/api/users/{id}", userHandler::updateUser)
                .DELETE("/api/users/{id}", userHandler::deleteUser)
                .build();
        }
        
        public static void main(String[] args) {
            SpringApplication.run(ReactiveApplication.class, args);
        }
    }
    
    // Functional endpoint handler
    @Component
    public class UserHandler {
        private final UserRepository userRepository;
        
        public UserHandler(UserRepository userRepository) {
            this.userRepository = userRepository;
        }
        
        public Mono<ServerResponse> getAllUsers(ServerRequest request) {
            Flux<User> users = userRepository.findAll();
            return ServerResponse.ok().body(users, User.class);
        }
        
        public Mono<ServerResponse> getUserById(ServerRequest request) {
            String id = request.pathVariable("id");
            return userRepository.findById(Long.valueOf(id))
                .flatMap(user -> ServerResponse.ok().bodyValue(user))
                .switchIfEmpty(ServerResponse.notFound().build());
        }
        
        public Mono<ServerResponse> createUser(ServerRequest request) {
            Mono<User> userMono = request.bodyToMono(User.class);
            return userMono.flatMap(user -> 
                userRepository.save(user)
                    .flatMap(savedUser -> ServerResponse.created(URI.create("/api/users/" + savedUser.id()))
                        .bodyValue(savedUser))
            );
        }
    }
    
    // Reactive repository
    @Repository
    public interface ReactiveUserRepository extends ReactiveCrudRepository<User, Long> {
        Flux<User> findByUsername(String username);
        Mono<User> findByEmail(String email);
        @Query("SELECT * FROM users WHERE active = true")
        Flux<User> findActiveUsers();
    }
    

    Modern Testing Patterns

    import org.junit.jupiter.api.Test;
    import org.junit.jupiter.api.DisplayName;
    import org.junit.jupiter.api.Nested;
    import org.junit.jupiter.params.ParameterizedTest;
    import org.junit.jupiter.params.provider.ValueSource;
    import org.junit.jupiter.params.provider.CsvSource;
    import org.junit.jupiter.api.extension.ExtendWith;
    import org.mockito.Mock;
    import org.mockito.junit.jupiter.MockitoExtension;
    import org.testcontainers.containers.PostgreSQLContainer;
    import org.testcontainers.junit.jupiter.Container;
    import org.testcontainers.junit.jupiter.Testcontainers;
    import static org.assertj.core.api.Assertions.*;
    import static org.mockito.Mockito.*;
    
    @ExtendWith(MockitoExtension.class)
    @DisplayName("UserService Tests")
    class UserServiceTest {
        
        @Mock
        private UserRepository userRepository;
        
        @Mock
        private EmailService emailService;
        
        private UserService userService;
        
        @BeforeEach
        void setUp() {
            userService = new UserService(userRepository, emailService);
        }
        
        @Nested
        @DisplayName("Create User Tests")
        class CreateUserTests {
            
            @Test
            @DisplayName("Should create user successfully with valid data")
            void shouldCreateUserSuccessfully() {
                // Given
                UserCreateDto dto = new UserCreateDto("testuser", "test@example.com");
                User expectedUser = new User(1L, "testuser", "test@example.com");
                
                when(userRepository.save(any(User.class))).thenReturn(Mono.just(expectedUser));
                when(userRepository.existsByUsername("testuser")).thenReturn(Mono.just(false));
                when(userRepository.existsByEmail("test@example.com")).thenReturn(Mono.just(false));
                
                // When
                Mono<User> result = userService.createUser(dto);
                
                // Then
                StepVerifier.create(result)
                    .assertNext(user -> {
                        assertThat(user.id()).isEqualTo(1L);
                        assertThat(user.username()).isEqualTo("testuser");
                        assertThat(user.email()).isEqualTo("test@example.com");
                    })
                    .verifyComplete();
                
                verify(emailService).sendWelcomeEmail(expectedUser);
            }
            
            @ParameterizedTest
            @ValueSource(strings = {"", "ab", "a".repeat(51)})
            @DisplayName("Should reject invalid usernames")
            void shouldRejectInvalidUsernames(String invalidUsername) {
                // Given
                UserCreateDto dto = new UserCreateDto(invalidUsername, "test@example.com");
                
                // When & Then
                assertThatThrownBy(() -> userService.createUser(dto))
                    .isInstanceOf(ValidationException.class)
                    .hasMessageContaining("Invalid username");
            }
        }
    }
    
    // Integration testing with TestContainers
    @Testcontainers
    @SpringBootTest
    class UserRepositoryIntegrationTest {
        
        @Container
        static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16-alpine")
                .withDatabaseName("testdb")
                .withUsername("test")
                .withPassword("test");
        
        @DynamicPropertySource
        static void postgresProperties(DynamicPropertyRegistry registry) {
            registry.add("spring.datasource.url", postgres::getJdbcUrl);
            registry.add("spring.datasource.username", postgres::getUsername);
            registry.add("spring.datasource.password", postgres::getPassword);
        }
        
        @Autowired
        private UserRepository userRepository;
        
        @Test
        void shouldSaveAndRetrieveUser() {
            // Given
            User user = new User(null, "testuser", "test@example.com");
            
            // When
            User saved = userRepository.save(user);
            
            // Then
            assertThat(saved.id()).isNotNull();
            
            Optional<User> retrieved = userRepository.findById(saved.id());
            assertThat(retrieved).isPresent();
            assertThat(retrieved.get().username()).isEqualTo("testuser");
        }
    }
    

    Performance Considerations

    JVM Performance Tuning

    // Efficient collections usage
    public class CollectionOptimization {
        
        // Use appropriate collection types
        private final Map<String, User> userCache = new ConcurrentHashMap<>();  // Thread-safe
        private final List<String> recentItems = new CopyOnWriteArrayList<>();   // Read-heavy
        private final Queue<Task> taskQueue = new ConcurrentLinkedQueue<>();     // Lock-free
        
        // Use primitive collections for performance-critical code
        private final Int2ObjectHashMap<User> userById = new Int2ObjectHashMap<>();
        
        // Lazy initialization
        private volatile ExpensiveResource resource;
        
        public ExpensiveResource getResource() {
            ExpensiveResource result = resource;
            if (result == null) {
                synchronized (this) {
                    result = resource;
                    if (result == null) {
                        resource = result = new ExpensiveResource();
                    }
                }
            }
            return result;
        }
    }
    
    // Memory-efficient data processing
    public class StreamOptimization {
        
        public List<UserDto> processUsersLargeDataset() {
            try (Stream<User> userStream = Files.lines(Paths.get("users.csv"))
                    .skip(1) // Skip header
                    .parallel() // Parallel processing for large files
                    .map(this::parseUser)
                    .filter(Objects::nonNull)
                    .filter(user -> user.isActive())) {
                
                return userStream
                        .map(this::convertToDto)
                        .collect(Collectors.toList());
            } catch (IOException e) {
                throw new RuntimeException("Failed to process users", e);
            }
        }
        
        // Use primitive streams for numeric operations
        public IntSummaryStatistics getAgeStatistics(List<User> users) {
            return users.stream()
                    .mapToInt(User::age)
                    .summaryStatistics();
        }
    }
    
    // Connection pooling and resource management
    @Configuration
    public class DatabaseConfig {
        
        @Bean
        @Primary
        public DataSource dataSource() {
            HikariConfig config = new HikariConfig();
            config.setJdbcUrl("jdbc:postgresql://localhost:5432/mydb");
            config.setUsername("user");
            config.setPassword("password");
            config.setMaximumPoolSize(20);
            config.setMinimumIdle(5);
            config.setConnectionTimeout(30000);
            config.setIdleTimeout(600000);
            config.setMaxLifetime(1800000);
            config.setLeakDetectionThreshold(60000);
            return new HikariDataSource(config);
        }
    }
    

    Reactive Programming Performance

    // Backpressure handling
    @Service
    public class DataProcessingService {
        
        public Flux<ProcessedData> processDataWithBackpressure(Flux<RawData> rawData) {
            return rawData
                    .onBackpressureBuffer(1000, // Buffer up to 1000 items
                        rawData::log, // Log dropped items
                        BufferOverflowStrategy.DROP_OLDEST)
                    .publishOn(Schedulers.boundedElastic(), 256) // Limit concurrency
                    .flatMap(this::processItem, 10) // Process 10 items in parallel
                    .doOnError(error -> log.error("Processing error", error))
                    .retryWhen(Retry.backoff(3, Duration.ofSeconds(1))
                        .maxBackoff(Duration.ofSeconds(10))
                        .jitter(0.5))
                    .timeout(Duration.ofMinutes(5));
        }
        
        // Efficient batching
        public Flux<BatchResult> processInBatches(Flux<DataItem> items, int batchSize) {
            return items
                    .window(batchSize)
                    .flatMap(window -> window.collectList())
                    .flatMap(this::processBatch);
        }
    }
    
    // Caching strategies
    @Service
    public class CacheService {
        
        private final Cache<String, User> userCache = Caffeine.newBuilder()
                .maximumSize(10_000)
                .expireAfterWrite(Duration.ofMinutes(30))
                .refreshAfterWrite(Duration.ofMinutes(10))
                .recordStats()
                .build();
        
        @Cacheable(value = "users", key = "#id")
        public User getUserById(Long id) {
            return userCache.get(id.toString(), key -> userRepository.findById(id)
                    .orElseThrow(() -> new UserNotFoundException(id)));
        }
        
        // Reactive cache with Spring Boot
        @Bean
        public ReactiveCacheManager cacheManager() {
            return new ReactiveCaffeineCacheManager(
                Caffeine.newBuilder()
                        .maximumSize(1000)
                        .expireAfterWrite(Duration.ofMinutes(10))
                        .build()
            );
        }
    }
    

    Profiling and Monitoring

    # JVM monitoring with jcmd
    jcmd <pid> VM.flags
    jcmd <pid> GC.heap_info
    jcmd <pid> Thread.print
    jcmd <pid> GC.class_histogram
    
    # Java Flight Recorder
    java -XX:StartFlightRecording=duration=60s,filename=myrecording.jfr -jar app.jar
    
    # JDK Mission Control (visual monitoring)
    jmc
    
    # Memory analysis with jmap and jhat
    jmap -dump:format=b,file=heapdump.hprof <pid>
    jhat heapdump.hprof
    
    # Performance profiling with async-profiler
    ./profiler.sh -d 30 -f profile.svg <pid>
    
    # Thread dump analysis
    jstack <pid> > thread_dump.txt
    # or with jcmd
    jcmd <pid> Thread.print > thread_dump.txt
    

    Testing Strategy

    Gradle Configuration (build.gradle.kts)

    plugins {
        application
        jacoco
        checkstyle
        pmd
        id("org.springframework.boot") version "3.3.0"
        id("io.spring.dependency-management") version "1.1.5"
    }
    
    group = "com.example"
    version = "0.1.0"
    
    java {
        toolchain {
            languageVersion = JavaLanguageVersion.of(21)
        }
    }
    
    repositories {
        mavenCentral()
    }
    
    dependencies {
        // Spring Boot starters
        implementation("org.springframework.boot:spring-boot-starter-webflux")
        implementation("org.springframework.boot:spring-boot-starter-data-r2dbc")
        implementation("org.springframework.boot:spring-boot-starter-actuator")
        implementation("org.springframework.boot:spring-boot-starter-validation")
        
        // Database
        implementation("org.postgresql:r2dbc-postgresql")
        implementation("org.flywaydb:flyway-core")
        implementation("org.springframework:spring-jdbc")
        
        // Utility libraries
        implementation("com.fasterxml.jackson.core:jackson-databind")
        implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310")
        implementation("org.apache.commons:commons-lang3")
        
        // Development tools
        compileOnly("org.projectlombok:lombok")
        annotationProcessor("org.projectlombok:lombok")
        
        // Testing
        testImplementation("org.springframework.boot:spring-boot-starter-test")
        testImplementation("org.springframework.security:spring-security-test")
        testImplementation("io.projectreactor:reactor-test")
        testImplementation("org.testcontainers:junit-jupiter")
        testImplementation("org.testcontainers:postgresql")
        testImplementation("org.testcontainers:r2dbc")
        
        // Code quality
        checkstyle("com.github.sevntu-checkstyle:sevntu-checks:1.44.1")
    }
    
    tasks.test {
        useJUnitPlatform()
        
        testLogging {
            events("passed", "skipped", "failed")
            showExceptions = true
            showCauses = true
            showStackTraces = true
        }
        
        // Parallel test execution
        maxParallelForks = (Runtime.getRuntime().availableProcessors() / 2).takeIf { it > 0 } ?: 1
    }
    
    // JaCoCo configuration for code coverage
    jacoco {
        toolVersion = "0.8.12"
    }
    
    tasks.jacocoTestReport {
        dependsOn(tasks.test)
        reports {
            xml.required.set(true)
            html.required.set(true)
            csv.required.set(false)
        }
    }
    
    tasks.jacocoTestCoverageVerification {
        violationRules {
            rule {
                limit {
                    minimum = "0.80".toBigDecimal() // 80% coverage minimum
                }
            }
        }
    }
    
    // Checkstyle configuration
    tasks.checkstyleMain {
        source = fileTree("src/main/java")
    }
    
    tasks.checkstyleTest {
        source = fileTree("src/test/java")
    }
    
    // PMD configuration
    pmd {
        ruleSets = listOf(
            "category/java/bestpractices.xml",
            "category/java/codesize.xml",
            "category/java/design.xml",
            "category/java/performance.xml",
            "category/java/security.xml"
        )
    }
    

    Modern Testing Patterns

    // Test slices for focused testing
    @WebFluxTest(UserController.class)
    @Import({UserService.class, SecurityConfig.class})
    class UserControllerTest {
        
        @Autowired
        private WebTestClient webTestClient;
        
        @MockBean
        private UserService userService;
        
        @Test
        void shouldReturnUserWhenFound() {
            // Given
            User user = new User(1L, "testuser", "test@example.com");
            when(userService.getUserById(1L)).thenReturn(Mono.just(user));
            
            // When & Then
            webTestClient.get()
                    .uri("/api/users/1")
                    .accept(MediaType.APPLICATION_JSON)
                    .exchange()
                    .expectStatus().isOk()
                    .expectBody()
                    .jsonPath("$.id").isEqualTo(1)
                    .jsonPath("$.username").isEqualTo("testuser");
        }
    }
    
    // Property-based testing with jqwik
    @Property
    void stringReversalIsInverse(@ForAll("validStrings") String str) {
        String reversed = new StringBuilder(str).reverse().toString();
        String doubleReversed = new StringBuilder(reversed).reverse().toString();
        assertThat(doubleReversed).isEqualTo(str);
    }
    
    @Provide
    Arbitrary<String> validStrings() {
        return Arbitraries.strings()
                .withChars("abc")
                .ofMinLength(1)
                .ofMaxLength(100);
    }
    

    Security Best Practices

    Input Validation and Sanitization

    import jakarta.validation.constraints.*;
    import org.hibernate.validator.constraints.URL;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    
    // DTO with validation annotations
    public record UserCreateDto(
        
        @NotBlank(message = "Username is required")
        @Size(min = 3, max = 50, message = "Username must be between 3 and 50 characters")
        @Pattern(regexp = "^[a-zA-Z0-9_]+$", message = "Username can only contain letters, numbers, and underscores")
        String username,
        
        @NotBlank(message = "Email is required")
        @Email(message = "Invalid email format")
        @Size(max = 100, message = "Email must be less than 100 characters")
        String email,
        
        @NotBlank(message = "Password is required")
        @Size(min = 8, max = 128, message = "Password must be between 8 and 128 characters")
        @Pattern(regexp = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]", 
                 message = "Password must contain at least one lowercase letter, one uppercase letter, one digit, and one special character")
        String password
    ) {
        
        // Custom validation method
        public UserCreateDto {
            if (email != null && email.toLowerCase().contains("@admin.com")) {
                throw new IllegalArgumentException("Admin email domains are not allowed");
            }
        }
    }
    
    // Password encryption service
    @Service
    public class PasswordService {
        
        private final PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(12);
        
        public String encodePassword(String rawPassword) {
            return passwordEncoder.encode(rawPassword);
        }
        
        public boolean matches(String rawPassword, String encodedPassword) {
            return passwordEncoder.matches(rawPassword, encodedPassword);
        }
    }
    
    // Input sanitization for XSS prevention
    @Component
    public class InputSanitizer {
        
        private static final org.owasp.encoder.Encoder encoder = org.owasp.encoder.Encoder.getInstance();
        
        public String sanitizeForHtml(String input) {
            return input == null ? null : encoder.encodeForHTML(input);
        }
        
        public String sanitizeForJavaScript(String input) {
            return input == null ? null : encoder.encodeForJavaScript(input);
        }
    }
    

    Authentication and Authorization

    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
    import org.springframework.security.config.web.server.ServerHttpSecurity;
    import org.springframework.security.web.server.SecurityWebFilterChain;
    import org.springframework.security.web.server.authentication.AuthenticationWebFilter;
    
    @Configuration
    @EnableWebFluxSecurity
    public class SecurityConfig {
        
        @Bean
        public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
            return http
                    .csrf(ServerHttpSecurity.CsrfSpec::disable)
                    .authorizeExchange(exchanges -> exchanges
                            .pathMatchers("/api/auth/**").permitAll()
                            .pathMatchers("/api/public/**").permitAll()
                            .pathMatchers("/actuator/health").permitAll()
                            .pathMatchers("/api/admin/**").hasRole("ADMIN")
                            .pathMatchers("/api/users/**").hasAnyRole("USER", "ADMIN")
                            .anyExchange().authenticated()
                    )
                    .oauth2ResourceServer(oauth2 -> oauth2
                            .jwt(jwt -> jwt.jwtDecoder(jwtDecoder()))
                    )
                    .addFilterAt(jwtAuthenticationFilter(), AuthenticationWebFilter.class)
                    .build();
        }
        
        @Bean
        public JwtDecoder jwtDecoder() {
            return NimbusJwtDecoder.withJwkSetUri("https://your-auth-server/.well-known/jwks.json")
                    .build();
        }
        
        @Bean
        public ReactiveAuthenticationManager authenticationManager() {
            return new UserRepositoryReactiveAuthenticationManager(userRepository, passwordService);
        }
    }
    
    // Method-level security
    @Service
    public class DocumentService {
        
        @PreAuthorize("hasRole('USER') and @documentSecurity.canRead(#documentId, authentication.name)")
        public Mono<Document> getDocument(Long documentId) {
            return documentRepository.findById(documentId);
        }
        
        @PreAuthorize("hasRole('ADMIN') or @documentSecurity.isOwner(#documentId, authentication.name)")
        public Mono<Document> updateDocument(Long documentId, DocumentUpdateDto updateDto) {
            return documentRepository.findById(documentId)
                    .filter(document -> canUpdate(document, AuthenticationHolder.getCurrentUsername()))
                    .flatMap(document -> {
                        document.update(updateDto);
                        return documentRepository.save(document);
                    });
        }
        
        @PostAuthorize("returnObject.isPresent() && returnObject.get().isPublic()")
        public Optional<Document> getPublicDocument(Long documentId) {
            return documentRepository.findById(documentId);
        }
    }
    

    Dependency Security Scanning

    # Add to build.gradle.kts
    plugins {
        id("org.owasp.dependencycheck") version "10.0.3"
        id("com.github.ben-manes.versions") version "0.51.0"
    }
    
    // OWASP Dependency Check
    dependencyCheck {
        failBuildOnCVSS = 7.0f
        suppressionFile = "dependency-check-suppressions.xml"
        analyzers {
            experimentalEnabled = false
        }
    }
    
    // Dependency version updates
    tasks.named("dependencyUpdates") {
        checkForGradleUpdate = true
        outputFormatter = "json"
        outputDir = "build/dependencyUpdates"
        reportfileName = "report"
    }
    

    Integration Patterns

    Database Integration with R2DBC

    import org.springframework.data.annotation.Id;
    import org.springframework.data.relational.core.mapping.Table;
    import org.springframework.data.repository.reactive.ReactiveCrudRepository;
    import org.springframework.r2dbc.core.DatabaseClient;
    import reactor.core.publisher.Flux;
    import reactor.core.publisher.Mono;
    
    @Table("users")
    public record User(
        @Id Long id,
        String username,
        String email,
        Instant createdAt,
        boolean active
    ) {
        public User {
            if (createdAt == null) {
                createdAt = Instant.now();
            }
        }
    }
    
    @Repository
    public interface UserRepository extends ReactiveCrudRepository<User, Long> {
        Flux<User> findByUsername(String username);
        Flux<User> findByEmail(String email);
        Flux<User> findByActiveTrue();
        
        @Query("SELECT * FROM users WHERE username LIKE :pattern")
        Flux<User> findByUsernamePattern(String pattern);
    }
    
    // Custom repository with complex queries
    @Repository
    public class CustomUserRepository {
        
        private final DatabaseClient databaseClient;
        
        public CustomUserRepository(DatabaseClient databaseClient) {
            this.databaseClient = databaseClient;
        }
        
        public Flux<UserSummary> findUserSummaries() {
            return databaseClient.sql("SELECT id, username, email FROM users WHERE active = true")
                    .map((row, metadata) -> new UserSummary(
                        row.get("id", Long.class),
                        row.get("username", String.class),
                        row.get("email", String.class)
                    ))
                    .all();
        }
        
        public Mono<Integer> bulkUpdateStatus(List<Long> userIds, boolean active) {
            String placeholders = userIds.stream()
                    .map(id -> "?")
                    .collect(Collectors.joining(","));
            
            return databaseClient.sql(
                    "UPDATE users SET active = :active WHERE id IN (" + placeholders + ")"
                )
                .bind("active", active)
                .bind(0, userIds.get(0))
                // ... bind remaining parameters
                .fetch()
                .rowsUpdated();
        }
    }
    

    Message Queue Integration with RabbitMQ

    import org.springframework.amqp.rabbit.core.RabbitTemplate;
    import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.amqp.core.*;
    
    @Configuration
    public class RabbitMQConfig {
        
        public static final String USER_QUEUE = "user.queue";
        public static final String USER_EXCHANGE = "user.exchange";
        public static final String USER_ROUTING_KEY = "user.created";
        
        @Bean
        public Queue userQueue() {
            return QueueBuilder.durable(USER_QUEUE).build();
        }
        
        @Bean
        public TopicExchange userExchange() {
            return new TopicExchange(USER_EXCHANGE);
        }
        
        @Bean
        public Binding userBinding() {
            return BindingBuilder.bind(userQueue())
                    .to(userExchange())
                    .with(USER_ROUTING_KEY);
        }
        
        @Bean
        public Jackson2JsonMessageConverter messageConverter() {
            return new Jackson2JsonMessageConverter();
        }
        
        @Bean
        public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
            RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
            rabbitTemplate.setMessageConverter(messageConverter());
            return rabbitTemplate;
        }
    }
    
    @Service
    public class UserEventPublisher {
        
        private final RabbitTemplate rabbitTemplate;
        
        public UserEventPublisher(RabbitTemplate rabbitTemplate) {
            this.rabbitTemplate = rabbitTemplate;
        }
        
        public void publishUserCreated(User user) {
            UserCreatedEvent event = new UserCreatedEvent(user.id(), user.username(), user.email());
            rabbitTemplate.convertAndSend(
                RabbitMQConfig.USER_EXCHANGE,
                RabbitMQConfig.USER_ROUTING_KEY,
                event
            );
        }
    }
    
    @Component
    public class UserEventConsumer {
        
        private final EmailService emailService;
        private final AuditService auditService;
        
        public UserEventConsumer(EmailService emailService, AuditService auditService) {
            this.emailService = emailService;
            this.auditService = auditService;
        }
        
        @RabbitListener(queues = RabbitMQConfig.USER_QUEUE)
        public void handleUserCreated(UserCreatedEvent event) {
            log.info("Received user created event: {}", event);
            
            // Send welcome email
            emailService.sendWelcomeEmail(event.userId(), event.email());
            
            // Create audit record
            auditService.recordUserCreation(event.userId(), event.username());
        }
    }
    
    // Event record
    public record UserCreatedEvent(
        Long userId,
        String username,
        String email,
        Instant timestamp
    ) {
        public UserCreatedEvent {
            if (timestamp == null) {
                timestamp = Instant.now();
            }
        }
    }
    

    Redis Integration for Caching

    import org.springframework.data.redis.core.ReactiveRedisTemplate;
    import org.springframework.data.redis.core.ReactiveValueOperations;
    import reactor.core.publisher.Mono;
    
    @Service
    public class CacheService {
        
        private final ReactiveRedisTemplate<String, Object> redisTemplate;
        private final ReactiveValueOperations<String, Object> valueOps;
        
        public CacheService(ReactiveRedisTemplate<String, Object> redisTemplate) {
            this.redisTemplate = redisTemplate;
            this.valueOps = redisTemplate.opsForValue();
        }
        
        public <T> Mono<T> get(String key, Class<T> type) {
            return valueOps.get(key)
                    .cast(type);
        }
        
        public <T> Mono<T> getOrCompute(String key, Supplier<Mono<T>> supplier, Duration ttl, Class<T> type) {
            return get(key, type)
                    .switchIfEmpty(
                        supplier.get()
                            .flatMap(result -> set(key, result, ttl).thenReturn(result))
                    );
        }
        
        public <T> Mono<Boolean> set(String key, T value, Duration ttl) {
            return valueOps.set(key, value, ttl);
        }
        
        public Mono<Boolean> delete(String key) {
            return redisTemplate.delete(key).map(count -> count > 0);
        }
        
        // Rate limiting implementation
        public Mono<Boolean> isRateLimited(String identifier, int maxRequests, Duration window) {
            String key = "rate_limit:" + identifier;
            
            return redisTemplate.opsForValue()
                    .increment(key)
                    .flatMap(count -> {
                        if (count == 1) {
                            // Set expiration for first request in window
                            return redisTemplate.expire(key, window).thenReturn(count);
                        }
                        return Mono.just(count);
                    })
                    .map(count -> count > maxRequests);
        }
    }
    

    Modern Development Workflow

    Gradle Configuration (build.gradle.kts)

    plugins {
        application
        jacoco
        checkstyle
        pmd
        id("org.springframework.boot") version "3.3.0"
        id("io.spring.dependency-management") version "1.1.5"
        id("com.google.cloud.tools.jib") version "3.4.1"
    }
    
    group = "com.example"
    version = "0.1.0"
    
    java {
        toolchain {
            languageVersion = JavaLanguageVersion.of(21)
        }
    }
    
    repositories {
        mavenCentral()
    }
    
    dependencies {
        // Spring Boot starters
        implementation("org.springframework.boot:spring-boot-starter-webflux")
        implementation("org.springframework.boot:spring-boot-starter-data-r2dbc")
        implementation("org.springframework.boot:spring-boot-starter-actuator")
        implementation("org.springframework.boot:spring-boot-starter-validation")
        
        // Database
        implementation("org.postgresql:r2dbc-postgresql")
        implementation("org.flywaydb:flyway-core")
        implementation("org.springframework:spring-jdbc")
        
        // Message queue
        implementation("org.springframework.boot:spring-boot-starter-amqp")
        
        // Caching
        implementation("org.springframework.boot:spring-boot-starter-data-redis-reactive")
        
        // Security
        implementation("org.springframework.boot:spring-boot-starter-security")
        implementation("org.springframework.security:spring-security-oauth2-resource-server")
        
        // Utility libraries
        implementation("com.fasterxml.jackson.core:jackson-databind")
        implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310")
        implementation("org.apache.commons:commons-lang3")
        implementation("org.apache.commons:commons-collections4")
        
        // Development tools
        compileOnly("org.projectlombok:lombok")
        annotationProcessor("org.projectlombok:lombok")
        developmentOnly("org.springframework.boot:spring-boot-devtools")
        
        // Testing
        testImplementation("org.springframework.boot:spring-boot-starter-test")
        testImplementation("org.springframework.security:spring-security-test")
        testImplementation("io.projectreactor:reactor-test")
        testImplementation("org.testcontainers:junit-jupiter")
        testImplementation("org.testcontainers:postgresql")
        testImplementation("org.testcontainers:r2dbc")
        testImplementation("org.testcontainers:rabbitmq")
        
        // Performance testing
        testImplementation("org.junit.jupiter:junit-jupiter-params")
        testImplementation("net.jqwik:jqwik:1.8.3")
    }
    
    application {
        mainClass.set("com.example.Application")
    }
    
    tasks.test {
        useJUnitPlatform()
        testLogging {
            events("passed", "skipped", "failed")
        }
    }
    
    // Jib configuration for Docker image generation
    jib {
        from {
            image = "eclipse-temurin:21-jre-alpine"
        }
        to {
            image = "my-registry.com/my-app:latest"
        }
        container {
            jvmFlags = listOf("-Xms512m", "-Xmx2g")
            ports = listOf("8080")
            environment = mapOf(
                "SPRING_PROFILES_ACTIVE" to "prod"
            )
        }
    }
    

    Pre-commit Configuration

    # .pre-commit-config.yaml
    repos:
      - repo: https://github.com/pre-commit/pre-commit-hooks
        rev: v5.0.0
        hooks:
          - id: trailing-whitespace
          - id: end-of-file-fixer
          - id: check-yaml
          - id: check-added-large-files
          - id: check-merge-conflict
          - id: check-executables-have-shebangs
    
      - repo: https://github.com/codacy/codacy-checkstyle.git
        rev: 5.1.0
        hooks:
          - id: codacy-checkstyle-java
            args: ["-c", "/path/to/checkstyle.xml"]
    
      - repo: https://github.com/ulises-jeremias/pre-commit-pmd
        rev: v2.3.1
        hooks:
          - id: pmd
            args: ["-d", "src/main/java", "-r", "ruleset.xml"]
    
      - repo: local
        hooks:
          - id: gradle-spotless
            name: Code formatting with Spotless
            entry: ./gradlew spotlessApply
            language: system
            files: '\.(java|kt|kts)$'
    
          - id: gradle-test
            name: Run tests
            entry: ./gradlew test
            language: system
            pass_filenames: false
            always_run: true
    
          - id: gradle-check
            name: Run code quality checks
            entry: ./gradlew check
            language: system
            pass_filenames: false
            always_run: true
    

    Docker Best Practices

    # Multi-stage Docker build with Jib integration
    # This Dockerfile is for local development; use Jib for production
    
    # Build stage
    FROM eclipse-temurin:21-jdk-alpine AS builder
    
    WORKDIR /app
    
    # Copy gradle wrapper and cache dependencies
    COPY gradlew gradlew.bat gradle/ ./
    COPY build.gradle.kts settings.gradle.kts ./
    
    # Download dependencies
    RUN ./gradlew --no-daemon dependencies
    
    # Copy source code
    COPY src/ ./src/
    
    # Build application
    RUN ./gradlew --no-daemon bootJar -x test
    
    # Runtime stage
    FROM eclipse-temurin:21-jre-alpine
    
    # Security best practices
    RUN addgroup --system --gid 1001 appgroup && \
        adduser --system --uid 1001 --ingroup appgroup appuser && \
        mkdir -p /app && \
        chown -R appuser:appgroup /app
    
    WORKDIR /app
    
    # Copy application jar
    COPY --from=builder /app/build/libs/*.jar app.jar
    
    # Set appropriate permissions
    RUN chmod +x app.jar
    
    # Switch to non-root user
    USER appuser
    
    # Health check
    HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
        CMD curl -f http://localhost:8080/actuator/health || exit 1
    
    EXPOSE 8080
    
    # JVM optimizations
    ENV JAVA_OPTS="-Xms512m -Xmx2g -XX:+UseG1GC -XX:+UseStringDeduplication"
    
    ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]
    

    Backend Development Patterns

    Spring Boot Application Structure

    @SpringBootApplication
    @EnableReactiveSecurity
    @EnableR2dbcAuditing
    public class Application {
        
        public static void main(String[] args) {
            SpringApplication.run(Application.class, args);
        }
        
        @Bean
        public WebFluxConfigurer corsConfigurer() {
            return new WebFluxConfigurer() {
                @Override
                public void addCorsMappings(CorsRegistry registry) {
                    registry.addMapping("/api/**")
                            .allowedOrigins("http://localhost:3000")
                            .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                            .allowedHeaders("*")
                            .maxAge(3600);
                }
            };
        }
    }
    
    // Global error handling
    @ControllerAdvice
    public class GlobalExceptionHandler {
        
        private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
        
        @ExceptionHandler(ValidationException.class)
        public ResponseEntity<ErrorResponse> handleValidationException(ValidationException ex) {
            log.warn("Validation error: {}", ex.getMessage());
            return ResponseEntity.badRequest()
                    .body(new ErrorResponse("VALIDATION_ERROR", ex.getMessage()));
        }
        
        @ExceptionHandler(ResourceNotFoundException.class)
        public ResponseEntity<ErrorResponse> handleResourceNotFoundException(ResourceNotFoundException ex) {
            log.warn("Resource not found: {}", ex.getMessage());
            return ResponseEntity.status(HttpStatus.NOT_FOUND)
                    .body(new ErrorResponse("RESOURCE_NOT_FOUND", ex.getMessage()));
        }
        
        @ExceptionHandler(Exception.class)
        public ResponseEntity<ErrorResponse> handleGenericException(Exception ex) {
            log.error("Unexpected error occurred", ex);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body(new ErrorResponse("INTERNAL_ERROR", "An unexpected error occurred"));
        }
    }
    
    // Audit configuration
    @Configuration
    @EnableJpaAuditing(auditorAwareRef = "auditorProvider")
    public class AuditConfig {
        
        @Bean
        public AuditorAware<String> auditorProvider() {
            return () -> {
                Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
                if (authentication == null || !authentication.isAuthenticated()) {
                    return Optional.of("system");
                }
                return Optional.of(authentication.getName());
            };
        }
    }
    
    // Custom metrics with Micrometer
    @Component
    public class CustomMetrics {
        
        private final Counter userRegistrationCounter;
        private final Timer userLoginTimer;
        private final Gauge activeUserGauge;
        
        public CustomMetrics(MeterRegistry meterRegistry) {
            this.userRegistrationCounter = Counter.builder("users.registered")
                    .description("Number of user registrations")
                    .register(meterRegistry);
            
            this.userLoginTimer = Timer.builder("users.login.duration")
                    .description("User login duration")
                    .register(meterRegistry);
            
            this.activeUserGauge = Gauge.builder("users.active")
                    .description("Number of active users")
                    .register(meterRegistry, this, CustomMetrics::getActiveUserCount);
        }
        
        public void incrementUserRegistration() {
            userRegistrationCounter.increment();
        }
        
        public Timer.Sample startLoginTimer() {
            return Timer.start();
        }
        
        public void recordLoginTime(Timer.Sample sample) {
            sample.stop(userLoginTimer);
        }
        
        private double getActiveUserCount() {
            // Implementation to count active users
            return 0.0;
        }
    }
    

    Created by: MoAI Language Skill Factory
    Last Updated: 2025-11-06
    Version: 2.0.0
    Java Target: 21 (LTS) with modern Spring Boot and reactive patterns

    This skill provides comprehensive Java development guidance with 2025 best practices, covering everything from basic project setup to advanced enterprise integration and production deployment patterns.

    Recommended Servers
    Vercel Grep
    Vercel Grep
    InstantDB
    InstantDB
    Cloudflare Workers Observability
    Cloudflare Workers Observability
    Repository
    kivo360/quickhooks
    Files