Annotation

roach·2021년 3월 17일
0

Java

목록 보기
5/5

개념

Annotation 은 metadata 라고 볼수 있습니다. 컴파일 과정과 런타임 과정에서 코드를 어떻게 컴파일하고 처리할 것인지를 알려주는 정보입니다. 사실 이러한 기능을 이용해서 생각보다 재미있는 기능들을 이용할 수 있기에 직접만들어보고, 이해되지 않았던 부분들을 정리했다.

사실 간단히 개념만 짚고 넘어가면 어디에 쓰이는지 잘모른다. 직접 해보는게 중요!

서론

  • 특정 블로그를 보던 중 되지도 않는 코드를 적어놓은 블로그때문에 삽질해서 그냥 정리함
  • 사실 알아두어야 할것이 괜히 메타 데이터니 주석이니 라고 어노테이션을 표현하는것이 아니다. 보면 볼수록 그 표현들이 와닿을 것이다.

Meta Annotation

  • @Retention : 어느 시점까지 어노테이션이 영향을 미치는지 결정 (Scope 라고 생각하면 쉬움)
  • @Documentation : 문서에도 어노테이션의 정보가 표현됩니다.
  • @Target : 어노테이션이 적용될 위치를 결정합니다.
  • @Inherited : 해당 어노테이션을 선언하면 부모 클래스에서 어노테이션을 상속 가능함.
  • @Repeatable : 반복적으로 어노테이션을 선언할 수 있게 합니다.

요구사항

  • 어노테이션에 data = 10 이라고 적으면 int 형 필드에 10을 주입시켜주는것.

코드 작성

  • 일단 인터페이스를 설계해보자

    • 필드가 Target 이고 RUNTIME 동안 유지되야 하니깐..

      import java.lang.annotation.ElementType;
      import java.lang.annotation.Retention;
      import java.lang.annotation.RetentionPolicy;
      import java.lang.annotation.Target;
      
      @Target(ElementType.FIELD)
      @Retention(RetentionPolicy.RUNTIME) 
      public @interface InsertIntData {
      
          int data() default 0;
      
      }
  • 자 일단 어노테이션은 이정도로 설계 해두면 될것 같다.

  • 이제 주입을 어떤 시나리오로 할건지 생성하자

public class Example {

    @InsertIntData(data = 30)
    private int data;

    public Integer getInject() {
        return data;
    }

}
  • 이렇게 필드위에 적으면 해당 int data 필드가 30으로 바뀌게 하는것이다.
import java.lang.reflect.InvocationTargetException;

public class Main {

    public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {

        CustomContextContainer customContextContainer = new CustomContextContainer();
        //Example  data = 30;
        Example example = customContextContainer.get(Example.class);

        System.out.println(example.getInject());
    }

}
  • 자이제 우리의 ExceptionContainer 안에 핸들링을 해주는 메소드들을 넣자
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

public class CustomContextContainer {

    private <T> T invokeAnnotation(T instance) throws IllegalAccessException {
        Field[] fields = instance.getClass().getDeclaredFields();
        for(Field field : fields) {
            InsertIntData annotation = field.getAnnotation(InsertIntData.class);
            if(annotation != null && field.getType() == int.class) {
                field.setAccessible(true);
                field.set(instance, annotation.data());
            }
        }
        return instance;
    }

    public  <T> T get(Class<T> obj) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        T instance = obj.getDeclaredConstructor().newInstance();
        instance = invokeAnnotation(instance);
        return instance;
    }

}
  • 선언된 필드 들 중 InserIntData 어노테이션이 붙은것들을 찾아서, 해당 필드에 값을 주입시켜준다.
  • 이제 이렇게 해보니 왜 주석이니 메타데이터니 하는 이유를 알것같다. 주석보다는 메타데이터가 옳은 표현이긴 하다. 여하튼 이제 뭐 Validate 나 간단한 로직정도는 커스텀으로 짤 수 있을 것 같다.
  • 사실 공부한이유가 AspectJ 를 쓸때 어노테이션 지식이 필요해서 이참에 정리나 할겸 해봤다.
  • 다음에는 AspectJ 를 만들어서 스프링에서 자동 로깅 시스템을 해보려고 한다. (대표적인 예제)
profile
모든 기술에는 고민을

1개의 댓글

comment-user-thumbnail
2021년 3월 31일

리플렉션 공부하고싶지만... 밀린 공부가 많아서 우선순위 큐에서 약간 밀렸네요.
꼭 공부해봐야겠어요!

답글 달기