programing

Lombok @Builder 및 JPA 기본 생성자

goodsources 2023. 2. 2. 21:15
반응형

Lombok @Builder 및 JPA 기본 생성자

Spring Data JPA와 함께 Lombok 프로젝트를 사용하고 있습니다.롬복과 연결할 방법이 없을까요?@BuilderJPA 디폴트 컨스트럭터를 사용할 수 있습니까?

코드:

@Entity 
@Builder
class Person {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
}

JPA는 디폴트컨스트럭터를 필요로 하는 것으로 알고 있습니다.@Builder주석입니다.그것에 대한 회피책이 있습니까?

이 코드는 에러를 표시합니다.org.hibernate.InstantiationException: No default constructor for entity: : app.domain.model.Person

갱신필

피드백과 존의 답변을 바탕으로 더 이상 사용하지 않겠다는 답변을 업데이트했습니다.@Tolerate또는@Data대신 접근자 및 변이자를 만듭니다.@Getter그리고.@Setter, 를 사용하여 기본 컨스트럭터를 만듭니다.@NoArgsConstructor마지막으로 빌더가 필요로 하는 모든 args 컨스트럭터를 만듭니다.@AllArgsConstructor.

빌더 패턴을 사용하고 싶기 때문에 컨스트럭터와 뮤테이터 메서드의 가시성을 제한하고 싶다고 생각합니다.이를 실현하기 위해 델에서는package private경유로access의 속성@NoArgsConstructor그리고.@AllArgsConstructor주석 및value의 속성@Setter주석입니다.

중요한

올바르게 덮어쓰는 것을 잊지 마세요.toString,equals,그리고.hashCode상세한 것에 대하여는, Vlad Mihalcea의 다음의 투고를 참조해 주세요.

package com.stackoverflow.SO34299054;

import static org.junit.Assert.*;

import java.util.Random;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

import org.junit.Test;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@SuppressWarnings("javadoc")
public class Answer {

    @Entity
    @Builder(toBuilder = true)
    @AllArgsConstructor(access = AccessLevel.PACKAGE)
    @NoArgsConstructor(access = AccessLevel.PACKAGE)
    @Setter(value = AccessLevel.PACKAGE)
    @Getter
    public static class Person {

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

        /*
         * IMPORTANT:
         * Set toString, equals, and hashCode as described in these
         * documents:
         * - https://vladmihalcea.com/the-best-way-to-implement-equals-hashcode-and-tostring-with-jpa-and-hibernate/
         * - https://vladmihalcea.com/how-to-implement-equals-and-hashcode-using-the-jpa-entity-identifier/
         * - https://vladmihalcea.com/hibernate-facts-equals-and-hashcode/
         */
    }

    /**
     * Test person builder.
     */
    @Test
    public void testPersonBuilder() {

        final Long expectedId = new Random().nextLong();
        final Person fromBuilder = Person.builder()
            .id(expectedId)
            .build();
        assertEquals(expectedId, fromBuilder.getId());

    }

    /**
     * Test person constructor.
     */
    @Test
    public void testPersonConstructor() {

        final Long expectedId = new Random().nextLong();
        final Person fromNoArgConstructor = new Person();
        fromNoArgConstructor.setId(expectedId);
        assertEquals(expectedId, fromNoArgConstructor.getId());
    }
}

이전 버전 사용@Tolerate그리고.@Data:

사용.@Toleratenoarg 컨스트럭터를 추가할 수 있도록 했습니다.

빌더 패턴을 사용하고 싶기 때문에 세터 방식의 가시성을 제어하고 싶다고 생각합니다.

@Data주석으로 인해 생성된 세터가 생성됩니다.public, 적용하다@Setter(value = AccessLevel.PROTECTED)들판으로 가는 것은 그들을 만든다.protected.

올바르게 덮어쓰는 것을 잊지 마세요.toString,equals,그리고.hashCode상세한 것에 대하여는, Vlad Mihalcea의 다음의 투고를 참조해 주세요.

package lombok.javac.handlers.stackoverflow;

import static org.junit.Assert.*;

import java.util.Random;

import javax.persistence.GenerationType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

import lombok.AccessLevel;
import lombok.Builder;
import lombok.Data;
import lombok.Setter;
import lombok.experimental.Tolerate;

import org.junit.Test;

public class So34241718 {

    @Builder
    @Data
    public static class Person {

        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        @Setter(value = AccessLevel.PROTECTED)
        Long id;

        @Tolerate
        Person() {}

       /* IMPORTANT:
          Override toString, equals, and hashCode as described in these 
          documents:
          - https://vladmihalcea.com/the-best-way-to-implement-equals-hashcode-and-tostring-with-jpa-and-hibernate/
          - https://vladmihalcea.com/how-to-implement-equals-and-hashcode-using-the-jpa-entity-identifier/
          - https://vladmihalcea.com/hibernate-facts-equals-and-hashcode/
          */
    }

    @Test
    public void testPersonBuilder() {

        Long expectedId = new Random().nextLong();
        final Person fromBuilder = Person.builder()
            .id(expectedId)
            .build();
        assertEquals(expectedId, fromBuilder.getId());

    }

