Annotation

Posted by yunki kim on April 23, 2022

  어노테이션은 메타데이터의 한 형식이다. 어노테이션은 어노테이션을 달은 연산에 대해 직접적인 영향을 주지 않는다.

  어노테이션을 다음과 같은 목적으로 사용될 수 있다.

    1. Information for the compiler: 어노테이션을 통해 에러를 찾아내고 경고를 억제할 수 있다.

    2. Compile-time and deployment-time processing: 소프트웨어 툴들은 어노테이션을 실행해 코드를 나타낼 수 있다.

    3. Runtime processing: 일부 어노테이션들은 런타임에 검증되는 데에 사용될 수 있다.

Annotations Basics

The Format of an Annotation

  어노테이션에서 '@'는 컴파일러에게 다음에 오는 것이 어노테이션임을 알려주며 어노테이션은 다음과 같은 모양을 한다.

1
@Override
cs

  어노테이션은 요소들을 포함할 수 있으며 이 경우 다음과 같이 사용된다.

1
2
3
4
@Author(name = "skull" age="24")
 
// 만약 요소가 하나면 요소의 이름을 생략할 수 있다.
@SuppressWarnings("unchecked")
cs

  두 개 이상의 서로 다른 어노테이션을 같이 사용할 수 있다.

1
2
3
4
5
@Author(name = "Jane Doe")
@EBook
class MyClass {
    ...
}
cs

   만약 같이 사용되는 두 개 이상의 어노테이션이 같다면, 이를 repeating annotation이라 칭한다. Repeating annotation은 Java SE8 부터 지원되는 기능이다. 

  어노테이션 타입은 java.lang 또는 java.lang.annotation 에 정의도니 타입 중 하나일 수 있다. 

Where Annotations Can Be Used

  어노테이션은 클래스, 필드, 메서드 선언 등에 사용될 수 있다. 선언에 사용될 경우 어노테이션은 선언과 같은 줄에 사용하는 것이 컨벤션이다. 이런 형태의 어노테이션을 type annotation이라 한다.

1
2
3
4
5
6
7
8
9
10
11
12
// 클래스 인스턴스 생성
new @interned MyObject();
// Type Casting 
myString (@NonNull String) str;
// implements clause
class UnmodifiableList<T> implements @Readonly List<@Readonly T> {
    ...
// Thrown exception declaration
void monitorTemperature() throws @Critical TemperatureException {
    ...
}
cs

Declaring an Annotation 

  어노테이션을 활용하면 많은 주석들을 없앨 수 있다. 모든 클래스의 시작에 다음과 같은 메타 데이터를 추가한다 해보자.

1
2
3
4
5
6
7
8
9
10
11
12
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
 
}
cs

  주석과 같은 내용을 나타내기 위해 다음과 같은 어노테이션 타입을 정의할 수 있다.

1
2
3
4
5
6
7
8
9
@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();
}
cs

  이런 어노테이션의 정의는 인터페이스의 정의와 상당히 유사하며 interface 키워드 앞에 '@'가 붙는 정도의 차이만 존재한다. 사실 어노테이션은 인터페이스의 한 종류다. 어노테이션 정의의 바디 부분에는 어노테이션 타입 요소에 대한 정의가 포함되며 메서드와 유사하다. 또 한, 위에의 lastModified 와 같이 선택적으로 디폴트 값을 명시할 수 도 있다.

  정의된 어노테이션은 다음과 같이 사용할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@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
 
}
cs

Predifined Annotation Types

  자바는 표준 라이브러리에는 어노테이션들이 정의되 있고 목적에 따라 사용할 수 있다. @Override 가 그 대표적인 예시이다. Java 8 기준으로 자바는 다음과 같은 어노테이션들을 사용한다.

https://docs.oracle.com/javase/tutorial/java/annotations/predefined.html

 

Predefined Annotation Types (The Java™ Tutorials > Learning the Java Language > Annotations)

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

Type Annotations and Pluggable Tye Systems

  java SE 8 이전에는 어노테이션을 선언 목적으로만 사용할 수 있었다. 하지만 java 8 이후 부터는 타입을 사용하는 모든 곳에 어노테이션을 사용할 수 있게 되었다. 예를 들어 인스턴스 생성(new), implements 등에 사용할 수 있다. 이런 곳에 사용되는 어노테이션을 type annotation이라 한다.

    Type annotation은 타입 체킹을 개선하기 위해 만들어 졌다. Java 8의 type annotation 도입이 타입 체킹 프레임워크를 제공하는 것은 아니다. 하지만 이를 통해 자바 컴파일러와 함께 사용되는 플러그인을 만들거나 다운로드해 사용할 수 있게 되었다.

  예를 들어 특정 변수가 null이면 안되고 NullPointerException을 피하고 싶다면, 다음과 같은 커스텀 플러그인을 만들어 null을 체크할 수 있다.

1
@NonNull String str;
cs

  이 코드를 실행했을 때 만약 잠재적 위험이 존재한다면 에러를 띄운다. 

Repeating Annotations

  두 개 이상의 같은 어노테이션을 같이 사용해야할 경우가 있다 해보자.

1
2
3
@Alert(role="Manager")
@Alert(role="Administrator")
public class UnauthorizedAccessException extends SecurityException { ... }
cs

    양립성의 이유로 repeatable annotation은 자바 컴파일러에 의해 자동으로 생성되는 container annotation에 저장된다. 이를 위해서는 다음과 같은 선언이 필요하다.

1. Declare a Repeatable Annotation Type

  어노테이션 타입은 반드시 @Repeatable 메타 어노테이션을 사용해야 한다.@Repeatable 을 사용하면 자바 컴파일러가 반복되는 어노테이션을 저장하기 위해 스토어를 생성한다.

1
2
3
4
5
6
7
8
9
import java.lang.annotation.Repeatable;
 
// @Schedule 어노테이션은 @Scheduels 어노테이션에 저장된다.
@Repeatable(Schedules.class)
public @interface Schedule {
  String dayOfMonth() default "first";
  String dayOfWeek() default "Mon";
  int hour() default 12;
}
cs

2. Declare the Containing Annotation Type

  Repeatable annotation을 저장하는 어노테이션은 반드시 배열로된 value 요소를 가지고 있어야 한다. 이 배열의 타입은 repeatable annotation type 이어야 한다. 위 에서 선언한 Schedule을 저장하기 위한 어노테이션은 다음과 같다.

1
2
3
4
public @interface Schedules {
    Schedule[] value();
}
 
cs

 

출처 - https://docs.oracle.com/javase/tutorial/java/annotations/index.html