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 활용
Originally published at https://dss99911.github.io
Top comments (0)