Lombok 설정에서 늘 켜기만 하고 넘어갔던 annotation processing이 무엇인지 파고든 글이다. 사수와의 대화로 시작해 어노테이션 프로세서의 정의와 동작 시점을 짚고, 엔티티에서 DTO를 생성하는 커스텀 프로세서를 직접 만들어본다. Lombok이 왜 새 클래스를 만들지 않는지는 2부로 넘긴다.
핵심 포인트- 어노테이션 프로세서는 자바 컴파일러가 제공하는 기능으로 컴파일 단계에서 코드를 검사하고 조작하거나 생성한다.
- Lombok뿐 아니라 코드를 자동 생성하는 라이브러리 대부분이 이 단계에서 만들어낸다고 보면 된다.
- IDE의 annotation processing 체크박스와 빌드 설정이 무엇을 켜는 것인지가 여기서 설명된다.
- 얻는 이득은 getter나 setter 같은 반복되는 보일러플레이트 코드를 줄이는 것이다.
- 실제 코드 생성은 JavaPoet 같은 라이브러리로 클래스와 패키지, 생성자, 필드까지 조립한다.
- Lombok은 새 클래스를 만들지 않고 바이트코드 수준에서 코드를 조작한다는 점이 다르다.
상세 정리- 도입부: 주니어 시절 사수에게 어노테이션 프로세서를 아느냐는 질문을 받고 Lombok 설정에서 본 체크박스만 떠올렸던 대화로 시작한다.
- 문제의식: 그 옵션이 무엇이고 Lombok이 어떻게 동작하는지 알면 개발할 때 시야가 넓어진다고 본다.
- 어노테이션의 정의: 오버라이드 표기처럼 쓰는 메타성 데이터의 일종이다.
- 단서: 그 어노테이션 정의를 열어보면 적용 대상과 유지 정책이 지정돼 있어, 어노테이션으로 무언가를 처리한다는 추측이 가능해진다.
- 프로세서의 정의: 특정 어노테이션을 기반으로 컴파일 단계에서 코드를 검사하고 조작하거나 생성하게 해주는 컴파일러 기능이다.
- 이미 쓰고 있는 것들: 쿼리 빌더 계열처럼 코드를 자동 생성하는 라이브러리 대부분이 이 단계를 쓴다.
- 이득: 단순 중복 코드, 이른바 보일러플레이트를 줄인다. Lombok을 썼을 때의 이점을 떠올리면 바로 와닿는다.
- 예제 설계: JPA를 쓰면 엔티티 클래스와 DTO 클래스가 각각 존재하고 구조가 비슷한 경우가 많다는 데서 착안했다.
- 예제 목표: 엔티티 클래스를 기반으로 생성자와 getter를 가진 DTO 클래스를 자동 생성하는 기능을 만든다.
- 사용 방법: 평범한 엔티티 클래스에 커스텀 어노테이션을 붙이고 컴파일하면 생성 경로에 DTO 클래스가 만들어진다.
- 생명주기: clean하면 사라지고 컴파일 시점에 다시 생성되는 것을 확인할 수 있다.
- 구현 1: 프로세서의 추상 클래스를 상속한 구현체가 필요하며, 지정한 어노테이션이 붙은 클래스를 찾는 역할을 한다.
- 구현 2: 찾은 클래스를 바탕으로 새 코드를 만들며, 이때 JavaPoet을 쓰면 클래스 이름과 패키지, 생성자, 메서드, 필드, 어노테이션까지 조립할 수 있다.
- 실무에서의 위치: 직접 만들어 쓸 일은 많지 않다고 인정한다. 대부분 이미 잘 만들어진 라이브러리가 있고, 직접 만들면 설정과 수정 비용이 더 커질 수 있다.
- 그럼에도 알아야 하는 이유: 알고 안 쓰는 것과 몰라서 못 쓰는 것은 다르며, 최소한 이런 기능을 쓰는 라이브러리가 있는지 찾아볼 수 있게 된다.
- 남은 의문: Lombok은 새 클래스가 생기지 않는데 어떻게 된 것이냐는 질문을 스스로 던진다.
- 2부 예고: Lombok은 새 클래스를 만드는 대신 바이트코드 레벨에서 코드를 조작한다고 밝히고 다음 편으로 넘긴다.
왜 읽나Lombok을 쓰면서 annotation processing 체크박스를 왜 켜는지 모르고 넘어갔다면, 그 옵션이 무엇을 켜는 것이고 그 위에서 무엇을 만들 수 있는지 예제로 확인할 수 있다.