Backend/Java

annotations

가은파파 2021. 2. 6. 22:35

학습목표

  • 애노테이션 정의하는 방법
  • @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.

 

  1. 어노테이션 클래스를 생성한다.

  2. 어노테이션 파서 클래스를 생성한다.

  3. 어노테이션을 사용한다.

  4. 컴파일하면, 어노테이션 파서가 어노테이션을 처리한다.

  5. 자동 생성된 클래스가 빌드 폴더에 추가된다.

대표적인 애노테이션 프로세서의 대표적인 예로 롬복(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

 

Lesson: Annotations (The Java™ Tutorials > Learning the Java Language)

The Java Tutorials have been written for JDK 8. Examples and practices described in this page don't take advantage of improvements introduced in later releases and might use technology no longer available. See Java Language Changes for a summary of updated

docs.oracle.com

 

'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