- 명명 패턴
- 변수, 함수의 이름을 일관된 방식으로 작성하는 패턴
- 단점
- 오타나면 안된다.
- 명명패턴을 써야하는 곳(의도한 곳)에서만 쓸거라는 보장이 없다.
- 명명패턴을 적용한 요소를 매개변수로 전달할 방법이 마땅치 않다.
따라서 애너테이션으로 해결할 수 있는 일을 명명패턴으로 처리할 이유가 없다.
일단 자바에서 제공하는 애너테이션을 사용하고 정말 필요한 경우에 애너테이션을 직접 정의해서 사용하라.
마커 애너테이션
아무런 매개변수 없이 단순히 대상에 마킹하는 용도로 사용되는 애너테이션을 의미한다.
/**
* 테스트 메서드임을 선언하는 애너테이션
* 매개변수 없는 정적 메서드 전용
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Test{}
위와같이 주석으로 해당 애너테이션의 설명을 적어둘 수 있지만 주석처럼 동작을 강제 할 수 는 없기 때문에
애너테이션 프로세서에서 해당 요구사항을 충족시켜 구현을 해야한다.
반복 가능 애너테이션
자바 8에서 여러 개의 값을 받는 애너테이션을 만들 수 있다.
@Repeatable
을 단 애너테이션을 반환하는 '컨테이너 애너테이션'을 정의하는것이다.@Repeatable
에 이 컨테이너 애너테이션의 class 객체를 매개변수로 전달해야한다.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ExceptionTestContainer {
ExceptionTest[] value();
}
컨테이너 애너테이션은 내부 애너테이션(ExceptionTest
)타입의 배열을 반환하는 value()
를 정의해야 한다.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Repeatable(ExceptionTestContainer.class)
public @interface ExceptionTest {
Class<? extends Throwable> value();
}
반복 가능 애너테이션을 하나만 적용한 경우와 여러 개를 적용한 경우를 구분하기 때문에 주의해야한다.
아래와 같은 메서드가 있다고 가정하자.
public class Repeatable {
@ExceptionTest(IllegalArgumentException.class)
@ExceptionTest(NullPointerException.class)
public void repeatAnnotationMethod() {
}
@ExceptionTest(IllegalArgumentException.class)
public void notRepeatAnnotationMethod() {
}
}
반복 가능 애너테이션(ExceptionTest
)을 여러 번 단다음 반복 가능 애너테이션이 있는지를 isAnnotationPresent()
로 검사한다면 false
를 반환한다.
이 경우 Contatiner 애너테이션(ExceptionTestContainer
)을 인식하기 때문이다.
한개만 단 다면 반대의 상황이 된다.
아래 테스트 코드로 확인해 볼 수 있다.
class RepeatableTest {
@DisplayName("두개이상, 반복가능 애너테이션이 달려있다면 Container를 인식한다.")
@Test
void name() throws NoSuchMethodException {
//given
Method repeatAnnotationMethod = Repeatable.class.getMethod("repeatAnnotationMethod");
//when
boolean annotationPresent = repeatAnnotationMethod.isAnnotationPresent(java.lang.annotation.Repeatable.class);
boolean exceptionTestAnnotationPresent = repeatAnnotationMethod.isAnnotationPresent(ExceptionTest.class);
boolean exceptionTestContainerAnnotationPresent = repeatAnnotationMethod.isAnnotationPresent(ExceptionTestContainer.class);
//then
assertThat(repeatAnnotationMethod).isNotNull();
assertThat(annotationPresent).isFalse();
assertThat(exceptionTestAnnotationPresent).isFalse();
assertThat(exceptionTestContainerAnnotationPresent).isTrue();
}
@DisplayName("단 한개의 반복가능 애너테이션이 달려있다면 Container를 인식하지 않는다..")
@Test
void name2() throws NoSuchMethodException {
//given
Method notRepeatAnnotationMethod = Repeatable.class.getMethod("notRepeatAnnotationMethod");
//when
boolean annotationPresent = notRepeatAnnotationMethod.isAnnotationPresent(java.lang.annotation.Repeatable.class);
boolean exceptionTestAnnotationPresent = notRepeatAnnotationMethod.isAnnotationPresent(ExceptionTest.class);
boolean exceptionTestContainerAnnotationPresent = notRepeatAnnotationMethod.isAnnotationPresent(ExceptionTestContainer.class);
//then
assertThat(notRepeatAnnotationMethod).isNotNull();
assertThat(annotationPresent).isFalse();
assertThat(exceptionTestAnnotationPresent).isTrue();
assertThat(exceptionTestContainerAnnotationPresent).isFalse();
}
}
관련 Java-Bom 질문
해당 예외의 클래스파일이 런타임에는 존재하지 않을 수 있다
@interface 의 value 메서드
javax.annotation.processing
'Reading Record > 이펙티브자바' 카테고리의 다른 글
[아이템 40] @Override 애너테이션을 일관되게 사용하라 (0) | 2020.06.30 |
---|---|
[아이템 41] 정의하려는 것이 타입이라면 마커 인터페이스를 사용하라 (0) | 2020.06.30 |
[아이템 59, 60] 라이브러리를 익히고 사용하라, 정확한 답이 필요하다면 float와 double은 피하라 (0) | 2020.06.28 |
[아이템 57, 58] 지역변수의 범위를 최소화하라, 전통적인 for 문보다는 for-each 문을 사용하라 (0) | 2020.06.28 |
[아이템 4] 인스턴스화를 막으려거든 private 생성자를 사용하라 (0) | 2020.06.16 |