자바의 Annotation 에 대해서

  • 어노테이션을 사용하는 이유 (효과) 는 무엇일까?

     

  • 나만의 어노테이션은 어떻게 만들 수 있을까?

  1. 어노테이션을 사용하는 이유와 효과

어노테이션을 이용하여 얻을 수 있는 이점은 다음과 같습니다.

  1. 코드 문서화와 가독성 향상: 어노테이션은 코드에 메타데이터를 포함하여 읽기 쉽고 이해하기 쉽도록 도와줍니다. 예를 들어, @Override 어노테이션은 해당 메서드가 부모 클래스나 인터페이스의 메서드를 재정의한다는 것을 명시적으로 나타냅니다. 이는 코드를 읽는 사람들에게 재정의된 메서드라는 사실을 명확히 전달해줍니다.

  2. 컴파일 타임 체크와 안전성 보장: 어노테이션을 사용하여 컴파일 타임에 코드를 검사하고 오류를 방지할 수 있습니다. 예를 들어, @Override 어노테이션은 해당 메서드가 부모 클래스나 인터페이스의 메서드를 재정의하는지 여부를 컴파일러가 검사할 수 있도록 도와줍니다. 이는 잘못된 메서드 시그니처로 인한 오류를 사전에 방지할 수 있습니다.

  3. 런타임 처리와 동적 기능 추가: 어노테이션은 런타임에 클래스나 메서드의 동작을 변경하거나 보완하는 데 사용할 수 있습니다. 예를 들어, 스프링 프레임워크에서 @Autowired 어노테이션은 의존성 주입을 자동화하는 데 사용됩니다. 또한 JUnit 프레임워크에서 @Test 어노테이션은 해당 메서드가 테스트 메서드임을 나타내어 테스트 실행 중에 인식될 수 있도록 도와줍니다.

  4. 커스텀 도메인과 메타프로그래밍: 개발자는 자신만의 어노테이션을 정의하여 도메인 특정 기능을 확장할 수 있습니다. 이를 통해 메타프로그래밍 기법을 사용하여 더 유연하고 효율적인 코드를 작성할 수 있습니다.

 

  1. 나만의 어노테이션은 어떻게 만들 수 있을까?

대상타입 (@Target), 유효시간(@Retention) 을 설정한 후 해당 어노테이션이 설정된 경우에 수행할 작업을 작성해주면 된다.

 

예를 들어 문자열에 FU 가 포함되어 있는 경우 이를 공백문자열로 바꾸는 어노테이션을 만들어보자.

 

코드로 보면 다음과 같습니다.

  1. 어노테이션 정의

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ReplaceFU {
}

특정 문자열(Field)을 대상으로 하기에 @Target은 ElementType.FIELD

문자열의 검사는 런타임시에 이뤄져야 하기 때문에 @Retention(RetentionPolicy.RUNTIME) 을 적용하여 만들었습니다.

 

  1. 어노테이션 처리

import java.lang.reflect.Field;

public class AnnotationProcessor {
    public static void process(Object obj) throws IllegalAccessException {
        Class<?> clazz = obj.getClass();
        Field[] fields = clazz.getDeclaredFields();

        for (Field field : fields) {
            if (field.isAnnotationPresent(ReplaceFU.class)) {
                field.setAccessible(true);
                String value = (String) field.get(obj);
                if (value != null && value.contains("FU")) {
                    field.set(obj, value.replace("FU", ""));
                }
            }
        }
    }
}

런타임에 리플렉션을 활용하여 값을 바꿔주기 위해 위와 같이 작성하였습니다.

 

  1. 필드에 어노테이션 적용 및 테스트

public class MyClass {
    @ReplaceFU
    private String myField;

    public MyClass(String myField) {
        this.myField = myField;
    }
}

 

public class Main {
    public static void main(String[] args) throws IllegalAccessException {
        MyClass myObject = new MyClass("This is FU example.");
        System.out.println("Before processing: " + myObject.getMyField());

        AnnotationProcessor.process(myObject);

        System.out.println("After processing: " + myObject.getMyField());
    }
}
Before processing: This is FU example.
After processing: 

 

어노테이션의 처리의 경우 IDE 상에서 추적하기가 힘들다는 단점이 있지만, 캡슐화가 아주 잘 지켜진 예시라고 할 수 있습니다.

댓글을 작성해보세요.

채널톡 아이콘