12주차 과제: 애노테이션
목표
자바의 애노테이션에 대해 학습하세요.
학습할 것 (필수)
- 애노테이션 정의하는 방법
- @retention
- @target
- @documented
- 애노테이션 프로세서
어노테이션
- 클래스나 메소드 등의 선언시에 @를 사용하는 것을 말한다. 메타데이터(Metadata)라고도 불린다
어노테이션의 사용
-
컴파일러에게 정보를 알려주거나
-
컴파일할 때와 설치시의 작업을 지정하거나
-
실행할 때 별도의 처리가 필요할 때
-
어노테이션은 클래스, 메소드, 변수 등 모든 요소에 선언할 수 있다
어노테이션 정의하는 방법
어노테이션 선언 예제)
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UserAnnotation {
public int number();
public String text() default "This is first annotation";
}
@Target
은 해당 어노테이션 사용 대상을 지정한다. 여기서는ElementType.METHOD
를 소괄호 안에 넣어 줌으로써 이 어노테이션은 메소드에 사용할 수 있다고 지정된것이다.@Retention
은 어노테이션 유지 정보를 지정하는 데 사용한다. 소괄호 안에RetentionPolicy.RUNTIME
으로 지정하면 실행시에 이 어노테이션을 참조하게 된다.- 어노테이션 이름인
UserAnnotation
에@interface
로 선언하면@UserAnnotation
으로 어노테이션이 사용가능해진다 - 어노테이션 선언 안에는
number()
라는 메소드와text()
라는 메소드가 있다.number()
의 리턴 타입은int
이며,text()
리턴타입은String
이다 이렇게 메소드 처럼 어노테이션 안에 선언해 놓으면, 이 어노테이션을 사용할 때 해당 항목에 대한 타입으로 값을 지정가능하다. text()
를 보면default
라는 예약어를 쓴 뒤 문자열이 지정되어 있는 것을 볼 수 있다.default
예약어를 사용할 경우에는default
뒤에 있는 값이 이 어노테이션을 사용할 때의 기본값이 된다. 즉 값을 지정하지 않아도default
값으로 지정된다.
예시
- 몰라도된다
public class UserAnnotationSample {
@UserAnnotation(number = 0)
public static void main(String[] args) {
UserAnnotationSample sample = new UserAnnotationSample();
}
@UserAnnotation(number = 1)
public void annotationSample1() {
}
@UserAnnotation(number = 2, text = "second")
public void annotationSample2() {
}
@UserAnnotation(number = 3, text = "third")
public void annotationSample3() {
}
}
public class UserAnnotationCheck {
public static void main(String[] args) {
UserAnnotationCheck sample = new UserAnnotationCheck();
sample.checkAnnotations(UserAnnotationSample.class);
}
public void checkAnnotations(Class useClass) {
Method[] methods = useClass.getDeclaredMethods();
for(Method tempMethod : methods){
UserAnnotation annotation = tempMethod.getAnnotation(UserAnnotation.class);
if (annotation != null){
int number = annotation.number();
String text = annotation.text();
System.out.println(tempMethod.getName() + "() : number=" + number + " text=" + text);
} else {
System.out.println(tempMethod.getName()+"() : annotation is null");
}
}
}
}
- Class 클래스에 선언되어 있는 getDeclaredMethods() 메소드를 호출하면, 해당 클래스에 선언되어 있는 메소드들의 목록을 배열로 리턴한다
- Method 클래스에 선언되어 있는 getAnnotation() 이라는 메소드를 호출하면, 해당 메소드에 선언되어 있는 매개 변수로 넘겨준 어노테이션이 있는지 확인하고 있을 경우 그 어노테이션의 객체를 리턴해준다
- 어노테이션에 선언된 메소드를 호출하면 그 값을 리턴해준다
main() : number=0 text=This is first annotation
annotationSample1() : number=1 text=This is first annotation
annotationSample2() : number=2 text=second
annotationSample3() : number=3 text=third
JDK 6까지 미리 정해져 있는 어노테이션
- @Override
- @Deprecated
- @SupressWarnings
@Override
- 해당 메소드가 부모 클래스에 있는 메소드를 Override했다는 것을 명시적으로 선언한다
- 명확하게 이 메소드는 Override 된거이므로 컴파일러에게 맞는지 물어본다.
@Deprecated
- 미리 만들어져 있는 클래스나 메소드가 더 이상 사용되지 않는 경우 컴파일러에게 "더이상 사용하지 않으니 사용하게되면 경고를 달라" 명시한다.
@SupressWarings
- 컴파일할 때 경고를 안줘도 된다고 말해주는것
@Override 예제
public class AnnotationOverride extends Parent {
@Override
public void printName() {
System.out.println("AnnotationOverride");
}
}
public class Parent {
public Parent() {
System.out.println("Parent Constructor");
}
public void printName() {
System.out.println("Parent printName()");
}
}
이걸
public class AnnotationOverride extends Parent {
@Override
public void printName(String args) {
System.out.println("AnnotationOverride");
}
}
이렇게 변경하면 에러가 발생한다
@Deprecated
- 컴파일 경고가 발생한다
사용하는 이유
- 협업에서 개발을 할 때 다른 개발자가 개발한것을 지우면 안되기 때문
어노테이션을 선언하기 위한 메타 어노테이션
- 메타 어노테이션 (Meta Annotation) 은 어노테이션을 선언할 때 사용한다
메타 어노테이션 종류
- @Target
- @Retention
- @Documented
- @Inherited
@Target
-
어노테이션을 어떤 것에 적용할지를 선언할 때 사용한다.
@Target(ElementType.METHOD)
@Retention
- 얼마나 오래 어노테이션 정보가 유지되는지
@Retention(RetentionPolicy.RUNTIME)
@Target 처럼 괄호 안에 지정하는 적용 가능한 대상은 다음과 같다
@Documented
- 해당 "어노테이션에 대한 정보가 Javadocs(API)문서에 포함된다는 것"을 선언
@Inherited
- 모든 자식 클래스에서 부모 클래스의 어노테이션을 사용가능하다는 것을 선언한다.
어노테이션에는 상속이 안된다
- enum 클래스가 상속을 지원하지 않듯이 어노테이션을 선언할 때도 미리 만들어 놓은 어노테이션을 확장하는것이 불가능하다. 재사용이 불가능하다.
- 어노테이션을 만드는이유?
- 제약사항 등을 선언하기 위해
- @Deprecated, @Override, @NotNull
- 용도를 나타내기 위해
- @Entity, @TestCase, @WebService
- 행위를 나타내기 위해
- @Statefull, @Transaction
- 처리를 나타내기 위해
- @Column, @XmlElement
- 제약사항 등을 선언하기 위해
어노테이션 프로세서
어노테이션 프로세서란?
- 자바 컴파일러의 컴파일 단계에서, 유저가 정의한 어노테이션의 소스코드를 분석하고 처리하기 위해 사용되는 훅이다. 컴파일 에러나 컴파일 경고를 만들어 내거나, 소스코드(.java)와 바이트코드(.class)를 내보내기도 한다
어노테이션 프로세서 사용 예제
- Lombok
- AutoService : java.util.ServiceLoader 용 파일 생성 유틸리티
- @Override
- Dangger 2 : 컴파일 타임 DI 제공
어노테이션 프로세서 장점
- 런타임 비용이 없음(컴파일 타임에 조작이 완료된 상황이기 때문에)
어노테이션 프로세싱의 애플리케이션
- 소스 레벨 어노테이션 프로세싱은 Java5부터 나타났다. 이는 컴파일 단계에서 추가 소스 파일을 생성하는 편리한 기술이다
- 소스 파일이 Java 파일 일 필요는 없다. 소스 코드의 어노테이션을 기반으로 모든 종류의 설명, 메타 데이터, 문서, 리소스 또는 기타 모든 유형의 파일을 생성할 수 있다.
- 중요한 점은 어노테이션 프로세서 API의 한계이다. 기존 파일을 변경하지 않고 새 파일을 생성하는 데만 사용할 수 있다.
어노테이션 프로세싱 API
- 어노테이션 프로세싱은 여러 라운드로 수행된다. 각 라운드는 컴파일러가 소스 파일에서 어노테이션을 검색하고 이러한 어노테이션에 적합한 어노테이션 프로세서를 선택하는 것으로 시작된다. 차례로 각 어노테이션 프로세서는 해당 소스에서 호출된다.
- 프로세스 중에 파일이 생성되면 생성된 파일을 입력으로 사용하여 다른 라운드가 시작이된다. 이 프로세스는 처리단계에서 새 파일이 생성되지 않을 때까지 계속된다
- 각 어노테이션 프로세서는 해당 소스에서 차례로 호출된다. 이 프로세스 중에 파일이 생성되면 생성된 파일을 입력으로 사용하여 다른 라운드가 시작된다. 이 프로세스는 처리 단계에서 새 파일이 생성되지 않을 때까지 계속된다.
- 어노테이션 처리 API는 javax.annotation.processing 패키지에 있다. 구현해야 할 주요 인터페이스는 AbstractProcessor 클래스 형태의 부분 구현이 있는 프로세서 인터페이스다 이 클래스는 자체 주석 프로세서를 만들기 위해 확장할 클래스이다
Reference
'스터디 > LiveStudy' 카테고리의 다른 글
14주차 과제: 제네릭 (0) | 2021.02.21 |
---|---|
13주차 과제 : I/O (0) | 2021.02.08 |
11주차 과제: Enum (0) | 2021.01.25 |
10주차 과제: 멀티쓰레드 프로그래밍 (6) | 2021.01.18 |
9주차 과제: 예외 처리 (0) | 2021.01.11 |