지금까지 살펴본 것은 모두 소스코드에서 컴파일 완료된 .class 파일을 변경하여 사용하는 방법을 알아봤었다. 그렇다면, 컴파일 되기 전에 자바 소스코드 -> 컴파일 사이에 아예 조작하는 방법은 없을까?
•
> lombok 이 그 대표적인 예시가 된다.
1. Lombok?
•
lombok 라이브러리는 보통 객체를 만들고 나서 자주 구현하게 되는 getters, setters, equals, hashCodes 와 같은 매소드들을 @Getter, @Setter, @EqualsAndHashCodes 과 같은 어노테이션과 어노테이션 프로세스를 제공하여 표준적으로 작성해야할 코드를 개발자 대신 생성해준다.
2. 살펴보기
2-1. 라이브러리 추가하기
dependencies { compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok'}
Groovy
복사
2-2. annotation-processor 체크 (in IntelliJ)
2-3. 코드 작성
package me.flash.annotationprocessor;import jakarta.persistence.Entity;import jakarta.persistence.GeneratedValue;import jakarta.persistence.GenerationType;import jakarta.persistence.Id;import jakarta.persistence.Table;import lombok.Getter;import lombok.Setter;@Entity@Table(name = "customer")@Getter@Setterpublic class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long userId; private String userName; public User() { } public User(String name) { this.userName = name; }}
Java
복사
class UserTest { @Test void getUserNameTest() { User user = new User(); user.setUserName("flash"); assertThat(user.getUserName()).isEqualTo("flash"); }}
Java
복사
//User.class file : annotation 에 의해서 자동으로 생성된 getters and setterspublic class User { @Id @GeneratedValue( strategy = GenerationType.IDENTITY ) private Long userId; private String userName; public User() { } public User(String name) { this.userName = name; } public Long getUserId() { return this.userId; } public String getUserName() { return this.userName; } public void setUserId(final Long userId) { this.userId = userId; } public void setUserName(final String userName) { this.userName = userName; }}
Java
복사
3. 원리
•
컴파일 시점에 어노테이션 프로세서를 사용하여 소스코드의 AST 를 조작한다.
◦
4. 논란
•
공개된 API 가 아니라 컴파일러 내부 클래스를 사용하여 기존 소스코드를 조작하고 있다.
•
특히 이클립스의 경우는 javaagent 를 사용하여 컴파일러 클래스까지 조작하여 사용한다. 해당 클래스들 역시 공개된 API 가 아니다보니, 버전 호환성에 문제가 생길 수 있고, 언제라도 그런 문제가 발생해도 이상하지 않다.
•