관리 메뉴

HAMA 블로그

자바 어노테이션의 모든것 - (2) 본문

Java

자바 어노테이션의 모든것 - (2)

[하마] 이승현 (wowlsh93@gmail.com) 2015. 7. 4. 13:17

2. 자바 어노테이션 이야기


2-1. 왜 어노테이션인가?


어노테이션은 J2SE 5 에 이미 소개되어졌고 , 중요한 탄생 이유는 프로그래머에게 그들의 코드에 대한 메타데이터를 자신의 코드에 직접적으로 기술할수있는것을 제공하기위함이다. 어노테이션이 만들어지기전에 프로그래머가 자신의 코드를 기술하는 방법은  transient 키워드를 사용한다던가, 주석(comments) 를 통하여, 인터페이스를 이용등등 중구난방이었다.그리고 여러타입의 어플리케이션에서 코드를 기술하는 메커니즘은 주로 XML 이 사용되어졌는데  이것은 그리 좋은 방법은 아닌게  코드와 XML (XML 은 코드가 아니다) 사이에 디커플링이 발생되고  이것은 어플리케이션을 유지보수하기 힘들게 한다.


자바 스펙에서 어노테이션은 다음에서 나타내 지고 있다 :


2-2. 소개 


어노테이션을 나타내는(설명해주는) 가장 좋은 단어는  메타데이터이다. (자신의 정보를 담고있는 데이타) . 
자바 어노테이션은 코드메타데이타이다. 

그것은 코드 그 자신에 대한 정보를 담고있다.어노테이션은 패키지,클래스,메소드,변수,파라미터등에서 사용될수있으며 자바 8 부터는  코드의 거의모든 부분에서 사용될수있다. 이것은 타입 어노테이션으로 불려지는데 아래에 살펴보겠다. 

어노테이션이 적용된 "코드" 는 직접적으로 그들의 "어노테이션" 으로부터 영향받아지지는 않고 단지 서드 시스템에 그것(주석) 에 대한 정보를 제공한다.

 어노테이션은 런타임에 활용할수있기도하며, 단지 소스레벨에서만 사용가능하게도 만들수있다. 


2-3. Consumers (소비자) 


어노테이션의 목적이 정확히 먼지, 어떻게 사용되는지 이해하는건 쉽지 않다, 그것들은 어떠한 기능적 로직을 가지고 있지 않으며 , 코드에 영향을 미치지 않는다.  어노테이션이 뭘 할까? 

이것을 위한 설명으로 난 어노테이션 컨슈머스라고 말하는게 있는데 ,  이것들은 시스템이나 서드파티 어플리케이션 (스프링같은) 으로서  어노테이션이 적용된  코드를 어노테이션 정보로부터 의존적인 여러가지 행동을 취한다.

예를들어 자바 빌트인 어노테이션경우에는 소비자는 자바가상머신(JVM) 이며 어노테이션이 적용된 코드를 실행한다.  사용자 정의 어노테이션의 경우의  예로는  JUnit, Spring 등이 있다.

그리고 소비자는 코드에서부터 어노테이션을 분석하기위해  자바 리플렉션을 이용한다. 


2-4. 유즈 케이스 

어노테이션은 다양한 목적으로 사용되는데 대표적으로는 

  •  컴파일러를 위한 정보제공 :  Java 8 @FunctionalInterface , @supresswarnings
  •  자동 문서 작성 :  generate reports automatically like Jenkins, Jira or Teamcity.
  •  코드 자동 생성 :  A good example of this is the JAXB library.
  •  런타임 프로세싱 : testing (Junit), dependency injection (Spring), logging (Log4J) ,data access (Hibernate) etc.


2-5. Java 8 에서 어노테이션 


Java 8 은 여러가지 훌륭한 기능을 가지고 왔는데 어노테이션 프레임워크도 발전되었다. 

다음 예예를 통해 확인해 보도록 하자.  

@Repeatable:  

1/**
2 * Container for the {@link CanBeRepeated} Annotation containing a list of values
3*/
4@Retention( RetentionPolicy.RUNTIME )
5@Target( ElementType.TYPE_USE )
6public @interface RepeatedValues
7{
8    CanBeRepeated[] value();
9}

Afterwards, we create the annotation itself and we mark it with the Meta annotation @Repeatable:

1@Retention( RetentionPolicy.RUNTIME )
2@Target( ElementType.TYPE_USE )
3@Repeatable( RepeatedValues.class )
4public @interface CanBeRepeated
5{
6 
7    String value();
8}

Finally we can see how to use it (repeatedly) in a given class:

1@CanBeRepeated"the color is green" )
2@CanBeRepeated"the color is red" )
3@CanBeRepeated"the color is blue" )
4public class RepeatableAnnotated
5{
6 
7}

If we would try to do the same with a non repeatable annotation:

01@Retention( RetentionPolicy.RUNTIME )
02@Target( ElementType.TYPE_USE )
03public @interface CannotBeRepeated
04{
05 
06    String value();
07}
08 
09@CannotBeRepeated"info" )
10/*
11 * if we try repeat the annotation we will get an error: Duplicate annotation of non-repeatable type
12 *
13 * @CannotBeRepeated. Only annotation types marked
14 *
15 * @Repeatable can be used multiple times at one target.
16 */
17// @CannotBeRepeated( "more info" )
18public class RepeatableAnnotatedWrong
19{
20 
21}

We would get an error from the compiler like:

