Java Annotation은 메타데이터를 코드에 추가하는 데 사용되며, 이를 통해 다양한 정보를 코드에 부여할 수 있습니다. 하지만 모든 Annotation이 항상 유지되지는 않습니다. Annotation이 어느 시점까지 유지될지는 RetentionPolicy에 따라 결정됩니다.
이 글에서는 RetentionPolicy가 무엇인지, 각 옵션(SOURCE, CLASS, RUNTIME)이 어떤 의미를 가지는지, 그리고 이를 실제로 어떻게 활용할 수 있는지 자세히 살펴보겠습니다.
1. RetentionPolicy란?
Java의 RetentionPolicy는 Annotation이 어느 시점까지 유지될지를 정의합니다. @Retention 어노테이션을 사용하여 RetentionPolicy를 지정할 수 있습니다.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Logging {
String value() default "";
}
RetentionPolicy에는 세 가지 옵션이 있습니다:
- SOURCE
- CLASS
- RUNTIME
이 옵션들은 각각 Annotation이 유지되는 기간을 결정합니다.
2. RetentionPolicy의 종류
(1) RetentionPolicy.SOURCE
- 설명: Annotation이 소스 코드에서만 유지됩니다. 컴파일 이후 .class 파일에는 포함되지 않습니다.
- 용도: 코드 레벨에서만 필요한 메타데이터로, 런타임이나 컴파일 이후에는 더 이상 필요 없는 경우 사용됩니다.
- 예: @Override, @SuppressWarnings
코드 예제
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.METHOD)
public @interface DeveloperNote {
String comment();
}
사용 예제
@DeveloperNote(comment = "This method is critical for performance")
public void process() {
// 메서드 로직
}
이 @DeveloperNote Annotation은 개발자가 코드를 읽을 때 참고용으로만 사용되며, 컴파일된 .class 파일에는 포함되지 않습니다.
(2) RetentionPolicy.CLASS
- 설명: Annotation이 컴파일된 .class 파일에 포함되지만, 런타임에는 사용되지 않습니다. JVM이 애플리케이션을 실행할 때는 이 정보를 읽을 수 없습니다.
- 용도: 런타임에서 필요하지 않지만, 컴파일 이후 다른 도구(예: 바이트코드 분석 도구)에서 활용할 수 있는 메타데이터를 저장할 때 사용됩니다.
- 기본값: RetentionPolicy.CLASS는 Annotation의 기본 RetentionPolicy입니다.
코드 예제
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
public @interface CompileTimeInfo {
String version();
}
사용 예제
@CompileTimeInfo(version = "1.0.0")
public class MyClass {
// 클래스 로직
}
이 Annotation은 .class 파일에는 포함되지만, 런타임에 Reflection으로 접근할 수는 없습니다.
(3) RetentionPolicy.RUNTIME
- 설명: Annotation이 컴파일된 .class 파일에 포함되고, 애플리케이션이 실행되는 동안(JVM 실행 시점)에도 유지됩니다. Reflection API를 사용하여 Annotation 정보를 읽을 수 있습니다.
- 용도: Spring, Hibernate, JPA 등 다양한 프레임워크와 라이브러리에서 동적으로 Annotation 정보를 처리할 때 사용됩니다.
- 예: @Entity, @Transactional, @Component
코드 예제
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Logging {
String level() default "INFO";
}
사용 예제
@Logging(level = "DEBUG")
public void execute() {
System.out.println("Executing method");
}
Reflection을 사용하여 Annotation 읽기
import java.lang.reflect.Method;
public class AnnotationTest {
public static void main(String[] args) throws Exception {
Method method = AnnotationTest.class.getMethod("execute");
if (method.isAnnotationPresent(Logging.class)) {
Logging logging = method.getAnnotation(Logging.class);
System.out.println("Logging level: " + logging.level());
}
}
@Logging(level = "DEBUG")
public void execute() {
System.out.println("Executing method");
}
}
출력 결과:
Logging level: DEBUG
3. RetentionPolicy 비교
RetentionPolicy소스 코드컴파일된 .class 파일런타임용도
SOURCE | 유지 | 포함 안 됨 | 사용 불가 | 개발자 주석, 코드 힌트 |
CLASS | 유지 | 포함 | 사용 불가 | 바이트코드 분석 도구 |
RUNTIME | 유지 | 포함 | 사용 가능 | Reflection, 프레임워크 |
4. RetentionPolicy 활용 사례
(1) SOURCE 활용
@Override와 같은 Annotation은 개발자가 코드 작성 시 참고할 수 있도록 도와줍니다. 컴파일 이후에는 의미가 없기 때문에 SOURCE로 설정됩니다.
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.METHOD)
public @interface CodeReview {
String reviewer();
String date();
}
(2) CLASS 활용
@CompileTimeInfo와 같은 Annotation은 런타임에는 필요 없지만, 컴파일 후 바이트코드를 분석하거나 다른 도구로 처리할 때 유용합니다.
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
public @interface Generated {
String value();
}
(3) RUNTIME 활용
@Logging, @Entity, @Component와 같은 Annotation은 런타임에 동적 처리를 위해 사용됩니다. 이는 Spring, Hibernate 등의 프레임워크에서 필수적입니다.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Transactional {
String isolation() default "DEFAULT";
}
5. RetentionPolicy 선택 가이드
Annotation을 만들 때, 어떤 RetentionPolicy를 선택할지 다음 기준을 참고하세요:
- 개발 단계에서만 필요한 경우: SOURCE를 사용.
- 개발자가 참고하거나 컴파일러가 경고를 생성하는 용도로 사용.
- 런타임에는 필요 없지만, .class 파일에 정보를 포함해야 하는 경우: CLASS를 사용.
- 바이트코드 분석, 문서 생성 도구에서 사용.
- Reflection 또는 프레임워크에서 동적으로 처리해야 하는 경우: RUNTIME을 사용.
- Spring, Hibernate, JPA 등의 프레임워크에서 Annotation을 활용.
6. 결론
Java의 RetentionPolicy는 Annotation의 유지 기간을 결정하는 중요한 요소입니다. 올바른 RetentionPolicy를 선택하면 코드의 의도를 명확히 하고, 컴파일러와 런타임 환경에서 적절히 동작하도록 제어할 수 있습니다.
- SOURCE는 코드 힌트와 주석에,
- CLASS는 바이트코드 분석 및 컴파일 이후 정보 제공에,
- RUNTIME은 Reflection 및 프레임워크 동작에 사용됩니다.
Annotation을 정의할 때 RetentionPolicy를 적절히 설정하여 효율적이고 명확한 코드를 작성해 보세요!