Java Lombok@Builder和JPA默认构造函数

Java Lombok@Builder和JPA默认构造函数,java,spring,spring-data-jpa,lombok,Java,Spring,Spring Data Jpa,Lombok,我正在使用ProjectLombok和SpringDataJPA。 有没有办法将Lombok@Builder与JPA默认构造函数连接起来 代码: 据我所知,JPA需要默认构造函数,它被@Builder注释覆盖。有什么解决办法吗 这段代码给了我一个错误: org.hibernate.InstantiationException:实体::app.domain.model.Person没有默认构造函数 根据反馈和John的回答,我更新了答案,不再使用@Tolerate或@Data,而是通过@Gette

我正在使用ProjectLombok和SpringDataJPA。 有没有办法将Lombok
@Builder
与JPA默认构造函数连接起来

代码:

据我所知,JPA需要默认构造函数,它被
@Builder
注释覆盖。有什么解决办法吗

这段代码给了我一个错误:
org.hibernate.InstantiationException:实体::app.domain.model.Person没有默认构造函数

根据反馈和John的回答,我更新了答案,不再使用
@Tolerate
@Data
,而是通过
@Getter
@Setter
创建访问器和变异器,通过
@noargsconstuctor
创建默认构造函数,最后,我们通过
@allargsconstuctor
创建生成器所需的所有args构造函数

由于您想要使用构建器模式,我想您想要限制构造函数和mutators方法的可见性。 为此,我们通过
@noargsconstuctor
@allargsconstuctor
注释上的
访问
属性和
@Setter
注释上的
属性将可见性设置为
包私有

重要

请记住正确覆盖
toString
equals
hashCode
。 有关详细信息,请参见Vlad Mihalcea的以下帖子:

package com.stackoverflow.SO34299054;
导入静态org.junit.Assert.*;
导入java.util.Random;
导入javax.persistence.Entity;
导入javax.persistence.GeneratedValue;
导入javax.persistence.GenerationType;
导入javax.persistence.Id;
导入org.junit.Test;
导入lombok.AccessLevel;
导入lombok.allargsconstuctor;
进口龙目造船厂;
进口龙目吸气剂;
导入lombok.noargsconstuctor;
进口龙目织机;
@抑制警告(“javadoc”)
公开课答案{
@实体
@生成器(toBuilder=true)
@AllArgsConstructor(access=AccessLevel.PACKAGE)
@NOARGS构造函数(access=AccessLevel.PACKAGE)
@Setter(值=AccessLevel.PACKAGE)
@吸气剂
公共静态类人员{
@身份证
@GeneratedValue(策略=GenerationType.AUTO)
私人长id;
/*
*重要:
*设置为字符串、等号和哈希代码,如以下所述
*文件:
* - 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/
*/
}
/**
*测试人员生成器。
*/
@试验
public void testPersonBuilder(){
final Long expectedId=new Random().nextLong();
final Person fromBuilder=Person.builder()
.id(预期id)
.build();
assertEquals(expectedId,fromBuilder.getId());
}
/**
*测试人员构造函数。
*/
@试验
public void testPersonConstructor(){
final Long expectedId=new Random().nextLong();
来自NoArgConstructor的最终人员=新人员();
fromNoArgConstructor.setId(expectedId);
assertEquals(expectedId,fromNoArgConstructor.getId());
}
}
使用
@容忍
@数据的旧版本

使用
@Tolerate
可以允许添加noarg构造函数

由于您想要使用构建器模式,我想您想要控制setter方法的可见性

@Data
注释使生成的Setter
成为公共的
,将
@Setter(value=AccessLevel.PROTECTED)
应用于字段使其受到
保护

请记住正确覆盖
toString
equals
hashCode
。 有关详细信息,请参见Vlad Mihalcea的以下帖子:

包lombok.javac.handlers.stackoverflow;
导入静态org.junit.Assert.*;
导入java.util.Random;
导入javax.persistence.GenerationType;
导入javax.persistence.GeneratedValue;
导入javax.persistence.Id;
导入lombok.AccessLevel;
进口龙目造船厂;
导入龙目数据;
进口龙目织机;
进口龙目羚;实验性;耐受性;
导入org.junit.Test;
公共类So34241718{
@建筑商
@资料
公共静态类人员{
@身份证
@GeneratedValue(策略=GenerationType.AUTO)
@Setter(值=AccessLevel.PROTECTED)
长id;
@容忍
Person(){}
/*重要:
重写toString、equals和hashCode,如下面所述
文件:
- 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/
*/
}
@试验
public void testPersonBuilder(){
Long expectedId=new Random().nextLong();
final Person fromBuilder=Person.builder()
.id(预期id)
.build();
assertEquals(expectedId,fromBuilder.getId());
}
@试验
public void testPersonConstructor(){
Long expectedId=new Random().nextLong();
来自NoArgConstructor的最终人员=新人员();
fromNoArgConstructor.setId(expectedId);
assertEquals(expectedId,fromNoArgConstructor.getId());
}
}

您还可以在类定义中结合使用
@Data@Builder@noargsconstuctor@allargsconstuctor
显式解决该问题。

如果注释lombok.allow on构造函数和javax.validation.constraint
@Entity 
@Builder
class Person {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
}
@RequiredArgsConstructor(onConstructor = @__(@PersistenceConstructor))
@Builder
@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;
}
@Entity 
@Builder
@NoArgsConstructor
@AllArgsContructor
class Person {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
}
@Data
@Builder
@AllArgsConstructor(access = AccessLevel.PACKAGE)
@NoArgsConstructor(access = AccessLevel.PACKAGE)
//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;
}