목표
자바의 애노테이션에 대해 학습하기
애노테이션 (annotation)은 프로그램의 소스코드 안에 다른 프로그램을 위한 정보를 미리 약속된 형식으로 포함시킨 것이다. 주석처럼 프로그램에 영향을 미치지 않으면서도 유용한 정보를 제공할 수 있다.
예를 들어 @Override 애노테이션은 상위클래스의 메소드를 오버라이딩하는 것이라는 걸 컴파일러에게 알려주는 역할을 한다. 추상메소드가 아닌 메소드를 하위클래스에서 오버라이딩하고자 할 때, 대소문자를 틀렸다고 가정해보자. 컴파일러는 하위클래스가 상위클래스의 메소드를 오버라이딩하는 것이 아닌, 새로운 메소드를 추가하는 것이라고 판단할 것이다. 하지만 @Override 애노테이션을 사용하게되면, 컴파일러가 상위클래스에 동일한 이름의 메소드가 있는지 확인하고, 없다면 컴파일 에러를 내준다.
애노테이션 정의하는 방법
애노테이션을 정의하는 방법은 인터페이스를 정의한 방법에서 @ 만 붙이면 된다.
@interface 애노테이션이름 {
타입 요소이름();
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
애노테이션 내에 선언된 메소드를 '애노테이션 요소(element)'라고 하며, 반환값이 있고 매개변수는 없는 추상 메소드의 형태를 가진다. 상속을 통해구현할 필요는 없다. 기본값을 정의할 수 있으며 애노테이션을 사용할 때, 기본값이 없는 요소들은 빠짐없이 값을 지정해주어야한다.
@Repeatable(Converts.class)
@Target({METHOD, FIELD, TYPE}) @Retention(RUNTIME)
public @interface Convert {
Class converter() default void.class;
String attributeName() default "";
boolean disableConversion() default false;
}
@Convert(converter = LocalDateAttributeConverter.class)
private LocalDate manufactureDate;
애노테이션의 요소가 오직 하나뿐이고, 이름이 value인 경우, 애노테이션을 적용할 때 요소의 이름을 생략하고 값만 적어도 된다.
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@API(status = STABLE, since = "5.0")
public @interface DisplayName {
String value();
}
@DisplayName("검수완료/검품완료 로직 테스트")
class CompletionServiceTest {
}
요소의 타입은 primitive type, String, enum, annotation, Class 만 허용된다. 매개변수를 선언할 수 없으며, throws를 통해 예외를 선언할 수도 없다. ArrayList<T> 와 같은 타입 매개변수 사용도 불가능하다.
@retention
애노테이션을 정의할 때, 애노테이션의 적용대상이나 유지기간등을 지정하게 되는데, 이 때 애노테이션에 사용하는 애노테이션을 메타 애노테이션이라고 한다.
애노테이션 (메타애노테이션) | 설명 |
@Override | 컴파일러에게 오버라이딩하는 메서드라는 것을 알린다 |
@Deprecated | 앞으로 사용하지 않을 것을 권장하는 대상에 붙인다 |
@SupperessWarnings | 컴파일러의 특정 경고메시지가 나타나지 않게 해준다 |
@SafeVarargs | 제너릭스 타입의 가변인자에 사용한다 |
@FuctionalInterface | 함수형 인터페이스라는 것을 알린다 |
@Native | native 메소드에서 참조되는 상수 앞에 붙인다 |
@Traget | 애노테이션이 적용가능한 대상을 지정하는데 사용한다 |
@Documented | 에노테이션 정보가 javadoc으로 작성된 문서에 포함되게 한다 |
@Inherited | 애노테이션이 하위클래스에 상속되도록 한다. |
@Retention | 애노테이션이 유지되는 범위를 지정하는데 사용한다 |
@Repeatable | 애노테이션을 반복해서 적용할 수 있게 한다 |
▲자바에서 기본적으로 제공하는 표준 애노테이션
retention 메타 애노테이션은 애노테이션이 유지되는 기간을 지정하는데 사용된다.
유지정책 | 의미 |
SOURCE | 소스 파일에만 존재 클래스 파일에는 존재하지 않음 |
CLASS (기본값) | 클래스 파일에 존재 실행시에 사용불가 |
RUNTIME | 클래스 파일에 존재 실행시에 사용가능 |
@Override나 @SupperessWarnings 처럼 컴파일러가 사용하는 애노테이션은 유지 정책이 SOURCE 다. 컴파일러를 직접 작성할 것이 아니라면, 이 유지정책은 필요 없다.
유지정책을 'RUNTIME'으로 하면, 실행 시에 '리플렉션 (reflection)'을 통해 클래스 파일에 저장된 애노테이션의 정보를 읽어서 처리할 수 있다. @FuctionalInterface 는 RUNTIME으로 되어있다. 지역변수에 붙은 애노테이션은 컴파일러만 인식할 수 있으므로, 유지정책이 RUNTIME인 애노테이션은 지역변수에 붙여도 실행 시에 인식되지 않는다.
유지정책 'CLASS'는 컴파일러가 애노테이션의 정보를 클래스 파일에 저장할 수 있게는 하지만, 클래스 파일이 JVM에 로딩될 때는 애노테이션의 정보가 무시되어 실행 시에 애노테이션에 대한 정보를 얻을 수 없다. 따라서, 기본값임에도 불구하고 잘 사용되지 않는다.
@target
애노테이션이 적용가능한 대상을 지정하는데 사용된다. 여러 개의 앖을 지정할 때는 괄호 { } 를 사용한다.
대상타입 | 의미 |
ANNOTATION_TYPE | 애너테이션 |
CONSTRUCTOR | 생성자 |
FIELD | 필드(멤버변수, enum상수) |
LOCAL_VARIABLE | 지역변수 |
METHOD | 메서드 |
PACKAGE | 패키지 |
PARAMETER | 매개변수 |
TYPE | 타입 (클래스, 인터페이스, enum) |
TYPE_PARAMETER | 타입 매개변수 |
TYPE_USE | 타입이 사용되는 모든 곳 |
TYPE은 타입을 선언할 때, 애노테이션을 붙일 수 있다는 뜻이고, TYPE_USE는 해당 타입의 변수를 선언할 때 붙일 수 있다는 뜻이다. FIELD는 기본형에, TYPE_USE는 참조형에 사용되는 차이가 있다.
@Target({FIELD, TYPE, TYPE_USE})
public @interface MyAnnotation { }
@MyAnnotation // TYPE
class MyClass {
@MyAnnotation // FIELD
int i;
@MyAnnotation // TYPE_USE
MyClass mc;
}
@documented
애노테이션에 대한 정보가 javadoc으로 작성한 문서에 포함되도록 한다. 자바에서 제공하는 기본 애노테이션 중에 @Override, @SupperessWarnings 를 제외하고는 모두 이 메타 애노테이션이 붙어 있다.
애노테이션 프로세서
어노테이션을 사용하기 위해서는 어노테이션 프로세서가 필요하다.
동작 구조.
1. 어노테이션 프로세서를 사용한다는 것을 자바 컴파일러가 알고 있는 상태에서 컴파일을 수행한다.
2. 어노테이션 프로세서들이 각자의 역할에 맞게 구현되어 있는 상태에서 실행되지 않은 어노테이션 프로세서를 실행한다.
3. 어노테이션 프로세서 내부에서 어노테이션에 대한 처리를 한다.
4. 자바 컴파일러가 모든 어노테이션 프로세서가 실행 되었는지 검사하고, 모든 어노테이션 프로세서가 실행되지 않았다면 반복한다.
Java의 정석
최근 7년동안 자바 분야의 베스트 셀러 1위를 지켜온 '자바의 정석'의 최신판. 저자가 카페에서 12년간 직접 독자들에게 답변을 해오면서 초보자가 어려워하는 부분을 잘 파악하
m.yes24.com
annotation processor 란
annotation processor는 자바 컴파일러 플러그인의 일종으로, 어노테이션에 대한 코드베이스를 검사, 수정, 생성하는 역할이다. 어노테이션을 사용하기 위해서는 어노테이션 프로세서가 필요하다. 동
im-recording-of-sw-studies.tistory.com
'Java | Spring' 카테고리의 다른 글
제네릭 (0) | 2021.03.06 |
---|---|
I/O (0) | 2021.03.06 |
Enum (0) | 2021.03.01 |
멀티쓰레드 프로그래밍 (0) | 2021.02.28 |
예외처리 (0) | 2021.02.25 |