Custom Annotation 만들기



Gson 이라는 클래스를 쓸때 @SerializedName("fieldName") 라는 쓰는 경우가 있고

이러한 Annotation의 원리가 궁금했다.


1. interface앞에 @를 붙여서 Annotation Interface를 선언한다.

2. Annotation을 구현한다. (Annotation 사용자의 경우)

3. Reflection을 이용하여 객체나 class에서 선언된 필드나 메소드를 찾고 적절한 동작을 구현한다.

의 순서로 접근하면 된다.



1. interface앞에 @를 붙여서 Annotation Interface를 선언한다.

@Inherited

@Documented

@Retention(RetentionPolicy.RUNTIME) // 컴파일 이후에도 JVM에 의해서 참조가 가능합니다.

//@Retention(RetentionPolicy.CLASS) // 컴파일러가 클래스를 참조할 때까지 유효합니다.

//@Retention(RetentionPolicy.SOURCE) // 어노테이션 정보는 컴파일 이후 없어집니다.

@Target({

        ElementType.PACKAGE, // 패키지 선언시

        ElementType.TYPE, // 타입 선언시

        ElementType.CONSTRUCTOR, // 생성자 선언시

        ElementType.FIELD, // 멤버 변수 선언시

        ElementType.METHOD, // 메소드 선언시

        ElementType.ANNOTATION_TYPE, // 어노테이션 타입 선언시

        ElementType.LOCAL_VARIABLE, // 지역 변수 선언시

        ElementType.PARAMETER, // 매개 변수 선언시

        ElementType.TYPE_PARAMETER, // 매개 변수 타입 선언시

        ElementType.TYPE_USE // 타입 사용시

})


public @interface CustomAnnotation {

    

    String name() default "default";

    String value() default "default";

}

- name(), value()가 attribute명이자 getter가 된다.

- default는 필드값을 안채우거나 하나만 쓸때 채워지는 값이다.

- interface위의 필드(Target, Retention 등)는 주석을 보거나 실생활에 쓰이고 있는 case를 참고하는것이 좋겠다.


1-1. 사용사례

 @Override

 package java.lang;

 ...

 @Target(ElementType.METHOD)

 @Retention(RetentionPolicy.SOURCE)

 public @interface Override {

 }

 @SerializedName

 package com.google.gson.annotations;

 ...

 @Retention(RetentionPolicy.RUNTIME)

 @Target({ElementType.FIELD})

 public @interface SerializedName {

     String value();

 }

@Test 

 package org.junit;

 ...

 @Retention(RetentionPolicy.RUNTIME)

 @Target({ElementType.METHOD})

 public @interface Test {

   Class<? extends Throwable> expected() default Test.None.class;

   long timeout() default 0L;

   public static class None extends Throwable {

        private static final long serialVersionUID = 1L;

        private None() {

        }

    }

}

- Override 주석을 보면 그 유명한 Effective Java의 저자 조슈아 블로치(Joshua Bloch)이고 Java 1.5부터 반영된것으로 보인다!!



2. Annotation을 구현한다. (Annotation 사용자의 경우)

public class CustomAnnotationImpl {

    @CustomAnnotation("aaa")

    private String name;


    @CustomAnnotation(value="ccc", name="bbb")

    private String value;


    CustomAnnotationImpl(String name, String value) {

        this.name = name;

        this.value = value;

    }


    public String getName() {

        return name;

    }


    public void setName(String name) {

        this.name = name;

    }


    public String getValue() {

        return value;

    }


    public void setValue(String value) {

        this.value = value;

    }


    @CustomAnnotation("print")

    public void printNameAndValue() {

        System.out.println("name=" + name + ", value=" + value);

    }

}

- 1에서처럼 매개변수가 여러개로 선언했으나 @CustomAnnotation("aaa")인 경우는 매개변수 선언 순서상의 마지막에 할당되는 것 같다.



