뭐라도 끄적이는 BLOG

Java Annotation 본문

Java/Java 기본

Java Annotation

Drawhale 2023. 7. 2. 06:16

Annotation

Annotation은 주석이라는 뜻이다. 하지만 Java의 기본 주석은 "//"또는 "/* */"로 사용해왔다. 이러한 일반 주석과 Annotation의 차이점은 Annotation에선 코드를 작성할 수 있다는 것이다. 코드를 작성할 수 있다는 것은 Annotation으로 뭔가를 할 수 있다는 뜻이 된다.

Annotation은 java 1.5에서 등장했다.

기존 자바는 선언적 프로그래밍 방식으로 개발을 하면서 각 계층별 설정 데이터들을 XML에 명시하였다. 이는 서비스의 규모가 클 수록 설정양이 많아지고 도메인 처리의 데이터들이 분산되어 있어 수정이 힘들었다.

이후 Annotation이 등장하면서 데이터 유효성 검사 등 직접 클래스에 명시해 줄 수 있게되어 수정이 필요할 때 쉽게 파악할 수 있게 되었고 Annotation의 재사용또한 가능해졌다.

@Override가 대표적인 Annotation중 하나

Annotation 정의하는 방법

@interface는 Annotation type을 선언하는 키워드이다. interface선언과 구분하기 위해 interface앞에 '@'를 붙인다.

public @interface Symbol {
}

Annotation 필드

Annotation에 필드같은 요소를 정의할 수 있다. 요소는 다음과 같은 규칙을 가지고 있다.

애노테이션 요소의 규칙

  • 요소의 타입은 기본형, String, enum, 어노테이션, Class만 허용
  • ()안에 매개변수는 선언할 수 없다.
  • 예외를 선언할 수는 없다.
  • 요소를 타입 매개변수로 정의 할 수 없다.
  • 배열을 선언할 수 있다.
  • default값을 지정할 수 있다.
public @interface Symbol {
    int num() default 100;
    String str() default "string";
    String[] strs();
    Week w() default Week.MON;
    Class c();
    Target t();
}
public class AnnotationMain {
    @Symbol(
            strs = {"kim", "park"},
            c = AnnotationMain.class,
            t = @Target(ElementType.ANNOTATION_TYPE)
    )
    public void name(){

    }
    public static void main(String[] args) {

    }
}

Annotation을 적용하고 각 요소에 값을 주고 사용하고 있다. default 가 주어진 요소는 생략할 수 있으며 없는 요소는 반드시 값을 주어야한다.

@Retention(RetentionPolicy.RUNTIME)
public @interface Symbol {
    int num() default 100;
    String str() default "string";
    String[] strs();
    Week w() default Week.MON;
    Class c();
    Target t();
}
public class AnnotationMain {
    public static void main(String[] args) {
        Method[] methods = AnnotationMain.class.getMethods();
        for(Method m : methods){
            if (m.isAnnotationPresent(Symbol.class)){
                System.out.println(m.getName());
                Symbol symbol = m.getDeclaredAnnotation(Symbol.class);
                System.out.println(symbol.num());
                System.out.println(symbol.str());
            }
        }
    }
}

java8 Annotation

  • 클래스 인스턴스를 생성할 때
    • new @Interned MyObject();
  • 타입 캐스트
    • myString = (@NonNull String) str;
  • 인터페이스 구현(implements)
    • class UnmodifiableList<T> implements @Readonly List<@Readonly T> { . . . }
  • 예외를 throws 할 때
    • void monitorTemperature() throws @Critical TemperatureException { . . . }

Java Reflection

모든 클래스 파일은 클래스로더(Classloader)에 의해 메모리에 올라갈 때, 클래스에 대한 정보가 담긴 객체를 생성한다. 이를 클래스 객체라고 한다. 이 객체를 참조할 때는 'className.class'의 형식을 사용한다.

className.class를 이용해서 클래스의 필드, 생성자, 메서드에 대한 정보를 얻을 수 있다.

Method Name Return Type Description
getFields() Field[] 접근 제어자가 public인 필드들을 Field 배열로 반환
부노 클래스의 필드들도 함께 반환합니다.
getConstructors() Constructor[] 접근 제어자가 public인 생성자들을 Constructor배열로 반환. 부모 클래스의 생성자들도 함께 반환 합니다.
getMethods() Method[] 접근 제어자가 public인 메서드들을 Method 배열로 반환. 부모 클래스의 메서드들도 함께 반환합니다.
getDeclaredFields() Field[] 접근 제어자에 상관없이 모든 필드들을 Field배열로 반환. 부모 클래스의 필드들은 반환하지 않습니다.
getDeclaredConstructors() Constructor[] 접근 제어자에 상관없이 모든 생성자들을 Constructor배열로 반환. 부모 클래스의 생성자들을은 반환하지 않습니다.
getDeclaredMethod() Method[] 접근 제어자에 상관없이 모든 메서드들을 Method배열로 반환. 부모 클래스의 메서들들은 반환하지 않습니다.

