# Java Lombok Java 개발을 하다 보면 반복적이고 번거로운 코드 작성이 빈번하게 발생한다. 이러한 문제를 해결하고자 여러 도구와 라이브러리가 존재하는데, 그 중에서도 Lombok은 매우 유용한 라이브러리이다. Lombok에 대해서 알아보자 ## Lombok이란? Lombok은 자바 코드에서 반복적인 부분을 줄여주는 라이브러리이다. 주로 `getter`, `setter`, `toString`, `equals`, `hashCode` 같은 메서드의 자동 생성과 빌더 패턴을 간단하게 구현할 수 있게 해준다. 이를 통해 코드의 가독성을 높이고, 개발자의 생산성을 크게 향상시킬 수 있다. ### Lombok의 주요 기능 - Getter와 Setter 자동 생성 - 생성자 자동 생성 - toString, equals, hashCode 메서드 자동 생성 - 빌더 패턴 구현 - 로그 처리 간소화 ## Lombok 설치 방법 Lombok을 사용하려면 먼저 프로젝트에 Lombok 라이브러리를 추가해야 한다. Maven을 사용하는 경우 `pom.xml` 파일에 다음과 같이 Lombok 의존성을 추가한다. ```xml <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.32</version> <!-- 최신 버전 확인 필요 --> <scope>provided</scope> </dependency> ``` Gradle을 사용하는 경우 `build.gradle` 파일에 다음과 같이 Lombok 의존성을 추가한다. ```gradle dependencies { compileOnly 'org.projectlombok:lombok:1.18.32' annotationProcessor 'org.projectlombok:lombok:1.18.32' } ``` IDE에서도 Lombok을 지원하도록 설정해야 한다. 예를 들어, `IntelliJ IDEA`에서는 Lombok 플러그인을 설치하고 설정을 통해 활성화할 수 있다. ## Lombok의 주요 어노테이션 Lombok의 다양한 기능을 사용하려면 어노테이션을 적절히 사용해야 한다. 여기서는 가장 자주 사용되는 어노테이션들을 살펴본다. ### @Getter와 @Setter `@Getter`와 `@Setter` 어노테이션을 사용하면 필드에 대한 getter와 setter 메서드를 자동으로 생성할 수 있다. ```java import lombok.Getter; import lombok.Setter; public class Person { @Getter @Setter private String name; @Getter @Setter private int age; } ``` 위 코드에서 `name`과 `age` 필드에 대해 Lombok이 자동으로 getter와 setter 메서드를 생성해준다. ### @ToString `@ToString` 어노테이션을 사용하면 객체의 모든 필드를 포함하는 toString 메서드를 자동으로 생성할 수 있다. ```java import lombok.ToString; @ToString public class Person { private String name; private int age; } ``` 위 코드에서 Lombok이 `name`과 `age` 필드를 포함하는 toString 메서드를 자동으로 생성해준다. ### @EqualsAndHashCode `@EqualsAndHashCode` 어노테이션을 사용하면 객체의 필드를 기반으로 equals와 hashCode 메서드를 자동으로 생성할 수 있다. ```java import lombok.EqualsAndHashCode; @EqualsAndHashCode public class Person { private String name; private int age; } ``` 위 코드에서 Lombok이 `name`과 `age` 필드를 기반으로 equals와 hashCode 메서드를 자동으로 생성해준다. ### @NoArgsConstructor, @AllArgsConstructor, @RequiredArgsConstructor Lombok은 생성자도 자동으로 생성할 수 있다. `@NoArgsConstructor`는 기본 생성자를, `@AllArgsConstructor`는 모든 필드를 인자로 받는 생성자를, `@RequiredArgsConstructor`는 final 필드나 @NonNull이 붙은 필드를 인자로 받는 생성자를 생성한다. ```java import lombok.NoArgsConstructor; import lombok.AllArgsConstructor; import lombok.RequiredArgsConstructor; import lombok.NonNull; @NoArgsConstructor @AllArgsConstructor @RequiredArgsConstructor public class Person { private String name; private int age; @NonNull private String address; } ``` 위 코드에서 Lombok이 기본 생성자, 모든 필드를 받는 생성자, 그리고 `address` 필드만을 받는 생성자를 자동으로 생성해준다. ### @Builder `@Builder` 어노테이션을 사용하면 빌더 패턴을 간단하게 구현할 수 있다. ```java import lombok.Builder; @Builder public class Person { private String name; private int age; private String address; } ``` 위 코드에서 Lombok이 빌더 패턴을 자동으로 구현해준다. 이를 통해 객체를 생성할 때 유연하게 필드를 설정할 수 있다. ```java Person person = Person.builder() .name("John Doe") .age(30) .address("123 Main St") .build(); ``` ## Lombok의 활용 예제 여기서는 간단한 예제 코드를 통해 Lombok을 활용하는 방법을 알아본다. ### 예제 1: 단순한 DTO 클래스 ```java import lombok.Getter; import lombok.Setter; import lombok.ToString; import lombok.NoArgsConstructor; import lombok.AllArgsConstructor; @Getter @Setter @ToString @NoArgsConstructor @AllArgsConstructor public class UserDTO { private String username; private String email; } ``` 위 코드에서 Lombok을 사용해 getter, setter, toString 메서드와 기본 생성자, 모든 필드를 받는 생성자를 자동으로 생성하였다. 이를 통해 코드가 훨씬 간결해졌다. ### 예제 2: 빌더 패턴을 이용한 객체 생성 ```java import lombok.Builder; import lombok.ToString; @Builder @ToString public class User { private String username; private String email; private String password; } ``` 빌더 패턴을 사용하여 객체를 유연하게 생성할 수 있다. ```java User user = User.builder() .username("johndoe") .email("johndoe@example.com") .password("securepassword") .build(); System.out.println(user); ``` 위 코드는 `User` 객체를 생성하고, 그 정보를 출력한다. ## Lombok을 사용하면서 주의할 점 Lombok은 매우 편리한 라이브러리지만, 몇 가지 주의할 점이 있다. 1. 디버깅 어려움: Lombok이 자동으로 생성한 코드가 보이지 않기 때문에, 디버깅이 어려울 수 있다. 2. IDE와의 호환성: Lombok을 제대로 사용하려면 IDE에서 Lombok 플러그인을 설치하고 설정해야 한다. 3. 코드 가독성: 너무 많은 Lombok 어노테이션을 사용하면 코드가 지나치게 간결해져서, 오히려 가독성이 떨어질 수 있다. ## Lombok의 동작 원리 Lombok은 컴파일 시점에 소스 코드를 변경하여 필요한 메서드나 생성자를 자동으로 생성한다. 이는 주로 자바의 애노테이션 프로세서(annotation processor)와 AST(Abstract Syntax Tree) 변환을 통해 이루어진다. Lombok은 이 과정을 통해 개발자가 직접 작성해야 할 코드를 자동으로 추가해준다. ### AST(Abstract Syntax Tree) AST는 Abstract Syntax Tree의 약자로, 추상 구문 트리라고도 불린다. 이는 소스 코드의 구문 구조를 추상화한 트리 형태의 자료구조이다. AST는 코드의 구문 요소(예: 변수, 연산자, 제어 구조 등)를 트리 형태로 표현하여, 컴파일러가 소스 코드를 분석하고 처리하는 데 사용된다. #### AST의 구조 AST는 노드와 에지(edge)로 구성된 트리 형태를 가지며, 각 노드는 소스 코드의 특정 구문 요소를 나타낸다. 예를 들어, 변수 선언, 함수 호출, 조건문 등이 노드로 표현된다. 트리의 루트 노드는 프로그램 전체를 나타내며, 자식 노드는 해당 구문 요소의 하위 요소를 나타낸다. #### 예제: 간단한 코드의 AST 다음은 간단한 자바 코드와 이에 해당하는 AST의 예이다. ##### 소스 코드 ```java public class Example { public static void main(String[] args) { int a = 5; int b = 10; int sum = a + b; System.out.println(sum); } } ``` ##### AST 구조 ```plaintext Class Example └── Method main ├── Declaration int a = 5 ├── Declaration int b = 10 ├── Declaration int sum = a + b └── MethodCall System.out.println(sum) ``` 위와 같은 AST 구조는 각 구문 요소를 트리 형태로 표현하며, 컴파일러는 이 트리를 사용하여 소스 코드를 분석하고 변환한다. ## AST의 역할 AST는 컴파일러와 프로그래밍 도구에서 여러 중요한 역할을 한다. ### 1. 구문 분석(Syntax Analysis) 구문 분석은 소스 코드를 읽고, 이를 구문 규칙에 따라 트리 형태로 표현하는 과정이다. 컴파일러는 소스 코드를 구문 분석하여 AST를 생성한다. 이를 통해 코드의 구조를 이해하고, 구문 오류를 탐지할 수 있다. ### 2. 의미 분석(Semantic Analysis) AST를 기반으로 컴파일러는 의미 분석을 수행한다. 이는 변수의 타입 확인, 범위 검사, 함수 호출의 일치 여부 등을 포함한다. 의미 분석을 통해 코드의 논리적 오류를 발견하고, 타입 체크를 수행한다. ### 3. 코드 변환(Code Transformation) AST는 코드 변환의 기초가 된다. 컴파일러는 최적화를 위해 AST를 변환하거나, 다른 형태의 중간 표현(intermediate representation)으로 변환할 수 있다. Lombok은 애노테이션 프로세서를 사용하여 AST를 수정하고, 필요한 메서드나 생성자를 추가하는 방식으로 코드 변환을 수행한다. ### 4. 코드 생성(Code Generation) 최종적으로 컴파일러는 AST를 기반으로 목표 언어(target language)의 코드를 생성한다. 자바 컴파일러의 경우, AST를 바이트코드로 변환하여 JVM에서 실행 가능한 형태로 만든다. ## Lombok과 AST Lombok은 애노테이션 프로세서를 사용하여 AST를 수정하는 방식으로 작동한다. 다음은 Lombok이 AST를 어떻게 활용하는지 자세히 설명한다. ### 애노테이션 프로세서와 AST 변환 Lombok의 애노테이션 프로세서는 컴파일 시점에 Lombok 애노테이션을 탐지하고, 이를 기반으로 AST를 수정한다. 예를 들어, `@Getter` 애노테이션이 붙은 필드에 대해 getter 메서드를 자동으로 생성하는 과정은 다음과 같다. 1. 애노테이션 탐지: Lombok 애노테이션 프로세서가 소스 코드에서 `@Getter` 애노테이션을 탐지한다. 2. AST 수정: 탐지된 `@Getter` 애노테이션을 기반으로 AST를 수정하여 해당 필드에 대한 getter 메서드를 추가한다. 3. 변환된 코드 컴파일: 수정된 AST를 사용하여 최종 바이트코드를 생성한다. ### 예제: Lombok의 AST 변환 아래는 Lombok을 사용한 간단한 예제 코드와 이에 대한 AST 변환 과정이다. #### Lombok 코드 ```java import lombok.Getter; import lombok.Setter; public class Person { @Getter @Setter private String name; @Getter @Setter private int age; } ``` #### AST 변환 과정 1. 애노테이션 탐지: `@Getter`와 `@Setter` 애노테이션을 탐지한다. 2. AST 수정: `name`과 `age` 필드에 대해 getter와 setter 메서드를 추가한다. #### 변환된 AST ```plaintext Class Person ├── Field String name ├── Field int age ├── Method getName() ├── Method setName(String name) ├── Method getAge() └── Method setAge(int age) ``` 위와 같이 Lombok 애노테이션 프로세서는 AST를 수정하여 getter와 setter 메서드를 추가한다. 이 과정은 개발자가 직접 코드를 작성하지 않아도 필요한 메서드가 자동으로 생성되도록 한다. ## Lombok의 한계 Lombok은 자바 개발에서 매우 유용한 도구이지만, 모든 도구가 그렇듯이 몇 가지 한계와 주의해야 할 점이 있다. 이번 글에서는 Lombok의 한계와 이러한 한계를 극복하기 위한 방법에 대해 설명한다. Lombok을 효과적으로 사용하기 위해서는 이러한 한계를 잘 이해하고 적절히 대응하는 것이 중요하다. 1. 디버깅의 어려움 - Lombok을 사용하면 자동으로 생성된 코드가 소스 코드에 명시적으로 보이지 않는다. 이로 인해 디버깅이 어려워질 수 있다. 특히, IDE에서 제공하는 디버깅 기능을 사용할 때 자동 생성된 코드가 보이지 않기 때문에 코드의 흐름을 파악하는 데 어려움을 겪을 수 있다. 2. IDE와의 호환성 문제 - Lombok은 일부 IDE에서 완벽하게 지원되지 않을 수 있다. 특히, 새로운 버전의 IDE나 Lombok이 출시될 때 호환성 문제가 발생할 수 있다. 이는 코드 자동 생성 기능이 제대로 작동하지 않거나, IDE에서 경고 메시지가 표시되는 등의 문제를 야기할 수 있다. 3. 코드 가독성 저하 - Lombok은 코드의 반복성을 줄여주지만, 너무 많은 Lombok 애노테이션을 사용하면 오히려 코드의 가독성이 떨어질 수 있다. 이는 특히 팀원들이 Lombok의 기능에 익숙하지 않을 경우 문제가 될 수 있다. 4. 컴파일 속도 영향 - Lombok은 컴파일 시점에 코드를 변환하기 때문에, 프로젝트가 커질수록 컴파일 속도에 영향을 미칠 수 있다. 이는 특히 대규모 프로젝트에서 문제될 수 있다. 5. 표준 Java 문법과의 충돌 - Lombok이 생성한 코드가 표준 Java 문법과 충돌할 수 있다. 예를 들어, Lombok이 생성한 메서드가 기존 코드와 이름이 충돌하거나, 특정 상황에서 예상치 못한 동작을 할 수 있다.