3. Reflection을 이용하여 객체나 class에서 선언된 필드나 메소드를 찾고 적절한 동작을 구현한다.

 Field 찾기

         for (Field field : fieldArray) {

            String fieldName = field.getName();

            CustomAnnotation testAnnotation = field.getAnnotation(CustomAnnotation.class);

            Annotation[] annotationArray = field.getDeclaredAnnotations();

            boolean isAnnotationPresent = field.isAnnotationPresent(CustomAnnotation.class);


            if (testAnnotation != null) {

                field.setAccessible(true);

                

                if (obj != null) {

                    String fieldValue = (String)field.get(obj);

                    field.set(obj, "33");

                    fieldValue = (String)field.get(obj);

                }

            }

        }

 Method 찾기

         for (Method method : methodArray) {

            String methodName = method.getName();

            CustomAnnotation testAnnotation = method.getAnnotation(CustomAnnotation.class);

            Annotation[] annotationArray = method.getDeclaredAnnotations();

            boolean isAnnotationPresent = method.isAnnotationPresent(CustomAnnotation.class);

            

            if (testAnnotation != null) {                

                if (obj != null) {

                    method.invoke(obj);

                }

            }

        }

- 하지만 Reflection은 성능이 좋지 않다는 치명적인 단점이 있다. 매개변수의 타입체킹도 런타임에 되서 위험할 수도 있고...

  잘 쓰면 괜찮다고는 하지만 그만큼 적절한가를 따져야 한다.



위 내용에 대한 코드는 github에서 확인하실 수 있습니다.

https://github.com/ndukwon/Duk_Java_library/tree/master/src/com/duk/lab/java/annotation



Reference:

- http://jdm.kr/blog/216

- https://medium.com/@ggikko/java-%EC%BB%A4%EC%8A%A4%ED%85%80-annotation-436253f395ad

- https://www.javatpoint.com/custom-annotation






'Program Languages > Java' 카테고리의 다른 글

Custom Annotation 만들기  (0) 2017.06.26
Loop 문법과 속도  (0) 2017.06.26

Loop 문법과 속도



필자는 ArrayList를 즐겨쓰기 때문에 for문을 어떻게 쓰건 거의 상관없지만

LinkedList를 쓴다면 for문에 따라 속도영향이 있다.



0. list가 다음과 같이 있다고 가정

List<Integer> linkedList = new LinkedList<>();

List<Integer> arrayList = new ArrayList<>();


for (int i = 0; i < 100000; i++) {

linkedList.add(i);

arrayList.add(i);

}



1. 기본 3항 for문: 'for ( ;  ; )'

for (int i = 0; i < list.size(); i++) {

Integer value = list.get(i);

}

- 시간: 5382ms (arraylist의 경우: 4ms)



2. for each문: 'for (a : A)'

for (Integer value : list) {

}

- 시간: 2ms (arraylist의 경우: 4ms)

- JAVA 5에서 추가됨



3. while + iterator 문: 'while (iterator.hasNext())'

Iterator<Integer> iterator = list.iterator();


while (iterator.hasNext()) {

Integer value = iterator.next();

}

- 시간: 3ms (arraylist의 경우: 3ms)



4. 'forEach()' 문

list.forEach((value) -> {

});

- 시간: 42ms (arraylist의 경우: 46ms)

JAVA 8에서 추가됨

- 조금느릴 수 있지만 Parallel을 지원한다.



5. 결론

- linkedList의 경우: for-each문, while + iterator 문 이 빠르다.

- arrayList의 경우: 크게 차이없다.



위 내용에 대한 코드는 github에서 확인하실 수 있습니다.

https://github.com/ndukwon/Duk_Java_library/blob/master/src/com/duk/lab/java/FundamentalTest.java



Reference:

- https://dzone.com/articles/devoxx-2012-java-8-lambda-and


'Program Languages > Java' 카테고리의 다른 글

Custom Annotation 만들기  (0) 2017.06.26
Loop 문법과 속도  (0) 2017.06.26

+ Recent posts