plugin getters generate example data java spring spring-data-jpa lombok

getters - lombok java example @data



Lombok @Builder y JPA Constructor predeterminado (5)

Estoy usando el proyecto Lombok junto con Spring Data JPA. ¿Hay alguna forma de conectar Lombok @Builder con el constructor predeterminado JPA?

Código:

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

Hasta donde sé, JPA necesita un constructor predeterminado que se anula con la anotación @Builder . ¿Hay alguna solución para eso?

Este código me da el error: org.hibernate.InstantiationException: No default constructor for entity: : app.domain.model.Person


El uso de @NoArgsConstructor y @AllArgsContructor ayudará a resolver el problema de tener un constructor predeterminado con @Builder .

p.ej

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

Esto se debe a que @Builder requiere todo constructor de argumentos y especificar solo un constructor predeterminado causará un problema.

Aquí hay más explicaciones: https://github.com/rzwitserloot/lombok/issues/1389#issuecomment-369404719


Parece que el orden de las anotaciones es importante aquí, usando las mismas anotaciones, pero diferentes órdenes, puede 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.


Si las anotaciones lombok.Tolerate en constructor y javax.validation.constraints.NotNull en alguna propiedad se usan al mismo tiempo, sonarqube lo marcará como un error crítico: PROPIEDAD se marca "javax.validation.constraints.NotNull" pero no se inicializado en este constructor.

Si el proyecto usa SpringData con JPA, se puede resolver usando org.springframework.data.annotation.PersistenceConstructor (¡Anotación Spring, no JPA!)

Luego, en combinación con Lombok, las anotaciones serán así:

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

Para el constructor de Lombok también necesita agregar:

@Builder @AllArgsConstructor


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


Actualizado

Según los comentarios y la answer de John, actualicé la respuesta para que ya no use @Tolerate o @Data y, en su lugar, creamos @Getter y mutadores a través de @Getter y @Setter , creamos el constructor predeterminado a través de @NoArgsConstructor , y finalmente creamos todos los argumentos constructor que el constructor requiere a través de @AllArgsConstructor .

Como desea utilizar el patrón de construcción, imagino que desea restringir la visibilidad de los métodos de constructor y mutadores. Para lograr esto, establecemos la visibilidad del package private través del atributo de access en las anotaciones @NoArgsConstructor y @AllArgsConstructor y el atributo de value en la anotación @Setter .

Importante

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

package com..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 anterior usando @Tolerate y @Data :

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

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

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

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

package lombok.javac.handlers.; 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()); } }