Lombok Builder 사용시 유의할점

Lombok Builder 사용시 유의할점

개발을 매우 편리하게 도와주는 Lombok의 @Builder를 자주 사용하실텐데요, 사용상 주의하셔야 할 점이 있습니다.

Obj obj = new Obj();
obj.setId(1);
obj.setName("하나");
Obj obj = Obj.builder 
    .id(1)
    .name("하나")
    .build();

특정상황에서 위 선언한 두개의 객체가 다른 값들을 가질수 있다는점을 유의하셔야합니다.

멤버변수에 초기값을 지정했을때 차이가 발생하는데 아래 예시를 통해 알아보겠습니다.

@Getter
@Setter
@NoArgsConstructor
public class Obj 
{
    private int id;
    private String name;
    private String attr1="x";
    private String attr2="x";
    private String attr3="x";
 
 
    @Builder
    public obj (int id, String name, String attr1, String attr2, String attr3)
    {
        this.id = id;
        this.name = name;
        this.attr1 = attr1;
        this.attr2 = attr2;
        this.attr3 = attr3;
    }
}
public class Test
{
    @Test
    public void newObject()
    {  
        Obj obj = new Obj();
        obj.setId(1);
        obj.setName("하나");
         
        Assertion.assertEqual("x", obj.getAttr1); // => 성공
    }
     
    @Test
    public void builderObject()
    {
        Obj obj = Obj.builder
            .id(1)
            .name("하나")
            .build();
        Assertion.assertNotEqual("x", obj.getAttr1); // => 성공
        Assertion.assertNull(obj.getAttr1); // => 성공
    }
}

위의 유닛테스트와 같이 Builder로 객체 생성시 지정하지 않은 필드에 대해서는 필드 지정 초기 값이 반영되지 않고 null로 설정됩니다.

즉.

Obj obj = Obj.builder
            .id(1)
            .name("하나")
            .build();

위 코드는 아래와 같이 사용되는 것과 같음에 유의 하셔야합니다.

Obj obj = Obj.builder
            .id(1)
            .name("하나")
            .attr1(null)
            .attr2(null)
            .attr3(null)           
            .build();

추가내용

Lombok 에서 생성해주는 @Builder를 디컴파일 해보면 아래와 같은 코드를 확인 할 수 있습니다.

public class Obj {
    private int id;
    private String name;
    private String attr1 = "x";
    private String attr2 = "x";
    private String attr3 = "x";
 
    public Obj(int id, String name, String attr1, String attr2, String attr3) {
        this.id = id;
        this.name = name;
        this.attr1 = attr1;
        this.attr2 = attr2;
        this.attr3 = attr3;
    }
 
    public static Obj.ObjBuilder builder() {
        return new Obj.ObjBuilder();
    }
 
    public int getId() {
        return this.id;
    }
 
    public String getName() {
        return this.name;
    }
 
    public String getAttr1() {
        return this.attr1;
    }
 
    public String getAttr2() {
        return this.attr2;
    }
 
    public String getAttr3() {
        return this.attr3;
    }
 
    public void setId(final int id) {
        this.id = id;
    }
 
    public void setName(final String name) {
        this.name = name;
    }
 
    public void setAttr1(final String attr1) {
        this.attr1 = attr1;
    }
 
    public void setAttr2(final String attr2) {
        this.attr2 = attr2;
    }
 
    public void setAttr3(final String attr3) {
        this.attr3 = attr3;
    }
 
    public Obj() {
    }
 
    public static class ObjBuilder {
        private int id;
        private String name;
        private String attr1; // 초기값이 미설정되어있음
        private String attr2; // 초기값이 미설정되어있음
        private String attr3; // 초기값이 미설정되어있음
 
        ObjBuilder() {
        }
 
        public Obj.ObjBuilder id(final int id) {
            this.id = id;
            return this;
        }
 
        public Obj.ObjBuilder name(final String name) {
            this.name = name;
            return this;
        }
 
        public Obj.ObjBuilder attr1(final String attr1) {
            this.attr1 = attr1;
            return this;
        }
 
        public Obj.ObjBuilder attr2(final String attr2) {
            this.attr2 = attr2;
            return this;
        }
 
        public Obj.ObjBuilder attr3(final String attr3) {
            this.attr3 = attr3;
            return this;
        }
 
        public Obj build() {
            return new TestObj2(this.id, this.name, this.attr1, this.attr2, this.attr3);
        }
    }
}