본문 바로가기
Java관련/Java

Java 애너테이션

by devstep 2022. 11. 23.

애너테이션

학습주제

  • 애너테이션 정의하는 방법
  • @Retention
  • @Target
  • @Documented
  • 애너테이션 프로세서

애너테이션

  • 애너테이션은 주석이라는 뜻
  • 애너테이션과 일반적인 주석이 다른 점
    • 일반 주석은 사람을 위한 것이고, 애너테이션은 컴파일러를 위해 작성한 주석
  • 문법 오류를 체크할 수 있도록 힌트 제공. 예) @Override
  • 빌드 시 코드 자동 생성. 예) 롬복 라이브러리
  • 런타임 시점에 참고해서 특정 동작을 하도록 할 때 사용. 예) 스프링의 aop

표준 애너테이션

  • 자바에서 기본으로 제공하는 애너테이션
    1. 자바코드 작성시 사용되는 애너테이션
    2. 메타 애너테이션 : 애터테이션을 정의할 때 사용하는 애너테이션. 애너테이션에 붙이는 애너테이션

@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 를 등록하려면,
    1. META-INF 디렉토리 하위에 services 디렉토리를 만들고
    2. javax.annotation.processing.Processor 라는 파일을 만들고
    3. 그 안에 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

댓글