본문 바로가기
개발

[Lombok] @Builder와 @SuperBuilder (3탄)

by angeloper 2023. 6. 28.
반응형

이제 Lombok의 끝자락으로 왔습니다.

 

2탄에서는 단일 클래스에서 @SuperBuilder를 사용하였을 시에 어떻게 되는지 확인하였습니다. 앞서 말씀드렸다시피 상속을 사용하여 객체에 @Builder를 사용하였을 시에 문제가 발생하였는데, @SuperBuilder는 어떻게 생겨먹었길래 오류가 해소되는지 한번 소스를 확인해 봅니다.

물론, 앞의 소스를 통해서 "아~ 이렇게 되는구나. 그럼 상속 시에는 이렇게 되겠네?"라고 하시는 분들도 계실 겁니다. 그러나, 예측과 실제 보는 부분은 다른 것이므로 직접 확인해 봅니다.

 

주석을 통한 @SuperBuilder를 사용한 원 소스는 다음과 같습니다.

// Person 클래스
package com.example.builder.entity;

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;

@AllArgsConstructor
@NoArgsConstructor
@SuperBuilder
public class Person {
    private Long id;
    private String name;
    private int age;
}

// Student 클래스
package com.example.builder.entity;

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;

@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
public class Student extends Person {
    private String schoolName;
    private String schoolYear;
}

그럼 원래의 소스가 어떻게 풀어져서 나왔는지 확인해 봅시다.

// Person 클래스
package com.example.builder.entity;

public class Person {
    private Long id;
    private String name;
    private int age;

    protected Person(final PersonBuilder<?, ?> b) {
        this.id = b.id;
        this.name = b.name;
        this.age = b.age;
    }

    public static PersonBuilder<?, ?> builder() {
        return new PersonBuilderImpl();
    }

    public Person(final Long id, final String name, final int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public Person() {
    }

    public abstract static class PersonBuilder<C extends Person, B extends PersonBuilder<C, B>> {
        private Long id;
        private String name;
        private int age;

        public PersonBuilder() {
        }

        public B id(final Long id) {
            this.id = id;
            return this.self();
        }

        public B name(final String name) {
            this.name = name;
            return this.self();
        }

        public B age(final int age) {
            this.age = age;
            return this.self();
        }

        protected abstract B self();

        public abstract C build();

        public String toString() {
            return "Person.PersonBuilder(id=" + this.id + ", name=" + this.name + ", age=" + this.age + ")";
        }
    }

    private static final class PersonBuilderImpl extends PersonBuilder<Person, PersonBuilderImpl> {
        private PersonBuilderImpl() {
        }

        protected PersonBuilderImpl self() {
            return this;
        }

        public Person build() {
            return new Person(this);
        }
    }
}

// Student 클래스
package com.example.builder.entity;

public class Student extends Person {
    private String schoolName;
    private String schoolYear;

    protected Student(final StudentBuilder<?, ?> b) {
        super(b);
        this.schoolName = b.schoolName;
        this.schoolYear = b.schoolYear;
    }

    public static StudentBuilder<?, ?> builder() {
        return new StudentBuilderImpl();
    }

    public Student() {
    }

    public Student(final String schoolName, final String schoolYear) {
        this.schoolName = schoolName;
        this.schoolYear = schoolYear;
    }

    public abstract static class StudentBuilder<C extends Student, B extends StudentBuilder<C, B>> extends Person.PersonBuilder<C, B> {
        private String schoolName;
        private String schoolYear;

        public StudentBuilder() {
        }

        public B schoolName(final String schoolName) {
            this.schoolName = schoolName;
            return this.self();
        }

        public B schoolYear(final String schoolYear) {
            this.schoolYear = schoolYear;
            return this.self();
        }

        protected abstract B self();

        public abstract C build();

        public String toString() {
            String var10000 = super.toString();
            return "Student.StudentBuilder(super=" + var10000 + ", schoolName=" + this.schoolName + ", schoolYear=" + this.schoolYear + ")";
        }
    }

    private static final class StudentBuilderImpl extends StudentBuilder<Student, StudentBuilderImpl> {
        private StudentBuilderImpl() {
        }

        protected StudentBuilderImpl self() {
            return this;
        }

        public Student build() {
            return new Student(this);
        }
    }
}

위 소스를 확인해보니, 상속을 받은 Student 클래스는 기존 Person 클래스와 별 다를 것이 없어 보입니다. 그러나, Generic을 사용하여 표기를 통한 부분으로 처음 오류 나는 부분을 해결한 것으로 생각됩니다.

상속을 받은 Student Class의 Diagram(intellij 기능 사용)

추가적으로 궁금한 점이 있으시면 댓글로 남겨주세요.!

반응형