1. Java Annotation이란?
자바에서 어노테이션(Annotation)은 코드에 메타데이터를 추가하는 방법입니다. 어노테이션은 코드 자체를 변경하지 않지만, 코드에 대한 추가적인 정보를 제공하거나 특정 처리를 할 수 있게 도와줍니다. 주로 컴파일러나 런타임에서 이 정보를 활용하여 특정 작업을 자동으로 처리하거나, 개발자가 의도한 동작을 명확히 할 수 있도록 합니다.
어노테이션의 예를 들면:
- @Override
- 메서드가 부모 클래스의 메서드를 오버라이드하고 있다는 것을 컴파일러에 알려주는 역할을 합니다.
- 오타나 실수로 메서드 시그니처가 일치하지 않는 경우 컴파일러가 경고를 줍니다.
- @Entity
- JPA에서 데이터베이스 테이블과 매핑되는 클래스를 표시할 때 사용합니다.
- 해당 클래스가 엔티티로서 데이터베이스의 테이블과 매핑된다는 의미를 컴파일러와 런타임 시스템에 전달할 수 있습니다.
- @Deprecated
- 더 이상 사용되지 않는 메서드나 클래스를 표시할 때 사용합니다. 이를 통해 다른 개발자들에게 해당 코드가 더 이상 사용되지 않거나 향후 삭제될 가능성이 있음을 경고합니다.
어노테이션은 크게 빌드 도구나 프레임워크에서 처리되는 경우가 많으며, 예를 들어 Spring Framework에서는 어노테이션을 통해 의존성 주입이나 트랜잭션 관리 등을 자동화할 수 있습니다.
어노테이션 자체는 실제 코드 실행에는 영향을 주지 않지만, 프로그램의 메타데이터로서 중요한 역할을 합니다.
2. 커스텀 어노테이션
- 목적 : 생성/수정 api별로 필드값의 null check를 하는 커스텀 어노테이션을 만들고 싶습니다.
1) CheckedValidator.class
- 필드값의 Null 체크 및 응답 문구를 세팅하는 클레스
import com.oss.springBootTest.dto.annotation.Checked;
import io.micrometer.common.util.StringUtils;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import org.springframework.util.ObjectUtils;
public class CheckedValidator implements ConstraintValidator<Checked, Object> {
private String displayName; // 한글 필드명
@Override
public void initialize(Checked constraintAnnotation) {
this.displayName = constraintAnnotation.name(); // 한글 필드명 저장
}
@Override
public boolean isValid(Object object, ConstraintValidatorContext context) {
if(!ObjectUtils.isEmpty(object)){
return true;
}
// 필드명을 자동으로 가져오기 위해 컨텍스트에서 정보 조회
// 필드명 저장
String fieldName;
try {
fieldName = context.getDefaultConstraintMessageTemplate();
} catch (Exception e) {
fieldName = "값"; // 필드명을 가져오지 못할 경우 기본값 설정
}
String errorMsg = "";
if(StringUtils.isNotBlank(displayName) && StringUtils.isNotBlank(fieldName)){
errorMsg = String.format("%s(%s)", displayName, fieldName);
}
// 기본 에러 메시지를 동적으로 변경
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(
String.format("%s필드는 null이 될 수 없습니다.", errorMsg))
.addConstraintViolation();
return false; // 검증 실패
}
}
2) Checked.class(Interface)
- 커스텀 어노테이션
import com.oss.springBootTest.aop.CheckedValidator;
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Constraint(validatedBy = CheckedValidator.class) // 유효성 검사 로직과 연결
@Target({ ElementType.FIELD, ElementType.PARAMETER }) // 필드, 파라미터에 적용 가능
@Retention(RetentionPolicy.RUNTIME) // 런타임까지 유지
public @interface Checked {
String message() default "";// 노출메세지
String name() default ""; // 필드명(한글명)
Class<?>[] groups() default {}; // 그룹 지정 (기본값)
Class<? extends Payload>[] payload() default {}; // 추가 정보 제공 (기본값)
}
3) ShppDircBoxDto.class
- api 테스트를 위한 Dto
import com.oss.springBootTest.dto.annotation.Checked;
import com.oss.springBootTest.dto.annotation.ValidationGroups;
import lombok.*;
@ToString
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ShppDircBoxDto {
// Getter 메서드들
@Checked(message = "shppNo", name = "배송번호", groups = {ValidationGroups.CreateGroup.class, ValidationGroups.UpdateGroup.class}) // shppNo 필드에 어노테이션 적용
private String shppNo;
@Checked(groups = ValidationGroups.CreateGroup.class) // shppBoxSeq 필드에 어노테이션 적용
private String shppBoxSeq;
@Checked(message = "wblNo", name = "운송장번호", groups = ValidationGroups.UpdateGroup.class)
private String wblNo;
}
4) GlobalExceptionHandler.class
- api 테스트 시 에러 문구를 응답해주기 위한 ControllerAdvice
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Map<String, Object>> handleValidationExceptions(MethodArgumentNotValidException ex) {
Map<String, Object> errors = new HashMap<>();
Map<String, String> fieldErrors = new HashMap<>();
for (FieldError error : ex.getBindingResult().getFieldErrors()) {
fieldErrors.put(error.getField(), error.getDefaultMessage());
}
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
errors.put("timestamp", LocalDateTime.now().format(formatter));
errors.put("status", HttpStatus.BAD_REQUEST.value());
errors.put("error", "Bad Request");
errors.put("fieldErrors", fieldErrors);
return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
}
}
5) ShppDircBoxController.class
- 생성, 수정 api 테스트 Controller
import com.oss.springBootTest.dto.ShppDircBoxDto;
import com.oss.springBootTest.dto.annotation.ValidationGroups;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequiredArgsConstructor
@RestController
@RequestMapping("/api")
public class ShppDircBoxController {
@PostMapping("/check")
public ResponseEntity<String> checkFields(@RequestBody @Validated(ValidationGroups.CreateGroup.class) ShppDircBoxDto shppDircBox) {
System.out.println("shppDircBox = " + shppDircBox);
return ResponseEntity.ok("Validation Passed!");
}
@PostMapping("/update")
public ResponseEntity<String> updateFields(@RequestBody @Validated(ValidationGroups.UpdateGroup.class) ShppDircBoxDto shppDircBox) {
System.out.println("shppDircBox = " + shppDircBox);
return ResponseEntity.ok("Validation Passed!");
}
}
- 테스트 결과
1) CreateGroup


'백엔드 면접준비 > Java' 카테고리의 다른 글
7. 동기,비동기, 블로킹, 논블록킹 (1) | 2025.03.08 |
---|---|
6. Garbage Collection(GC) (1) | 2025.03.07 |
3. Java Collection Framework(JCF) (1) | 2025.02.03 |
2. Java 멀티쓰레드 환경(volatile, synchronized, atomic) (1) | 2025.02.02 |
1.JVM (0) | 2025.02.02 |