ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Java] 어노테이션
    IT/개발(자바, 서블릿, 스프링 등) 2020. 1. 25. 19:34

    어노테이션(annotation)은 실행하고는 상관없이 자바 소스코드에 주석문처럼 추가하는 부가적인 정보다. 어노테이션은 서로 다른 이름으로 구성된 정보들을 가지는 하나의 단위이며 이것을 메타데이터(metadata) 라고 한다. 어노테이션과 메타데이터는 같은 의미이며 보편적으로 많이 사용하는 용어는 어노테이션이다. 어노테이션은 컴파일러를 비롯해 개발에 사용되는 여러 도구에 정보를 제공할 목적으로 사용한다.

     

    1. 어노테이션 개요

    어노테이션 선언

     

    [어노테이션 선언]

    @interface 어노테이션명 {

          데이터타입 변수명();

    }

     

    인터페이스를 선언하는 방법과 비슷하다. interface 대신 @interface 키워드를 사용한다.

     

    @interface Check {
    	String name();
        int val();
    }

    이름은 Check이고 name과 val이라는 데이터 정보를 나타내는 어노테이션을 선언한 예이다. name, val은 추상 메서드로 선언했으나, 값을 가지는 변수처럼 사용되므로 필드라고 생각해도 좋다.

     

    @interface로 선언한 어노테이션은 자동으로 Annotation 인터페이스를 상속받는다. 즉, Annotation은 모든 어노테이션의 상위 상위 객체이다. 따라서 Annotation에 선언된 모든 메서드를 어노테이션 객체에서 사용할 수 있다.

     

    제어자 및 타입 메서드 설명
    Class<? extends Annotation> annotationType() 어노테이션의 클래스 객체 반환
    boolean equals(Object obj) 매개변수로 전달받은 어노테이션과 논리적으로 동일한지 판단
    int hashCode() 어노테이션의 해시코드값 반환
    String toString() 어노테이션의 문자열값 반환

     

    어노테이션 사용

     

    [어노테이션 사용]

    @어노테이션명(변수명 = 값, 변수명 = 값)

     

    어노테이션에 데이터를 저장하려면 괄호 () 안에 어노테이션에서 선언한 '변수명=값' 형식으로 지정하며, 여러 개의 값을 지정할 땐 콤마(,)를 구분자로 사용한다.

     

    @Check(name="first", val=123_
    public static void test() {...}

     

    어노테이션 유지 정책

     

    어노테이션 정보들은 유지 범위 값에 따라 서로 다른 범위로 사용할 수 있다. 어노테이션에 지정할 수 있는 유지 범위 값을 가지는 객체는 lang.annotation.RetentionPolicy 열거형 클래스다. RetentionPolicy에 정의돈 열거 상수는 다음과 같다.

     

    SOURCE: 소스 파일에서만 유지하고 컴파일 때 삭제함

    CLASS: 컴파일된 바이트코드(.class)에서 유지됨. 그러나 실행 때 JVM이 사용할 수 없음.

    RUNTIME: 컴파일된 바이트코드(.class)에서 유지됨. 실행 때 JVM이 사용 가능함.

     

    어노테이션에 유지 정책을 적용해 선언하려면 자바에서 기본적으로 제공하는 @Retention 어노테이션을 지정한다. 

    [@Retention 어노테이션 사용]

    @Retention(RetentionPolicy.열거상수]

     

    @Retention(RetentionPolicy.RUNTIME)
    @interface Check {
    	String name();
        int val();
    }

     

    정보 추출

    어노테이션은 개발 또는 배치(deployment) 도구에서 사용하고자 소스코드에  추가하는 정보다. 프로그램 실행 시 어노테이션 정보를 사용할 때는 리플렉션(reflection)을 사용해 정보를 추출해야 한다. 리플렉션은 클래스의 정보(선언된 클래스, 메서드, 변수에 대한 정보)를 처리할 수 있게 해주는 기능이다. java.lang.reflect 패키지의 API에서 제공한다.

     

    리플렉션을 위한 Class 객체

     

    리플렉션을 사용하려면 가장 먼저 Class 객체를 생성해야 한다. Class 객체는 클래스에 대한 정보를 가지는 객체로 다음 두가지 방법으로 생성할 수 있다.

     

    final Class<?> getClass()

     

    Test.class 또는 Check.class

     

    만약 Test가 일반 클래스라면 Test.class는 Test 클래스에 대한 정보를 갖는 Class 객체가 생성되고, Check가 어노테이션이라면 Check.class는  Check 어노테이션에 대한 정보를 갖는다. 아래는 Class 객체에 대한 정보를 추출하는 메서드다.

     

    Method getMethod(String) : 인자로 지정된 이름의 메서드를 Method 객체로 반환

    boolean isAnnotationPresent(Class): 매개변수로 전달받은 어노테이션의 적용 여부 판단

    Annotation getAnnotation(Class): 매개변수로 전달받은 어노테이션을 Annotation 객체로 반환

    Annotation[] getAnnotation(): 적용한 모든 어노테이션을 Annotation 객체로 반환

     

    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.reflect.Method;
    
    @Retention(RetentionPolicy.RUNTIME)
    @interface Check {
        String name();
        int val();
    }
    
    public class AnnoTest {
        @Check(name="first", val=123)
        public static void test(){
            AnnoTest obj = new AnnoTest();
    
            try{
                Class<?> c = obj.getClass();
                Method m = c.getMethod("test");
    
                Check check = m.getAnnotation(Check.class);
                System.out.println(check.name() + " : " + check.val());
            } catch (Exception e){
                e.printStackTrace();
            }
        }
    
        public static void main(String[] args) {
            test();
        }
    }
    

     

    표준 어노테이션

     

    표준 어노테이션은 자바 API에서 기본으로 제공하는 어노테이션을 말하며 java.lang.annotation과 java.lang 패키지에서 제공한다.

     

    java.lang.annotation

     

    @Retention 

    현재 선언하는 어노테이션의 유지 범위를 설정한다.

     

    @Document

    현재 선언하는 어노테이션을 자바 문서로 작성할 때 포함할 것인지 설정한다. @Document는 문서에 포함을 표시하는 어노테이션으로서 별도의 값을 지정할 필요가 없다.

     

    @Target

    현재 선언하는 어노테이션의 적용 대상을 설정한다. @Target의 값은 ElementType 열거형 클래스에서 정의된 상수를 사용한다. ElementType의 열거 상수는 다음과 같다.

     

    상수 적용 대상
    ANNOTATION_TYPE 어노테이션 선언
    CONSTRUCTOR 생성자 선언
    FIELD 필드 선언
    LOCAL_VARIABLE 지역변수 선언
    METHOD 메서드 선언
    MODULE 모듈 선언
    PACKAGE 패키지 선언
    PARAMETER 매개변수 선언
    TYPE 클래스, 인터페이스, 열거형 클래스 선언
    TYPE_PARAMETER 타입 매개변수 선언
    TYPE_USE 타입 사용

    예를 들어 다음처럼 선언하면 클래스, 인터페이스, 열거형 클래스를 선언하는 부분에서 사용할 수 있는 어노테이션이다.

     

    @Target(ElementType.TYPE)

     

    여러 대상을 지정할 땐 다음처럼 중괄호{} 안에 콤마로 구분하여 ElementType 상수를 지정한다.

     

    @Target({ElementType.TYPE, ElementType.METHOD})
    @Inherited

    상위 객체에 선언된 어노테이션에 @Inherited가 설정되면 하위 객체에서도 상속받아 사용할 수 있다. @Inherited는 상속을 표시하는 어노테이션으로서 값을 지정할 필요가 없다.

     

Designed by Tistory.