이 포스팅의 코드 및 정보들은 강의를 들으며 정리한 내용을 토대로 작성한 것입니다.
public @interface Pizza {
}
먼저 휫자 annotation을 선언하고
@Retention(RetentionPolicy.RUNTIME)
public @interface Pizza {
}
Retention 전략을 준다. @Retention은 annotation을 사용한, 그곳에 있는 annotation 정보를 언제까지 유지할 것인가에 대해 지정할 수 있다.
@Retention(RetentionPolicy.RUNTIME)
@Target()
public @interface Pizza {
}
@Target은 annotation을 사용할 곳인데 Java8에는 크게 두 개의 type이 추가됐다.
public static void main(String[] args) {
}
static class FeelsLikePizza<T> {
}
FeelsLikePizza<T>
가 어떤 특정한 타입을 사용하는, Generic한 클래스라고 정의할 때
T
라고 하는 Function에 정의되어 있는 <T, R>을 Type Parameter, Type Variable이라고 불리우며, 이 Type Parameter 옆에다가 붙일 수 있다.
이를 @Target(ElementType.TYPE_PARAMETER), 즉 ElementType.TYPE_PARAMETER
옵션이 허용해주는 것이다.
@Target(ElementType.TYPE_PARAMETER)
가 없어지면 컴파일 에러가 나면서 사용이 제한된다.
어떤 특정한 타입의 인자를 받는 메서드를 하나 만들고 접근 지시자 뒤
와 리턴 타입
사이에다가 타입을 지정한다.
접근 지시자
와 리턴 타입
사이에 있는 Type Parameter인 C와 print()의 파라미터 타입
인 C는 다르다.
@Target(ElementType.TYPE_PARAMETER)
를 정의했으므로, 접근 지시자
와 리턴 타입
사이에 있는 Type Parameter에도 annotation을 붙일 수 있다. 하지만 그냥 메서드의 파라미터 타입 옆에는 붙일 수 없다.
ElementType의 TYPE_PARAMETER보다 자유롭게 사용하고 싶을 때 TYPE_USE 옵션을 사용할 수 있다.
TYPE_PARAMETER를 포함해서 Type을 선언하는 모든 곳에 이 annotation을 쓸 수 있게 된다.
이렇게 휫자 annotation을 여러군데 놓을 수 있다.
지금은 이렇게 휫자를 여러 개 놓으면 컴파일 에러가 발생하지만 @Repeatable
을 써서 annotation의 중복을 허용하게 만들 수 있으며, 이는 annotation들을 감싸고 있다고 볼 수 있다.
public @interface PizzaContainer {
}
이 Container annotation type을 @Repeatable
에다가 선언해줘야 한다.
이때 Container가 가지고 있는 @Retention이나 @Target정보는 반드시 자기 자신이 감싸는 annotation보다 같거나 넓어야 한다. 보통은 같게 만들어 놓는다.
설정을 안 해놓거나 범위가 좁으면 이렇게 에러가 난다.
이렇게 Container에는 자기 자신이 감싸고 있을 annotation을 배열을 가지고 있으면 된다.
Pizza annotation에다가 문자열로 무슨 휫자인지 정의하도록 value()를 하나 선언해놓는다.
이렇게 다른 클래스에다가 중복해서 휫자라는 annotation을 선언할 수 있고, 이거를 가져다가 읽어서 쓰기만 하면 된다.
쓰는 방법은
첫째로 getAnnotationsByType으로 휫자 타입으로 바로 읽어오는 방법이 있다.
이 방법은 타입에 해당하는 다 가져오는데, 여기에서는 두 개의 annotation이 배열로 온다.
또는 Container type으로 가져오는 방법이 있는데, 이는 휫자 컨테이너에서 annotation 하나로 가져오면 된다.
휫자 컨테이너로 가져온 다음에
value()를 통해서 휫자 container의 배열을 꺼내오면 된다.
// Pizza.java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE_USE)
@Repeatable(PizzaContainer.class)
public @interface Pizza {
String value();
}
// PizzaContainer.java
@Rentention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE_USE)
public @interface PizzaContainer {
Pizza[] value();
}
// Main
@Pizza("포테이토")
@Pizza("고구마")
public class Main {
public static void main(String[] args) {
PizzaContainer pizzaContainer = Main.class.getAnnotation(PizzaContainer.class);
Arrays.stream(pizzaContainer.value()).forEach(c -> {
System.out.println(c.value()));
});
}
}