2015-12-12 74 views
23

私はSpring Data JPAとともにプロジェクトLombokを使用しています。 Lombok @Builderを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

追加してみてください '@ NoArgsConstructor' https://projectlombok.org/api/lombok/NoArgsConstructor.html –

+0

追加してみてください引数なし​​のコンストラクタ.AFAIK、' @ Builder'あなたのno argsコンストラクタをオーバーライドしません –

+0

ええ、@Idは必須フィールドです。 NoArgsはそれをカットするつもりはない – krzakov

答えて

27

は、フィードバックとジョンのanswerに基づいて

を更新しました私はもはや@Tolerateまたは@Dataを使用し、代わりに私たちはアクセサとミューテーターを作成するための答えを更新しました@Getter@Setterでデフォルトのコンストラクタを@NoArgsConstructorで作成し、最後に@AllArgsConstructorでビルダーが必要とするすべてのargsコンストラクタを作成します。

ビルダーパターンを使用したいので、コンストラクタとミューテータのメソッドの可視性を制限したいと思います。 package privateの可視性を@NoArgsConstructor@AllArgsConstructorアノテーションのaccess属性と@Setterアノテーションのvalue属性を使用して設定しました。

重要

適切toStringequals、そしてhashCodeを上書きすることを忘れないでください。 詳細については、ヴラッド・ミホールセアことにより、以下の記事を参照してください:@Tolerate@Dataを使用して

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を使用すると、noargコンストラクタを追加できます。

ビルダーパターンを使用したいので、セッターメソッドの可視性を制御したいと思っています。

@Dataアノテーションは、生成されたセッターをpublicとし、@Setter(value = AccessLevel.PROTECTED)を適用すると、protectedとなります。

toStringequals、および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()); 
    } 
} 
+1

私はkrzakovと同じ質問をしていました。私は '@ Tolerate'を使ってそのヒントを使って解決しました。そのジェフのおかげで。しかし、 '@ Data'アノテーションを追加する理由は何ですか?この場合、セッターは不要であり、 '@Data'はデフォルトの動作でequal/hash/toStringを上書きし、問題を引き起こします。 – wollodev

+0

エンティティで '@Data'を使用しないでください。 – waste

+0

これがtoString、equals、およびhashCodeに関係する場合は、適切な実装に関するドキュメントへのリンクを追加しました。 – Jeff

35

ます。また、クラス定義に組み合わせ@Builder @NoArgsConstructor @AllArgsConstructorで明示的にそれを解決することができます。コンストラクタといくつかの財産上のjavax.validation.constraints.NotNull上の注釈lombok.Tolerateを同時に使用する場合は

+2

これは受け入れられた回答よりも優れています。実験的な機能、子供を避けてください。 – Michael

+0

これは、アクセサメソッド(ゲッタ)を自動的に作成しないことに注意してください。 – Jeff

0

、sonarqubeは重大なエラーとしてそれをマークします:PROPERTYは、「javaxのがマークされています。 validation.constraints.NotNull "が、このコンストラクタで初期化されていません。その後

プロジェクトは、JPAとSpringDataを使用している場合、それはorg.springframework.data.annotation.PersistenceConstructor使用して解決することができる(春の注釈ではなく、JPAに!)

を、ロンボク島との組み合わせで、注釈ますこのようなこと:

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

はロンボクビルダーのためにあなたにも追加する必要があります。

@Builder 
@AllArgsConstructor 
関連する問題