Post

(Spring) annotation - lombok, builder

@Data

https://projectlombok.org/features/Data

  • @Data = RequiredArgsConstructor + ToString + EqualsAndHashCode + Getter + Setter
    • lombok.noArgsConstructor.extraPrivate=true 이면 private NoArgsConstructor 까지 붙는다. (1.16.22에서는 기본으로 활성화) 단, 필드 final 아닐 때
  • 여기서 RequiredArgsConstructor는 다른 Constructor 애너테이션이나 명시적으로 선언된 Constructor가 없을 때만 붙는다.
  • callSuper를 설정해야 하는 경우 해당 애너테이션과 Data를 함께 써도 된다. (설정된 애너테이션을 defer 처리 해주기 때문에 순서 상관 없다.)
이름과 파라미터 수

가 같은 메서드가 사용자 정의 Setter가 있다면 @Setter를 붙여도 기본 타입 세터가 만들어지지 않는다.

1
2
3
4
5
6
// @Setter 소용 없다.
private int code


public void setCode(ResponseCode code) { } // 이게 있으면, @Setter를 붙여도 아래 함수가 자동으로 생성되지 않기 때문에
public void setCode(int code) { }    // 이렇게 직접 적어주어야만 한다.

@ConstructorProperties

lombok 1.16.20 부터 롬복 애너테이션 사용해서 생성된 생성자에 @ConstructorProperties를 기본으로 붙여주지 않는다.

@Builder

  • 빌더를 직접 정의한다면…

item2/builder/NutritionFacts.java

@Builder를 붙이면?
  • @AllArgsConstructor(access = AccessLevel.PACKAGE)로 생성자가 만들어진다.
  • @Data를 붙였을 때 따라오는 @RequiredArgsConstructor가 무시된다.
  • 그러나 명시적으로 @RequiredArgsConstructor, @NoArgsConstructor, @AllArgsConstructor를 붙여주는 경우 public 생성자로도 접근이 가능하다.
    • @NoArgsConstructor나 @RequiredArgsConstructor는 단독으로 @Builder와 함께 사용하는 경우 AllArgsConstructor가 없다고 에러가 발생하므로 @AllArgsConstructor도 같이 붙여주어야 한다.
  • 그래서… @Builder + @Data 조합으로 사용하거나 (이러면 @Setter 생성되어 final이 아니면 나쁘다.)
    1
    2
    3
    4
    5
    6
    
    // @NoArgs가 꼭 필요한 경우 (MyBatis) NoArgs 때문에 final을 못쓰기 때문에 Setter가 없어야 한다.
    @Builder
    @Getter
    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    
  • 근데 이런 케이스는 거의 없기도 하고, 빌더와 다른 생성자를 함께 두는게 좀 어색하기도 하다.
  • MyBatis에서 (useActualParamName 옵션 없는 경우 && custom 생성자를 사용하는 경우) 생성자 파라미터 정의 순서대로 매핑이 되는 것을 방지하기 위해 NoArgs를 넣어주는 경우도 있는데, 근본적으로 useActualParamName을 활성화 해주는게 올바른 접근이다.
  • [Spring] DB 관련 : Mybatis
  • 빌더와 상속 :https://www.baeldung.com/lombok-builder-inheritance
빌더를 사용하면서, 몇몇 필수값은 반드시 입력 받고 싶다면?
빌더를 사용하면서, 필드를 기본값으로 초기화 하고 싶다면!?
  • 필드에 =으로 기본값으로 초기화하려면, 대상 필드에 @Builder.Default를 사용해야 하는데…
    • 이 방식은@Builder.Default는 쓰지 않는 것이 좋다 라는 얘기도 있고,
    • f1 = f2.getName() 요런 식으로 다른 필드의 속성을 이용해서 또 다른 필드를 초기화하는건 불가능하다. (빌더가 static이라, static context에서 non-static 필드를 참조할 수가 없당)
    • 외부에서 빌더를 통해 객체 생성 시 해당 필드를 .field()로 초기화 할 수 있기 때문에, 해당 필드 초기화 권한을 내부로 한정하는 것도 불가능하다. (필드가 final이 아닌 경우)
  • 생성자에 @Builder 붙이면 된다.
    • 내부적으로만 초기화 할 값들은 생성자 파라미터에서 빼버리면 되고
    • 옵셔널 값의 경우 생성자 파라미터에 두고 null check해서 할당하면 된다.
특정 필드는 외부에서 받지 않고 내부에서 자체 초기화 하고 싶다면?

생성자에 @Builder 쓰면 생성자 파라미터에 있는 것만 빌더로 받아서 생성자로 넘어온다. 생성자에서 자체 초기화해주면 된다.

Kotlin의 data는 copy()를 지원해주어 객체를 불변으로 다루기 편한데… lombok에는 이런 기능이 없나?

You can use @Builder for copy constructors: foo.toBuilder().build() makes a shallow clone. Consider suppressing the generating of the builder method if you just want this functionality, by using: @Builder(toBuilder = true, builderMethodName = “”).
https://projectlombok.org/features/Builder
https://github.com/projectlombok/lombok/issues/908

Lombok 설치

  1. IntelliJ에서 Preferences -> Build, Execution, Deployment -> Compiler, Annotation Processors. Click Enable Annotation Processing 반드시 해준다. 이걸 안하면 cannot fine symbol 에러 또는 무슨 길이가 다르다느니 하는 빌드 에러가 발생함.

  2. (생략가능)IntelliJ Perference에서 lombok 플러그인 검색해서 설치한다. 이걸 설치 안하면 컴파일은 가능하지만, lombok에서 만들어준 getter,setter,constructor 등에 접근하려 할 때 IDE가 이를 resolve하지 못해 빨간색으로 뜬다. 다시 말하지만 컴파일은 가능함.

3.여기서 The Lombok Gradle Plugin 부분을 따라하면 된다. 2번을 생략했다면 Gradle without a plugin 부분을 따라하면 된다. 그리고 뭔가 수정했다면 꼭 그냥 빌드가 아니라 Rebuild를 해보기 바란다.

#####

This post is licensed under CC BY 4.0 by the author.