자바

어노테이션

tttck88 2019. 9. 17. 18:26

어노테이션은 메타데이터기 때문에 컴파일 과정과 실행 과정에서 코드를 어떻게 컴파일하고 처리할 것인지를 알려주는 정보이다.

 

어노테이션은 다음 세 가지 용도로 쓰인다.

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();
				}
			}
		}
	}

}

 

출처 - 이것이 자바다