我正在使用项目Lombok和Spring Data JPA.有没有办法将Lombok @Builder
与JPA默认构造函数连接?
码:
@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
更新
基于反馈和John的回答,我已经更新了不再使用的答案,@Tolerate
或者@Data
我们通过创建访问器和mutator,@Getter
并@Setter
创建默认构造函数@NoArgsConstructor
,最后我们创建构建器所需的所有args构造函数@AllArgsConstructor
.
既然你想使用构建器模式,我想你想要限制构造函数和mutators方法的可见性.为实现此目的,我们package private
通过注释上的属性和注释上的access
属性设置可见性.@NoArgsConstructor
@AllArgsConstructor
value
@Setter
重要
记住要正确重写toString
,equals
和hashCode
.有关详细信息,请参阅Vlad Mihalcea的以下帖子:
该条最佳方式对实施-等于-哈希码和-的toString与 - JPA-和休眠
如何对实现-等于-和哈希码 - 使用最JPA实体标识符
休眠-事实,等于和 - 哈希码
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
:
使用@Tolerate
工作允许添加noarg构造函数.
由于您想要使用构建器模式,我想您想要控制setter方法的可见性.
该@Data
注解使得生成的制定者public
,应用@Setter(value = AccessLevel.PROTECTED)
的领域,因此他们protected
.
记住要正确重写toString
,equals
和hashCode
.有关详细信息,请参阅Vlad Mihalcea的以下帖子:
该条最佳方式对实施-等于-哈希码和-的toString与 - JPA-和休眠
如何对实现-等于-和哈希码 - 使用最JPA实体标识符
休眠-事实,等于和 - 哈希码
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批注放在最高位置,在我的情况下,我会遇到此错误,因为我想按字母顺序对批注进行排序。