자바의 Annotation 에 대해서
어노테이션을 사용하는 이유 (효과) 는 무엇일까?
나만의 어노테이션은 어떻게 만들 수 있을까?
어노테이션을 사용하는 이유와 효과
어노테이션을 이용하여 얻을 수 있는 이점은 다음과 같습니다.
코드 문서화와 가독성 향상: 어노테이션은 코드에 메타데이터를 포함하여 읽기 쉽고 이해하기 쉽도록 도와줍니다. 예를 들어,
@Override
어노테이션은 해당 메서드가 부모 클래스나 인터페이스의 메서드를 재정의한다는 것을 명시적으로 나타냅니다. 이는 코드를 읽는 사람들에게 재정의된 메서드라는 사실을 명확히 전달해줍니다.컴파일 타임 체크와 안전성 보장: 어노테이션을 사용하여 컴파일 타임에 코드를 검사하고 오류를 방지할 수 있습니다. 예를 들어,
@Override
어노테이션은 해당 메서드가 부모 클래스나 인터페이스의 메서드를 재정의하는지 여부를 컴파일러가 검사할 수 있도록 도와줍니다. 이는 잘못된 메서드 시그니처로 인한 오류를 사전에 방지할 수 있습니다.런타임 처리와 동적 기능 추가: 어노테이션은 런타임에 클래스나 메서드의 동작을 변경하거나 보완하는 데 사용할 수 있습니다. 예를 들어, 스프링 프레임워크에서
@Autowired
어노테이션은 의존성 주입을 자동화하는 데 사용됩니다. 또한 JUnit 프레임워크에서@Test
어노테이션은 해당 메서드가 테스트 메서드임을 나타내어 테스트 실행 중에 인식될 수 있도록 도와줍니다.커스텀 도메인과 메타프로그래밍: 개발자는 자신만의 어노테이션을 정의하여 도메인 특정 기능을 확장할 수 있습니다. 이를 통해 메타프로그래밍 기법을 사용하여 더 유연하고 효율적인 코드를 작성할 수 있습니다.
나만의 어노테이션은 어떻게 만들 수 있을까?
대상타입 (@Target), 유효시간(@Retention) 을 설정한 후 해당 어노테이션이 설정된 경우에 수행할 작업을 작성해주면 된다.
예를 들어 문자열에 FU 가 포함되어 있는 경우 이를 공백문자열로 바꾸는 어노테이션을 만들어보자.
코드로 보면 다음과 같습니다.
어노테이션 정의
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ReplaceFU {
}
특정 문자열(Field)을 대상으로 하기에 @Target은 ElementType.FIELD
문자열의 검사는 런타임시에 이뤄져야 하기 때문에 @Retention(RetentionPolicy.RUNTIME) 을 적용하여 만들었습니다.
어노테이션 처리
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", ""));
}
}
}
}
}
런타임에 리플렉션을 활용하여 값을 바꿔주기 위해 위와 같이 작성하였습니다.
필드에 어노테이션 적용 및 테스트
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 상에서 추적하기가 힘들다는 단점이 있지만, 캡슐화가 아주 잘 지켜진 예시라고 할 수 있습니다.
댓글을 작성해보세요.