애너테이션
학습주제
- 애너테이션 정의하는 방법
- @Retention
- @Target
- @Documented
- 애너테이션 프로세서
애너테이션
- 애너테이션은 주석이라는 뜻
- 애너테이션과 일반적인 주석이 다른 점
- 일반 주석은 사람을 위한 것이고, 애너테이션은 컴파일러를 위해 작성한 주석
- 문법 오류를 체크할 수 있도록 힌트 제공. 예) @Override
- 빌드 시 코드 자동 생성. 예) 롬복 라이브러리
- 런타임 시점에 참고해서 특정 동작을 하도록 할 때 사용. 예) 스프링의 aop
표준 애너테이션
- 자바에서 기본으로 제공하는 애너테이션
- 자바코드 작성시 사용되는 애너테이션
- 메타 애너테이션 : 애터테이션을 정의할 때 사용하는 애너테이션. 애너테이션에 붙이는 애너테이션
@Retention
- 애너테이션이 유지되는 기간을 지정하는데 사용된다.
- 애너테이션의 유지 정책의 종류
- SOURCE : 소스 파일에만 존재. 클래스파일에는 존재하지 않음.
- CLASS : 클래스 파일에 존재. 실행 시에 사용 불가. 기본값
- RUNTIME : 클래스 파일에 존재. 실행 시에 사용 가능.
- 애너테이션 RetentionPolicy 예시
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface FunctionalInterface {}
SOURCE
- 컴파일러가 사용하는 애너테이션
- 컴파일러에서 사용하는 retention policy이므로 사용자가 정의할 일이 없다.
- @Override, @SuppressWarnings
- 지역변수에 붙은 애너테이션은 컴파일러만 인식할 수 있으므로, 유지정책이 RUNTIME인 애터네이션을 붙여도 실행 시에는 인식되지 않는다.
RUNTIME
- 실행 시에 리플렉션을 통해 클래스 파일에 저장된 애너테이션의 정보를 읽어서 처리할 수 있다.
CLASS
컴파일러가 애너테이션의 정보를 클래스 파일에 저장한다. 하지만 클래스 파일이 JVM에 로딩될 때는 애너테이션의 정보가 무시되어 실행 시에 애너테이션에 대한 정보를 얻을 수 없다.
그래서 유지 정책의 기본값임에도 잘 사용되지 않는다.
@Target
- 애너테이션이 적용 가능한 대상을 지정하는데 사용
- 여러 개 지정할 경우 {}를 사용
대상 타입 | 의미 |
---|---|
ANNOTATION_TYPE | 애너테이션, 메타애노테이션이 됨 |
CONSTRUCTOR | 생성자 |
FIELD | 멤버변수, enum 상수, 기본형에 사용됨 |
LOCAL_VARIABLE | 지역변수 |
METHOD | 메서드 |
PACKAGE | 패키지 |
PARAMETER | 매개변수 |
TYPE | 타입(클래스,인터페이스,enum)선언시 애너테이션 붙일 수 있다. |
TYPE_PARAMETER | 타입 매개변수(Java8) |
TYPE_USE | 타입이 사용되는 모든 곳(Java8), 해당 타입의 변수를 선언할 때 붙일 수 있다. 참조형에 사용됨 |
- FIELD는 기본형에, TYPE_USE는 참조형에 사용된다.
import static java.lang.annotation.ElementType.*; @Target({FIELD, TYPE, TYPE_USE}) public @interface MyAnnotation{} @MyAnnotation //TYPE public class MyClass { @MyAnnotation //FIELD int i; @MyAnnotation //TYPE_USE MyClass myClass; }
- Target 예시
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, MODULE}) @Retention(RetentionPolicy.SOURCE) public @interface SuppressWarnings { String[] value(); //애너테이션 요소 }
@Documented
애너테이션에 대한 정보가 javadoc으로 작성한 문서에 포함되도록 한다. 자바에서 제공하는 기본 애너테이션 중에 @Override, @SuppressWarnings를 제외하고는 모두 이 메타 애너테이션이 붙어 있다.
- @Documented 붙은 것과 붙지 않은 표준 애너테이션
//Override @Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface Override { }
//SafeVarargs
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD})
public @interface SafeVarargs {}
---
## 애너테이션 정의하는 방법
```java
@interface 애너테이션이름 {
타입 요소이름(); //애너테이션의 요소 선언.
}
애너테이션의 요소
- 애너테이션 내에 선언된 메서드
- 반환값이 있고 매개변수는 없는 추상 메서드의 형태를 가지고, 상속을 통해 구현하지 않아도 된다.
- 애너테이션을 적용할 때 이 요소들의 값을 빠짐없이 지정해주어야 한다.
- 애너테이션 요소는 기본값을 가질 수 있고, 값 미지정시 기본값이 사용된다.
- 요소가 단 하나이고. 요소명이 value()이면 적용할 때 요소명을 생략할 수 있다.
- 마커 애너테이션 : 요소가 하나도 정의되지 않은 애너테이션
- 애너테이션 요소 규칙
- 요소 타입은 기본형, String, enum, 애너테이션, Class 만 허용
- ()안에 매개변수 선언할 수 없다
- 예외 선언할 수 없다
- 요소를 타입 매개변수로 정의할 수 없다.
@interface TestInfo {
int count() default 1; //기본값 1
String testedBy();
String[] testTools();
TestType testType(); //enum TestType {FIRST, FINAL}
DateTime testDate(); //다른 애너테이션
}
@interface DateTime {
String yymmdd();
String hhmmss();
}
//애너테이션 요소 적용 예시
@TestInfo(
count = 3, testedBy = "Hong",
testTools = {"JUnit", "AutoTester"},
testType = TestType.FIRST,
testDate = @DateTime(yymmdd = "221101", hhmmss = "235959")
)
public class NewClass { }
java.lang.annotation.Annotation
- 모든 애너테이션의 조상
- 애너테이션은 상속이 허용되지 안으므로 명시적으로 Annotation을 조상으로 지정할 수 없다.
애너테이션 프로세서
- 컴파일 타임에 애노테이션 정보를 참고하여 코드를 분석하고 생성하는 등의 작업을 할 수 있는 기능
- lombok 라이브러리는 대표적인 어노테이션 프로세서
- 롬복을 사용하고 클래스 파일을 열어보면 만들지도 않은 메소드가 추가된다. 이것은 컴파일할 때 생성된다.
- 예) 롬복의 @Setter : setter 메서드가 클래스 파일에 생성되어 있다.
- 인텔리제이에서 애너테이션 프로세서 설정 : setting/Build,Execution,Deployment/Compiler/Annotation Processors/Enable annotation processing
- annotation processor의 장점은 코드 분석, 생성의 동작이 '컴파일 타임'에 이루어지기 때문에 런타임에 비용이 추가되지 않는다는 것.
annotation processor 동작 원리
- 컴파일러는 코드에 annotation processor가 있는 것을 어떻게 아는 것일까?
- Annotation Processor 를 등록하려면,
- META-INF 디렉토리 하위에 services 디렉토리를 만들고
- javax.annotation.processing.Processor 라는 파일을 만들고
- 그 안에 AbstractProcessor 클래스를 상속받아 구현하고 있는 클래스의 FQCN 을 작성
참고자료
'Java관련 > Java' 카테고리의 다른 글
필요없는 검사 예외 사용은 피하라 (0) | 2023.01.15 |
---|---|
Java 제네릭 (0) | 2022.11.28 |
Java enum (0) | 2022.11.04 |
Java 클래스 (0) | 2022.09.30 |
Java 예외 처리 (0) | 2022.09.29 |
댓글