1Duplicate annotation of non-repeatable type
  • Since Java 8 is also possible to use annotations within types. That is anywhere you can use a type, including the new operator, castings, implements and throws clauses. Type Annotations allow improved analysis of Java code and can ensure even stronger type checking. The following examples clarify this point:
01@SuppressWarnings"unused" )
02public static void main( String[] args )
03{
04    // type def
05    @TypeAnnotated
06    String cannotBeEmpty = null;
07 
08    // type
09    List<@TypeAnnotated String> myList = new ArrayList<String>();
10 
11    // values
12    String myString = new @TypeAnnotated String( "this is annotated in java 8" );
13 
14}
15 
16// in method params
17public void methodAnnotated( @TypeAnnotated int parameter )
18{
19    System.out.println( "do nothing" );
20}


All this was not possible until Java 8.

  • @FunctionalInterface: this annotation indicates that the element annotated is going to be a functional interface. A functional interface is an interface that has just one abstract method (not a default one). The compiler will handle the annotated element as a functional interface and will produce an error if the element does not comply with the needed requirements. Here is an example of functional interface annotation:
01// implementing its methods
02@SuppressWarnings( "unused" )
03MyCustomInterface myFuncInterface = new MyCustomInterface()
04{
05 
06    @Override
07    public int doSomething( int param )
08    {
09        return param * 10;
10    }
11};
12 
13// using lambdas
14@SuppressWarnings( "unused" )
15    MyCustomInterface myFuncInterfaceLambdas = ( x ) -> ( x * 10 );
16}
17 
18@FunctionalInterface
19interface MyCustomInterface
20{
21/*
22 * more abstract methods will cause the interface not to be a valid functional interface and
23 * the compiler will thrown an error:Invalid '@FunctionalInterface' annotation;
24 * FunctionalInterfaceAnnotation.MyCustomInterface is not a functional interface
25 */
26    // boolean isFunctionalInterface();
27 
28    int doSomething( int param );
29}

This annotation can be applied to classes, interfaces, enums and annotations and it is retained by the JVM and available in Run time. Here is its declaration:

1@Documented
2 @Retention(value=RUNTIME)
3 @Target(value=TYPE)
4public @interface FunctionalInterface



2-6. Retrieving   어노테이션 


자바 리플렉션 API 는 여러가지 메소드를 포함한다. 그 메소드들은 런타임에 클래스,메소드등으로부터  

어노테이션 정보를 얻을수있게 한다. 그것을 통해서 스프링같은 서드파티 프레임워크는 클래스들을 

조작할수있게 된다.


저런 모든 메소드들을 포함한 인터페이스는 AnnotatedElement 이며 대표적으로 다음과 같다.

  • getAnnotations():  주어진 엘리먼트가 가지고있는 모든 어노테이션을 배열로 가져온다.
  • isAnnotationPresent(annotation):  엘리먼트가 어노테이션을 가지고있는지 체크한다.
  • getAnnotation(class): 파라미터로 넘겨진 엘리먼트에 대한 단일 어노테이션을 가져온다.

This class is implementing by java.lang.Classjava.lang.reflect.Method and java.lang.reflect.Field among others, so can be used basically with any kind of Java element.

Now we are going to see an example of how to read the annotations present in a class or method using the methods listed above:

We write a program that tries to read all the annotations present in a class and its methods (we use for this example the classes defined before):

01public static void main( String[] args ) throws Exception
02{
03 
04    Class<AnnotatedClass> object = AnnotatedClass.class;
05    // 클래스로부터 모든 어노테이션을 가져온다.
06    Annotation[] annotations = object.getAnnotations();
07    for( Annotation annotation : annotations )
08    {
09        System.out.println( annotation );
10    }
11 
12    // 어노테이션이 존재하는지 체크한다.
13    if( object.isAnnotationPresent( CustomAnnotationClass.class ) )
14    {
15 
16        // 원하는 엘리먼트의 어노테이션을 가져온다.
17        Annotation annotation = object.getAnnotation( CustomAnnotationClass.class );
18 
19        System.out.println( annotation );
20 
21    }
22    // 클래스내에 있는 모든 메소드들에 대해 어노테이션을 확인한다.
23    for( Method method : object.getDeclaredMethods() )
24    {
25 
26        if( method.isAnnotationPresent( CustomAnnotationMethod.class ) )
27        {
28 
29            Annotation annotation = method.getAnnotation( CustomAnnotationMethod.class );
30 
31            System.out.println( annotation );
32 
33        }
34 
35    }
36}

The output of this program would be:

1@com.danibuiza.javacodegeeks.customannotations.CustomAnnotationClass(getInfo=Info, author=danibuiza, date=2014-05-05)
2 
3@com.danibuiza.javacodegeeks.customannotations.CustomAnnotationClass(getInfo=Info, author=danibuiza, date=2014-05-05)
4 
5@com.danibuiza.javacodegeeks.customannotations.CustomAnnotationMethod(author=friend of mine, date=2014-06-05, description=annotated method)
6@com.danibuiza.javacodegeeks.customannotations.CustomAnnotationMethod(author=danibuiza, date=2014-06-05, description=annotated method)

In the program above we can see the usage of the method getAnnotations() in order to retrieve all annotations for a given object (a method or a class). We also showed how to check if an specific annotation is present and to retrieve it in positive case using the methods isAnnotationPresent() and getAnnotation().





Reference 

http://tutorials.jenkov.com/java-reflection/annotations.html

http://tutorials.jenkov.com/java/annotations.html

http://www.javacodegeeks.com/2014/11/java-annotations-tutorial.html

http://hmkcode.com/spring-configuration-xml-annotation-java/



Comments