    @Test
    public void testPersonConstructor() {

        Long expectedId = new Random().nextLong();
        final Person fromNoArgConstructor = new Person();
        fromNoArgConstructor .setId(expectedId);
        assertEquals(expectedId, fromNoArgConstructor.getId());
    }
}

또한 다음과 같이 명시적으로 해결할 수 있습니다.@Data @Builder @NoArgsConstructor @AllArgsConstructor클래스 정의에서 결합됩니다.

여기서는 주석 순서가 중요한 것 같습니다.주석은 같지만 순서가 다르면 코드를 사용할 수도 있고 사용할 수도 없습니다.

동작하지 않는 예를 다음에 나타냅니다.

@AllArgsConstructor
@Builder
@Data
@Entity
@EqualsAndHashCode
@NoArgsConstructor
@RequiredArgsConstructor
@Table
@ToString
public class Person implements Serializable {
  private String name;
}

다음은 작동 예를 제시하겠습니다.

@Builder
@Data
@Entity
@EqualsAndHashCode
@AllArgsConstructor
@NoArgsConstructor
@RequiredArgsConstructor
@Table
@ToString
public class Person implements Serializable {
  private String name;
}

맨 위에 @Builder 주석이 있는지 확인하십시오.이 경우 주석을 알파벳 순으로 정렬하려고 이 오류가 발생했습니다.

주석이 롬복일 경우.컨스트럭터 및 javax.validation.constraints에서 허용됩니다.일부 속성에서는 Not Null이 동시에 사용됩니다.Sonarqube는 이를 중대한 오류로 마킹합니다.PROPERTY는 "javax.validation.constraints"로 마킹됩니다.Not Null"이지만 이 생성자에서는 초기화되지 않았습니다.

프로젝트가 JPA와 함께 SpringData를 사용하는 경우 org.springframework.data.notation을 사용하여 해결할 수 있습니다.PersistenceConstructor(스프링 주석, JPA 아님)

그러면 Lombok과 조합하여 다음과 같이 주석을 달 수 있습니다.

@RequiredArgsConstructor(onConstructor = @__(@PersistenceConstructor))

Lombok Builder의 경우 다음 항목도 추가해야 합니다.

@Builder
@AllArgsConstructor

다음 조합을 사용하려면

  • 롬복
  • JPA
    • 크러드
    • @EqualsAndHashCode
  • 불변성 - 최종 공개 필드
  • 노게터
  • 셋터 없음
  • 의한 @Builder ★★★★★★★★★★★★★★★★★」@With

사용:

//Lombok & JPA
//https://stackoverflow.com/questions/34241718/lombok-builder-and-jpa-default-constructor

//Mandatory in conjunction with JPA: an equal based on fields is not desired
@lombok.EqualsAndHashCode(onlyExplicitlyIncluded = true)
//Mandatory in conjunction with JPA: force is needed to generate default values for final fields, that will be overriden by JPA
@lombok.NoArgsConstructor(access = AccessLevel.PRIVATE, force = true)
//Hides the constructor to force usage of the Builder.
@lombok.AllArgsConstructor(access = AccessLevel.PRIVATE)
@lombok.ToString
//Good to just modify some values
@lombok.With
//Mandatory in conjunction with JPA: Some suggest that the Builder should be above Entity - https://stackoverflow.com/a/52048267/99248
//Good to be used to modify all values
@lombok.Builder(toBuilder = true)
//final fields needed for imutability, the default access to public - since are final is safe 
@lombok.experimental.FieldDefaults(makeFinal = true, level = AccessLevel.PUBLIC)
//no getters and setters
@lombok.Getter(value = AccessLevel.NONE)
@lombok.Setter(value = AccessLevel.NONE)

//JPA
@javax.persistence.Entity
@javax.persistence.Table(name = "PERSON_WITH_MOTTO")
//jpa should use field access 
@javax.persistence.Access(AccessType.FIELD)
public class Person {
  @javax.persistence.Id
  @javax.persistence.GeneratedValue
  //Used also automatically as JPA
  @lombok.EqualsAndHashCode.Include
  Long id;
  String name;
  String motto;
}

「」를 사용합니다.@NoArgsConstructor ★★★★★★★★★★★★★★★★★」@AllArgsContructor하는 데 .@Builder

@Entity 
@Builder
@NoArgsConstructor
@AllArgsContructor
class Person {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
}

그 이유는@Builder에는 모든 인수 생성자가 필요하며 기본 생성자만 지정하면 문제가 발생합니다.

자세한 설명은 https://github.com/rzwitserloot/lombok/issues/1389#issuecomment-369404719 입니다.

저는 이 모든 주석을 사용하여 이 문제를 해결했습니다.

@Data
@Builder
@AllArgsConstructor(access = AccessLevel.PACKAGE)
@NoArgsConstructor(access = AccessLevel.PACKAGE)

Jeff의 답변은 정상적으로 동작하지만, @Builder는 아직 자기 참조 관계를 지원하지 않습니다.

상세한 것에 대하여는, 다음의 질문을 참조해 주세요.

JPA @Onto두 열이 null이 아닌 하나의 자체 참조 관계입니다.

언급URL : https://stackoverflow.com/questions/34241718/lombok-builder-and-jpa-default-constructor

반응형