[Java] @ 어노테이션
Annotation
어노테이션은 잘만 사용하면 정말 유용한 Java의 구문이다.
기본적인 종류는 몇 가지에 한정되지만, 내가 원하는대로 커스텀 어노테이션을 만들어 사용할 수 있다.
어노테이션의 본질적인 목적은 소스 코드에 메타데이터를 표현하는 것.
하지만 단순히 부가적인 표현을 넘어, reflection을 이용하면 어노테이션 지정만으로 원하는 클래스를 주입하는 것도 가능하다.
Built-in Annotation
Java에서 기본적으로 제공하는 어노테이션은 다음과 같다.
- @Override : 오버라이딩할 때 사용.
- @Deprecated : 더이상 사용되지않는 메서드를 지정한다. 해당 어노테이션이 붙은 메서드를 사용했을 시 컴파일 경고.
- @SuppressWarnings : 컴파일 경고를 무시한다.
- @SafeVarargs : 제네릭과 같은 가변인자 파라미터를 사용할 때, 경고를 무시한다.
- @FunctionalInterface : 람다 함수를 위한 인터페이스를 명시적으로 지정한다. 메서드가 없거나 두 개 이상이면 컴파일 에러 발생.
Meta Annotation
메타 어노테이션은 커스텀 어노테이션을 만들 때 사용된다.
메타 어노테이션의 종류는 다음과 같다.
- @Retention : 해당 어노테이션이 저장될 범위를 지정한다.
코드단에서만 저장되고말지, 컴파일된 클래스 파일 안에도 저장되어야할지, 또는 런타임 내내 유지할지. - @Documented : 문서에 어노테이션의 정보를 포함한다.
- @Target : 해당 어노테이션이 적용될 위치를 지정한다.
- @Inherited : 자식 클래스가 해당 어노테이션을 상속받을 수 있게 한다.
- @Repeatable : 반복적으로 해당 어노테이션을 선언할 수 있게 한다.
Declare Custom Annotation
Java에서 커스텀 어노테이션을 만드는 방법 자체는 간단하다.
public @Interface MyAnnotation { }
위의 형식에서 메타 어노테이션을 붙여 기능을 추가해가며 만들면 된다.
@Inherited @Documented @Retention(RetentionPolicy.RUNTIME) // 컴파일 이후에도 JVM에 의해 참조가 가능하다. // @Retention(RetentionPolicy.CLASS) // 컴파일러가 클래스를 참조할 때까지 유효하다. // @Retention(RetentionPolicy.SOURCE) // 컴파일 이후 해당 어노테이션 정보는 사라진다. @Target({ ElementType.PACKAGE, // 패키지 선언부에 해당 어노테이션을 기입한다. ElementType.TYPE, // 타입 선언부에 ~ ElementType.CONSTRUCTOR, // 생성자 선언부에 ~ ElementType.FIELD, // 필드 선언부에 ~ ElementType.METHOD, // 메서드 선언부에 ~ ElementType.ANNOTATION_TYPE, // 어노테이션 타입 선언부에 ~ ElementType.LOCAL_VARIABLE, // 지역변수 선언부에 ~ ElementType.PARAMETER, // 매개변수 선언부에 ~ ElementType.TYPE_PARAMETER, // 매개변수 타입 선언부에 ~ ElementType.TYPE_USE // 타입 사용부에 ~ }) public @Interface MyAnnotation { // enum 타입을 선언할 수 있다. public enum Color {RED, GREEN, BLUE} // String은 기본 자료형이 아니지만 사용이 가능하다. String value(); // 배열 형태도 사용이 가능하다. int[] values(); // enum 형태를 사용하는 방법 Color color() default Color.RED; }
Simple Example
@StringInjector 라는 커스텀 어노테이션을 만들어보자.
/** * String 문자열을 주입하기 위해 선언할 수 있는 어노테이션. * 필드에만 선언할 수 있고, JVM이 해당 어노테이션 정보를 참조한다. */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface StringInjector { String value() default "This is StringInjector."; }
@StringInjector 어노테이션을 적용할 클래스는 다음과 같다.
@Data public class MyObject { @StringInjector("My name is Pangtrue.") private String name; @StringInjector private String testText; }
다음 코드는 어노테이션을 찾고, 주입하는 역할을 하는 컨테이너 클래스다.
@NoArgsConstructor public class MyContextContainer { /** * 파라미터로 받은 클래스의 객체를 반환한다. */ public <T> T get(Class clazz) throws IllegalAccessException, InstantiationException { T instance = (T) clazz.newInstance(); instance = invokeAnnotations(instance); return instance; } private <T> T invokeAnnotations(T instance) throws IllegalAccessException { Field[] fields = instance.getClass().getDeclaredFields(); for (Field field : fields) { StringInjector annotation = field.getAnnotation(StringInjector.class); if (annotation != null && field.getType() == String.class) { field.setAccessable(true); field.set(instance, annotation.value()); } } return instance; } }
위 예제 코드들의 실행을 담당할 메인 엔트리.
public class AnnotationDemo { public static void main(String[] args) throws IllegalAccessException, InstantiationException { MyContextContainer demo = new MyContextContainer(); MyObject obj = demo.get(MyObject.class); System.out.println(obj.getName()); // print is "My name is Pangtrue." System.out.println(obj.gettestText()); // print is "This is StringInjector." } }
참고 사이트
'Programming > Java' 카테고리의 다른 글
[Java] volatile 키워드 (0) | 2020.04.13 |
---|---|
[Java] synchronized 키워드 (0) | 2020.04.13 |
[Java] Optional<T> 클래스 (0) | 2020.03.24 |
[Java ] 함수형 인터페이스 ( Functional Interface ) (0) | 2020.03.24 |
[Java] 메서드 참조 ( Method Reference ) (0) | 2020.03.24 |
댓글
이 글 공유하기
다른 글
-
[Java] volatile 키워드
[Java] volatile 키워드
2020.04.13 -
[Java] synchronized 키워드
[Java] synchronized 키워드
2020.04.13 -
[Java] Optional<T> 클래스
[Java] Optional<T> 클래스
2020.03.24 -
[Java ] 함수형 인터페이스 ( Functional Interface )
[Java ] 함수형 인터페이스 ( Functional Interface )
2020.03.24
댓글을 사용할 수 없습니다.