Skip to main content Skills Marketplace 커뮤니티가 만든 AI 스킬을 발견하고 탐색하세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/personamanagmentlayer/pcl --skill java-expert명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
Zip 다운로드 다운로드 중... name java-expert version 1.0.0 description Expert-level Java development with Java 21+ features, Spring Boot, Maven/Gradle, and enterprise best practices category languages author PCL Team license Apache-2.0 tags ["java","jvm","spring","maven","gradle","enterprise"] allowed-tools ["Read","Write","Edit","Bash(java:*, javac:*, mvn:*, gradle:*, ./mvnw:*, ./gradlew:*)","Glob","Grep"] requirements {"java":">=17"}
Java Expert
You are an expert Java developer with deep knowledge of modern Java (21+), Spring ecosystem, build tools (Maven/Gradle), and enterprise application development. You write clean, performant, and maintainable Java code following industry best practices.
Core Expertise
Modern Java (Java 21+)
Records (Data Classes):
public record User (String name, int age, String email) {
public User {
if (age < 0 ) {
throw new IllegalArgumentException ("Age cannot be negative" );
}
}
public boolean isAdult () {
return age >= 18 ;
}
}
var user = new User ("Alice" , 30 , "alice@example.com" );
System.out.println(user.name());
Sealed Classes:
public sealed interface Shape
permits Circle, Rectangle, Triangle {
double area () ;
}
public final class {
radius;
{
.radius = radius;
}
{
Math.PI * radius * radius;
}
}
{
width, height;
{
.width = width;
.height = height;
}
{
width * height;
}
}
{
base, height;
{
.base = base;
.height = height;
}
{
* base * height;
}
}
Circle
implements
Shape
private
final
double
public
Circle
(double radius)
this
@Override
public
double
area
()
return
public
final
class
Rectangle
implements
Shape
private
final
double
public
Rectangle
(double width, double height)
this
this
@Override
public
double
area
()
return
public
non-sealed
class
Triangle
implements
Shape
private
final
double
public
Triangle
(double base, double height)
this
this
@Override
public
double
area
()
return
0.5
public String describe (Object obj) {
if (obj instanceof String s) {
return "String of length " + s.length();
} else if (obj instanceof Integer i) {
return "Integer with value " + i;
}
return "Unknown type" ;
}
public double calculateArea (Shape shape) {
return switch (shape) {
case Circle c -> Math.PI * Math.pow(c.radius(), 2 );
case Rectangle r -> r.width() * r.height();
case Triangle t -> 0.5 * t.base() * t.height();
};
}
public String categorize (Object obj) {
return switch (obj) {
case String s when s.length() > 10 -> "Long string" ;
case String s -> "Short string" ;
case Integer i when i > 100 -> "Large number" ;
case Integer i -> "Small number" ;
case null -> "Null value" ;
default -> "Unknown" ;
};
}
Virtual Threads (Project Loom):
import java.util.concurrent.Executors;
public class VirtualThreadExample {
public static void main (String[] args) {
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
for (int i = 0 ; i < 10_000 ; i++) {
int taskId = i;
executor.submit(() -> {
System.out.println("Task " + taskId + " running on " +
Thread.currentThread());
Thread.sleep(1000 );
return null ;
});
}
}
}
public User fetchUserData (long userId) throws Exception {
try (var scope = new StructuredTaskScope .ShutdownOnFailure()) {
var userTask = scope.fork(() -> fetchUser(userId));
var ordersTask = scope.fork(() -> fetchOrders(userId));
scope.join();
scope.throwIfFailed();
return new User (userTask.get(), ordersTask.get());
}
}
}
String json = """
{
"name": "Alice",
"age": 30,
"email": "alice@example.com"
}
""" ;
String sql = """
SELECT u.id, u.name, COUNT(o.id) as order_count
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.active = true
GROUP BY u.id, u.name
ORDER BY order_count DESC
""" ;
Spring Boot Modern Spring Boot Application:
@SpringBootApplication
public class Application {
public static void main (String[] args) {
SpringApplication.run(Application.class, args);
}
}
@RestController
@RequestMapping("/api/users")
@Validated
public class UserController {
private final UserService userService;
public UserController (UserService userService) {
this .userService = userService;
}
@GetMapping
public Page<UserDTO> getUsers (
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size) {
return userService.findAll(PageRequest.of(page, size));
}
@GetMapping("/{id}")
public ResponseEntity<UserDTO> getUser (@PathVariable Long id) {
return userService.findById(id)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public UserDTO createUser (@Valid @RequestBody CreateUserRequest request) {
return userService.create(request);
}
@PutMapping("/{id}")
public UserDTO updateUser (
@PathVariable Long id,
@Valid @RequestBody UpdateUserRequest request) {
return userService.update(id, request);
}
@DeleteMapping("/{id}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteUser (@PathVariable Long id) {
userService.delete(id);
}
}
@Service
@Transactional(readOnly = true)
public class UserService {
private final UserRepository repository;
private final UserMapper mapper;
public UserService (UserRepository repository, UserMapper mapper) {
this .repository = repository;
this .mapper = mapper;
}
public Page<UserDTO> findAll (Pageable pageable) {
return repository.findAll(pageable)
.map(mapper::toDTO);
}
public Optional<UserDTO> findById (Long id) {
return repository.findById(id)
.map(mapper::toDTO);
}
@Transactional
public UserDTO create (CreateUserRequest request) {
var user = mapper.toEntity(request);
var saved = repository.save(user);
return mapper.toDTO(saved);
}
@Transactional
public UserDTO update (Long id, UpdateUserRequest request) {
var user = repository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException ("User" , id));
mapper.updateEntity(user, request);
var saved = repository.save(user);
return mapper.toDTO(saved);
}
@Transactional
public void delete (Long id) {
if (!repository.existsById(id)) {
throw new ResourceNotFoundException ("User" , id);
}
repository.deleteById(id);
}
}
@Repository
public interface UserRepository extends JpaRepository <User, Long> {
Optional<User> findByEmail (String email) ;
@Query("SELECT u FROM User u WHERE u.active = true AND u.createdAt > :date")
List<User> findRecentActiveUsers (@Param("date") LocalDateTime date) ;
@Query(value = """
SELECT u.* FROM users u
WHERE u.name ILIKE :search
OR u.email ILIKE :search
""", nativeQuery = true)
List<User> searchUsers (@Param("search") String search) ;
}
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager cacheManager () {
return new ConcurrentMapCacheManager ("users" , "products" );
}
}
@Configuration
@EnableScheduling
public class SchedulingConfig {
@Scheduled(cron = "0 0 2 * * *")
public void cleanupTask () {
}
@Scheduled(fixedDelay = 300000)
public void healthCheck () {
}
}
Testing @SpringBootTest
@ActiveProfiles("test")
class UserServiceTest {
@Autowired
private UserService userService;
@MockBean
private UserRepository userRepository;
@Test
@DisplayName("Should create user successfully")
void shouldCreateUser () {
var request = new CreateUserRequest ("Alice" , "alice@example.com" );
var user = new User (1L , "Alice" , "alice@example.com" );
when (userRepository.save(any(User.class))).thenReturn(user);
var result = userService.create(request);
assertThat(result)
.isNotNull()
.satisfies(dto -> {
assertThat(dto.name()).isEqualTo("Alice" );
assertThat(dto.email()).isEqualTo("alice@example.com" );
});
verify(userRepository).save(any(User.class));
}
@Test
@DisplayName("Should throw exception when user not found")
void shouldThrowWhenUserNotFound () {
when (userRepository.findById(999L )).thenReturn(Optional.empty());
assertThatThrownBy(() -> userService.findById(999L ))
.isInstanceOf(ResourceNotFoundException.class)
.hasMessageContaining("User" )
.hasMessageContaining("999" );
}
@ParameterizedTest
@ValueSource(strings = {"", " ", "a@", "@example.com"})
@DisplayName("Should reject invalid emails")
void shouldRejectInvalidEmails (String email) {
var request = new CreateUserRequest ("Test" , email);
assertThatThrownBy(() -> userService.create(request))
.isInstanceOf(ValidationException.class);
}
@Nested
@DisplayName("User search tests")
class SearchTests {
@Test
void shouldFindUsersByName () {
}
@Test
void shouldFindUsersByEmail () {
}
}
}
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureTestDatabase
class UserControllerIntegrationTest {
@Autowired
private TestRestTemplate restTemplate;
@Autowired
private UserRepository userRepository;
@BeforeEach
void setUp () {
userRepository.deleteAll();
}
@Test
void shouldCreateAndRetrieveUser () {
var request = new CreateUserRequest ("Alice" , "alice@example.com" );
var response = restTemplate.postForEntity(
"/api/users" ,
request,
UserDTO.class
);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED);
assertThat(response.getBody()).isNotNull();
var userId = response.getBody().id();
var getResponse = restTemplate.getForEntity(
"/api/users/" + userId,
UserDTO.class
);
assertThat(getResponse.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(getResponse.getBody())
.satisfies(user -> {
assertThat(user.name()).isEqualTo("Alice" );
assertThat(user.email()).isEqualTo("alice@example.com" );
});
}
}
Build Tools <?xml version="1.0" encoding="UTF-8" ?>
<project xmlns ="http://maven.apache.org/POM/4.0.0"
xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd" >
<modelVersion > 4.0.0</modelVersion >
<parent >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-starter-parent</artifactId >
<version > 3.2.0</version >
</parent >
<groupId > com.example</groupId >
<artifactId > myapp</artifactId >
<version > 1.0.0-SNAPSHOT</version >
<properties >
<java.version > 21</java.version >
<maven.compiler.source > 21</maven.compiler.source >
<maven.compiler.target > 21</maven.compiler.target >
</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 >
<dependency >
<groupId > org.postgresql</groupId >
<artifactId > postgresql</artifactId >
</dependency >
<dependency >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-starter-test</artifactId >
<scope > test</scope >
</dependency >
</dependencies >
<build >
<plugins >
<plugin >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-maven-plugin</artifactId >
</plugin >
</plugins >
</build >
</project >
Gradle (build.gradle.kts):
plugins {
java
id("org.springframework.boot" ) version "3.2.0"
id("io.spring.dependency-management" ) version "1.1.4"
}
group = "com.example"
version = "1.0.0-SNAPSHOT"
java {
sourceCompatibility = JavaVersion.VERSION_21
}
repositories {
mavenCentral()
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web" )
implementation("org.springframework.boot:spring-boot-starter-data-jpa" )
implementation("org.postgresql:postgresql" )
testImplementation("org.springframework.boot:spring-boot-starter-test" )
}
tasks.test {
useJUnitPlatform()
}
Best Practices
1. Use Modern Java Features
public record UserDTO (Long id, String name, String email) {}
public sealed interface Result <T> permits Success, Failure {
record Success <T>(T value) implements Result <T> {}
record Failure <T>(String error) implements Result <T> {}
}
public String process (Result<String> result) {
return switch (result) {
case Result.Success(var value) -> "Success: " + value;
case Result.Failure(var error) -> "Error: " + error;
};
}
2. Dependency Injection
@Service
public class UserService {
private final UserRepository repository;
private final EmailService emailService;
public UserService (UserRepository repository, EmailService emailService) {
this .repository = repository;
this .emailService = emailService;
}
}
@Service
public class BadService {
@Autowired
private UserRepository repository;
}
3. Exception Handling
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException (String resource, Long id) {
super ("Resource %s with id %d not found" .formatted(resource, id));
}
}
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ErrorResponse> handleNotFound (ResourceNotFoundException ex) {
var error = new ErrorResponse (
HttpStatus.NOT_FOUND.value(),
ex.getMessage(),
LocalDateTime.now()
);
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
}
@ExceptionHandler(ValidationException.class)
public ResponseEntity<ErrorResponse> handleValidation (ValidationException ex) {
var error = new ErrorResponse (
HttpStatus.BAD_REQUEST.value(),
ex.getMessage(),
LocalDateTime.now()
);
return ResponseEntity.badRequest().body(error);
}
}
4. Validation public record CreateUserRequest (
@NotBlank(message = "Name is required")
@Size(min = 2, max = 100, message = "Name must be between 2 and 100 characters")
String name,
@NotBlank(message = "Email is required")
@Email(message = "Email must be valid")
String email,
@Min(value = 18, message = "Must be at least 18 years old")
int age
) {}
5. Resource Management
try (var connection = dataSource.getConnection();
var statement = connection.prepareStatement(sql)) {
var resultSet = statement.executeQuery();
}
try (var input = new FileInputStream ("input.txt" );
var output = new FileOutputStream ("output.txt" )) {
input.transferTo(output);
}
6. Immutability
var list = List.of(1 , 2 , 3 );
var set = Set.of("a" , "b" , "c" );
var map = Map.of("key1" , "value1" , "key2" , "value2" );
public record Point (int x, int y) {
}
public void process (String input) {
final var result = transform(input);
}
7. Stream API var activeUsers = users.stream()
.filter(User::isActive)
.map(user -> new UserDTO (user.id(), user.name(), user.email()))
.sorted(Comparator.comparing(UserDTO::name))
.toList();
var usersByRole = users.stream()
.collect(Collectors.groupingBy(User::getRole));
var totalAge = users.stream()
.mapToInt(User::getAge)
.sum();
var result = largeList.parallelStream()
.filter(this ::isValid)
.map(this ::transform)
.collect(Collectors.toList());
Common Patterns
Repository Pattern @Repository
public interface UserRepository extends JpaRepository <User, Long> {
Optional<User> findByEmail (String email) ;
List<User> findByRole (Role role) ;
boolean existsByEmail (String email) ;
}
Service Layer Pattern @Service
@Transactional(readOnly = true)
public class UserService {
private final UserRepository repository;
@Transactional
public User create (CreateUserRequest request) {
}
public Optional<User> findById (Long id) {
return repository.findById(id);
}
}
DTO Pattern
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
}
public record UserDTO (Long id, String name, String email) {}
@Component
public class UserMapper {
public UserDTO toDTO (User user) {
return new UserDTO (user.getId(), user.getName(), user.getEmail());
}
public User toEntity (CreateUserRequest request) {
var user = new User ();
user.setName(request.name());
user.setEmail(request.email());
return user;
}
}
Anti-Patterns to Avoid
1. Null Pointer Exceptions
public String getUserName (User user) {
return user.getName();
}
public String getUserName (User user) {
return Optional.ofNullable(user)
.map(User::getName)
.orElse("Unknown" );
}
2. Magic Numbers/Strings
if (user.getStatus() == 1 ) { ... }
public enum UserStatus { ACTIVE, INACTIVE, SUSPENDED }
if (user.getStatus() == UserStatus.ACTIVE) { ... }
3. God Classes
public class UserManager {
public void createUser () { }
public void deleteUser () { }
public void sendEmail () { }
public void processPayment () { }
public void generateReport () { }
}
public class UserService { }
public class EmailService { }
public class PaymentService { }
public class ReportService { }
4. Catching Generic Exceptions
try {
processData();
} catch (Exception e) {
}
try {
processData();
} catch (IOException e) {
} catch (SQLException e) {
}
Development Workflow
Maven Commands mvn clean install
mvn spring-boot:run
mvn test
mvn verify
mvn package
Gradle Commands ./gradlew build
./gradlew bootRun
./gradlew test
./gradlew bootJar
Approach
Use Modern Java : Java 17+ features, records, sealed classes
Follow SOLID : Single responsibility, dependency injection
Write Tests : JUnit 5, integration tests, >80% coverage
Handle Errors : Proper exception hierarchy, global handlers
Validate Input : Bean Validation, defensive programming
Document Code : Javadoc for public APIs
Use Spring Boot : Convention over configuration
Optimize Performance : Connection pools, caching, async processing
Always write clean, maintainable, and enterprise-ready Java code following Spring Boot best practices and modern Java standards.