상속관계에서 Builder를 적용했을 때 발생한 이슈에 대해 작성한 글입니다.
발생 배경
엔티티에 @Builder 어노테이션을 사용하였습니다.
@Entity
@DiscriminatorValue("PRODUCT")
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Product extends Item {
@Enumerated(EnumType.STRING)
@Column(nullable = false)
private ProductStatus status;
// ...
}
다만 Product의 부모 엔티티인 Item에도 @Builder 어노테이션이 있는데요
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "dtype", discriminatorType = DiscriminatorType.STRING)
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Item {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(targetEntity = User.class, fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
// ..
}
이 때 아래와 같은 에러가 발생했습니다.
error: builder() in Product cannot hide builder() in Item
@Builder
^
return type ProductBuilder is not compatible with ItemBuilder
문제
에러 메세지를 보면 유추할 수 있듯이, 이 에러는 상속 관계의 엔티티에서 빌더를 잘 못 사용하여 발생한 에러입니다.
@Builder 어노테이션을 사용하여 초기화할 때, 자식 클래스에서 부모 클래스의 필드를 발견하지 못하며 따라 자식 클래스를 초기화 할 때 부모 클래스의 필드를 초기화 할 수 없어 발생하는 에러입니다.
해결
이 문제를 @SuperBuilder 어노테이션을 통해 해결할 수 있습니다.@SuperBuilder를 사용하면 자식 클래스에서 빌더를 생성할 때 부모 클래스의 필드와 메서드가 자동으로 포함됩니다. 따라 부모의 클래스를 초기화할 수 있게 됩니다.
@SuperBuilder 어노테이션을 사용하여 코드를 수정했습니다.
Product.java
@Entity
@DiscriminatorValue("PRODUCT")
@Getter
@SuperBuilder
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Product extends Item {
@Enumerated(EnumType.STRING)
@Column(nullable = false)
private ProductStatus status;
// ...
}
Item.java
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "dtype", discriminatorType = DiscriminatorType.STRING)
@Getter
@SuperBuilder
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Item {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(targetEntity = User.class, fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
// ..
}