어노테이션
어노테이션은 메타데이터기 때문에 컴파일 과정과 실행 과정에서 코드를 어떻게 컴파일하고 처리할 것인지를 알려주는 정보이다.
어노테이션은 다음 세 가지 용도로 쓰인다.
1. 컴파일러에게 코드 문법 에러를 체크하도록 정보를 제공
2. 소프트웨어 개발 툴이 빌드나 배치시 코드를 자동으로 생성할 수 있도록 정보를 제공
3. 실행 시(런타임 시) 특정 기능을 실행하도록 정보를 제공
어노테이션 타입 정의와 적용
public @interface AnnotationName {
}
이렇게 정의한 어노테이션은 코드에서 다음과 같이 사용한다.
@AnnotationName
어노테이션은 엘리먼트를 멤버로 가질 수 있다. 각 엘리먼트는 타입과 이름으로 구성되며, 디폴트 값을 가질 수 있다.
pubic @interface AnnotationName {
타입 elementName() {default 값};
}
어노테이션 적용 대상
어노테이션이 적용될 대상을 지정할 때에는 @Target 어노테이션을 사용한다.
@Target의 기본 엘리먼트인 value는 ElementType 배열을 값으로 가진다.
@Target({ElementType.TYPE,ElementType.FILELD,ElementType.METHOD})
public @interface AnnotationName {
}
위와 같은 어노테이션을 정의할 경우에는 클래스,필드,메소드에만 어노테이션이 적용될 수 있다.
@AnnotationName
public class ClassName {
@AnnotationName
private String fieldName;
//@AnnotationName (x) ---- @Target에 Construct가 없어 생성자는 적용 못한다.
public ClassName() {}
@AnnotationName
public void methodName() {}
}
어노테이션 유지 정책
어노테이션 정의 시 한 가지 더 추가해야 할 내용은 사용 용도에 따라 @AnnotationName을 어느범위까지 유지할 것인지 지정해야 한다. 즉 소스상에서만 유지할 건지, 컴파일도니 클래스까지 유지할 건지, 런타임 시에도 유지할 건지를 지정해야 한다.
SOURCE - 소스상에서만 어노테이션 정보를 유지한다. 소스 코드를 분석할 때만 의미가 있으며, 바이트 코드 파일에는 정보가 남지 않는다.
CLASS - 바이트 코드파일까지 어노테이션 정보를 유지한다. 하지만 리플렉션을 이용해서 어노테이션 정보를 얻을 수는 없다.
RUNTIME - 바이트 코드 파일까지 어노테이션 정보를 유지하면서 리플렉션을 이요해서 런타입 시에 어노테이션 정보를 얻을 수 있다.
(리플렉션이란 런타임 시에 클래스의 메타 정보를 얻는 기능을 말한다. 예를 들어 클래스가 가지고 있은 필드가 무엇인지, 어떤 생성자를 갖고 있는지, 어떤 메소드를 가지고 있는지, 적용된 어노테이션이 무엇인지 알아내는 것이 리플렉션이다.)
@Target({ElementType.TYPE,ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationName {
}
런타임 시 어노테이션 정보 사용하기
getFields() - 필드 정보를 배열로 리턴
getConstructors() - 생성자 정보를 배열로 리턴
getDeclaredMethods() - 메소드 정보를 배열로 리턴
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface PrintAnnotation {
String value() default "-";
int number() default 15;
}
public class Service {
@PrintAnnotation
public void method() {
System.out.println("실행 내용1");
}
@PrintAnnotation("*")
public void method2() {
System.out.println("실행 내용2");
}
@PrintAnnotation(value="#", number=20)
public void method3() {
System.out.println("실행 내용3");
}
}
public class PrintAnnotaionExample {
public static void main(String[] args) {
//Service 클래스로부터 메소드 정보를 얻음
Method[] declartMethods = Service.class.getDeclaredMethods();
//Method 객체를 하나씩 처리
for(Method method : declartMethods) {
//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.println(printAnnotation.value());
}
System.out.println();
try {
//메소드 호출
method.invoke(new Service());
} catch (Exception e) {
System.out.println();
}
}
}
}
}
출처 - 이것이 자바다