메타 Annotation

메타 데이터가 데이터에 대한 데이터인 것처럼 메타 AnnotationAnnotation을 위한 Annotation. 즉, Annotation을 정의하는데 사용하는 Annotation이다. Annotation의 적용대상(target), 유지기간(retention)등을 지정하는데 사용된다.

메타 Annotation은 java.lang.annotation 패키지에 포함되어 있다.

@Target 애노테이션이 적용가능한 대상을 지정하는데 사용합니다.
@Documented 애노테이션 정보가 javadoc으로 작성된 문서에 포함되게 합니다.
@Inherited 애노테이션이 자손 클래스에 상속되도록 합니다.
@Retention 애노테이션이 유지되는 범위를 지정하는데 사용합니다.
@Repeatable 애노테이션을 반복해서 적용할 수 있게 합니다.

@Retention

Annotation이 유지(retention)되는 기간을 지정하는데 사용한다. 즉, 어느 시점까지 가져갈지 설정하는 것이다.

 

SOURCE는 Annotation을 사실상 주석처럼 사용한다고 보면 된다. 컴파일러가 컴파일 할 때 해당 Annotation의 메모리는 버린다. '@Override'나 '@SuppressWarnings'처럼 컴파일러가 사용하는 애노테이션은 유지 정책이 'SOURCE'이다. 컴파일러를 직접 만드는 것이 아니라면 주석처럼 사용된다.

 

CLASS(디폴드 값)는 컴파일러가 컴파일 시에는 Annotation의 메모리를 가져가지만, 실질적으로 런타임시에는 사라지게 된다. 런타임시에 사라진다는 것은 리플렉션으로 선언된 Annotation 데이터를 가져올 수 없게 된다는 것이다. 즉, 실행 타임에서 Annotation에 대한 데이터를 활용할 수 없다는 것을 의미한다.

해당 클래스에 있는 Annotation의 정보를 가져오고 싶을 때 유지정책이 SOURCE나 CLASS라면 가져오는 것이 불가능하다.

RUNTIME은 Annotation을 런타임시에까지 사용할 수 있다. JVM이 자바 바이트코드가 담긴 class파일에서 런타임 환경을 구성하고 런타임을 종료할 때까지 메모리에 남아 있습니다.

@Target

Annotation이 적용가능한 대상을 지정하는데 사용한다. 적용가능한 대상을 여럿 지정하고 싶다면 {}배열을 사용할 수 있다. 요소 타입이 ElementType[] 배열이기 때문에 적용가능한 대상을 여러 개의 값을 지정할 수 있다.

@Target({ElementType.FIELD, ElementType.METHOD})
ElementType 설명
ANNOTATION_TYPE 애노테이션
CONSTRUCTOR 생성자
FIELD 필드(멤버변수, enum상수)
LOCAL_VARIABLE 지역변수
METHOD 메서드
PACKAGE 패키지
PARAMETER 매개변수
TYPE 타입(클래스, 인터페이스, enum)
TYPE_PARAMETER 타입 매개변수
TYPE_USE 타입이 사용되는 곳(타입의 변수를 선언할 때)

FIELD는 기본형 TYPE_USE는 참조형에 사용된다.

@Documented

Annotation정보가 javadoc으로 작성된 문서에 포함되도록 하는 메타 Annotation이다. 자바에서 제공하는 기본 Annotation 중 '@Override'와 '@SuppressWarnings'를 제외하고는 모두 @Documented 메타 Annotation이 붙어 있다.

마커 애노테이션(Marker Annotation)

값을 지정할 필요가 없는 경우, Annotation의 요소를 하나도 정의하지 않을 수 있습니다. 이런 Annotation을 마커 Annotation이라고 합니다. 대표적으로 @Override가 있습니다.

애노테이션 프로세서

소스코드 레벨에서 소스코드에 붙어있는 Annotation 정보를 읽어와 컴파일러가 컴파일 중 새로운 소스코드를 생성하거나 기존의 코드 변경을 가능하게 한다. 바이트 코드도 생성 가능하며 소스코드와 별개의 리소스도 생성 가능하다. 대표적으로 Lombok의 @Getter, @Setter, @Builder가 있다.

@Override처럼 메서드가 잘못된 대상임을 체크해 주는것도 Annotation 프로세서 라고 한다.

반응형

'Java > Java 기본' 카테고리의 다른 글

Java Generic  (0) 2023.07.02
Java I/O  (0) 2023.07.02
Java Enum  (0) 2023.07.02
Java Thread  (0) 2023.07.02
Java Exception, Error  (0) 2023.07.02