annotatioin의 정의를 알아보자. wikipedia - Annotation을 다음과 같이 설명한다.
An annotation is extra information associated with a particular point in a document or other piece of information.
annotation은 문서나 정보의 일부분과 관련된 추가 정보이다.
쉽게 말해 어떤 것에 대한 부가 정보
다.
위와 같은 표시([1])도 annotation이다.
그렇다면 Java에서 annotation은 어떻게 정의할까? 이것 역시 wikipedia - Java annotation에서 설명하고 있다.
In the Java computer programming language, an annotation is a form of syntactic metadata that can be added to Java source code.
자바 프로그래밍에서 annotation은 자바 소스 코드에 추가할 수 있는 구문적인 metadata의 한 형태이다.
자바 소스 코드에 대한 metadata
이다. metadata라고 하면 뭔가 어렵다. 위의 내용과 대응시켜보면 자바 소스 코드에 대한 부가 정보
라고 할 수 있다.
Java annotation은 왜 쓰는걸까? 실생활에서 먼저 생각해보면 바로 와닿을 수 있다.
우리는 어떠한 풍경, 인물, 장면을 한 화면에 담기 위해 디지털 카메라로 사진을 찍는다. 카메라로 촬영한 장면은 부가 정보
가 있다. 촬영했을 때의 GPS, 촬영 날짜, 카메라의 기종 등등 수많은 metadata
가 저장된다.
GPS를 통해 어디에서 찍었는지를 알 수 있고 이를 활용하여 찍은 장소를 알 수 있거나 같은 장소에서 찍은 또다른 사진을 검색할 수 있다. 즉, metadata를 가공하거나 분석하여 추가 정보를 얻거나 혹은 검색성을 향상시킬 수 있다.
Java에서는 어떨까? 다음 예제 코드를 통해 알아보자.
class A {
@Deprecated
static void methodFrist() {
System.out.println("This is first method");
}
void methodSecond() {
System.out.println("This is second method");
}
}
class B extends A {
@Override
void methodSecond() {
super.methodSecond();
}
}
@Deprecated
는 javadoc에서 다음과 같이 정의한다.
A program element annotated @Deprecated is one that programmers are discouraged from using.
프로그래머가 사용하지 못하도록 하는 것이라고 한다. 청개구리 심보로 한번 사용을 해보겠다.
다음과 같이 컴파일하기 전에 노란색의 경고가 뜬다.
@Override
는 javadoc에서 다음과 같이 정의한다.
Indicates that a method declaration is intended to override a method declaration in a supertype.
supertype의 메서드 선언을 override하기 위한 것이라고 가리킨다.
위의 override한 메서드인 methodSecond의 철자를 methodSeconds로 하면??
위와 같이 @Override에 컴파일 에러가 난다.
이처럼 Java annotaiton은 자바 소스 코드에 대한 부가 정보를 알려주고 이를 통해 컴파일러가 오류를 감지하거나 이를 통해 프로그래머에게 경고를 줄 수 있다.
The Java™ Tutorials 에서는 Annotation Type을 선언하는 방법을 소개한다.
중요한 코드를 그룹으로 만든다고 가정하자.
@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();
}
위의 코드처럼 선언이 가능하다. 주요 부분을 설명하면 다음과 같다.
@interface : annotation type은 interface 형태로 나타낸다.
body 부분 : method처럼 보이는 부분. 위와 같이 선언한다.
default : 사용자정의에 따라 기본값도 설정할 수 있다.
@ClassPreamble(
author = "제임스 고슬링",
date = "02/10/2024",
currentRevision = 1,
lastModified = "02/19/2024",
lastModifiedBy = "조슈아 블로크",
reviewers = {"빌조이", "브라이언 고츠", "아서 반 호프"}
)
class GenerateCode {
// field, method을 선언한다
}
위의 예제처럼 class선언 위에 @ClassPreamble을 선언하여 GerateCode class에 대한 부가정보를 알 수 있게 해준다.
이것 말고도 나만의 어노테이션을 만들 수 있다.
이 때, 추가적으로 알아야 하는 meta annotaiton이 있다. meta annotaion은 annotation을 설명해주는 annotation이다. @Retention
과 @Target
이다. Java Language Specification 참고
java.lang.annotation.Target에 위치
annotation type 선언에 사용된다.
선언하는 annotation이 적용되는 context(범위)를 설정한다.
context를 지정하기 위해 java.lang.annotation.ElementType[] 유형의 단일 요소를 적용한다.
@Target의 대상이다.
패키지 선언 : java.lang.annotation.ElementType.PACKAGE
타입 선언 : java.lang.annotation.ElementType.TYPE
메서드 선언 : java.lang.annotatioin.ElementType.METHOD
생성자 선언 : java.lang.annotation.ElementType.CONSTRUCTOR
gerneric class, interfaces, methods, constructors의 타입 파라미터 선언 : java.lang.annotation.ElementType.TYPE_PARAMETER
Field 선언 : java.lang.annotation.ElementType.FIELD
Formal & 예외 파라미터 선언 : java.lang.annotation.ElementType.PARAMETER
Local 변수 선언 : java.lang.annotation.ElementType.LOCAL_VARIABLE
source code까지만 유지
컴파일하면서 annotation정보가 사라진다
대표적인 annotation : lombok의 @Getter
, @Setter
@Getter 가 RetentionPolicy가 SOURCE로 되어 있다. 처리 순서를 알면 왜 RetentionPolicy가 SOURCE인지 알게 된다.
게터, 세터 등등의 lombok annotation들은 파일이 실행될 때 lombok의 전처러기에 해당 메서드(ex.getNumber(), setNumber())가 생성되도록 지시한다.
컴파일타임이 실행될 때 롬복이 메서드들을 바이트코드로 생성한다.
lombok annotation은 2번에서 역할을 다했기 때문에 결국 RetentionPolicy는 SOURCE까지 이면 된다.
클래스 파일까지만 유지
runtime에는 annotation정보가 사라진다
Java에서 default로 정해져 있다.
런타임 시점까지 유지
대표적인 annotation : spring의 @Controller
, @Service
, @Autowired
이 @Controller, @Service, @Autowired는 Reflection api를 활용하여 런타임에 동적으로 컴포넌트 스캔이 가능해야 하기 때문에 RetentionPolicy가 RUNTIME이어야 한다.
그렇다면 이제 이 meta annotation들을 활용한 annotation을 만들어 보자.
어떤 최적화가 필요한 메서드가 있다고 가정하자.
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.METHOD)
public @interface NeedOptimization {
String reason() default "";
}
위처럼 표시할 수 있게 돼 다른 사람이 최적화가 필요한 메서드의 부가 정보를 알 수 있다.
한가지만 더 만들어 보자
API의 버전을 명시해주고 싶다고 하자. 그렇다면 다음과 같이 annotation type을 만들 수 있다.
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.METHOD)
public @interface ApiVerison {
String value();
}
이렇게 Api의 버전정보를 명시해주는 annotation을 만들 수 있다.
자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]의 첫번째 과제