@AllArgsConstructor, @RequiredArgsConstructor 사용 주의
@AllArgsConstructor
public class User {
private String nickName;
private String name;
}
위의 코드를 보면 @AllArgsConstructor 를 선언하게 되면
자동으로 nickName 과 name 을 받는 생성자가 만들어집니다.
보통 인스턴스를 생성할 때 아래와 같이 만듭니다.
User user = new User("Hyuk", "진혁");
여기서 개발자가 리펙토링을 하면서 nickName 과 name 의 위치를 바꿔준다고 가정합니다.
@AllArgsConstructor
public class User {
private String name;
private String nickName;
}
name과 nickName 의 위치가 바뀌게 되면 @AllArgsConstructor 에서 생성되는 파라미터의 순서도 뒤바뀌게 됩니다. IDE 에서는 이 부분에 대해 리펙토링을 해주지 않기 때문에 기존 소스에서 인스턴스를 생성하는 로직을 확인하지 못하면 에러없이 인자가 뒤바뀌는 크리티컬한 문제를 야기할 수 있습니다.
// 생성자
public User(String name, String nickName) { ... }
// 기존 인스턴스 생성 코드
User user = new User("Hyuk", "진혁"); // name: Hyuk, nickName : 진혁 ..
@RequireArgsConstrutor 도 마찬가지이며,
@Data 에 @RequireArgsConstrutor 어노테이션이 포함되어 있기 때문에 @Data도 같이 주의하셔야 합니다.
@Data 에서는 @Setter를 지원하기 때문에 변경 기능을 제공하지 않기 위한 필드의 안전성을 보장받기 힘들고, JPA 에서의 양방향 연관 관계시 @ToString 의 순환 참조 문제가 발생할 수 있습니다.
이를 위한 차선책이 있습니다.
@Builder 어노테이션을 사용하는 것입니다.
그럼 인스턴스를 생성할 때 좀 더 명시적이게 되겠죠 .
public class User {
private String name;
private String nickName;
@Builder
public User(String name, String nickName) {
this.name = name;
this.nickName = nickName;
}
// 인스턴스 생성 코드
User user = User.builder().name("진혁").nickName("Hyuk").build();
그런데 왜 @Builder 를 생성자 위에 붙일까요??
필드에 추가적인 어노테이션 있으면 생성자로 전달이 안되는 경우가 있다고 합니다.
또한 클래스 위에 어노테이션이 있을 경우 모든 필드에 대한 매개변수가 허용됩니다.
만약 JPA를 사용하면서 id 값이 auto_increament 나 createAt 같은 값이 AuditingEntityListener 가 설정되어있다면 필요가 없겠죠. 그렇기 때문에 생성자를 필요 조건에 따라 지정하고, 생성자 위에 @Builder를 붙이는게 좋습니다.
추가적으로 @Builder에 대한 내용을 더 보니
@Builder
@Builder ... and Bob's your uncle: No-hassle fancy-pants APIs for object creation! @Builder was introduced as experimental feature in lombok v0.12.0. @Builder gained @Singular support and was promoted to the main lombok package since lombok v1.16.0. @Builder with @Singular adds a clear method since ...
projectlombok.org
AllArgsConstructor 관련 글이 존재하였는데요.
Finally, applying @Builder to a class is as if you added @AllArgsConstructor(access = AccessLevel.PACKAGE) to the class and applied the @Builder annotation to this all-args-constructor. This only works if you haven't written any explicit constructors yourself.
@Builder 사용시에 @AllArgsConstructor(access = AccessLevel.PACKAGE) 를 암묵적으로 사용해도 된다는 내용입니다.
하지만 @AllArgsConstructor 보다는 필요한 필드에 대한 생성자를 직접 작성하여 사용하는 것이 바람직하지 않을까 싶습니다.