@Inherited 어노테이션이란?
설명
Java에서 사용하는 meta annotatino입니다.
meta annotation은 다른 annotation을 위한 annotation을 말합니다.
목적
특정 annotation을 상속 가능(inheritable) 하도록 만들 때 사용합니다.
사용 방식
특정 annotation에 @Inherited를 추가합니다.
제한사항
클래스 수준의 annotation에만 적용 가능합니다. 메소드나 필드 수준의 annotation에는 적용되지 않습니다.
인터페이스에 사용해도 구현체에는 상속되지 않습니다.
테스트를 해보면 다음과 같다.
@Inherited 예시 코드
MyInheritedAnnotation이란 커스텀 어노테이션을 만들고, @Inherited를 추가합니다.
그리고 ParentClass에서 해당 커스텀 어노테이션을 사용합니다.
그 후 ChildClass를 만들어서 ParentClass를 상속받고, 해당 ChildClass가 처음에 만든 MyInheritedAnnotation에게 영향을 받고 있는지 확인하는 테스트를 진행합니다.
@Inherited
@Retention(value = RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyInheritedAnnotation {
// 커스텀 어노테이션
}
@MyInheritedAnnotation
public class ParentClass {
// 커스텀 어노테이션을 사용하는 클래스
}
public class ChildClass extends ParentClass {
// 커스텀 어노테이션을 사용하는 클래스를 상속 받음.
}
public class AnnotationTest {
@Test
public void testInheritedAnnotation() {
// ParentClass에 @MyInheritedAnnotation이라는 커스텀 어노테이션이 존재하는지?
assertTrue(ParentClass.class.isAnnotationPresent(MyInheritedAnnotation.class));
// ChildClass에 마찬가지로 @MyInheritedAnnotatino이 존재하는지 확인.
assertTrue(ChildClass.class.isAnnotationPresent(MyInheritedAnnotation.class));
}
}
위와 같은 테스트 코드는 성공합니다. MyInheritedAnnotation에 @Inherited 어노테이션이 존재하기 때문에, 해당 어노테이션을 사용하는 클래스 (ParentClass)를 상속받은 ChildClass도 @MyInheritedAnnotatino을 추가한 것과 마찬가지이기 때문입니다.
@Inherited를 제거
아래와 같이 Inherited를 제거하면 어떻게 될까요?
@Retention(value = RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyInheritedAnnotation {
}
테스트 코드를 아래처럼 수정해야 합니다.
자세히보시면 두 번째 ChildClass를 비교하는 데이터가 assertFalse로 변경된 것을 확인할 수 있습니다.
ChildClass는 수정하지 않았지만, MyInheritedAnnotation에 @Inherited가 없어서 상속받아지지 않았습니다.
public class AnnotationTest {
@Test
public void testInheritedAnnotation() {
assertTrue(ParentClass.class.isAnnotationPresent(MyInheritedAnnotation.class));
// assertFalse
assertFalse(ChildClass.class.isAnnotationPresent(MyInheritedAnnotation.class));
}
}
@Inherited를 사용한 annotatino을 상속
여기서 개인적으로 궁금한건 MyInheritedAnnotation을 사용하는 annotation은 MyInheritedAnnotation에 적용된 Inherited가 적용되는지였습니다.
@Inherited
@Retention(value = RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyInheritedAnnotation {
}
@MyInheritedAnnotation
@Retention(value = RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ExtendedAnnotation {
}
@ExtendedAnnotation
public class ParentClass {
}
public class ChildClass extends ParentClass {
}
public class AnnotationTest {
@Test
public void testInheritedAnnotation() {
// assertFalse
assertFalse(ParentClass.class.isAnnotationPresent(MyInheritedAnnotation.class));
// assertFalse
assertFalse(ChildClass.class.isAnnotationPresent(MyInheritedAnnotation.class));
}
}
결론은 애초에 잘못된 생각이었습니다.
@RestController로 예를 들면 다음과 같습니다.
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {
@AliasFor(
annotation = Controller.class
)
String value() default "";
}
스프링 WEB에서 많이 사용하는 RestController annotatino을 사용할 땐, meta annotatino인 @Controller와 @ResponseBody가 지원하는 기능들을 사용할 수 있지만, 해당 @RestControlelr 어노테이션을 사용하는 클래스가 @Controller @ResponseBody를 사용한다고 의미하는 것은 아닌 것과 같았습니다.
'Java' 카테고리의 다른 글
[Java] Java에서 List를 Array로 변경하기 (0) | 2023.12.20 |
---|