애노테이션 정의하는 방법
■ 애노테이션이란?
애노테이션은 Java5부터 등장한 기능으로 주석이라는 뜻을 가지고 있다.
그러나 우리가 알고 있는 주석의 의미와는 다르게 인터페이스를 기반으로 한 문법이며
특별한 의미를 부여하거나 기능을 하는 코드를 작성할 수 있다.
■ 애노테이션 정의 방법
public @interface Test { ... }
@interface는 애노테이션 타입을 선언하는 키워드이다.
애노테이션 타입 선언을 일반적인 인터페이스(interface) 선언과 구분하기 위해 interface앞에 @를 붙인다.
■ 애노테이션 필드
애노테이션 안에 필드와 같은 요소들을 정의할 수 있다.
- 요소의 타입은 기본형, Striing, enum, 애노테이션, Class만 가질 수 있음
- 매개변수 선언을 할 수 없음
- 예외 선언을 할 수 없음
- 요소를 타입 매개변수로 정의할 수 없음
- 배열 선언 가능
- default 값 지정 가능 / int num() default 10;
public @interface Test {
int num() default 10;
String value();
String[] arr();
Class c1();
Target t();
}
위의 예시에서 기본형, String, 배열, Class, Target 애노테이션을 정의할 수 있었다.
그러한 요소들을 아래와 같이 적용하여 사용할 수 있다.
public class Main {
@Test( value = "Hello",
arr = {"aaa", "bbb", "ccc"},
cc = Main.class,
t = @Target(ElementType.ANNOTATION_TYPE))
public void method() { }
public static void main(String[] args) { }
}
■ 빌트인 애노테이션
Java에 내장되어 있는 애노테이션
1. @Override
현재 메소드가 슈퍼 클래스의 메소드를 재정의한 것을 컴파일러에게 명시
메소드에 슈퍼 클래스가 없으면 에러를 발생
2. @Deprecated
마커 애노케이션으로 미리 만들어져 있는 클래스나 메소드가 더 이상 사용되지 않는 경우 경고를 알린다.
주로 버전의 차이때문에 발생한다.
3. @SuppressWarning
경고를 제거하는 애노테이션으로 개발자가 의도를 가지고 설계를 했는데, 컴파일러는 이를 알지 못하고 컴파일 경고를 띄을 수 있기 때문에 이것을 제거하는 목적으로 사용한다.
4. @SafeVarargs
Java 7 이상에서 사용가능하며, 제네릭과 같은 가변인사 매개변수 사용 시 경고를 무시한다.
5. Functionalinterface
Java 8 이상에서 사용 가능하고, 컴파일러에게 함수형 인터페이스라는 것을 알린다.
※ 함수형 인터페이스는 1개의 추상 메소드만 가지고 있는 인터페이스로 지난 번에 배운 Runnable이 있다.
메타 애노테이션(@Retention, @Target, @Documented)
@Retention
애노테이션이 유지되는 기간인 Life Time을 설정하는 애노테이션이다.
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
RetentionPolicy value();
}
// 아래는 RetentionPolicy
public enum RetentionPolicy {
SOURCE,
CLASS,
RUNTIME
}
Retention 괄호 안에 지정하는 요소들을 하나씩 살펴보면,
SOURCE : 애노테이션 정보가 컴파일 시 사라짐
CLASS : 디폴드 값으로, 클래스 파일에 있는 애노테이션 정보가 컴파일러에 의해서 참조 가능, 그러나 VM에서는 사라짐
RUNTIME : 실행 시 애노테이션 정보가 VM에 의해서 참조 가능
@Target
애노테이션이 적용 가능한 대상을 지정한다.
만약 다른 타입을 사용하면 에러가 발생한다.
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
ElementType[] value();
}
// 아래는 ElementType public enum ElementType {
TYPE,
FIELD,
METHOD,
PARAMETER,
CONSTRUCTOR,
LOCAL_VARIABLE,
ANNOTATION_TYPE,
PACKAGE,
TYPE_PARAMETER,
TYPE_USE,
MODULE,
...
}
ElementType을 살펴보자.
■ 기존
- TYPE : Class, Interface, enum, 등
- FIELD : 필드 값, enum 상수 값
- METHOD : 메소드
- PARAMETER : 메소드 파라미터
- CONSTRUCTOR : 생성자
- LOCAL_VARIABLE : 지역변수
- ANNOTATION_TYPE : 애노테이션
- PACKAGE : 자바 패키지
■ jdk 1.8 이후 추가
- TYPE_PARAMETER : 타입 매개변수
- TYPE_USE : 타입 사용 // jdk 9 이후
- MODULE : 모듈
■ jdk 14 이후 추가
- RECORD_COMPONENT : Record 컴포넌트
@Documented
애노테이션 정보가 javadoc으로 작성된 문서에 포함되도록 하는 메타 애노테이션
Java에서 제공하는 기본 애노테이션 중에 @Override와 @SuppressWarnings를 제외하고 모두 @Documented 애노테이션이 붙어 있다.
애노테이션 프로세서
■ 애노테이션 프로세서란?
Java 컴파일러의 컴파일 단계에서, 사용자가 정의한 애노테이션의 코드를 분석하고 처리하기 위해 사용되는 훅이다.
컴파일 에러, 경고나 소스코드(.java)와 바이트 코드(.class)를 내보내기도 한다.
■ 사용 예제
1. Lombok(롬복)
- @Getter, @Setter, @Builder
2. AutoService
- java.util.ServiceLoader용 파일 생성 유틸리티
- 리소스 파일을 만들어 줌
- META-INF > service > ServiceLoader용 레지스트리 파일을 생성
3. @Override
- 컴파일러가 오버라이딩하는 메소드가 잘못된 대상임을 체크해주는 행위도 애노테이션 프로세서의 한 종류
4. Dagger2
- 컴파일 타임 DI 제공 -> 런타임 비용이 없어짐
5. 안드로이드 라이브러리
- ButterKnife : @BindView(뷰 아이디와 애노테이션을 붙인 필드 바인딩)
- DeepLinkDispatcher : 특정 URI 링크를 액티비티로 연결할 때 사용
■ 애노테이션 프로세서의 장단점
1. 장점
- 컴파일 시점에서 동작하기 때문에 런타임 비용이 없다.
2. 단점
- 현재 public한 API가 없다