| name | moai-lang-java |
| description | Java 21 LTS development specialist covering Spring Boot 3.3, virtual threads, pattern matching, and enterprise patterns. Use when building enterprise applications, microservices, or Spring projects. |
| version | 1.0.0 |
| category | language |
| tags | java, spring-boot, jpa, hibernate, virtual-threads, enterprise |
| context7-libraries | /spring-projects/spring-boot, /spring-projects/spring-framework, /spring-projects/spring-security |
| related-skills | moai-lang-kotlin, moai-domain-backend |
| updated | Sun Dec 07 2025 00:00:00 GMT+0000 (Coordinated Universal Time) |
| status | active |
Quick Reference (30 seconds)
Java 21 LTS Expert - Enterprise development with Spring Boot 3.3, Virtual Threads, and modern Java features.
Auto-Triggers: Java files (.java), build files (pom.xml, build.gradle, build.gradle.kts)
Core Capabilities:
- Java 21 LTS: Virtual threads, pattern matching, record patterns, sealed classes
- Spring Boot 3.3: REST controllers, services, repositories, WebFlux reactive
- Spring Security 6: JWT authentication, OAuth2, role-based access control
- JPA/Hibernate 7: Entity mapping, relationships, queries, transactions
- JUnit 5: Unit testing, mocking, TestContainers integration
- Build Tools: Maven 3.9, Gradle 8.5 with Kotlin DSL
Implementation Guide (5 minutes)
Java 21 LTS Features
Virtual Threads (Project Loom):
// Lightweight concurrent programming
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
IntStream.range(0, 10_000).forEach(i ->
executor.submit(() -> {
Thread.sleep(Duration.ofSeconds(1));
return i;
})
);
}
// Structured concurrency (preview)
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Supplier<User> user = scope.fork(() -> fetchUser(userId));
Supplier<List<Order>> orders = scope.fork(() -> fetchOrders(userId));
scope.join().throwIfFailed();
return new UserWithOrders(user.get(), orders.get());
}
Pattern Matching for Switch:
String describe(Object obj) {
return switch (obj) {
case Integer i when i > 0 -> "positive integer: " + i;
case Integer i -> "non-positive integer: " + i;
case String s -> "string of length " + s.length();
case List<?> list -> "list with " + list.size() + " elements";
case null -> "null value";
default -> "unknown type";
};
}
Record Patterns and Sealed Classes:
record Point(int x, int y) {}
record Rectangle(Point topLeft, Point bottomRight) {}
int area(Rectangle rect) {
return switch (rect) {
case Rectangle(Point(var x1, var y1), Point(var x2, var y2)) ->
Math.abs((x2 - x1) * (y2 - y1));
};
}
public sealed interface Shape permits Circle, Rectangle {
double area();
}
public record Circle(double radius) implements Shape {
public double area() { return Math.PI * radius * radius; }
}
Spring Boot 3.3
REST Controller:
@RestController
@RequestMapping("/api/users")
@RequiredArgsConstructor
public class UserController {
private final UserService userService;
@GetMapping("/{id}")
public ResponseEntity<UserDto> getUser(@PathVariable Long id) {
return userService.findById(id)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
@PostMapping
public ResponseEntity<UserDto> createUser(@Valid @RequestBody CreateUserRequest request) {
UserDto user = userService.create(request);
URI location = URI.create("/api/users/" + user.id());
return ResponseEntity.created(location).body(user);
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
return userService.delete(id)
? ResponseEntity.noContent().build()
: ResponseEntity.notFound().build();
}
}
Service Layer:
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class UserService {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
public Optional<User> findById(Long id) {
return userRepository.findById(id);
}
@Transactional
public User create(CreateUserRequest request) {
if (userRepository.existsByEmail(request.email())) {
throw new DuplicateEmailException(request.email());
}
var user = User.builder()
.name(request.name())
.email(request.email())
.passwordHash(passwordEncoder.encode(request.password()))
.status(UserStatus.PENDING)
.build();
return userRepository.save(user);
}
}
Spring Security 6
Security Configuration:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public/**").permitAll()
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()))
.sessionManagement(session ->
session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.csrf(csrf -> csrf.disable())
.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
JPA/Hibernate Patterns
Entity Definition:
@Entity
@Table(name = "users")
@Getter @Setter
@NoArgsConstructor @Builder
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
@Column(nullable = false, unique = true)
private String email;
@Enumerated(EnumType.STRING)
private UserStatus status;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Order> orders = new ArrayList<>();
}
Repository with Custom Queries:
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByEmail(String email);
boolean existsByEmail(String email);
@Query("SELECT u FROM User u LEFT JOIN FETCH u.orders WHERE u.id = :id")
Optional<User> findByIdWithOrders(@Param("id") Long id);
Page<User> findByNameContainingIgnoreCase(String name, Pageable pageable);
}
DTOs as Records:
public record UserDto(Long id, String name, String email, UserStatus status) {
public static UserDto from(User user) {
return new UserDto(user.getId(), user.getName(), user.getEmail(), user.getStatus());
}
}
public record CreateUserRequest(
@NotBlank @Size(min = 2, max = 100) String name,
@NotBlank @Email String email,
@NotBlank @Size(min = 8) String password
) {}
Advanced Patterns
Virtual Threads Integration
@Service
@RequiredArgsConstructor
public class AsyncUserService {
public UserWithDetails fetchUserDetails(Long userId) throws Exception {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Supplier<User> userTask = scope.fork(() -> userRepo.findById(userId).orElseThrow());
Supplier<List<Order>> ordersTask = scope.fork(() -> orderRepo.findByUserId(userId));
scope.join().throwIfFailed();
return new UserWithDetails(userTask.get(), ordersTask.get());
}
}
public void processUsersInParallel(List<Long> userIds) {
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
userIds.stream().map(id -> executor.submit(() -> processUser(id))).toList();
}
}
}
Build Configuration
Maven 3.9:
<project>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.0</version>
</parent>
<properties><java.version>21</java.version></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>
</dependencies>
</project>
Gradle 8.5 (Kotlin DSL):
plugins {
id("org.springframework.boot") version "3.3.0"
id("io.spring.dependency-management") version "1.1.4"
java
}
java { toolchain { languageVersion = JavaLanguageVersion.of(21) } }
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}
Testing with JUnit 5
Unit Testing:
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
@Mock private UserRepository userRepository;
@InjectMocks private UserService userService;
@Test
void shouldCreateUser() {
when(userRepository.existsByEmail(anyString())).thenReturn(false);
when(userRepository.save(any())).thenReturn(User.builder().id(1L).build());
var result = userService.create(new CreateUserRequest("John", "john@test.com", "pass"));
assertThat(result.getId()).isEqualTo(1L);
}
}
Integration Testing with TestContainers:
@Testcontainers
@SpringBootTest
class UserRepositoryTest {
@Container
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16-alpine");
@DynamicPropertySource
static void props(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", postgres::getJdbcUrl);
}
@Autowired UserRepository repo;
@Test
void shouldSaveUser() {
var user = repo.save(User.builder().name("John").email("john@test.com").build());
assertThat(user.getId()).isNotNull();
}
}
Context7 Integration
Library mappings for latest documentation:
/spring-projects/spring-boot- Spring Boot 3.3 documentation/spring-projects/spring-framework- Spring Framework core/spring-projects/spring-security- Spring Security 6/hibernate/hibernate-orm- Hibernate 7 ORM patterns/junit-team/junit5- JUnit 5 testing framework
Works Well With
moai-lang-kotlin- Kotlin interoperability and Spring Kotlin extensionsmoai-domain-backend- REST API, GraphQL, microservices architecturemoai-domain-database- JPA, Hibernate, R2DBC patternsmoai-foundation-quality- JUnit 5, Mockito, TestContainers integrationmoai-infra-docker- JVM container optimization
Troubleshooting
Common Issues:
- Version mismatch:
java -version, checkJAVA_HOMEpoints to Java 21 - Compilation errors:
mvn clean compile -Xorgradle build --info - Virtual thread issues: Ensure Java 21+ with
--enable-previewif needed - JPA lazy loading: Use
@TransactionalorJOIN FETCHqueries
Performance Tips:
- Enable Virtual Threads:
spring.threads.virtual.enabled=true - Use GraalVM Native Image for faster startup
- Configure connection pooling with HikariCP
Advanced Documentation
For comprehensive reference materials:
- reference.md - Java 21 features, Context7 mappings, performance
- examples.md - Production-ready Spring Boot examples
Last Updated: 2025-12-07 Status: Production Ready (v1.0.0)