어노테이션 그리고 리플렉션

어노테이션

어노테이션은 컴파일 과정과 실행 과정에서 코드를 어떻게 컴파일하고 처리할 것인지를 알려주는 정보이다.
@가 붙는 형태로 정의된다.

어노테이션은 다음의 용도로 사용된다.

1
2
3
컴파일러에게 문법에러 체크 ex(@Override)
개발 툴이 코드를 자동 생성할 수 있도록 정보제공
실행시 특정기능을 실행하도록 정보제공

어노테이션 정의 및 사용법

어노테이션 정의는 다음과 같이 할 수 있다.

Annotation
1
2
3
4
public @interface SHAnnotation {
String feature();
int age() default 0;
}

위에 정의한 어노테이션을 사용하기 위해서는 다음과 같이 사용할 수 있다.

Annotation
1
2
3
4
@SHAnnotation(feature="개발자", age=27);
혹은
@SHAnnotation(feature="개발자");
//아래의 경우 디폴트로 되어있는 age값을 세팅하지 않았다.

어노테이션을 적용할 수 있는 대상은 java.lang.annotation.ElementType에 정의 되어있다.
해당 열거형을 보면 아래와 같이 다양하게 존재한다.
즉 어노테이션을 적용할 수 있는 대상은 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// Field descriptor #37 Ljava/lang/annotation/ElementType;
public static final enum java.lang.annotation.ElementType TYPE;

// Field descriptor #37 Ljava/lang/annotation/ElementType;
public static final enum java.lang.annotation.ElementType FIELD;

// Field descriptor #37 Ljava/lang/annotation/ElementType;
public static final enum java.lang.annotation.ElementType METHOD;

// Field descriptor #37 Ljava/lang/annotation/ElementType;
public static final enum java.lang.annotation.ElementType PARAMETER;

// Field descriptor #37 Ljava/lang/annotation/ElementType;
public static final enum java.lang.annotation.ElementType CONSTRUCTOR;

// Field descriptor #37 Ljava/lang/annotation/ElementType;
public static final enum java.lang.annotation.ElementType LOCAL_VARIABLE;

// Field descriptor #37 Ljava/lang/annotation/ElementType;
public static final enum java.lang.annotation.ElementType ANNOTATION_TYPE;

// Field descriptor #37 Ljava/lang/annotation/ElementType;
public static final enum java.lang.annotation.ElementType PACKAGE;

// Field descriptor #37 Ljava/lang/annotation/ElementType;
public static final enum java.lang.annotation.ElementType TYPE_PARAMETER;

// Field descriptor #37 Ljava/lang/annotation/ElementType;
public static final enum java.lang.annotation.ElementType TYPE_USE;

어노테이션이 적용될 대상을 지정할 땐 @Target를 활용한다.

Annotation
1
2
3
4
5
6
7
8
9
10
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;

@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
public @interface SHAnnotation {
String feature();
int age() default 0;
}

// 적용 대상을 TYPE(클래스, 인터페이스, 열거타입), FILED로 설정하였다.

그럼 아래와 같이 어노테이션 적용이 가능해진다.

Annotation
1
2
3
4
5
6
7
8
9
10
11
12
13
@SHAnnotation(feature="개발자", age=27)
public class AnnotationTest {

@SHAnnotation(feature="디자이너")
public void method1() {
System.out.println("메소드1");
}

@SHAnnotation(feature="기획자", age=30)
public void method2() {
System.out.println("메소드2");
}
}

어노테이션 유지 정책

어노테이션은 용도에 따라 어느 범위까지 유지할 것인지 지정 가능하다. 세가지로 나뉘는데 다음과 같다.

1
2
3
SOURCE - 소스상에서만 유지
CLASS - 바이트 코드 까지 유지
RUNTIME - 바이트 코드까지 유지하며 리플렉션을 이용해 런타임 시 어노테이션 정보를 얻을 수 있다.

리플렉션?

위에 리플렉션에 대해 설명하자면 런타임 시에 클래스의 메타 정보를 얻는 기능을 의미한다. 클래스의 필드, 생성자, 메소드, 적용된 어노테이션 등을 런타임 시에 알아낼 수 있다.

다시 돌아와서 어노테이션의 유지는 @Retention으로 지정할 수 있다. 대부분 어노테이션은 런타임시에 유지되도록 하는경우가 많다.
다음은 어노테이션이 런타임시에 유지되도록 하는 코드이다.

Annotation
1
2
3
4
5
6
7
8
9
10
11
12
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface SHAnnotation {
String feature();
int age() default 0;
}

런타임 중 어노테이션 정보 사용

어노테이션을 만들었으면 사용방법 또한 알아야 할 것이다. 이에 대해 자세히 알아보자
클래스에 적용된 어노테이션 정보를 얻으려면 Class 클래스를 이용하면 되지만 필드, 생성자, 메소드에 적용된 어노테이션 정보를 얻으려면 Class 클래스의 메소드를 통해 리플렉션 과정이 필요하다. 이 말이 이해가 안되면 코드를 보고 이해하자.

위 까지 모든 과정을 거쳤으면 아래 실습이 문제없을것이다.

Annotation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import java.lang.reflect.Method;

public class PrintAnnotation {
public static void main(String[] args) {

SHAnnotation shAnnotation;

// 클래스의 어노테이션 정보 가져오기
shAnnotation = AnnotationTest.class.getAnnotation(SHAnnotation.class);
System.out.println(AnnotationTest.class.getName());
System.out.println(shAnnotation.feature());
System.out.println();

// 리플렉션을 통해 선언된 메소드 정보 가져오기
Method[] declaredMethods = AnnotationTest.class.getDeclaredMethods();

for(Method method:declaredMethods) {
//SHAnnotation 객체 얻기
shAnnotation = method.getAnnotation(SHAnnotation.class);

//어노테이션이 적용되었는지 체크
if(method.isAnnotationPresent(SHAnnotation.class)) {
System.out.println(method.getName());
System.out.println(shAnnotation.feature());
}

try {
//메소드 호출부
method.invoke(new AnnotationTest());
System.out.println();
}catch(Exception e) {
System.out.println(e.getStackTrace());
}
}
}
}

Share