Java 어노테이션(@annotation)을 활용한 커스텀 메타데이터 만들기

Java 어노테이션이란 (@annotation)

`Java 어노테이션`은 컴파일러, 런타임, 또는 다른 도구들에게 추가적인 정보를 제공하는 `메타데이터`입니다. 

`어노테이션`은 @ 기호를 사용하여 표시하며, 클래스, 메소드, 필드 등 다양한 요소에 적용할 수 있습니다.

 

실제로 Java 어노테이션은 다양한 분야에서 활용될 수 있습니다. 예를 들어, 우리가 가장 많이 접하는 @Override 어노테이션은 상위 클래스의 메소드를 재정의하고 있음을 나타내는데 사용됩니다. Spring Framework에서는 @Controller, @Service, @Autowired 등의 어노테이션을 사용하여 의존성 주입과 컴포넌트 스캔을 처리합니다. 또한 JUnit은 @Test, @Before, @After 등의 어노테이션을 사용하여 테스트 메소드를 식별하고 실행합니다.

커스텀 어노테이션을 만들어 커스텀 메타데이터를 추가하는 것은 코드의 가독성과 유지보수성을 향상시키는데 큰 도움이 됩니다. 예를 들어, 로깅, 보안, 성능 측정 등과 관련된 메타데이터를 어노테이션으로 표현하고, 해당 정보를 활용하여 어플리케이션을 조정하거나 분석할 수 있습니다.


어노테이션 만들기

Java에서 어노테이션을 만들려면 @interface 키워드를 사용하여 어노테이션을 선언합니다. 필요한 필드를 선언하고, 필드의 기본값을 설정할 수 있습니다.

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CustomAnnotation {
    String value() default "";
    int count() default 0;
}

위의 예제에서 CustomAnnotation 어노테이션은 `@Retention`과 `@Target` 어노테이션으로 설정되어 있습니다.

 

`@Retention`:

  • 어노테이션의 유지 정책을 정의합니다. 어노테이션이 코드에서 어떤 시점까지 유지될지를 결정합니다.
  • `RetentionPolicy.SOURCE`: 소스 코드에서만 유지되며, 컴파일 이후에는 버려집니다. 주로 코드 생성기나 컴파일 시점에만 사용되는 어노테이션에 적용됩니다.
  • `RetentionPolicy.CLASS`: 컴파일된 클래스 파일에 포함되지만, 런타임 시에는 사용할 수 없습니다. 주로 런타임 환경이 필요하지 않은 어노테이션에 적용됩니다.
  • `RetentionPolicy.RUNTIME`: 런타임 시에도 어노테이션 정보가 유지됩니다. 주로 런타임 환경에서 동적으로 처리해야 하는 어노테이션에 적용됩니다.

 

`@Target`:

  • 어노테이션을 적용할 수 있는 대상 유형을 지정합니다. 어노테이션이 적용될 수 있는 대상(위치)를 제한합니다. 
  • `ElementType.TYPE`: 클래스, 인터페이스, 열거형 등 타입 선언에 적용 가능합니다.
  • `ElementType.FIELD`: 필드(멤버 변수)에 적용 가능합니다.
  • `ElementType.METHOD`: 메소드에 적용 가능합니다.
  • `ElementType.PARAMETER`: 메소드의 파라미터에 적용 가능합니다.
  • `ElementType.CONSTRUCTOR`: 생성자에 적용 가능합니다.

어노테이션 적용하기

public class MyClass {
    @CustomAnnotation(value = "Hello World", count = 5)
    public void myMethod() {
        // 메소드 내용
    }
}

위의 예제에서 `@CustomAnnotation` 어노테이션은 value 필드와 count 필드에 값을 설정하고 있습니다. 이렇게 어노테이션을 사용하여 메타데이터를 추가하면, 해당 메소드를 사용하는 도구나 프레임워크에서 해당 정보를 활용할 수 있습니다.


동적으로 어노테이션 값 사용하기 

프로그램의 런타임 중에는 `리플렉션(reflection)`을 사용하여 어노테이션에 설정된 값을 동적으로 읽을 수 있습니다. 리플렉션을 통해 메소드나 클래스에 적용된 어노테이션의 값을 접근하고 활용할 수 있습니다.

public class AnnotationProcessor {
    public void processAnnotations(Class<?> clazz) {
        Method[] methods = clazz.getDeclaredMethods();
        
        for (Method method : methods) {
            if (method.isAnnotationPresent(CustomAnnotation.class)) {
                CustomAnnotation annotation = method.getAnnotation(CustomAnnotation.class);
                String value = annotation.value();
                int count = annotation.count();
                
                // 값 활용 및 추가적인 로직 작성
                System.out.println("Value: " + value);
                System.out.println("Count: " + count);
            }
        }
    }
}

위 코드는 전달받은 클래스의 메서드 중에서 `CustomAnnotation` 어노테이션이 적용된 메서드를 찾고, 해당 어노테이션의 값을 출력을 하는 코드입니다. 위는 리플렉션을 활용한 방법 중 하나이면 원하는 방식에 맞게 수정하면 됩니다.