[Spring] Lombok 이란?

2022년 06월 21일

TOC

1. Lombok이란?

Java로 개발을 하다보면 getter, setter, constructor작성 등의 많은 코드를 작성해야한다. Lombok은 이러한 기계적인 코드들을 어노테이션을 기반으로 코드를 자동화하여 작성해주는 Java의 라이브러리이다.

  • Lombok을 사용하면 코드의 길이를 줄여 코드를 단순화하고 코드의 가독성을 키울 수 있다.
  • 코드 자동 생성을 통해 생산성이 향상된다.
  • 반복되는 코드의 다이어트를 통한 가독성 및 유지보수성을 향상시킨다.

2. Lombok사용 설정

build.gradle의 dependencies에 다음과 같이 lombok 의존성을 추가해준다.

dependencies {
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
}

3. Lombok사용 예제

@Getter, @Setter

public class User {

    private String name;
    private String email;
    private LocalDateTime createdAt; // 생성된 시간
    private LocalDateTime updatedAt; // 업데이트된 시간

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public LocalDateTime getCreatedAt() {
        return createdAt;
    }

    public void setCreatedAt(LocalDateTime createdAt) {
        this.createdAt = createdAt;
    }

    public LocalDateTime getUpdatedAt() {
        return updatedAt;
    }

    public void setUpdatedAt(LocalDateTime updatedAt) {
        this.updatedAt = updatedAt;
    }
}

Lombok을 사용하지 않는다면 우리는 User class에서 getter와 setter 메서드를 구현하기 위해서는 위와 같이 변수 하나씩 선언을 해줘야 한다. 위의 User class에서는 변수가 4개밖에 없어도 getter, setter를 만드는데에만 8개의 메서드가 만들어졌으나 실제 DTO를 생성하다보면 훨씬 더 많은 변수들을 만들게 될 것이고 그에 따라 선언하는 메서드의 수도 크게 늘어날 것이다.

이러한 코드들은 Lombok의 @Getter, @Setter어노테이션을 사용하면 코드를 단순화 시킬 수 있다.

@Getter
public class User {

    @Setter
    private String name;

    private String email;
    private LocalDateTime createdAt;
    private LocalDateTime updatedAt;
}

@Getter, @Setter는 class전체에 할 수도 있으며 특정 변수에만 지정할 수도 있다. 특정 변수에 대해서만 지정할 경우 위의 name위에 위치한 @Setter처럼 변수 위에 지정하면 된다.

@NoArgsConstructor

parameter없이 생성되는 기본 constructor를 생성해주는 annotation이다.

@NoArgsConstructor
public class User {

    private String name;
    private String email;
    private LocalDateTime createdAt;
    private LocalDateTime updatedAt;

    // public User() { }  해당 코드를 @NoArgsConstructor이 만들어준다.
}

User user = new User();

@AllArgsConstructor

@NoArgsConstructor가 아무런 변수를 받지 않는 Constructor를 만들어주는 Annotation이었다면 @AllArgsConstructor은 객체가 갖고 있는 모든 변수를 받는 constructor를 만들어준다.

public class User {

    private String name;
    private String email;
    private LocalDateTime createdAt;
    private LocalDateTime updatedAt;

    public User(String name, String email, LocalDateTime createdAt, LocalDateTime updatedAt) {
        this.name = name;
        this.email = email;
        this.createdAt = createdAt;
        this.updatedAt = updatedAt;
    }
}

위의 코드에 Lombok의 @AllArgsConstructor적용하면 아래와 같이 코드가 줄어들게 된다.

@AllArgsConstructor
public class User {

    private String name;
    private String email;
    private LocalDateTime createdAt;
    private LocalDateTime updatedAt;
}

@RequiredArgsConstructor, @NonNull

필요한 변수만을 사용하는 construtor를 만들어주는 annotation이다. 필수적으로 사용되야하는 변수들은 @NonNull 또는 final을 붙이며 설정한다.

public class User {

    private String name;
    private String email;
    private LocalDateTime createdAt;
    private LocalDateTime updatedAt;

