ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Lombok을 이용해 Constructor/Getter/Setter/Builder에서 벗어나는법
    소프트웨어 개발 툴 2019. 2. 17. 17:25


    자바 개발자라면 늘 마주치는 재미없는 일이 있다. 바로 자파 파일 생성후 생성자 만들어주고 Getter, Setter만들어 주고 거기다가 Builder까지 만들어주는 아주 지루한 작업이 존재한다. 요즘은 IDE가 좋아 키보드 숏컷 몇번으로 모두 생성이 가능하지만 그래도 귀찮은 일이 아닐 수 없다. 이런 지루한 작업에서 우리를 벗어나게 해 줄 구원같은 라이브러리가 있으니 바로 Lombok이다. Lombok은 Annotation을 이용해 Getter, Setter, Builder등등을 만들어준다. 나도 Lombok이 어디까지 지원하는지 다 찾아보진 않았지만 기본적으로 Getter/Setter/Builder를 지원하고, Synchronized, Logger관련, JPA관련 어노테이션도 지원하는 것으로 알고 있다. 지난포스트에서 Lombok을 설치하는 방법에 대해 알아보았다. 이번 포스트를 통해 Lombok라이브러리를 사용하기 위한 준비와, 사용하는 방법을 알아보도록 하자. 

    예상 독자

    이 포스트의 독자들은 중급 자바 프로그래머들이다. 자바 프로젝트를 몇 개 해봤고, 자바 IDE사용에 능숙하다. 이 포스트에서 사용되는 자바 프로젝트는 그래들 기반이므로 Gradle이 익숙하지 않은 독자들은 Gradle을 이용해 자바 프로젝트 만들기를 참고하길 바란다. 또 아직 Lombok을 설치하지 않았다면 Lombok 환경설정 포스트를 통해 Lombok을 먼저 설치하도록 하자.

    목표

    • Constructor
    • Getter/Setter
    • Synchronized
    • Logger

    Constructor

    @AllArgsConstructor 

    생성자를 만드는 것 만큼 귀찮은 일이 없다. 예를들어 다음과 같은 자바 모델이 있다고 해 보자.

    package myFirstGradleProject;

    import java.util.Date;

    public class Customer {
    private String name;
    private Integer age;
    private Date dateOfBirth;
    private String gender;
    private Integer height;
    }

    우리는 아래처럼 생성자를 만들어 주어야 할 것이다.

    package myFirstGradleProject;

    import java.util.Date;

    public class Customer {
    private String name;
    private Integer age;
    private Date dateOfBirth;
    private String gender;
    private Integer height;

    public Customer(String name, Integer age, Date dateOfBirth, String gender, Integer height) {
    this.name = name;
    this.age = age;
    this.dateOfBirth = dateOfBirth;
    this.gender = gender;
    this.height = height;
    }
    }

    Lombok을 사용해 보자. 

    package myFirstGradleProject;

    import lombok.AllArgsConstructor;

    import java.util.Date;

    @AllArgsConstructor
    public class Customer {
    private String name;
    private Integer age;
    private Date dateOfBirth;
    private String gender;
    private Integer height;
    }

    이렇게  @AllArgsConstructor 어노테이션을 이용하면 Lombok이 자동으로 생성자를 만들어 준다. 되는지 확인 해 보자.

    /*
    * This Java source file was generated by the Gradle 'init' task.
    */
    package myFirstGradleProject;

    import java.util.Date;

    public class App {
    public String getGreeting() {
    return "Hello world.";
    }

    public static void main(String[] args) {
    Customer c = new Customer("F.SoftwareEngineer", 17, new Date(), "Female", 180);
    System.out.println(new App().getGreeting());
    }
    }

    코드가 정상적으로 컴파일 되는 것을 확인 할 수 있다.

    @NoArgsConstructor 

    또는 @NoArgsConstructor를 이용해 매개변수를 받지 않는 생성자를 만들 수도 있다.
    package myFirstGradleProject;

    import lombok.NoArgsConstructor;

    import java.util.Date;

    @NoArgsConstructor
    public class Customer {
    private String name;
    private Integer age;
    private Date dateOfBirth;
    private String gender;
    private Integer height;
    }

    @RequiredArgsContructor

    또는 필요한 멤버만 받는 생성자를 만들 수도 있다. 
    package myFirstGradleProject;

    import lombok.RequiredArgsConstructor;

    import java.util.Date;

    @RequiredArgsConstructor
    public class Customer {
    private String name;
    private Integer age;
    private Date dateOfBirth;
    private String gender;
    private Integer height;
    }

    그러면 어떤 멤버가 필요한지 어떻게 지정하는가? 바로 @NonNull 어노테이션을 이용해 지정 할 수 있다.

    package myFirstGradleProject;

    import lombok.NonNull;
    import lombok.RequiredArgsConstructor;

    import java.util.Date;

    @RequiredArgsConstructor
    public class Customer {
    @NonNull private String name;
    private Integer age;
    @NonNull private Date dateOfBirth;
    private String gender;
    private Integer height;
    }

    메인 함수에서 다음과 같이 Customer를 생성 할 수 있게된다.

    Customer c = new Customer("F.SoftwareEngineer",  new Date());

    Getter/Setter

    Lombok을 사용하면 Getter/Setter도 Annotation으로 지정 할 수 있다.

    package myFirstGradleProject;

    import lombok.Getter;
    import lombok.NonNull;
    import lombok.RequiredArgsConstructor;
    import lombok.Setter;

    import java.util.Date;

    @RequiredArgsConstructor
    @Getter @Setter
    public class Customer {
    @NonNull private String name;
    private Integer age;
    @NonNull private Date dateOfBirth;
    private String gender;
    private Integer height;
    }

    메인에서 Customer의 getter/setter를 불러보자.

    Customer c = new Customer("F.SoftwareEngineer",  new Date());
    System.out.println(c.getName());

    getter/setter에 접근 할 수 있음을 확인 할 수 있다.

    Builder

    내가 개발하면서 가장 귀찮은 것 중에 하나다 Builder를 만드는 것이다. 이것은 자바 모델과도 거의 비슷한것이 반복된 내용만 가득하고.. 사용하는건 정말 편하고 좋은데 Builder자체를 만드는것은 귀찮은 일이다. Lombok 어노테이션을 사용하면 Builder도 자동으로 만들 수 있다.

    package myFirstGradleProject;

    import lombok.*;

    import java.util.Date;

    @RequiredArgsConstructor
    @Getter @Setter
    @Builder
    public class Customer {
    @NonNull private String name;
    private Integer age;
    @NonNull private Date dateOfBirth;
    private String gender;
    private Integer height;
    }

    이제 Builder를 사용해 오브젝트를 생성 해 보자.

    Customer c = Customer.builder()
    .name("f.softwareengineer")
    .age(78)
    .dateOfBirth(new Date())
    .gender("female")
    .height(188)
    .build();
    System.out.println(c.getName());

    만약 @Builder 어노테이션이 없었다면 코드의 양은 이렇다.

    package myFirstGradleProject;

    import lombok.*;

    import java.util.Date;

    @RequiredArgsConstructor
    @Getter @Setter
    public class Customer {
    @NonNull private String name;
    private Integer age;
    @NonNull private Date dateOfBirth;
    private String gender;
    private Integer height;

    public static class builder {
    private String name;
    private Integer age;
    private Date dateOfBirth;
    private String gender;
    private Integer height;

    public builder() {

    }

    public builder name(String name) {
    this.name = name;
    return this;
    }
    public builder age(Integer age) {
    this.age = age;
    return this;
    }
    public builder dateOfBirth(Date dateOfBirth) {
    this.dateOfBirth = dateOfBirth;
    return this;
    }
    public builder gender(String gender) {
    this.gender = gender;
    return this;
    }
    public builder height(Integer height) {
    this.height = height;
    return this;
    }

    public Customer build() {
    Customer c = new Customer(this.name, this.dateOfBirth);
    c.age = this.age;
    c.gender = this.gender;
    c.height = this.height;
    return c;
    }
    }
    }

    여기다가 생성자와 게터 세터까지 추가하면 boilerplate 코드만 백줄이 넘는 것이다..

    Logger

    Logger를 사용한다면 @Slf4j를 이용해 로거 어노테이션을 추가 할 수 있다. 

    /*
    * This Java source file was generated by the Gradle 'init' task.
    */
    package myFirstGradleProject;

    import lombok.extern.java.Log;
    import lombok.extern.slf4j.Slf4j;

    import java.util.Date;

    @Slf4j
    public class App {
    public String getGreeting() {
    return "Hello world.";
    }

    public static void main(String[] args) {
    Customer c = Customer.builder()
    .name("f.softwareengineer")
    .age(78)
    .dateOfBirth(new Date())
    .gender("female")
    .height(188)
    .build();
    log.info("Hello World!"); # 로거 어노테이션 추가로 이용 가능.
    }
    }

    이 어노테이션이 아니라면 서비스마다 아래의 방법으로 로거를 초기화 해야 한다.

    private static Logger LOG = LoggerFactory.getLogger(App.class);

    참고로 logger는 build.gradle의 dependencies란에 다음과 같이 추가 할 수 있다.

    compile group: 'org.slf4j', name: 'slf4j-log4j12', version: '1.7.25'

    Synchronized

    자바에서는 이미 synchronized라는 키워드를 이용해 임계영역(Critical Section)을 보장 할 수 있다. 하지만 이는 100% 안전하지 않고 데드락이 유발되는 경우도 있다고 한다. Lombok은 이런 점을 보완했다고 하니 synchronized가 필요한 메서드에 이용 할 수 있다.

    package myFirstGradleProject;

    import lombok.Synchronized;

    public class CustomerService {
    @Synchronized
    public void synchronizedCustomerService(final Customer c) {
    // does some work
    }
    }

     이 포스트에서는 Lombok이 제공하는 여러가지 Annotation과 Lombok사용법에 대해서 알아보았다. 스프링 프레임워크도 어노테이션 기반이 많은데 대부분 JPA관련이라 아쉬운 점이 있었다. Lombok은 그야말로 개발자가 시간을 조금 더 효율적으로 사용 할 수 있도록 도와주는 라이브러리인것 같다.


    댓글

f.software engineer @ All Right Reserved