자바

JAVA 자바 어노테이션 유지 정책과 런타임 시 어노테이션 정보 활용하기

알통몬_ 2017. 3. 12. 19:29
반응형


안녕하세요 알통몬입니다.

공감 및 댓글은 포스팅 하는데 아주아주 큰 힘이 됩니다!!

포스팅 내용이 찾아주신 분들께 도움이 되길 바라며

더 깔끔하고 좋은 포스팅을 만들어 나가겠습니다^^

 

어노테이션 유지 정책

 어노테이션 정의 시 사용 용도에 따라 @AnnotationName을 어느 범위까지 유지할 것인지 지정해야 합니다.

소스상에만 유지할 건지, 컴파일된 클래스까지 유지할 건지, 런타임 시에도 유지할 건지를 지정해야 합니다. 

어노테이션 유지 정책은 

java.lang.annotation.RetentionPolicy 열거 상수로 아래와 같이 정의되어 있습니다.


RetentionPolicy 열거 상수  설명

SOURCE                    소스상에서만 어노테이션 정보를 유지한다. 소스 코드                                                               를 분석할 때만 의미가 있으며 바이트 코드 파일에는                                                                 정보를 남기지 않는다.

CLASS                       바이트 코드 파일까지 어노테이션 정보를 유지한다.

                               리플랙션을 이용해서 어노테이션 정보를 얻을 수 없다.

RUNTIME                    바이트 코트까지 어노테이션 정보를 유지하면서 리플랙션을 

                              이용해서 런타임 시에 어노테이션 정보를 얻을 수 있다.


리플랙션(Reflection) : 런타임 시에 클래스의 메타 정보를 얻는 기능. 

클래스가 가지고 있는 필드가 무엇인지, 어떤 생성자를 가지고 있는지, 어떤 메서드를 가지고 있는지, 적용된 어노테이션이 무엇인지 알아내는 것. 

어노테이션 유지정책을 이용할 때는 @Retention 어노테이션을 사용합니다. 

@Retention의 기본 엘리먼트인 value는 RetentionPolicy 타입이므로 위 세 가지 상수 중 하나를 지정.

코드 자동 생성 툴을 개발하지 않는 이상, 작성하는 어노테이션은 대부분 런타임 시점에 사용하기 위한 용도


사용 ex)

@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})

@Retention(RetentionPolicy.RUNTIME)

public @interface AnnotationName {

}


런타임 시 어노테이션 정보 활용하기

 어노테이션 자체는 표식일 뿐이지만, 리플랙션을 이용해서 어노테이션의 적용 여부와 엘리먼트 값을 읽고 적절히 처리할 수 있습니다. 클래스에 적용된 어노테이션 정보를 얻으려면 java.jang.Class를 이용하면 되지만, 필드, 생성자, 메서드에 적용된 어노테이션 정보를 얻으려면 Class의 다음 메서드를 통해서 java.lang.reflect 패키지의 Field, Constructor, Method 타입의 배열을 얻어야 합니다.


리턴 타입        메서드명(매개 변수)       설명

Field[]           getFields()                 필드 정보를 Field 배열로 리턴

Constructor[]   getConstructors()          생성자 정보를 Constructor 배열로 리턴

Method[]       getDeclaredMethods()     메서드 정보를 Method 배열로 리턴


그런 다음 Class, Field, Constructor, Method가 가지고 있는 다음 메서드를 호출해서 적용된 어노테이션 정보를 얻을 수 있습니다.


리턴 타입      메서드명(매개변수)

boolean       isAnnotationPresent(Class<? extends Annotation> annotationClass)

                지정한 어노테이션이 적용되었는지 여부, Class에서 호출했을 때 상위 클래스에 적용                                된 경우도 true를 리턴합니다.


Annotation    getAnnotation(Class<T> annotationClass)

                지정한 어노테이션이 적용되어 있으면 어노테이션을 리턴하고 그렇지 않으면 null을 리                              턴합니다. Class에서 호출했을 때 상위 클래스에 적용된 경우에도 어노테이션을 리턴합니다.


Annotation[]  getAnnotations()

                적용된 모든 어노테이션을 리턴합니다. Class에서 호출했을 때 상위 클래스에 적용된                              어노테이션도 모두 포함합니다. 적용된 어노테이션이 없을 경우 길이가 0인 배열을 리턴합니다.

                

Annotation[]   getDeclaredAnnotations()

                 직접 적용된 모든 어노테이션을 리턴합니다. Class에서 호출했을 때 상위 클래스에 

                 적용된 어노테이션은 포함하지 않습니다.


사용 예제)

1)

package sec15.exam01_annotation;


import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;


@Target({ElementType.METHOD})

@Retention(RetentionPolicy.RUNTIME)

public @interface PrintAnnotation {

String value() default "-";

int number() default 15;

}

@Target은 메서드에만 적용하도록 했고, @Retention은 런타임 시까지 어노테이션 정보를 유지하도록 했습니다. 
2)

printAnnotation 을 적용한 클래스입니다.
package sec15.exam01_annotation;

public class Service {
@PrintAnnotation
public void method1() {
System.out.println("실행 내용1");
}

@PrintAnnotation("*")
public void method2() {
System.out.println("실행 내용2");
}
@PrintAnnotation(value="#", number=20)
public void method3() {
System.out.println("실행 내용3");
}
}


3)
package sec15.exam01_annotation;

import java.lang.reflect.Method;

public class PrintAnnotationExample {
public static void main(String[] args) {
//Service 클래스로부터 메소드 정보를 얻음
Method[] declaredMethods = Service.class.getDeclaredMethods();
                                  Service 클래스에 선언된 메소드 얻기(리플랙션)
//Method 객체를 하나씩 처리
for(Method method : declaredMethods) {
//PrintAnnotation이 적용되었는지 확인
if(method.isAnnotationPresent(PrintAnnotation.class)) {
//PrintAnnotation 객체 얻기
      PrintAnnotation printAnnotation = method.getAnnotation(PrintAnnotation.class);
//메소드 이름 출력
System.out.println("[" + method.getName() + "] ");
//구분선 출력
for(int i=0; i<printAnnotation.number(); i++) {
System.out.print(printAnnotation.value());
}
System.out.println();
try {
//메소드 호출
method.invoke(new Service());
} catch (Exception e) {}
System.out.println();
}
}
}
}
 


반응형