by-nc-sa     개발자, DBA가 함께 만들어가는 구루비 지식창고!

Annotation




어노테이션

Annotation

Annotation 이란

  • 메타데이터, 한 마디로 데이터의 데이터다
  • 어노테이션이 나오기 전까지 메타데이터는 프로퍼티 파일과 XML파일을 활용하였다.
  • 어노테이션은 주로 데이터를 문서화하거나, 컴파일 타임이나 런타임시에 원하는 동작을 수행할 수 있도록 하는 데 사용된다.
  • 닷넷프레임워크 1.0에서 어트리뷰트라는 기능을 제공하자, 자바에서 어노테이션을 통한 메타데이터 활용 기술을 제공했다.

Annotation의 장점

  • 코드의 가독성 증대
    • 관련 코드 곁에 메타데이터를 설정할 수 있으므로 코드의 가독성 증대 된다.
  • 개발 효율성 증대
    • 복잡한 XML 스키마를 파악하지 않아도 되며, 개발시 개발 툴과 컴파일러의 도움을 받을 수 있으므로 개발 효율성이 증대 된다.
  • 별도의 파서를 적용하지 않고도 간단히 런타임 시에 활용할 수 있는 편리함이 있다.
  • JUnit, Framework, Permission Module 에서 사용

Annotation을 반대하는 사람들의 의견

  • 메타정보와 소스의 결합자체를 못마땅하다.
  • 메타데이터는 그 자체로 코드에 독립적이어야 하며 한 곳에 모여져서 어플리케이션의 구성을 한눈에 알 수 있어야 바람직하다는 주장.
  • 어노테이션은 코드를 이용해서 검증하는게 가능하지만 XML의 DTD나 스키마를 이용하는 검증 방식에 비해서 훨씬 불편하다.

Annotation의 단점

  • 어노테이션 처리시 리플렉션을 통해 해당 클래스를 분석해야 하는 오버헤드가 있다.
    • XML 파일을 이용하는 방법도 오버헤드가 있으므로, 경우에 따라서 어노테이션이 더 빠를 수도 있음.
  • 어노테이션은 모듈이나 어플리케이션 전반적인 메타데이터를 설정할 수 없다.
    • 어노테이션의 범위는 클래스나 패키지 레벨로 한정되기 때문에 여러 클래스에 걸친 공통적인 설정이나 모듈레벨 설정이 어렵다.
    • 웹 어플리케이션 개발시 서블릿 필터나, 인터셉터를 이용해서 문제 해결이 가능함.

XML과 어노테이션같이 쓰기

  • 대부분의 일반적인 웹 어플리케이션에 적합한 방법 이다.
  • 어플리케이션 상에서 디자인 타임에 결정되는 부분에 대해서는 어노테이션을 사용하는 것이 좋고,
    실제 디플로이 환경에 따라 바뀔 수 있는 부분의 경우 XML을 사용하여 표기하는 것이 좋다.

Annotation 형태

  • Marker Annotation
    • 이름만 있는 어노테이션
    • @AnnotationName
  • Single-Element Annotation
    • 하나의 원소만을 가지고 있는 어노테이션
    • @AnnotationName(elementValue)
  • Normal Annotation
    • 여러 개의 원소를 갖는 어노테이션
    • @AnnotationName(element=value, element=value, ...)

Builtln Annotation

Standard Annotations

  • @Deprecated
    • 특정 클래스나 인터페이스, 메소드, 필드 등이 앞으로 더이상 사용되지 말아야 한다는 것을 경고하기 위해서 사용.
    • 컴파일러는 deprecated된 메소드나 클래스 혹은 변수를 사용할 때마다 경고를 발생시킨다.
  • @Override
    • 메소드에 대해서만 사용되어야 한다. (클래스, 패키지 선언, 기타 구조체는 안된다.)
    • 수퍼클래스에서 메소드를 오버라이드한다는 것을 나타내며, 슈퍼클래스의 메소드를 재정의하지 못하면 컴파일 에러가 발생.
  • @SuppressWarning
    • 컴파일러에게 경고를 하지 않도록 지시 한다.
    • all, deprecation, unchecked, fallthrough, path, serial, finally 등의 금지 옵션이 있다.

Meta-Annotations

  • @Target
    • 어노테이션을 정의 시 어노테이션이 사용 가능한 대상을 지정한다.
    • ElementType의 상수로 정의
ElementType 상수 의미
ANNOTATION_TYPE 어노테이션 형
CONSTRUCTOR 생성자
FIELD enum 상수를 포함한 필드(멤버변수)
LOCAL_VARIABLE 지역변수
METHOD 메소드
PACKAGE 패키지
PARAMETER 매개변수
TYPE 클래스, 인터페이스(어노테이션 형 포함), 열거형
@Target({ElementType.TYPE,
    ElementType.METHOD,
    ElementType.CONSTRUCTOR,
    ElementType.ANNOTATION_TYPE})
  • @Retention
    • 어노테이션 정보의 유지 범위를 설정
    • RetentionPolicy의 상수로 정의
    • @Retention(RetentionPolicy.SOURCE)
