티스토리 뷰

Spring/Spring Basic

Spring Basic : Project Lombok

Korean Eagle 2020. 6. 30. 16:45
728x90

0. Lombok은 이제 없으면 안될 정도로 중요한 라이브러리가 되었다. 한번씩 혼동될 때까 있어 정리한다.

 

1. Lombok 소스코드 Generator로 컴파일하기 전에 lombok 모듈을 거쳐 소스코드 생성되고 생성된 코드를 컴파일하게 된다.

 

2. 기능

  2-1 val, var

  2-2 @NonNull - 속성이나 생성자에 지정되어 Null 체크를 하여 Null이면 NullPointException을 발생시킨다.

  2-3 @Cleanup - finally block의 close를 자동 호출해 준다.

  2-4 @Setter, @Getter

  2-5 @ToString

  2-6 @EqualsAndHashCode - equals, hashCode 메소드를 생성해 준다. 특정한 속성을 제외할 수도 있다.

  2-7 @NoArgsConstructor - fianl 속성이 있는 경우 컴파일 에러를 발생시킨다. (강제로 값을 지정할 수 있다.)

  2-8 @RequiredArgsConstructor - 모든 final과 @NotNull로 지정된 속성에 대한 생성자를 만들어 준다.

    2-8-1 @NonNull가 null인 경우 NullPointerException을 발생시킨다.

  2-9 @AllArgsContructor - 모든 속성에 대한 생성자를 만들어 준다. @NotNull 속성에 대한 Null 체크를 수행한다.

  2-10 @Data - @Getter, @Setter, @ToString, @EqualsAndHashCode, @RequiredArgsConstructor의 묶음이다.

    2-10-1 생성자가 하나라도 코딩이 되어 있는 경우는 생성자가 자동 생성되지 않는다.

  2-11 @Value - @Data의 Immutable 버전이다. 모든 속성이 private, final로 지정된다.

  2-12 @Builder - builder 패턴을 구현해 준다.

  2-13 @SneakyThrows - checked 예외처리 구문을 자동으로 생성해 준다.

  2-14 @Synchonized - java synchronized를 더 나은 버전을 자동 구현해 준다.

  2-15 @Getter(lazy=true) 캐시 기능을 제공하여 처음에만 로직을 수행하고 두 번째 부터는 캐시된 것을 돌려준다.

  2-16 @Log, @Slf4j 자동으로 로그 기능을 선언해 준다.

  2-17 그 외의 실험적인 기능들을 지원한다.

 


 

0. @NoArgsConstructor, @RequiredArgsConstructor, @AllArgsConstuctor

  0-1 시작하기에 앞어 생성자에서의 final 속성은 단 한번 생성자 호출시에 초기화 될 수 있다는 의미이다.

 

1. 아래 구조의 코드를 가지고 예를 든다.

 

public class LoginForm {
  
  private String username;
  private String password;
}

 

2. @NoArgsConstuctor

  2-1 인자가 없는 생성자를 만들어 준다.

 

public class LoginForm {
  
  private String username;
  private String password;
  
  public LoginForm() {}
  
}

 

  2-2 만약 final 속성이 하나라도 있으면 빈생성자 호출 시에 초기화가 안되기 때문에 에러가 발생햔다

    2-2-1 final 속성이 있음에도 사용하고 싶으면 force=true 속성을 사용할 수 있다.

    2-2-2 이런 경우 모든 final 속성들은 각 타입에 따라 0, false, null 등으로 초기화 된다.

    2-2-3 password를 final로 설정했다고 가정하고 force=true로 설정한 경우, 다음처럼 생성된다.

 

public class LoginForm {
  
  private String username;
  private final String password = null;
  
  public LoginForm() {}
  
}

 

  2-3 이러한 제약 때문에 @Data나 다른 생성자 자동생성 annotation과 함께 사용된다.

  2-4 staticName="" 형식의 static 생성자를 만들 수 있다. staticName은 아래에서 설명한다.

 

