当前位置:  开发笔记 > 编程语言 > 正文

Lombok @Builder和JPA Default构造函数

如何解决《Lombok@Builder和JPADefault构造函数》经验,为你挑选了3个好方法。

我正在使用项目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



1> Jeff..:

更新

基于反馈和John的回答,我已经更新了不再使用的答案,@Tolerate或者@Data我们通过创建访问器和mutator,@Getter@Setter创建默认构造函数@NoArgsConstructor,最后我们创建构建器所需的所有args构造函数@AllArgsConstructor.

既然你想使用构建器模式,我想你想要限制构造函数和mutators方法的可见性.为实现此目的,我们package private通过注释上的属性和注释上的access属性设置可见性.@NoArgsConstructor@AllArgsConstructorvalue@Setter

重要

记住要正确重写toString,equalshashCode.有关详细信息,请参阅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,equalshashCode.有关详细信息,请参阅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());
    }
}


我和krzakov有同样的问题,我用你的提示解决了它,使用`@Tolerate`.谢谢杰夫.但是你有没有理由添加`@Data`注释?在这种情况下,setter不是必需的,`@Data`用默认行为覆盖equ/hash/toString,这可能会产生问题.
@srnjak`@ Data`默认使用所有字段来生成`equals`和`hashCode`方法,包括`id`。简单的示例-保存前后,您可能具有相同的实体表示形式,从Java角度来看,它们将是不同的实例(带有和不带有id的实例)。这可能会导致混乱和一致性问题。如果您要覆盖这些方法,则可以使用`@ Data`。关于它的Hibernate文档中有一章:http://docs.jboss.org/hibernate/orm/5.3/userguide/html_single/Hibernate_User_Guide.html#mapping-model-pojo-equalshashcode

2> John John Pi..:

您还可以@Data @Builder @NoArgsConstructor @AllArgsConstructor结合使用类定义来明确解决它.



3> Karl.S..:

注释的顺序在这里似乎很重要,使用相同的注释,但是使用不同的顺序,可以使代码正常运行,也可以不正常运行。

这是一个无效的示例:

@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批注放在最高位置,在我的情况下,我会遇到此错误,因为我想按字母顺序对批注进行排序。

推荐阅读
吻过彩虹的脸_378
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有