Java Annotation Processor와 코드 생성 기법
Java Annotation Processor와 코드 생성 기법
Java에서 컴파일 타임에 코드를 생성하거나 변경하는 여러 가지 기법을 살펴봅니다.
Annotation Processor 개요
Annotation Processor는 컴파일 타임에 어노테이션을 처리하여 추가적인 작업을 수행합니다.
코드 생성/변경 기법
1. Java 소스 파일 추가 (표준 방식)
Annotation Processor의 일반적인 사용 방식입니다.
- 기존 소스 파일을 수정하지 않음
- 새로운 Java 소스 파일을 생성
- 예: Dagger, MapStruct, AutoValue
@AutoValue
public abstract class Person {
public abstract String name();
public abstract int age();
public static Person create(String name, int age) {
return new AutoValue_Person(name, age);
}
}
// AutoValue_Person.java가 자동 생성됨
2. 소스 파일 직접 수정 (Lombok 방식)
Lombok은 Eclipse/javac 컴파일러의 내부 API를 사용하여 AST(Abstract Syntax Tree)를 직접 수정합니다.
특징:
- 기존 클래스에 코드를 주입
- 컴파일러 종속적인 방법 사용
- 표준이 아닌 내부 API 사용
참고 문서: Project Lombok Trick Explained
3. 런타임 바이트코드 조작
CGLib이나 ASM 같은 라이브러리를 사용하여 런타임에 바이트코드를 조작합니다.
사용 사례:
- Spring AOP의 프록시 생성
- Hibernate의 Lazy Loading
- Mockito의 Mock 객체 생성
// CGLib을 사용한 프록시 생성 예시
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(MyClass.class);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method,
Object[] args, MethodProxy proxy) throws Throwable {
// 메서드 호출 전후 처리
return proxy.invokeSuper(obj, args);
}
});
MyClass proxy = (MyClass) enhancer.create();
4. 클래스 파일 바이트코드 후처리
컴파일된 .class 파일을 빌드 단계에서 수정합니다.
특징:
- 빌드 파이프라인에 통합
- 컴파일 후 별도의 처리 단계 필요
- AspectJ의 컴파일 타임 위빙 등
기법 비교
| 기법 | 시점 | 장점 | 단점 |
|---|---|---|---|
| 소스 파일 추가 | 컴파일 타임 | 표준 방식, 투명함 | 새 클래스 필요 |
| AST 수정 | 컴파일 타임 | 기존 클래스 수정 | 컴파일러 종속 |
| 런타임 바이트코드 | 런타임 | 유연함 | 성능 오버헤드 |
| 클래스 파일 후처리 | 빌드 타임 | 강력함 | 빌드 복잡도 증가 |
Lombok 동작 원리
Lombok이 @Data 어노테이션을 처리하는 과정:
- javac 실행: 컴파일러가 Lombok을 Annotation Processor로 로드
- AST 접근: 컴파일러의 내부 API를 통해 AST에 접근
- AST 수정: getter, setter, equals, hashCode 등의 메서드를 AST에 추가
- 바이트코드 생성: 수정된 AST로부터 바이트코드 생성
이는 공식 API가 아닌 내부 API를 사용하므로:
- Java 버전 업그레이드 시 호환성 문제 가능
- IDE 플러그인 필요 (실제 소스에는 없는 메서드이므로)
정리
- 표준적인 코드 생성이 필요하면 Annotation Processor를 통한 소스 파일 추가
- 기존 클래스 수정이 필요하면 Lombok 스타일 또는 바이트코드 조작 고려
- 런타임 동적 기능이 필요하면 CGLib/ASM 활용
Comments