3. @AllArgsConstructor

  3-1 모든 속성이 다 포함된 생성자를 만들어 준다.

 

public class LoginForm {

    private String username;
    private String password;

    public LoginForm(String username, String password) {
        this.username = username;
        this.password = password;
    }
}

 

  3-2 staticName="of" 이런 식으로 사용하면 모든 속성을 다 사용하는 static 생성자를 만들어 준다.

 

public class LoginForm {

    private String username;
    private String password;

    private LoginForm(String username, String password) {
        this.username = username;
        this.password = password;
    }
    
    public static LoginForm of(String username, String password) {
        return new LoginForm(usernmae, password);
    }
}

 

4. @RequiredArgsConstructor

  4-1 초기화가 필요한 속성만 골라서 초기화 한다.

    4-1-1 초기화가 필요한 속성이라는 것은 final로 지정되거나 @NotNull로 지정된 속성들이다.

    4-1-2 username이 final로 설정되었다고 가정하면 아래처럼 생성된다. @NotNull도 마찬가지다.

 

public class LoginForm {

    private final String username;
    private String password;

    public LoginForm(String username) {
        this.username = username;
    }
}

 

  4-2 이것도 staticName으로 static 생성자를 만들 수 있다.

 


 

5. @Builder

  5-1 이 annotation은 클래스나 메소드에 모두 사용가능하다.

  5-2 메소드(생성자 포함)에 달릴 수 있다.

  5-3 클래스에 달렸을 경우는 든 속성을 다 포함하는 private 생성자를 자동 생성하고 그 생성자에 붙는 것과 동일하다.

    5-3-1 즉 @AllArgsConstructor(access = AccessLevel.PRIVATE가 클래스에 붙은 것과 같은 효과

    5-3-2 예외가 있는데, 생성자를 생성하지 않아야 하고 + 어떤 @~ArgsConstructor도 붙이지 않아야 한다.

    5-3-3 Lombok은 이럴 경우에 all-args 생성자가 있는 것으로 간주하고 그 생성자에 @Builder를 붙여버린다.

    5-3-4 즉 @NoArgConstructor을 사용했다면, @AllArgsConstructor(access = AccessLevel.PRIVATE)가 생성 안된다.

    5-3-4 @NoArgConstructor을 쓰고 싶으면 수동으로 @AllArgs~ 를 붙여야 한다.

  5-4 이것이 붙는 경우 기본적으로 TBuilder이라는 private 생성자를 가진 내부 클래스를 만들어 준다.

    5-4-1 이 내부 클래스는 builder() 라는 함수를 가지고 있고 TBuilder객체를 생성해 준다.

  5-5 TBuilder 클래스는 각 속성마다 값을 설정해 주는 메소드를 생성해주고 반환값은 TBuilder 객체가 된다.

  5-6 TBuilder 클래스는 build() 메소드를 가지고 있다.

    5-6-1 TBuilder에서 제공한 값들을 모아 @Builder가 설정된 메소드에 넘겨 실제 객체를 생성해 준다.

    5-6-2 물론 메소드에 @Builder가 달린 경우는 그 메소드가 실행되고 그 지정한 타입이 리턴된다.

 

Before:

@Builder
 class Example<T> {
     private T foo;
     private final String bar;
 }
After:

class Example<T> {
     private T foo;
     private final String bar;

     private Example(T foo, String bar) {
         this.foo = foo;
         this.bar = bar;
     }

     public static <T> ExampleBuilder<T> builder() {
         return new ExampleBuilder<T>();
     }

     public static class ExampleBuilder<T> {
         private T foo;
         private String bar;

         private ExampleBuilder() {}

         public ExampleBuilder foo(T foo) {
             this.foo = foo;
             return this;
         }

         public ExampleBuilder bar(String bar) {
             this.bar = bar;
             return this;
         }

         @java.lang.Override public String toString() {
             return "ExampleBuilder(foo = " + foo + ", bar = " + bar + ")";
         }

         public Example build() {
             return new Example(foo, bar);
         }
     }
 }
728x90
댓글