JPA Entity @Builder

@entity란 무엇입니까?

JPA로 매핑할 테이블 및 클래스에 첨부되는 주석입니다.

@Entity 주석이 달린 클래스는 JPA에서 관리하는 객체가 됩니다.

주석 임의 사용

@Setter // 문제 1. 객체가 무분별하게 변경될 가능성 있음
@Getter
@NoArgsConstructor // 문제 2. 기본 생성자의 접근 제어자가 불명확함
@AllArgsConstructor // 문제 3. 객체 내부의 인스턴스 멤버들을 모두 가지고 있는 생성자를 생성
@Builder // 문제 4. 모든 매개변수가 생성자 param으로 들어가 객체 생성 시 받지 않아야 할 매개변수도 빌더에 노출
@Data // 문제 5. 사용하지 않는 어노테이션을 따로 exclude 할 수 없기 때문에 개별 어노테이션 사용
@Entity
public class User

문제 1. @Setter

@Setter를 사용하는 경우 객체가 언제든지 수정될 수 있으므로 객체의 안정성을 보장하기 어렵습니다.

특히 Entity에서 @Setter를 사용할 때 변경이 발생한 위치를 추적하기가 어렵습니다.

값의 변경이 필요한 경우 명시적 메서드 생성을 통해 변경하는 것이 좋습니다.

@Getter
@Entity
public class User {
    private String email;
    private String password;
    private String nickname;

    public void updateNickname(String nickname) {
        this.nickname = nickname;
    }
}

용해:@Setter 삭제 후 명시적 메소드 생성

문제 2. @NoArgsConstructor

기본 생성자의 접근 제어(NoArgsConstructor)를 PROTECTED로 설정하면 무분별한 객체 생성 여부를 다시 확인할 수 있습니다.

예를 들어 사용자 클래스에 이메일, 비밀번호, 닉네임 정보가 필요한 경우

기본 생성자를 만들지 않음으로써 불완전한 개체를 만들지 않도록 합니다.

기본 생성자의 권한을 별도로 설정하지 않으면 액세스 수준이 public이 되며 이 경우 다음과 같은 상황이 발생합니다.

// User.java
@Setter
@Getter
@NoArgsConstructor
public class User {
    private String email;
    private String password;
    private String nickname;
}


// Main.java
public static void main(String() args) {
    User user = new User();
    user.setEmail("[email protected]");
    user.setPassword("testpassword1!
!
"); // nickname 이 설정되지 않았기 때문에 user는 완전하지 않은 객체 }

사용자 개체를 생성하고 setter로 값을 설정하면 실수로 필요한 값을 설정하지 않고 개체가 생성됩니다.

그러나 다음과 같이 변경하면 IDE 단계에서 필수 값이 누락되는 것을 방지할 수 있습니다.

// User.java
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class User {
    private String email;
    private String password;
    private String nickname;
    
    public User(String email, String password) {
        this.email = email;
        this.password = password;
        // 파라미터가 두 개인 경우 default 값 설정
        this.nickname = "닉네임을 설정하세요";
    }
}


// Main.java
public static void main(String() args) {
    User user = new User(15, "[email protected]");
    
    // 기본 생성자가 없고 객체가 지정한 생성자를 사용해야하기 때문에
    // 무조건 완전한 상태의 객체가 생성되게 된다.
}

용해:@NoArgsConstructor(접속 = AccessLevel.PROTECTED)로 변경

문제 3. @AllConstructor

@AllConstructor는 클래스에 존재하는 모든 필드에 대한 생성자를 자동으로 생성합니다.
인스턴스 멤버 변수의 순서를 변경하면 입력 값의 순서도 변경되어 감지되지 않은 치명적인 오류가 발생할 수 있으므로 @AllConstructor를 사용하지 않는 것이 좋습니다.

용해:@AllConstructor 제거

작업 4. @Builder

클래스 레벨에서 @Builder와 @NoArgsConstructor를 함께 컴파일하면 오류가 발생합니다.

이것은 @AllArgsConstructor를 추가하여 해결할 수 있습니다.

그러나 위의 3번 문제에서 언급했듯이 AllArgsConstructor를 사용하지 않는 것이 좋습니다.

따라서 생성자에 @Builder를 선언하면 빌더에 객체를 생성할 때 받아서는 안 되는 매개변수를 노출시키는 문제를 해결할 수 있다.

@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class User {
    private String email;
    private String password;
    private String nickname;

    @Builder
    public User(String email, String password) {
        this.email = email;
        this.password = password;
        this.nickname = "닉네임을 설정하세요";
    }

    @Builder
    public User(String email, String password, String nickname) {
        this.email = email;
        this.password = password;
        this.nickname = nickname;
    }
}

용해:클래스에서 @Builder를 삭제하고 생성자에 @Builder를 추가합니다

작업 5. @data

@데이터는 @Getter입니다.
, @세터, @RequiredArgs 생성자, @ToString, @EqualsAndHashCode모든 것을 한 번에 수정하는 주석입니다.

@Data에 포함된 롬복 설정(예: callSuper, includeFieldNames, Exclude)를 지정할 수 없으며 사용하지 않는 주석도 즉시 선언됩니다.

따라서 @Data 주석을 사용하지 않고 필요한 개별 주석을 추가하는 것이 좋습니다.

용해:필요한 주석을 모두 추가하세요

용도

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
public class Member {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String email;
    
    private String password;
    
    private String nickname;

    public void updateNickname(String nickname) {
        this.nickname = nickname;
    }

    @Builder
    public User(String email, String password) {
        this.email = email;
        this.password = password;
        this.nickname = "닉네임을 설정하세요";
    }

    @Builder
    public User(String email, String password, String nickname) {
        this.email = email;
        this.password = password;
        this.nickname = nickname;
    }
}

https://velog.io/@mooh2jj/%EC%98%AC%EB%B0%94%EB%A5%B8%EC%97%94%ED%8B%B0%ED%8B%B0 빌더 -% EC%82%AC%EC%9A%A9%EB%B2%95

https://velog.io/@cieroyou/Builder-%EC%82%AC%EC%9A%A9%EB%B2%95

https://cobbybb.14

https://hilucky.238