    public User(String name, String email) {
        this.name = name;
        this.email = email;
    }

위와 같이 name과 email을 파라미터로 받는 생성자를 만들고 싶다면 해당 필드에 @NonNull이나 final을 붙여주면 @RequiredArgsConstructor가 해당 필드를 받는 생성자를 만들어 준다.

@RequiredArgsConstructor
public class User {

    @NonNull // @RequiredArgsConstructor에서 사용될 field들을 지정
    private String name;
    private final String email;

    private LocalDateTime createdAt;
    private LocalDateTime updatedAt;
}

@ToString

public class User {

    private String name;
    private String email;
    private LocalDateTime createdAt;
    private LocalDateTime updatedAt;

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\\'' +
                ", email='" + email + '\\'' +
                ", createdAt=" + createdAt +
                ", updatedAt=" + updatedAt +
                '}';
    }
}

toString의 경우도 Overriding을 하며 새로 지정해야하는 번거로움이 있었으나 Lombok을 사용하면 아래와 같이 @ToString 어노테이션을 붙임으로서 단순화시킬 수 있다. @ToString(exclude = "regionMoneyName")와 같이 특정 변수를 제외시킬 수도 있다.

@ToString
public class User {
    private String name;
    private String email;
    private LocalDateTime createdAt;
    private LocalDateTime updatedAt;

}

상위 클래스에도 적용을 하고 싶다면 callSuper 옵션을 true로 변경해줘야 한다. (default 값은 false이다.)

  • @ToString(callSuper=true)

@EqualsAndHashCode

equals method와 hashcode method를 자동으로 생성해준다. 특정 변수만을 사용해 Equals and hashCode를 설정할 수도 있다.

public class User {

    private String name;
    private String email;
    private LocalDateTime createdAt;
    private LocalDateTime updatedAt;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return name.equals(user.name) && email.equals(user.email);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, email);
    }
}

현재 위의 코드로는 name, email이 같으면 같은 객체로 보겠다고 equals,hashCode가 재정의된 것을 알 수 있다. 이를 Lombok으로 표현하면 아래와 같이 축약이 가능하다.

@EqualsAndHashCode(of = {"name", "email"})
public class User {
    private String name;
    private String email;
    private LocalDateTime createdAt;
    private LocalDateTime updatedAt;
}

상위 클래스에도 적용을 하고 싶다면 callSuper 옵션을 true로 변경해줘야 한다. (default 값은 false이다.)

  • @EqualsAndHashCode(callSuper=true)

@Data

entity객체를 사용할 때 가장 많이 사용하게 된다. @Data@Getter, @Setter, @RequiredArgsConstructor, @ToString, @EqualsAndHashCode를 모두 포함하는 annotaion이다. 하지만 실무에서는 너무 무겁고 객체의 안정성을 지키기 위해 @Data의 활동을 지양한다고 한다.

@Builder

다수의 필드를 가지는 복잡한 클래스의 경우, 생성자 대신에 빌더 패턴을 사용하는 경우가 많다. @AllArgsConstructor와 비슷하게 객체를 생성하고 변수값을 주입해주는데 객체의 생성을 builder의 형식으로 제공해준다. @Builder는 모든 변수들에 대해서 build하기를 원하면 Class위에 붙이고 특정 변수에 대해 build하기를 원한다면 생성자를 작성하고 생성자 위에 어노테이션을 붙여준다.

@EqualsAndHashCode(of = {"name"})
public class User {

    private String name;
    private String email;
    private LocalDateTime createdAt;
    private LocalDateTime updatedAt;

    @Builder
    public User(String name, String email) {
        this.name = name;
        this.email = email;
    }
}
class UserTest {

    @Test
    void builderTest() {
        User user1 = User.builder()
                .name("렉스")
                .email("rex@naver.com")
                .build();

        User user2 = new User("렉스", "rex@naver.com");
        assertThat(user1).isEqualTo(user2);
    }
}

Reference

Buy me a coffeeBuy me a coffee
Written by

@Seongwon

기술공유를 통해 새로운 가치 창조을 추구하는 백엔드 개발자 오성원입니다.
©SeongwonOh