자바 스터디 12주차 : 애노테이션

hwanse·2021년 2월 23일
0

Java

목록 보기
13/14

이 글은 백기선님의 라이브 스터디 참여 및 학습 내용에 관한 정리한 글입니다.





학습 목표

  1. 애노테이션 정의하는 방법
  2. @retention
  3. @target
  4. @documented
  5. 애노테이션 프로세서




관련 용어 정리

  • 메타 데이터(meta-data) : 한 마디로는 '데이터에 대한 데이터'이다. 다른 데이터를 설명해주는 데이터라고 볼 수 있다.
  • 애노테이션(annotation) : 사전적 의미로는 주석을 의미하며 프로그램에 대한 데이터를 제공하는 메타데이터의 한 종류
  • 자바 리플렉션(Java Reflection) : 구체적인 클래스 타입을 알지 못해도 그 클래스의 메소드, 타입, 변수들에 접근할 수 있도록 해주는 자바 API이다. 런타임 시점에 클래스 이름만 알고있다면 클래스에 대한 정보를 가져오거나 활용하는 경우에 사용되는 기술이다.


애노테이션이란?

소스 코드에 대한 문서를 따로 만들기 보단 소스 코드와 문서를 하나의 파일로 관리하는 것이 낫다고 생각했다고 한다. 그래서 개발 시 설명이 필요한 부분은 /** ~ */안에 해당 로직에 대한 설명을 달고 이러한 주석으로부터 HTML 문서를 생성하는 프로그램(javadoc.exe)을 만들고 사용했다. 이 기능을 응용하여 프로그램 소스코드 안에 다른 프로그램을 위한 정보를 미리 약속된 형식으로 포함시킨 것이 애노테이션이라고 한다. 이 애노테이션은 주석처럼 프로그래밍 언어에 영향을 끼치지 않으면서 다른 프로그램에게 유용한 정보를 제공할 수 있다는 것이 장점이다.

  • 특징
    • JDK 5 부터 등장
    • 애노테이션은 프로그램 의미 체계에 직접적인 영향을 주진 않으나 도구, 라이브러리에서 프로그램을 처리하는 방식에 영향을 주어 실행중인 프로그램의 의미 체계에 영향을 줄 수 잇다.
      • 예시: JUnit, 스프링 부트의 Annotation들, 롬복 등 ..
    • 애노테이션은 컴파일 타임 또는 런타임에 반영될 수 있다.


애노테이션 정의하는 방법

'@' 키워드를 사용하여 선언하게 되며 애노테이션 선언은 일반적으로 인터페이스 선언과 유사하다고 볼 수 있다. '@'키워드라 interface는 별개의 키워드이며 일반적으로 애노테이션을 선언할 때에는 아래과 같이 붙여쓰는 스타일을 권장한다.

public @interface MyChiken {

}
// 이와 같이 띄워쓰기를 해도 프로그램에는 영향을 주진 않는다.
public @              interface MyChiken2 { 
}

위 애노테이션은 엄밀히 말하자면 '@MyChiken'이라는 애노테이션이라 명칭하고 '@'를 빼면 'MyChiken' 타입이라고 지칭할 수 있다.


애노테이션의 요소

  • 애노테이션 내에 선언된 메소드를 애노테이션의 요소라고 한다.
  • 반환값이 있으며, 매개변수가 없는 추상 메소드의 형태이다.
  • 애노테이션 적용 시 이 요소들에 대한 값을 모두 지정해주어야 한다.
  • 각 요소는 default 값을 가질 수 있다.
  • 애노테이션의 요소가 오직 하나이며 이 요소의 이름이 value라면, 애노테이션을 적용할 때 생략이 가능하다.
  • 배열을 선언하여 요소를 지정할 수 있다.
  • 애노테이션도 인터페이스 처럼 상수 정의가 가능하지만 default 메소드는 정의할 수 없다.
  • 다른 애노테이션을 포함할 수 있다.

위 애노테이션의 요소들에 대한 예시를 만들어 보자.

public @interface PracticeAnnotation {

  int number = 100;  // 인터페이스와 동일하게 상수 정의도 가능

  String value() default "default값 지정이 된다~";  // default 값을 지정

  String[] values(); // 배열도 이용이 가능하다.

