어노테이션(Annotation)은 무엇일까?
어노테이션은 '주석'이다. JVM이 읽는 주석이다. 주석이 필요한 이유가 무엇일까?
철학책과 과학책이 있다. 과학책은 과학코너로 철학책은 철학코너로 분류하고 싶다. 그런데 철학책과 과학책은 외관으로 구분하기 어렵다. 그래서 색상 인식 분류기를 하나 구매했다.
색상인식분류기가 구분할 수 있도록 과학책 오른쪽 상단에 '파란원' 표시를 남겼다. 파란원이 있는 책은 과학코너로 분류되어야 한다. 어노테이션은 '파란원'과 같다. 클래스는 모두 구조가 같다. 모두 필드와 메소드로 구성되어 있다. 외관으로는 구분이 안되나 클래스의 목적은 제각기 다르다. 그래서 개발자는 처리를 달리하고 싶은 대상에 어노테이션을 표시해 JVM에게 알려준다.
@Entity
@Entity
public class Member {
@Id
public String name;
public int age;
public Member() {}
public Member(String name, int age) {
this.name = name;
this.age = age;
}
}
엔티티클래스는 일반클래스와 외관은 같으나, 사용목적이 다르다. 엔티티클래스는 JPA프레임워크가 전용으로 사용하는 클래스이다. JPA프레임워크가 해당 클래스를 인식할수 있도록 개발자는 '표시'를 남겨야 한다. 그리고 우리는 @Entity를 남기기로 약속했다.
@Data ( Member.java )
@Data
public class Member {
public String name;
public int age;
public Member(String name, int age) {
this.name = name;
this.age = age;
}
}
@Data는 Getter와 Setter를 자동으로 생성하는 어노테이션이다. 개발자는 Getter와 Setter를 반복적으로 만드는 것이 귀찮아졌다. 그래서 @Data라는 표시를 남겼다. @Data표시가 있는 클래스는 JVM이 컴파일 할 때 Getter와 Setter를 자동으로 생성한다.
Member.class
실제로 컴파일된 Member.class를 디컴파일하면 Getter와 Setter가 자동생성되어 있음을 알 수 있다. 이처럼 특정한 로직(logic)을 처리하고 싶은 대상에 어노테이션을 '표시'한다.
어노테이션의 어노테이션
어노테이션 코드를 보자.
@Data
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
public @interface Data {
String staticConstructor() default "";
}
@Override
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override { }
@Retention
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
RetentionPolicy value();
}
어노테이션은 @interface로 선언되며, 어노테이션도 어노테이션을 갖는다. 대표적으로 @Target, @Retention, @Documented가 있다.
@Target
어노테이션은 '표시'이다. @Target은 어디에 표시를 남길 것인가를 나타낸다.
- ElementType.TYPE
ElementType.TYPE은 클래스, 인터페이스, 열거형(enum) 그리고 어노테이션 타입이 포함된다. @Data는 @Target(ElementType.TYPE)이다. 그러므로 @Data는 클래스, 인터페이스, 열거형 그리고 어노테이션 클래스의 선언부에 표시를 남기는 어노테이션이다.
- ElementType.FIELD
필드에 표시를 남기는 어노테이션이다.
- ElemenType.METHOD
메소드에 표시를 남기는 어노테이션이다. 대표적으로 @Override가 있다.
@Retention
어노테이션 생존범위를 나타낸다. 표시는 '부가적' 요소로 필요 없으면 지워야 한다. 그래서 어노테이션은 3가지 생존범위가 있다.
- RetentionPolicy.SOURCE
RetentionPolicy.SOURCE 정책의 어노테이션은 컴파일이 완료되면 역할을 다하고 제거된다. @Getter가 대표적이다. Class파일에 Getter 메소드가 추가되면 더이상 해당 어노테이션이 필요없다. 컴파일이 완료되면 어노테이션이 제거될 수 있도록 @Retention을 RetentionPolicy.SOURCE로 설정해놓아야 한다.
- RetentionPolicy.CLASS
RetentionPolicy.SOURCE 정책의 어노테이션은 컴파일이 되고 JVM에 로드 될 때까지 살아있는 어노테이션이다. 대표적으로 @NonNull이 있다.
ex) @NonNull
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE, ElementType.TYPE_USE})
@Retention(RetentionPolicy.CLASS)
@Documented
public @interface NonNull {
}
어노테이션은 특정 로직을 적용할 대상을 '표시'하는거라 앞에서 말했다. @NonNull은 Null 체크로직을 적용할 파라미터, 필드, 메소드에 표시되어 진다. 사실 Null값이 들어가지 않은 대상은 컴파일 단계에서 잡아야 한다. IDE에서 값을 안 넣으면 빨간줄이 나와야 한다. 그만큼 중요한 과정이다. 그러면 RetentionPolicy.SOURCE 이어야 하는데 왜 RetentionPolicy.CLASS일까?
개발은 보통 외부에서 라이브러리를 가져와 진행한다. 외부 라이브러리의 파일은 컴파일 된 클래스 파일이다. 클래스 파일의 필드, 메소드나 파라미터에 Null값이 들어가지 않도록 Null값 체크를 해야한다. 그러므로 JVM이 인식할 수 있도록 클래스파일에도 @NonNull이 살아 있어야 한다.
- RetentionPolicy.RUNTIME
가장 많이 사용되고 있는 정책이다. 컴파일되고 로드되고 호출될 때까지 어노테이션을 유지하도록 하는 정책이다. JAVA는 객체지향언어로, 객체는 프로그램 실행 중에 동적으로 생성되는 경우가 많다. 이때 특정 대상은 특정 로직으로 처리해야 하는 경우가 있다.
JPA는 ORM기술로 APP - DB 사이에 트랜잭션이 발생하면 데이터를 주고 받도록 중간에서 제어해야 한다. 이때 사용되는 클래스 단위가 엔티티(Entity)이다. 트랜잭션은 프로그램 실행중 동적으로 발생한다. 이에 맞추어 JPA는 @Entity로 표시된 클래스를 객체로 만들어야 한다. 이와 같이, 프로그램 실행중에도 어노테이션이 유효해야하는 경우에는 RetentionPolicy.RUNTIME 정책으로 설정한다.
@Documented
마지막으로 @Documented가 있다. @Documented는 JAVA 공식문서에 저장이 필요한 어노테이션을 표시하는 어노테이션이다. 특정 프레임워크만 사용하지 않고 일반적으로 표준으로 사용되는 어노테이션에 @Documented 되어 있다.
이번 포스팅에서는 어노테이션의 개념과 대표적인 어노테이션의 어노테이션 3가지를 알아보았다. ( @Target, @Retention, @Documented ) 다음 포스팅에서 다룰 내용은 어노테이션의 속성이다. 어노테이션의 속성은 '@' 하나가 아닌 조금 더 구체적인 '표시'를 남길 수 있도록 도와준다.
참고자료
'JAVA > JAVA Basic' 카테고리의 다른 글
[JAVA] JDK 동작원리 (0) | 2024.02.22 |
---|---|
[JAVA] 어노테이션( Annotation )의 속성 (0) | 2023.05.29 |
[ JAVA ] InputStreamReader : 인코딩 (0) | 2021.07.12 |
[ JAVA ] 기반 스트림, 보조 스트림 (0) | 2021.07.12 |
[ JAVA ] 스트림이란? ( 바이트 기반 스트림 , 문자 기반 스트림 ) (0) | 2021.07.08 |