
스프링부트로 개발을 시작하면서 자주 보이는 어노테이션들이 있다.
그것은 바로 @NoArgsConstructor, @Builder, @AllArgsConstructor 이 3 가지이다.
김영한 강사님의 강의를 들으면서 @Builder에 대해서는 아직 학습하지 못했으나, 깃허브에서 다른 프로젝트 코드들을 본 결과 많이 사용되는 어노테이션이라는 것을 알 수 있었다.
각각 무엇을 의미하고 왜 사용하는 지 알아보자.
해석을 해보자면 아무 argument가 없는 생성자이다.
이 어노테이션의 경우 @NoArgsConstructor(access = AccessLevel.PROTECTED)와 같이 주로 사용한다.
언제 주로 사용하는 지 차근차근 알아보자.
@Entity
@Getter
@Setter
public class OrderItem {
@Id @GeneratedValue
@Column(name = "order_item_id")
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "item_id")
private Item item;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "order_id")
private Order order;
private int orderPrice;
private int count;
다음과 같은 코드가 존재한다.
// 주문상품 생성 방식 2가지
OrderItem orderItem = OrderItem.createOrderItem(item, item.getPrice(), count);
-------------------------------------------------------------------------------
OrderItem orderItem1 = new OrderItem();
orderItem1.setCount();
누군가는 위의 코드가 아닌 아래처럼 값을 Setter를 사용해서 전부 채우는 방식으로 개발할 수도 있다.
문제점은 유지보수 하기가 굉장히 어려워질 수가 있다는 점이다.
더군다나 Setter를 통해서 값을 채웠지만 몇 가지를 제외했다면 그 자리는 null을 반환할테니 해당 값을 가지지 않는 불완전한 객체가 될 것이다.
위의 처음의 방식 외의 다른 생성 방식은 전부 막아야 유지보수가 좋고 불완전한 객체 생성을 줄이는 코드가 될 것이다.
@Entity
@Getter
@Setter
public class OrderItem {
...
protected OrderItem() {
}
다음과 같이 코드를 작성해주면 위의 방식이 막히게 된다.
이렇게 코드를 작성하면 위의 방식을 해결할 수 있다.
하지만 어노테이션이 왜 나왔을까?
이러한 귀찮은 반복적인 작업을 한 문장으로 줄이기 위해 나왔다.
@Entity
@Getter
@Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class OrderItem {
}
Lombok을 사용하여 위와 같이 작성하면 한 줄로 해결할 수 있다.
이 어노테이션을 사용하면 접근 제한을 하여 기본 생성자의 Setter로 인한 무분별한 생성을 막아 의도하지 않은 엔티티를 만드는 것을 막을 수 있다.
모든 Argument를 받는 생성자를 만든다.
@Getter
@AllArgsConstructor
public class UserSignUpDto {
private String email;
private String nickname;
private String imageUrl;
}
@Getter
public class UserSignUpDto {
private String email;
private String nickname;
private String imageUrl;
public userSignUpDto(String email, String nickname, String imageUrl) {
this.email = email;
this.nickname = nickname;
this.imageurl = imageurl;
}
}
위의 두 코드는 같은 것을 의미한다.
모든 필드에 대한 생성자를 만들어주는 어노테이션이다.
빌더 어노테이션은 오늘 처음 사용해보았는데 값을 주입하는 과정에서 가독성을 향상시키기 위해 사용하였다.
왜 사용하는 지에 대해 초점을 두고 자세하게 설명은 하지 않겠다.
추후 학습을 원활히 마치면 정리를 해보려한다.
@Entity
@Builder
public class User {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_id")
private Long id;
private String email;
private String nickname;
private String imageUrl;
private int score;
}
User user = User.builder()
.email(userSignUpDto.getEmail())
.nickname(userSignUpDto.getNickname())
.imageUrl(userSignUpDto.getImageUrl())
.build();
@NoArgsConstructor(access = AccessLevel.PROTECTED)와 @Builder를 함께 사용하면 컴파일 에러가 발생한다.
해결 방법은 @AllArgsConstructor을 함께 사용하는 것이다.
💡 일반적으로 기본 생성자에 대한 접근 제어를 위해 @NoArgsConstructor(access=AccessLevel.PROTECTED)와 같이 사용한다.
무분별하게 생성되는 객체들을 한 번 더 체크해 줌으로써 의도하지 않은 엔티티 객체를 만드는 행위를 방지할 수 있기 때문이다.
하지만 @NoArgsConstructor(access = AccessLevel.PROTECTED)와 @Builder를 함께 사용하면 컴파일 에러가 발생한다.
이 글을 정리하면서 또다른 궁금증이 파생되었다.
Entity에서 위와 같은 어노테이션을 사용하는데 Dto에서 사용되는 어노테이션은 또 왜 사용되는걸까?
@NoArgsConstructor(access = AccessLevel.PROTECTED)를 이용하여 의미있는 생성자를 만들어 보자( + @Bulider)