RetentionPolicy 상수 의미
SOURCE 어노테이션 정보를 클래스 파일에 저장되지 않고 소스를 처리하는 도구에서만 사용.
CLASS 어노테이션 정보를 컴파일러는 클래스 파일에 저장하지만 VM에서는 읽지 않고 버려짐.
RUNTIME 어노테이션 정보를 컴파일러는 클래스 파일에 저장하고, VM에서 저장된 정보를 읽음.
  • @Documented : @Documented 해당 어노테이션을 Javadoc에 포함한다.
  • @Inherited 서브 클래스가 부모 어노테이션을 상속받도록 한다.

사용자 정의 Annotation

  • 프로그래머가 정의하는 어노테이션으로 class 형태로 만들어진다.
  • 어노테이션의 선언은 @interface 로 한다.
  • 이름 앞에 '@' 문자가 오는 것 외에는 기본적으로 인터페이스를 선언하는 것과 동일(메소드들의 내용은 없고 형태만 선언)
  • default 가 찍히지 않은 메소드는 필수로 입력해야 한다.
@Retention(RetentionPolicy.RUNTIME)
public @interface Maker {
  int num();
  String name();
  String id();
  String date() default "unsigned";
}
@Maker(num=1, name="김정식",  id="oramaster")
public class UseMaker {
			
	/**
	 * class.getAnnotations() 와 같이 어노테이션을 파싱할수 있다.<br/>
	 * 물론 어노테이션 인터페이스에서 @Retention(RetentionPolicy.RUNTIME) 를 선언해 줘야지만 가능하다<br/>
	 * 
	 */
	public static void main(String args[]) {
		for (Annotation a: UseMaker.class.getAnnotations()) {
			System.out.println("Annotation : " + a);
		}
	}
}

결과
Annotation : @com.oracleclub.sample.annotation.Maker(date=unsigned, num=1, name=김정식, id=oramaster)

Annotation 접근

  • 실행중인 프로그램에서 Annotation에 접근하는 방법을 알아보자
  • 인터페이스 java.lang.reflect.AnnotateElement를 통해서 실행중인 Annotation에 접근 할 수 있다.
  • boolean isAnnotationPresent(Class<? extends Annotation> annotationType)
    • Annotation 존재 여부를 반환한다.
    • Annotation이 존재하면 true, 존재하지 않으면 false 반환
  • <T extends Annotation> T getAnnotation(Class<T> annotationType)
    • Annotation을 반환
  • Annotation[] getAnnotations()
    • 존재하는 모든 Annotation들을 반환 (private 제외)
  • Annotation[] getDeclaredAnnotations()
    • 존재하는 모든 Annotation들을 반환 (private 포함)

간단한 예제

  • Junit 의 테스트 케이스 비슷한 예제.
  • SimpleTest 어노테이션 생성
SimpleTest.java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SimpleTest { }
  • SimpleTest를 사용하는 테스트 케이스 UseSimpleTest 생성
UseSimpleTest.java
public class UseSimpleTest {

  @SimpleTest
  public void test1(){
    System.out.println(" # test1 ");
  }
	
  @SimpleTest
  public void test2() throws Exception{
    throw new Exception(" # 에러 발생 ");
  }
	
  @SimpleTest
  public void test3(){
    System.out.println(" # test3 ");
  }
}
  • Annotation에 접근해서 테스트 해보자.
RunnerSimpleTest.java
public static void main(String[] args) throws Exception{
  RunnerSimpleTest.runner("com.oracleclub.sample.annotation.UseSimpleTest");		
}

private static void runner(String className) {

  int pass = 0;
  int fail = 0;
  Object testObject = null;

  try{		
    testObject = Class.forName(className).newInstance();
  }catch(Exception ce){
    System.out.println(className+"를 찾을 수 없습니다. ");  
  }

  for(Method m : testObject.getClass().getMethods()){		

    if(m.isAnnotationPresent(SimpleTest.class)){

      try{
        m.invoke(testObject, null);
        pass++;
      }catch(Exception e){
        System.out.println(m.getName()+" 테스트 실패 : "+e.getCause());					
        fail++;
      }
    } 
  }
  System.out.println(" # 테스트 종료 -> 성공 : "+pass+", 실패 : "+fail);  
}

//실행결과
 # test1 
test2 테스트 실패 : java.lang.Exception:  # 에러 발생 
 # test3 
 # 테스트 종료 -> 성공 : 2, 실패 : 1

Annotation Processing Tool

  • Annotation의 소스를 체크하고 컴파일을 처리해줌
  • JDK 5에는 어노테이션을 읽고 이해하는 API가 표준화되어 있지 않아 JDK에 들어있는 썬 고유의 라이브러리를 사용했고, 자바 SE 6에 기본으로 포함되었다.
  • JDK 5에는 APT(Annotation Processing Tool)라는 패키지가 포함되어, JSR 269(JSR 269 Pluggable Annotation Processing API)가 나오기 전까지 임시로 그 역할을 대신했다.
  • Apache Ant에서는 APT에 대응하는 앤트 타스크를 따로 두어 지원하였다. http://ant.apache.org/manual/CoreTasks/apt.html에서 확인할 수 있다.

Reference

문서에 대하여

  • 작성일자 : 김정식
  • 작성자 : 2008년 10월 31일
  • 이 문서는 오라클클럽 에서 작성하였습니다.
  • 이 문서를 다른 블로그나 홈페이지에 게재할 경우에는 출처를 꼭 밝혀 주시면 고맙겠습니다.

문서정보

Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.