핵심 정리
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RequiresRole {
String value();
}
class UserService {
@RequiresRole("admin")
void deleteUser(long userId) {
// ...
}
}
Method method = UserService.class.getDeclaredMethod("deleteUser", long.class);
RequiresRole role = method.getAnnotation(RequiresRole.class);
if (role != null && role.value().equals("admin")) {
System.out.println("관리자 권한 필요");
}문법
annotation을 읽을 때 먼저 보는 세 가지
| 요소 | 의미 |
|---|---|
@interface | 새 annotation 타입 선언 |
@Retention | 소스, 클래스 파일, 런타임 중 어디까지 남길지 |
@Target | class, method, field, parameter 등 붙일 수 있는 위치 |
| annotation element | String value() 같은 설정 값 |
getAnnotation(...) | 런타임에 annotation 읽기 |
@Retention: 언제까지 남길지 정하기
annotation은 붙였다고 항상 런타임에서 읽을 수 있는 것이 아닙니다. 컴파일러 힌트만 필요하면 SOURCE, 클래스 파일에 남기되 런타임 reflection 조회가 필요 없으면 CLASS, 런타임 프레임워크가 읽어야 하면 RUNTIME을 씁니다.
// 컴파일러나 정적 분석 도구용
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.METHOD)
public @interface GeneratedByTool {
}
// 런타임 프레임워크가 reflection으로 읽어야 함
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Controller {
String path();
}@Target: 붙일 수 있는 위치 제한
@Target은 annotation의 사용 위치를 제한합니다. 제한이 없으면 너무 넓게 붙을 수 있어 실수 범위가 커집니다. 의도가 method용이면 METHOD, class나 interface용이면 TYPE, 생성자 파라미터 검증용이면 PARAMETER처럼 좁히는 편이 안전합니다.
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Audit {
String value() default "";
}
@Audit("user-api")
class UserController {
@Audit("delete-user")
void delete(long id) {
}
}annotation element에는 primitive, String, Class, enum, annotation, 그리고 이들의 배열만 사용할 수 있습니다. 객체나 List 같은 임의 타입을 넣을 수 없습니다.
enum LogLevel {
INFO, WARN, ERROR
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Loggable {
LogLevel level() default LogLevel.INFO;
Class<?> target();
String[] tags() default {};
}선택 기준
| 목적 | 설정 |
|---|---|
| 컴파일러 경고 제어, 코드 생성 힌트 | RetentionPolicy.SOURCE |
| bytecode 분석 도구가 읽음 | RetentionPolicy.CLASS |
| Spring, JUnit 같은 런타임 프레임워크가 읽음 | RetentionPolicy.RUNTIME |
| 클래스나 인터페이스에만 붙임 | ElementType.TYPE |
| 메서드에만 붙임 | ElementType.METHOD |
| 파라미터 검증용 | ElementType.PARAMETER |
주의사항
annotation은 동작을 자동으로 만들지 않습니다. annotation을 읽는 컴파일러 플러그인, annotation processor, reflection 코드, 프레임워크 인터셉터가 있어야 실제 동작이 생깁니다.
@RequiresRole("admin")
void deleteUser(long userId) {
// annotation만 붙였다고 권한 검사가 자동 실행되지는 않음
}런타임에서 읽어야 하는 annotation에 RUNTIME retention을 빠뜨리면 reflection으로 조회되지 않습니다. 프레임워크가 annotation을 못 찾는다면 retention 설정부터 확인하는 편이 빠릅니다.
참고 링크
3 sources