학습목표
- 애노테이션 정의하는 방법
- @retention
- @target
- @documented
- 애노테이션 프로세서
애노테이션 기본
@GetMapping("hello") //hello 같이 동적인 변수는 들어갈 수 없다. static(정적)이어야 한다.
public String hello(){
return "hello";
}
# 애노테이션 정의하는 방법
애노테이션의 여러 가지가 있는 데 주로 3가지 용도로 쓰인다.
1. 컴파일러에 대한 정보 : 컴파일러가 오류를 감지하거나 경고를 억제하는 데 주석을 사용할 수 있다.
2. 컴파일 시간 및 배포 시간 처리 : Software tools 는 annotation 정보를 처리하여 코드를 생성, XML 파일 등을 생성할 수 있다.
3. 런타임 처리 : 일부 주석을 런타임에 검사할 수 있다.
주석을 사용할 수 있는 위치, 주석을 적용하는 방법, 자바 플랫폼에서 사용할 수 있는 사전 정의된 주석 유형, 표준판(Java SE API), 플로그형 유형 시스템과 맞게 annotation 타입을 사용하는 방법(강력한 Type체크를 할 수 있게), 그리고 반복되는 annotation을 어떻게 실행할 수 있는지.
아래와 같이 중요한 정보를 annotation으로 정의 하고 싶을 때, @interface 를 활용해 annotation타입을 정의할 수 있다.
public class Generation3List extends Generation2List {
// Author: John Doe
// Date: 3/17/2002
// Current revision: 6
// Last modified: 4/12/2004
// By: Jane Doe
// Reviewers: Alice, Bill, Cindy
// class code goes here
}
@interface ClassPreamble {
String author();
String date();
int currentRevision() default 1;
String lastModified() default "N/A";
String lastModifiedBy() default "N/A";
// Note use of array
String[] reviewers();
}
위와 같이 ClassPreamble 의 타입 annotation을 정의할 수 있다. 그럼 아래와 같이 활용할 수 있다.
@ClassPreamble (
author = "John Doe",
date = "3/17/2002",
currentRevision = 6,
lastModified = "4/12/2004",
lastModifiedBy = "Jane Doe",
// Note array notation
reviewers = {"Alice", "Bob", "Cindy"}
)
public class Generation3List extends Generation2List {
// class code goes here
}
@Deprecated는 더 이상 사용되지 않는 코드를 나타낸다. 컴파일러가 해당하는 메소드나 클래스에게 warning을 보낸다.
@Override는 컴파일러에게 해당 요소는 override라는 것을 알려준다. 해당 override메소드는 인터페이스와 상속과 논의된다. annotation을 하면 해당하는 슈퍼클래스 중 하나에서 올바르게 재정의 하지 못하면 컴파일러가 오류를 발생시킨다. > 오류를 방지하는데 도움이 된다.
@Override는 컴파일러가 구체적인 워닝을 알려준다.
# @retention
annotation을 정의할 때 쓰는 용도로, 메타주석중에 하나로 메타 알림 유형이 있다. 사용 용도에 따라, 어느 범위까지 유지할 것인가를 지정해야한다.
retention은 표시된 annotation이 저장되는 방법을 지정한다.
RetentionPolicy 방식은 3가지가 있다.
CLASS : 컴파일 시 컴파일러에 의해 유지되지만, JVM에 의해 무시된다. (바이트 코드 파일까지만 정보를 유지한다.)
그냥 보는 용도라면 SOURCE까지 내려서 적용해도 됨.
RUNTIME : JVM에 의해 유지되므로 런타임 환경에서 사용할 수 있다. (바이트 코드 파일까지 어노테이션 정보를 유지)
클래스 파일에도 남겨 놓겠다. >reflection(클래스에 대한 정보를 반추해봄)이 가능 > but 정말로 Runtime까지 필요한 정보인가? 고민해볼 필요 있다 (필요없다면 CLASS타입으로 바꾸면 된다.)
SOURCE : 소스 레벨에서만 유지되며 컴파일러에 의해 무시된다. (바이트 코드파일에서는 정보가 없다.) : 컴파일 하고 나면 해당 ANNOTATION정보가 없어짐. 왜냐하면 컴파일 할 때만 쓰겠다는 것. (EX. Override)
SOURCE -> CLASS -> RUNTIME
default 새팅은 RetentionPolicy.CLASS로 적용된다.
# @target
자바 요소 종류에 따라 다른 annotation을 제한하는 기능을 한다. The java.lang.annotation.ElementType 타입별로 해당하는 annotation이 적용된다.
Element TypesWhere the annotation can be applied
Element Types | Where the annotation can be applied |
TYPE | class, interface or enumeration |
FIELD | fields |
METHOD | methods |
CONSTRUCTOR | constructors |
LOCAL_VARIABLE | local variables |
ANNOTATION_TYPE | annotation type |
PARAMETER | parameter |
//Creating annotation
import java.lang.annotation.*;
import java.lang.reflect.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface MyAnnotation{
int value();
}
//Applying annotation
class Hello{
@MyAnnotation(value=10)
public void sayHello(){System.out.println("hello annotation");}
}
//Accessing annotation
class TestCustomAnnotation1{
public static void main(String args[])throws Exception{
Hello h=new Hello();
Method m=h.getClass().getMethod("sayHello");
MyAnnotation manno=m.getAnnotation(MyAnnotation.class);
System.out.println("value is: "+manno.value());
}}
# @documented
메타 어노테이션으로 어노테이션을 정의할 때, JavaDoc으로 생성되어 보여준다. @documented가 적용된 요소는 Javadoc tool을 통해 documented되어야 한다.
javadoc : java 소스에 문서화를 하는 방법으로 클래스나 메소드에 주석으로 기술한 내용을 javadoc 명령어나 또는 이를 이용한 빌드(maven의 pharse 등)을 사용하여 문서화할 수 있다. 문서할 주석을 달 경우 /**로 시작하고 */ 로 끝나야 한다.
# 애노테이션 프로세서
어노테이션 프로세싱은 컴파일 타임에 어노테이션을 분석한다. 그리고 나서 붙여진 어노테이션에 따라 클래스를 만들어 낸다. Here is how it works.
-
어노테이션 클래스를 생성한다.
-
어노테이션 파서 클래스를 생성한다.
-
어노테이션을 사용한다.
-
컴파일하면, 어노테이션 파서가 어노테이션을 처리한다.
-
자동 생성된 클래스가 빌드 폴더에 추가된다.
대표적인 애노테이션 프로세서의 대표적인 예로 롬복(lombok) 라이브러리를 들 수 있다. 애노테이션 프로세서로 클래스 파일을 만드는 과정에서 중요한 포인트는 자바의 서비스 로더(Service Loader)라는 기능을 알아두어야 한다.
서비스 로더는 구현체를 모르고 구현체를 쓸 수 있는 방법이다. 예를 들어 인터페이스를 하나 만들었다. 구글은 hello.jar파일로 네이버는 Annung.jar 가 있다고 하면 내가 지정하지 않고, jar파일만 바꿔끼면 해당하는 구현한 구현체를 가져 올 수 있다.
ServiceLoader<CodecFactory> loader = ServiceLoader.load(CodecFactory.class);
for (CodecFactory factory : loader) {
Encoder enc = factory.getEncoder("PNG");
if (enc != null)
... use enc to encode a PNG file
break;
}
서비스 로더는 애노테이션 프로세서를 사용하려면 컴파일러가 사용할 수 있도록 등록 해줘야한다.
1. 먼저 META-INF/services 에 ex. javax.annotation.processing.Processor 라는 파일을 위치시키고, 파일의 내용은 개행을 구분자로해서 프로세서들의 FQCN(Fully Qualified Class Name) : 구현체의 full package의 목록을 작성하면 된다.
2. 그리고 .jar 파일에 같이 패캐징하면 된다. 컴파일러가 MyProcessor.jar 를 이용해서 자동으로 javax.annotation.processing.Processor 파일을 발견하고 읽어서 MyProcessor 를 애노테이션 프로세서로 등록한다.
출처
docs.oracle.com/javase/tutorial/java/annotations/index.html
'Backend > Java' 카테고리의 다른 글
Java I/O (Input / Output) (0) | 2021.02.21 |
---|---|
JAVA 상속 (0) | 2021.02.20 |
Enum 자바의 열거형 (0) | 2021.01.29 |
[Java] 클래스 (0) | 2021.01.20 |
[Java] 선택문, 반복문 (0) | 2021.01.18 |