JDK 1.5 이전 버전에서는 컴파일러가 어노테이션을 처리할 수 있는 방법이 없었다.
예를 들어 JUnit에서는 @Test가 아닌 TestCase를 상속받아 테스트 케이스를 작성했다.
혹은 XML파일을 이용해 EJB(Enterprise JavaBeans)의 정보를 지정했다.
자바 기반 기업용 서버 컴포넌트 모델
자바의 어노테이션은 2종류가 있다
사용자 정의 어노테이션 구현 시 사용되는 어노테이션이다.
이 어노테이션이 어떻게 동작 해야하는지 컴파일러에게 알려주는 것.
ElementType.ANNOTATION_TYPE
: 어노테이션 타입 선언ElementType.CONSTRUCTOR
: 생성자 선언ElementType.FIELD
: 필드 선언 (멤버 변수)ElementType.LOCAL_VARIABLE
: 지역 변수 선언ElementType.METHOD
: 메소드 선언ElementType.PACKAGE
: 패키지 선언ElementType.PARAMETER
: 매개변수 선언ElementType.TYPE
: 클래스, 인터페이스, enum, annotation 타입 선언RetentionPolicy.SOURCE
: 컴파일 이후 버려지는 어노테이션. 즉, 런타임에는 유효하지 않다.RetentionPolicy.CLASS
: 런타임에는 유효하지 않지만, 컴파일러가 클래스 파일에 어노테이션 정보를 저장한다.. 이 방법으로 컴파일된 클래스를 로드하면 어노테이션 정보를 가져올 수 있다..RetentionPolicy.RUNTIME
: 런타임에도 유효한 어노테이션. 즉, 어노테이션 정보가 런타임에도 유지됩니다.해당 어노테이션 추가 시 이 어노테이션의 사용하는 클래스나 메소드가 javadoc을 만들 때.
해당 어노테이션도 그 javadoc에 포함되어야 한다.
import java.lang.annotation.*;
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyAnnotation {
String value();
}
@MyAnnotation("This is the parent class.")
public class Parent {
// ...
}
public class Child extends Parent {
// ...
}
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyClassAnnotation {
String name();
int version() default 1;
boolean isDeprecated() default false;
}
어노테이션을 사용자가 만들때 반드시 들어가야하는 정보는 두가지 이다.
@interface 그냥 interface는 무엇이 다를까.
@interface 5버전 부터 추가된 어노테이션 선언 시 사용되는 키워드이다.
그냥 interface와는 사용방법과 목적성 모두 차이가 있다.그냥 이름만 비슷할 뿐 아예 다른 것으로 인식하는 것이 올바를것 같다.
왜 @ + interface 라는 이름이 만들어졌을까를 찾아보니.
어노테이션과 인터페이스 사이의 유사성 존재하기 때문이라 판단되었다.어노테이션 : 일종의 메타데이터의 집합( 컴파일러에게 부가적인 데이터를 제공해주기 위한 코드)
인터페이스 : 메소드 시그니처의 집합둘 모두 정보의 집합이고 , 정보를 정의하는 것에 중점이 있기 때문에. 같은 인터페이스라는 이름을 채용했다 생각한다.
스프링이나 여러 라이브러리, 컴포넌트를 이용해 이미 많은 환경에서 어노테이션을 사용한다
String Bean의
Lombok의
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Test {
Class<? extends Throwable>[] expected() default {};
long timeout() default 0L;
@Retention(RetentionPolicy.RUNTIME)
@Target({})
public static class None extends Throwable {
private static final long serialVersionUID = 1L;
private None() {
}
}
}
public class MyTest {
@Test
public void testMethod() {
// 테스트 코드
}
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.SOURCE)
public @interface Getter {
AccessLevel value() default AccessLevel.PUBLIC;
boolean onMethod() default true;
boolean onParam() default false;
String onParam_() default "";
String prefix() default "";
}
@Getter
어노테이션이 적용된 필드를 찾는다.@Getter
어노테이션이 적용된 필드의 Getter 메서드를 자동으로 생성한다.롬복이나 스프링에서 제공하는 보증된 어노테이션 말고
회사 혹은 개인이 필요해 맞게 활용한 커스텀 어노테이션의 뭐가 있을까 하고
찾다가 발견한 우아한 형제들 기술 블로그의 글이 있다.시의적절한 커스텀 어노테이션
비회원도 몇몇 서비스를 이용 할 수 있도록 해야 하는데 회원정보 또한 미리보기가 가능하도록 해야 한다.
이를 위한 API를 하나더 만드는 것이 아닌 이용해 인증을 회피하는 어노테이션을 구현해
새로운 API를 만들고 분기처리를 하는것이 아닌 좀더 좋은 방향으로 개발한 예시 인것 같다.
커스텀 어노테이션의 장점은 간결함인것 같다.
하지만 단점도 간결함인것같다.어노테이션의 이름이 직관적이면서 다른 개발자가 어노테이션 코드를 어노테이션까지 확인해 가면서
개발해야 한다면 매우 불편한 일이 될것 같다.
@NoArgsConstructor 처럼 어노테이션의 이름만 가지고 아 이 어노테이션은 어느 역할을 하는지를 명시하는게 가장 중요하다 생각한다.