Retention
Retention
이 문서에서는 Retention 설정 옵션에 따른 차이를 다룬다.
@interface Retention
Library에서 Retention 코드를 찾아보면 다음과 같다. 편의상 주석은 제거하였다.
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
RetentionPolicy value();
}@Documented- 작성된 Annotation이 Javadoc에 문서화 됨을 표시@Target- 이 Annotation이 다른 Annotation type에 작성될 수 있음을 표시
Annotation 내부에는 RetentionPolicy라는 Enum 값을 저장할 수 있는 value 속성이 존재한다.
enum RetentionPolicy
RetentionPolicy의 코드는 다음과 같다.
public enum RetentionPolicy {
/**
* Annotations are to be discarded by the compiler.
*/
SOURCE,
/**
* Annotations are to be recorded in the class file by the compiler
* but need not be retained by the VM at run time. This is the default
* behavior.
*/
CLASS,
/**
* Annotations are to be recorded in the class file by the compiler and
* retained by the VM at run time, so they may be read reflectively.
*
* @see java.lang.reflect.AnnotatedElement
*/
RUNTIME
}설정 가능한 RetentionPolicy 값은 다음과 같다.
SOURCE - 컴파일러에 의해 삭제되는 Annotation
CLASS - 컴파일러에 의해 클래스파일에 기록되지만 런타임 시 VM에서는 관리하지 않음
RUNTIME - 컴파일러에 의해 클래스파일에 기록되고 VM에서 관리하여 실행 중 읽을 수 있음
RetentionPolicy.SOURCE
RetentionPolicy.SOURCE로 설정된 Annotation은 컴파일과 동시에 사라진다. 따라서 다음 용도로 사용이 가능하다.
코드상에 단순한 표식(Marking) 생성
컴파일 시 특정 코드로 치환되도록 자동화 구현
코드상에 단순한 표식 설정
예를 들어 테스트가 진행중인 메소드에 다음과 같이 표시를 남겨 정보를 줄 수 있다.
먼저 Annotation을 다음과 같이 생성한다.
그리고 특정 메소드에 Annotation을 작성하고 옵션으로 정보를 설정한다.
생성된 class 파일을 찾아서 디컴파일하면 다음과 같이 표시된다.
@TestInProgress Annotation이 사라진 것을 확인할 수 있다.
컴파일 시 특정 코드로 치환되도록 자동화 구현
대표적인 라이브러리로 Lombok이 있다. Lombok에서 사용하는 @Getter @Setter @ToString @EqualsAndHashCode 등이 해당된다.
Lombok을 이용하여 다음과 같이 클래스를 하나 만든다.
이 클래스에는 Lombok에서 제공하는 Annotation 4종류를 사용하였다.
@Data - Getter/Setter, ToString, EqualsAndHashCode 생성
@NoArgsConstructor - 기본 생성자 생성
@AllArgsConstructor - 모든 필드 초기화 생성자 생성
@Builder - 빌더 패턴을 위한 빌더 클래스 생성
디컴파일러를 이용하여 생성된 클래스를 살펴보면 다음과 같다.
생성된 내부에 Java에서 작성한 적이 없는 코드들이 추가되어 있는 것을 확인할 수 있다. 또한 @Builder 로 인하여 빌더 클래스가 하나 더 생긴것을 확인할 수 있다.
사용한 Lombok의 Annotation은 제거된 것을 확인할 수 있다. 각각의 Annotation을 보면 Retention 설정이 RetentionPolicy.SOURCE로 되어 있는 것을 확인할 수 있다.
해당 내용들을 직접 적용하려면 annotation processor 등의 처리가 필요하다.
RetentionPolicy.CLASS
RetentionPolicy.CLASS로 설정된 Annotation은 컴파일 이후의 바이트 코드까지 유지되지만 런타임 시점까지 반드시 유지할 필요는 없다. 따라서 RetentionPolicy.SOURCE와 RetentionPolicy.RUNTIME의 중간 정도로 이해할 수 있다. 보기에 따라서 상당히 애매해 보일 수 있지만 자바 애플리케이션을 만들 때 다수의 jar 파일을 사용하고, 이 jar 파일에는 class 파일만 들어있다는 것을 생각해보면 배포된 파일에는 포함되어야 하지만 실행 시에는 포함될 필요가 없는 경우 사용하는 형태라고 볼 수 있다.
RetentionPolicy.RUNTIME
RetentionPolicy.RUNTIME으로 설정된 Annotation은 VM에서 런타임 시점까지 유지한다. 런타임 시점까지 유지된다는 것은 코드를 통해 Annotation의 유무와 내부에 설정된 옵션을 읽을 수 있다는 의미이다. Java Reflection과 같은 기술을 사용하여 Annotation을 해석하고, 이에 따라 다른 작업을 수행할 수 있다.
다음 Book 클래스를 통해 좀 더 자세히 살펴본다.
Book 클래스에는 @TestEntity 라는 Annotation이 설정되어 있다. @TestEntity의 코드는 다음과 같다.
Retention 설정이 RetentionPolicy.RUNTIME으로 되어 있기 때문에 실행 중에도 Annotation이 유지되며 Java Reflection을 이용하여 이를 알아낼 수 있다.
메소드는 Method, 생성자는 Constructor, 필드는 Field 클래스에 존재하는 annotation 반환 명령을 이용하여 특정 Annotation이 존재하는지 확인할 수 있고, 필요하다면 모든 Annotation 목록을 반환하도록 만들 수 있다.
getAnnotation(Class) - 상속된 Annotation을 포함하여 특정 Annotation의 유무 조회
getDeclaredAnnotation(Class) - 상속된 Annotation을 제외하고 특정 Annotation의 유무 조회
getAnnotations() - 상속된 Annotation을 포함하여 목록 조회
getDeclaredAnnotations() - 상속된 Annotation을 제외하고 목록 조회
Last updated