  TypeTest types();  // 반환타입에 Enum도 사용 가능

  MyChiken annotationEl();  // 다른 애노테이션을 포함

}

enum TypeTest {
  TEST1, TEST2
}

@interface MyChiken {
  String name();
}

애노테이션 요소의 규칙사항
애노테이션의 요소를 정의할 때 반드시 지켜야하는 규칙은 다음과 같다.

  • 요소의 타입은 기본형, String, enum(열거체), 애노테이션, Class만 허용
  • 요소의 () 안에 매개변수를 선언할 수 없다.
  • 예외를 선언할 수 없다.
  • 요소를 타입 매개변수로 정의 할 수 없다.

위 규칙들을 어기고 있는 다음 예시를 보면서 이해 해보자.

@interface TestAnnotation {

  String test(int num, char ch);  // 매개변수는 선언 불가하다.
  
  int test2() throws Exception;   // 예외 선언은 불가하다.
  
  List<T> test3();                // 요소의 타압에 타입 매개변수는 사용할 수 없다.
}

java.lang.anntation.Annotation

모든 애노테이션의 조상은 Anntation이다. 애노테이션은 상속이 허용되지 않으며 명시적으로라도 Anntation 인터페이스를 조상으로 상속 받을 수 없다.

- Anntation 인터페이스를 명시적인 상속했을 때 컴파일 오류가 나는 모습


Annotation 인터페이스 선언부

Annotation 인터페이스는 위와 같이 정의되어 있으며, 모든 애노테이션 객체들은 equals(), hashCode(), toString()와 같은 메소드를 호출하는 것이 가능하다.


마커 애노테이션 (Maker Annotation)

값을 지정할 필요가 없는 경우에는 애노테이션의 요소를 정의하지 않아도 된다. 이러한 애노테이션 요소가 하나도 지정되어 있지 않은 애노테이션을 마커 애노테이션이라고 부른다.

- 예시

@interface TestAnno1 {
}

@interface TestAnno2 {
}


메타 애노테이션

메타 애노테이션은 '애노테이션을 위한 애노테이션'이라고 한다. 이 말은 앞서 정리한 '메타 데이터'와 같은 의미이다. 데이터에 대한 데이터 즉 애노테이션에 붙이는 애노테이션으로 애노테이션을 정의할 때 사용되는 것이다.

  • 애노테이션의 적용 대상(target), 유지기간(retention) 등을 지정하는데 사용된다.
  • java.lang.anntation 패키지에 포함되어 있다.

메타 애노테이션 종류

애노테이션설명
@Documented@Documented가 지정된 애노테이션은 javadoc과 같은 도구로 문서화 된다
@Target애노테이션이 적용가능한 대상을 지정하는데 사용된다
@Retention애노테이션이 유지되는 기간을 지정하는데 사용된다
@Inherited애노테이션이 자속 클래스에 상속되도록 한다
@Repeatable애노테이션을 여러번 붙이는 것이 가능하게 한다
@Native네이티브 메소드에 의해 참조되는 상수 필드에 붙이는 애노테이션

Target

애노테이션이 적용 가능한 대상을 지정하는데 사용되는 애노테이션으로 '@Target' 으로 지정할 수 있는 적용 대상의 종류는 다음과 같습니다.

대상 타입의미
ANNOTATION_TYPE애노테이션
CONSTRUCTOR생성자
FIELD필드(멤버변수, enum)
LOCAL_VARIABLE지역변수
METHOD메소드
PACKAGE패키지
PARAMETER매개변수
TYPE타입(클래스,인터페이스,enum)
TYPE_PARAMETER타입 매개변수(JDK 1.8부터)
TYPE_USE타입이 적용되는 모든 곳(JDK 1.8부터)

선언부

애노테이션의 요소로 ElementType[] 배열 타입의 value가 선언되어 있는 것을 볼 수 있다.

사용 예시

@Target({FIELD, TYPE, TYPE_USe})
public @interface MyApp {
}

@MyApp     // 적용 대상이 TYPE인 경우
class MyClazz {

  @MyApp 
  String value;     // 적용 대상이 FIELD인 경우

  @MyApp 
  MyClazz myClazz;  // 적용 대상이 TYPE_USE인 경우

}

Retention

애노테이션이 유지되는 기간을 지정하는데 사용, 애노테이션을 유지하는 정책의 종류는 다음과 같다.

