Saltar al contenido

Lombok @Builder y constructor predeterminado de JPA

Solución:

Actualizado

Según los comentarios y la respuesta de John, he actualizado la respuesta para que ya no use @Tolerate o @Data y en su lugar creamos accesores y mutadores a través de @Getter y @Setter, crea el constructor predeterminado a través de @NoArgsConstructor, y finalmente creamos el constructor all args que el constructor requiere a través de @AllArgsConstructor.

Como desea utilizar el patrón de constructor, imagino que desea restringir la visibilidad de los métodos de constructor y mutadores. Para lograr esto, configuramos la visibilidad en package private mediante el access atributo en el @NoArgsConstructor y @AllArgsConstructor anotaciones y el value atributo en el @Setteranotación.

Importante

Recuerde anular correctamente toString, equals, y hashCode. Vea las siguientes publicaciones de Vlad Mihalcea para más detalles:

  • la-mejor-manera-de-implementar-es-igual-código-hash-y-cadena-con-jpa-e-hibernación
  • cómo-implementar-es-igual-y-código-hash-usando-el-identificador-de-entidad-jpa
  • hibernate-hechos-igual-y-hashcode
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());
    }
}

Versión antigua usando @Tolerate y @Data:

Utilizando @Tolerate funcionó para permitir agregar un constructor noarg.

Dado que desea utilizar el patrón de construcción, imagino que desea controlar la visibilidad de los métodos de establecimiento.

los @Data la anotación hace que los setters generados public, aplicando @Setter(value = AccessLevel.PROTECTED) a los campos los hace protected.

Recuerde anular correctamente toString, equals, y hashCode. Vea las siguientes publicaciones de Vlad Mihalcea para más detalles:

  • la-mejor-manera-de-implementar-es-igual-código-hash-y-cadena-con-jpa-e-hibernación
  • cómo-implementar-es-igual-y-código-hash-usando-el-identificador-de-entidad-jpa
  • hibernate-hechos-igual-y-hashcode
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());
    }
}

También puedes resolverlo explícitamente con @Data @Builder @NoArgsConstructor @AllArgsConstructor combinado en la definición de clase.

Parece que el orden de las anotaciones es importante aquí, usando las mismas anotaciones, pero diferentes órdenes, puedes hacer que el código funcione o no.

Aquí hay un ejemplo que no funciona:

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

Y este es un ejemplo de trabajo:

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

Así que asegúrese de tener la anotación @Builder en la posición más alta, en mi caso encontré este error porque quería ordenar las anotaciones alfabéticamente.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *