2015-12-12 16 views
23

Ich verwende Projekt Lombok zusammen mit Spring Data JPA. Gibt es eine Möglichkeit Lombok zu verbinden @Builder mit JPA Standardkonstruktors?Lombok @Builder und JPA Standardkonstruktors

Code:

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

Soweit ich weiß, muss JPA Standardkonstruktors die durch @Builder Anmerkung außer Kraft gesetzt wird. Gibt es eine Abhilfe für das?

Dieser Code gibt mir Fehler: org.hibernate.InstantiationException: No default constructor for entity: : app.domain.model.Person

+1

Versuchen hinzufügen Hinzufügen einer '@ NoArgsConstructor' https://projectlombok.org/api/lombok/NoArgsConstructor.html –

+0

versuchen Sie, ein nicht args Konstruktor .AFAIK,' @ Builder' überschreibt nicht den Konstruktor "no args" –

+0

Ja, aber @Id ist ein Pflichtfeld. NoArgs wird es nicht schneiden – krzakov

Antwort

27

Aktualisiert

Basierend auf dem Feedback und Johns answer ich aktualisiert die Antwort auf nicht mehr @Tolerate verwenden oder @Data und stattdessen erstellen wir Zugriffs- und Mutatoren über @Getter und @Setter, den Standardkonstruktor über @NoArgsConstructor erstellen und schließlich schaffen wir die alle args Konstruktor, der Bauherr über @AllArgsConstructor erfordert.

Da Sie das Builder-Muster verwenden möchten, stellen Sie sich vor, Sie möchten die Sichtbarkeit der Konstruktor- und Mutator-Methoden einschränken. Um dies zu erreichen, setzen wir die Sichtbarkeit auf package private über das access Attribut auf den @NoArgsConstructor und @AllArgsConstructor Annotationen und das value Attribut auf der @Setter Annotation.

Wichtige

Denken Sie daran, richtig toString, equals und hashCode außer Kraft zu setzen. Auch die folgenden Beiträge von Vlad Mihalcea für Details:

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()); 
    } 
} 

alte Version mit @Tolerate und @Data:

Mit @Tolerate arbeitete das Hinzufügen eines noarg Konstruktor zu ermöglichen.

Da Sie die Erbauer verwenden möchten ich denke, Sie Sichtbarkeit der Setter-Methoden steuern möchten.

Die @Data Anmerkung macht die erzeugten Setter public, Anwendung @Setter(value = AccessLevel.PROTECTED) auf die Felder macht sie protected.

Denken Sie daran, die toString, equals und hashCode richtig zu überschreiben. Auch die folgenden Beiträge von Vlad Mihalcea für Details:

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()); 
    } 
} 
+1

Ich hatte die gleiche Frage wie Krzakov und ich löste es mit Ihrem Hinweis, mit '@ Tolerate'. Danke für diesen Jeff. Aber gibt es einen Grund, warum Sie die '@ Data' Annotation hinzufügen? Setter sind in diesem Fall nicht notwendig und '@ Data' überschreibt gleich/hash/toString mit dem Standardverhalten, was zu Problemen führen kann. – wollodev

+0

Verwenden Sie '@ Data' nicht mit Entitäten. – waste

+0

Wenn dies mit toString, equals und hashCode zu tun hat, habe ich Links zu Dokumenten bezüglich der korrekten Implementierung hinzugefügt. – Jeff

35

Sie können auch mit @Builder @NoArgsConstructor @AllArgsConstructor kombiniert auf der Klassendefinition es explizit lösen.

+2

Das ist besser als die angenommene Antwort. Vermeiden Sie experimentelle Eigenschaften, Kinder. – Michael

+0

Hinweis, dies erstellt nicht automatisch Accessor-Methoden (Getter). – Jeff

0

Wenn die Anmerkungen lombok.Tolerate auf Konstruktor und javax.validation.constraints.NotNull auf einer Eigenschaft zur gleichen Zeit verwendet werden, Sonarqube wird es als ein kritischer Fehler markiert: PROPERTY markiert ist „javax. validation.constraints.NotNull ", ist aber in diesem Konstruktor nicht initialisiert.

Wenn das Projekt SpringData mit JPA verwendet, kann es mit org.springframework.data.annotation.PersistenceConstructor gelöst werden (Frühling Anmerkung, nicht JPA!)

Dann mit Lombok in Kombination, Anmerkungen werden sein wie folgt aus:

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

Für Lombok Builder Sie auch hinzufügen müssen:

@Builder 
@AllArgsConstructor 
Verwandte Themen