유지정책설명
SOURCE소스 파일에만 존재, 클래스 파일에는 존재하지 않음
CLASS클래스 파일에 존재, 런타임 시점에는 사용 불가. (default)
RUNTIME클래스 파일에 존재, 런타임 시점에 사용 가능

선언부

각 유지정책 별 특징

  • SOURCE
    '@Override', '@SuppressWarning' 같은 앹노테이션들 처럼 컴파일러가 사용하는 애노테이션은 유지 정책이 SOURCE이다. 컴파일러를 직접 작성할 것이 아니라면 이 유지정책은 필요 없다고 한다.

  • CLASS(default)
    컴파일러가 애노테이션의 정보를 클래스 파일에 저장될 수 있게 하는 정책이다. 그런데 RUNTIME 유지정책도 클래스 파일에 똑같이 애노테이션 정보가 클래스 파일에 저장되고 런타임 시점에 사용 여부에 따라서 달라진다고 한다.
    왜 그럴까?
    유지정책이 CLASS일 경우에 클래스 파일을 JVM에 로딩될 때에는 이 CLASS 정책에 해당되는 애노테이션들은 무시되어 JVM 메모리에는 없다. 즉, 프로그램이 실행된 시점에는 이 애노테이션에 대한 데이터를 활용하고 싶어도 이 애노테이션에 대한 데이터가 메모리에 없기 때문에 활용할 수 없는 정책인 것이다.

  • RUNTIME
    애노테이션을 런타임시에도 사용할 수 있는 정책. JVM이 이 애노테이션에 대한 정보를 읽어 메모리에 담기 때문에 이 정책이 적용된 애노테이션은 프로그램이 종료될 때까지 메모리로 남게된다.
    또한 런타임 시점에 '리플렉션'이라는 기술을 이용하여 클래스 파일에 저장된 애노테이션의 정보를 읽어서 처리할 수 있다고 한다.

Documented

애노테이션에 대한 정보가 javadoc으로 작성한 문서에 포함되도록 한다.
자바에서 제공하는 기본 애노테이션 중에 '@Override'와 '@SupressWarnings'를 제외하고 모두 이 애노테이션이 붙어 있다.

다음은 PracticeAnntation 이라는 커스텀 애노테이션에 @Documented 를 넣어서 javadoc으로 문서화 해보려고한다.

PracticeAnntation에 @Documented 메타 애노테이션을 넣었다

PracticeAnntation을 사용하는 AnnotationClient 클래스에 적용


문서화를 위한 @Documented 애노테이션을 넣어주었고 이제 javadoc을 생성해보자. Intellij IDE가 간편하게 javadoc을 생성해주는 기능이 있다. 다음과 같은 절차로 진행해보자.

  1. shift 키를 2번 더블 터치
  2. 검색란에 'generate JavaDoc'을 검색하고 실행한다.
  3. 새로 올라온 Generate JavaDoc 팝업창에서 한글 문자를 표기하기 위한 option을 추가적으로 다음과 같은 내용을 넣어주어야 한다.
    • Other command line arguments 항목에-encoding UTF-8 -charset UTF-8 -docencoding UTF-8 이 문자열을 넣어준다.
  4. javadoc이 생성될 Output Directory 지정. 이 경로 아래에 javadoc이 저장된다.


위 과정을 완료하고나면 다음과 같이 javadoc 문서가 생성되고 확인할 수 있다.

내용을 보면 내가 정의한 PracticeAnntation에 대한 정보가 문서화 된 것을 볼 수 있다.



애노테이션 프로세서

  • 소스코드 레벨에서 소스코드에 붙어있는 애노테이션의 정보를 읽어옴
  • 컴파일러가 컴파일 중에 새로운 소스코드를 생성하거나 기존의 코드 변경을 가능하게 한다
  • 바이트 코드를 생성이 가능하며 소스코드와 별개의 리소스 생성이 가능

예시

  • 롬복
  • AutoService
  • @Override
  • Dagger2
  • 안드로이드 라이브러리

장점
컴파일 시점에 조작하기 때문에 런타임 비용이 제로

단점
public한 api가 없다.




참고

profile
만사가 귀찮은 ISFP가 쓰는 학습 블로그

0개의 댓글