Jackson JSONとHibernate JPAの問題による無限再帰


412

双方向の関連付けがあるJPAオブジェクトをJSONに変換しようとすると、

org.codehaus.jackson.map.JsonMappingException: Infinite recursion (StackOverflowError)

私が見つけたのはこのスレッドだけで、基本的には双方向の関連付けを回避することをお勧めします。誰かがこの春のバグの回避策を考えていますか?

------ EDIT 2010-07-24 16:26:22 -------

コードスニペット:

ビジネスオブジェクト1:

@Entity
@Table(name = "ta_trainee", uniqueConstraints = {@UniqueConstraint(columnNames = {"id"})})
public class Trainee extends BusinessObject {

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    @Column(name = "id", nullable = false)
    private Integer id;

    @Column(name = "name", nullable = true)
    private String name;

    @Column(name = "surname", nullable = true)
    private String surname;

    @OneToMany(mappedBy = "trainee", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @Column(nullable = true)
    private Set<BodyStat> bodyStats;

    @OneToMany(mappedBy = "trainee", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @Column(nullable = true)
    private Set<Training> trainings;

    @OneToMany(mappedBy = "trainee", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @Column(nullable = true)
    private Set<ExerciseType> exerciseTypes;

    public Trainee() {
        super();
    }

    ... getters/setters ...

ビジネスオブジェクト2:

import javax.persistence.*;
import java.util.Date;

@Entity
@Table(name = "ta_bodystat", uniqueConstraints = {@UniqueConstraint(columnNames = {"id"})})
public class BodyStat extends BusinessObject {

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    @Column(name = "id", nullable = false)
    private Integer id;

    @Column(name = "height", nullable = true)
    private Float height;

    @Column(name = "measuretime", nullable = false)
    @Temporal(TemporalType.TIMESTAMP)
    private Date measureTime;

    @ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinColumn(name="trainee_fk")
    private Trainee trainee;

コントローラ:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

@Controller
@RequestMapping(value = "/trainees")
public class TraineesController {

    final Logger logger = LoggerFactory.getLogger(TraineesController.class);

    private Map<Long, Trainee> trainees = new ConcurrentHashMap<Long, Trainee>();

    @Autowired
    private ITraineeDAO traineeDAO;

    /**
     * Return json repres. of all trainees
     */
    @RequestMapping(value = "/getAllTrainees", method = RequestMethod.GET)
    @ResponseBody        
    public Collection getAllTrainees() {
        Collection allTrainees = this.traineeDAO.getAll();

        this.logger.debug("A total of " + allTrainees.size() + "  trainees was read from db");

        return allTrainees;
    }    
}

研修生DAOのJPA実装:

@Repository
@Transactional
public class TraineeDAO implements ITraineeDAO {

    @PersistenceContext
    private EntityManager em;

    @Transactional
    public Trainee save(Trainee trainee) {
        em.persist(trainee);
        return trainee;
    }

    @Transactional(readOnly = true)
    public Collection getAll() {
        return (Collection) em.createQuery("SELECT t FROM Trainee t").getResultList();
    }
}

persistence.xml

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
             version="1.0">
    <persistence-unit name="RDBMS" transaction-type="RESOURCE_LOCAL">
        <exclude-unlisted-classes>false</exclude-unlisted-classes>
        <properties>
            <property name="hibernate.hbm2ddl.auto" value="validate"/>
            <property name="hibernate.archive.autodetection" value="class"/>
            <property name="dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
            <!-- <property name="dialect" value="org.hibernate.dialect.HSQLDialect"/>         -->
        </properties>
    </persistence-unit>
</persistence>

に追加@TransientTrainee.bodyStatsます。
phil294 2017年

2017年現在、@JsonIgnorePropertiesは最もクリーンなソリューションです。チェックアウトZammel AlaaEddineの答えを詳細については。
Utku、2017

この春の欠点はどうですか?
Nathan Hughes

回答:


293

@JsonIgnoreサイクルを断ち切るために使用できます。


1
@ベン:実はわかりません。おそらく、そのサポートは有効化されていませんでした:wiki.fasterxml.com/JacksonJAXBAnnotations
axtavt

40
ジャクソン1.6以降、より良い解決策があります。2つの新しいアノテーションを使用して、シリアル化中にゲッター/セッターを無視せずに無限再帰問題を解決できます。詳細については、以下の私の回答を参照してください。
カートブルバキ2014

1
@axtavt完璧な答えをありがとう。ところで、私は別の解決策を思いつきました:この値のゲッターの作成を単に回避できるので、JSONの作成中にSpringがそれにアクセスすることはできません(しかし、すべてのケースに適しているとは思わないので、あなたの答えはより良いです)
Semyon Danilov 2014

11
上記のすべてのソリューションでは、注釈を追加してドメインオブジェクトを変更する必要があるようです。サードパーティのクラスをシリアル化する場合、それらを変更する方法はありません。この問題を回避するにはどうすればよいですか?
Jianwu Chen

2
このソリューションは、状況によっては機能しません。jpaを使用したリレーショナルデータベースで@JsonIgnoreは、エンティティを更新するときに「外部キー」にnullを指定すると、
スリムな

629

JsonIgnoreProperties [2017 Update]:

JsonIgnorePropertiesを使用して、プロパティのシリアル化抑制したり(シリアル化中)、読み取ったJSONプロパティの処理を無視したりできます(デシリアライズ中)。これが探しているものではない場合は、以下をお読みください。

(これを指摘してくれたAs Zammel AlaaEddineに感謝します)。


JsonManagedReferenceおよびJsonBackReference

ジャクソン1.6以来、あなたは、直列化の際にゲッター/セッターを無視することなく、無限再帰の問題を解決するために2つのアノテーションを使用することができます@JsonManagedReference@JsonBackReference

説明

ジャクソンがうまく機能するためには、stackoverflowエラーの原因となる無限ループを回避するために、関係の2つの側の一方をシリアル化しないでください。

したがって、Jacksonは参照の前方部分(Set<BodyStat> bodyStatsTraineeクラス内の)を受け取り、それをjsonのようなストレージ形式に変換します。これは、いわゆるマーシャリングプロセスです。次に、Jacksonは参照の後ろの部分(つまりTrainee traineeBodyStatクラス内)を探し、それをシリアル化せずにそのままにします。関係のこの部分は、デシリアライゼーション中に再構築されます(非整列化、前方参照の)ます。

次のようにコードを変更できます(役に立たない部分は省略します)。

ビジネスオブジェクト1:

@Entity
@Table(name = "ta_trainee", uniqueConstraints = {@UniqueConstraint(columnNames = {"id"})})
public class Trainee extends BusinessObject {

    @OneToMany(mappedBy = "trainee", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @Column(nullable = true)
    @JsonManagedReference
    private Set<BodyStat> bodyStats;

ビジネスオブジェクト2:

@Entity
@Table(name = "ta_bodystat", uniqueConstraints = {@UniqueConstraint(columnNames = {"id"})})
public class BodyStat extends BusinessObject {

    @ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinColumn(name="trainee_fk")
    @JsonBackReference
    private Trainee trainee;

これで、すべて正常に動作するはずです。

さらに詳しい情報が必要な場合は、私のブログであるKeenformaticsにJsonおよびJackson Stackoverflowの問題に関する記事を書いています

編集:

チェックできるもう1つの便利なアノテーションは@JsonIdentityInfoです。これを使用すると、Jacksonがオブジェクトをシリアル化するたびに、ID(または選択した別の属性)が追加されるため、毎回完全に「スキャン」されることはありません。これは、相互に関連するオブジェクト間でチェーンループが発生している場合に役立ちます(例:Order-> OrderLine-> User-> Order以上)。

この場合、オブジェクトの属性を複数回読み取る必要がある可能性があるため(たとえば、同じ販売者を共有するより多くの製品が含まれる製品リストなど)、この注釈はそうすることを妨げます。私は常にFirebugのログを見て、Jsonの応答を確認し、コードで何が行われているのかを確認することをお勧めします。

出典:


29
明確な答えをありがとう。これは、@JsonIgnore後方参照を置くよりも便利なソリューションです。
UtkuÖzdemir2013

3
これは間違いなくそれを行う正しい方法です。サーバーサイドでジャクソンを使用するためにこのようにする場合、クライアントサイドで使用するjsonマッパーは問題ではなく、子から親へのリンクのマニュアルを設定する必要はありません。うまくいきます。ありがとう、カート
flosk8 14

1
素敵で詳細な説明、そして@JsonIgnore
Piotr Nowicki 2015

2
ありがとう!@JsonIdentityInfoは、多くの重複するループで複数のエンティティを含む循環参照に機能しました。
n00b

1
私の人生でこれを機能させることはできません。私はかなり同様のセットアップを持っていると思うが、私は何もなく、無限のrecurisionエラーを取得することはできませんので、私は明らかに何か間違っを持っている:
SWV

103

新しいアノテーション@JsonIgnorePropertiesは、他のオプションに関する問題の多くを解決します。

@Entity

public class Material{
   ...    
   @JsonIgnoreProperties("costMaterials")
   private List<Supplier> costSuppliers = new ArrayList<>();
   ...
}

@Entity
public class Supplier{
   ...
   @JsonIgnoreProperties("costSuppliers")
   private List<Material> costMaterials = new ArrayList<>();
   ....
}

こちらをご覧ください。ドキュメントと同じように機能します:http :
//springquay.blogspot.com/2016/01/new-approach-to-solve-json-recursive.html


@tero-このアプローチでも、エンティティに関連付けられたデータを取得しません。
Pra_A

@PAA HEY PAAエンティティと関連付けられていると思います!なぜそのようなことを言うのですか ?
tero17

1
@ tero17 2つ以上のクラスがある場合、無限再帰をどのように管理しますか?例:クラスA->クラスB->クラスC->クラスA。JsonIgnorePropertiesで運試しをしました
Villat

@Villatこれは解決すべき別の問題です。そのための新しい需要を開くことをお勧めします。
tero17

コードサンプルの+1。ジャクソンの初心者なので、@ JsonIgnorePropertiesの使用は、JavaDocを読んでも完全には明確ではありませんでした
Wecherowski

47

また、Jackson 2.0以降を使用すると、を使用できます@JsonIdentityInfo。これは、私の休止状態のクラスでは@JsonBackReference@JsonManagedReference問題があり、問題を解決できなかったおよびに比べてはるかにうまく機能しました。次のようなものを追加するだけです:

@Entity
@Table(name = "ta_trainee", uniqueConstraints = {@UniqueConstraint(columnNames = {"id"})})
@JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="@traineeId")
public class Trainee extends BusinessObject {

@Entity
@Table(name = "ta_bodystat", uniqueConstraints = {@UniqueConstraint(columnNames = {"id"})})
@JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="@bodyStatId")
public class BodyStat extends BusinessObject {

そしてそれはうまくいくはずです。


「これはずっとうまくいった」と説明していただけますか?管理された参照に問題がありますか?
UtkuÖzdemir2013

@UtkuÖzdemir私は@JsonIdentityInfo上記の私の答えに詳細を追加しました。
カートブルバキ

1
"@JsonManagedReference"を使用した場合、getメソッドが値を返すのに、stackoverflowエラーが発生せず、これがこれまでに見つかった最良のソリューションです。しかし、投稿を使用してデータを保存しようとすると、エラー415(サポートされていないメディアエラー)が返されました
cuser

1
@JsonIdentityInfoエンティティに注釈を追加しましたが、再帰の問題は解決しません。@JsonBackReference@JsonManagedReference解決のみですが、マッピングされたプロパティはJSONから削除されます。
Oleg Abrazhaev 16

19

また、Jackson 1.6は双方向参照の処理をサポートしています ...探しているように見えます(このブログエントリでも機能について言及しています)

また、2011年7月の時点で、Hibernateオブジェクトの処理の一部の側面で役立つ可能性がある「jackson-module-hibernate」も存在しますが、必ずしもこの特定のオブジェクト(注釈が必要)とは限りません。


リンクが無効になっています。リンクを更新しても、回答を編集してもかまいません。
GetMeARemoteJob


9

これは私にとって完全にうまくいった。親クラスへの参照を言及する子クラスにアノテーション@JsonIgnoreを追加します。

@ManyToOne
@JoinColumn(name = "ID", nullable = false, updatable = false)
@JsonIgnore
private Member member;

2
@JsonIgnoreこの属性がクライアント側に取得されるのを無視していると思います。子と一緒にこの属性が必要な場合(子がある場合)はどうなりますか?
Khasan 24

6

シリアライズ時にHibernateの遅延初期化問題を処理するように特別に設計されたJacksonモジュール(Jackson 2用)が追加されました。

https://github.com/FasterXML/jackson-datatype-hibernate

依存関係を追加するだけです(Hibernate 3とHibernate 4には異なる依存関係があることに注意してください)。

<dependency>
  <groupId>com.fasterxml.jackson.datatype</groupId>
  <artifactId>jackson-datatype-hibernate4</artifactId>
  <version>2.4.0</version>
</dependency>

ジャクソンのObjectMapperを初期化するときにモジュールを登録します。

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new Hibernate4Module());

ドキュメンテーションは現在素晴らしいものではありません。使用可能なオプションについては、Hibernate4Moduleコードを参照してください。


それが面白そうに見えるので、何の問題がそれで解決します。OPと同じ問題があり、上記を含むすべてのトリックが機能しません。
user1567291 2016年

6

ジャクソンで作業するとき、Json Infinite Recursionの問題を解決してください

これは私がoneToManyとManyToOneマッピングで行ったことです

@ManyToOne
@JoinColumn(name="Key")
@JsonBackReference
private LgcyIsp Key;


@OneToMany(mappedBy="LgcyIsp ")
@JsonManagedReference
private List<Safety> safety;

私は春のブートアプリケーションで休止状態のマッピングを使用しました
Prabu M

こんにちは著者、素晴らしいチュートリアルと素晴らしい投稿をありがとう。しかし、私はそれを見つけ@JsonManagedReference@JsonBackReferenceあなたに関連したデータ与えていない@OneToMany@ManyToOneも使用している場合、シナリオ@JsonIgnoreProperties関連するエンティティデータをスキップしないし。これを解決するには?
Pra_A

5

私にとっての最善の解決策は、@JsonViewシナリオごとに特定のフィルターを使用して作成することです。@JsonManagedReferenceおよびを使用することもできますが@JsonBackReference、これは、所有者が常に所有する側を参照し、反対側を参照しない、1つの状況のみに対するハードコーディングされたソリューションです。属性を別の方法で再アノテーションする必要がある別のシリアル化シナリオがある場合は、できません。

問題

2つのクラスを使用することができます、CompanyそしてEmployeeあなたがそれらの間の循環依存関係を持っています:

public class Company {

    private Employee employee;

    public Company(Employee employee) {
        this.employee = employee;
    }

    public Employee getEmployee() {
        return employee;
    }
}

public class Employee {

    private Company company;

    public Company getCompany() {
        return company;
    }

    public void setCompany(Company company) {
        this.company = company;
    }
}

そして、ObjectMapperSpring Boot)を使用してシリアル化しようとするテストクラス:

@SpringBootTest
@RunWith(SpringRunner.class)
@Transactional
public class CompanyTest {

    @Autowired
    public ObjectMapper mapper;

    @Test
    public void shouldSaveCompany() throws JsonProcessingException {
        Employee employee = new Employee();
        Company company = new Company(employee);
        employee.setCompany(company);

        String jsonCompany = mapper.writeValueAsString(company);
        System.out.println(jsonCompany);
        assertTrue(true);
    }
}

このコードを実行すると、次のようになります。

org.codehaus.jackson.map.JsonMappingException: Infinite recursion (StackOverflowError)

`@ JsonView`を使用したソリューション

@JsonViewフィルターを使用し、オブジェクトのシリアル化中に含めるフィールドを選択できます。フィルターは、識別子として使用される単なるクラス参照です。それでは、最初にフィルターを作成しましょう:

public class Filter {

    public static interface EmployeeData {};

    public static interface CompanyData extends EmployeeData {};

} 

フィルターはダミークラスであり、@JsonViewアノテーションを使用してフィールドを指定するためだけに使用されるので、必要な数だけ作成できます。実際に見てみましょう。ただし、最初にCompanyクラスに注釈を付ける必要があります。

public class Company {

    @JsonView(Filter.CompanyData.class)
    private Employee employee;

    public Company(Employee employee) {
        this.employee = employee;
    }

    public Employee getEmployee() {
        return employee;
    }
}

シリアライザがビューを使用するようにテストを変更します。

@SpringBootTest
@RunWith(SpringRunner.class)
@Transactional
public class CompanyTest {

    @Autowired
    public ObjectMapper mapper;

    @Test
    public void shouldSaveCompany() throws JsonProcessingException {
        Employee employee = new Employee();
        Company company = new Company(employee);
        employee.setCompany(company);

        ObjectWriter writter = mapper.writerWithView(Filter.CompanyData.class);
        String jsonCompany = writter.writeValueAsString(company);

        System.out.println(jsonCompany);
        assertTrue(true);
    }
}

これで、このコードを実行すると、で注釈が付けられた属性をシリアル化したいだけであることを明示的に示したので、無限再帰問題が解決されます@JsonView(Filter.CompanyData.class)

で会社の後方参照に到達Employeeすると、注釈が付けられていないことを確認し、シリアル化を無視します。また、REST APIを介して送信するデータを選択するための強力で柔軟なソリューションもあります。

Springを使用すると、RESTコントローラーのメソッドに必要な@JsonViewフィルターで注釈を付けることができ、シリアル化は返されるオブジェクトに透過的に適用されます。

確認する必要がある場合に使用されるインポートは次のとおりです。

import static org.junit.Assert.assertTrue;

import javax.transaction.Transactional;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;

import com.fasterxml.jackson.annotation.JsonView;

1
:これは再帰を解決するために、多くの代替ソリューションを説明する素晴らしい記事ですbaeldung.com/...
ヒューゴBaés

5

@JsonIgnorePropertiesが答えです。

このようなものを使用する::

@OneToMany(mappedBy = "course",fetch=FetchType.EAGER)
@JsonIgnoreProperties("course")
private Set<Student> students;

Jhipsterが生成されたコードでこれを使用するのを見たので、これを自信を持って使用します
ifelse.codes

答えてくれてありがとう。しかし、私はそれを見つけ@JsonManagedReference@JsonBackReferenceあなたに関連したデータ与えていない@OneToMany@ManyToOneも使用している場合、シナリオ@JsonIgnoreProperties関連するエンティティデータをスキップしないし。これを解決するには?
Pra_A

4

私の場合、関係を次のように変更するだけで十分です:

@OneToMany(mappedBy = "county")
private List<Town> towns;

に:

@OneToMany
private List<Town> towns;

別の関係はそのままでした:

@ManyToOne
@JoinColumn(name = "county_id")
private County county;

2
カートのソリューションを使用する方が良いと思います。JoinColumnソリューションは、参照されていないデータのデッドボディで終了する可能性があるためです。
flosk8 2014

1
これは実際に私を助けた唯一のものです。上から他のソリューションは機能しませんでした。理由はまだ
わかり

4

どこでもcom.fasterxml.jacksonを使用してください。私はそれを見つけるために多くの時間を費やしました。

<properties>
  <fasterxml.jackson.version>2.9.2</fasterxml.jackson.version>
</properties>

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>${fasterxml.jackson.version}</version>
</dependency>

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>${fasterxml.jackson.version}</version>
</dependency>

次にとを使用@JsonManagedReference@JsonBackReferenceます。

最後に、モデルをJSONにシリアル化できます。

import com.fasterxml.jackson.databind.ObjectMapper;

ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(model);

4

使用できます @JsonIgnoreが、これは外部キーの関係によりアクセス可能なjsonデータを無視します。したがって、外部キーデータを要求する場合(ほとんどの場合は必要です)、@ JsonIgnoreは役に立ちません。このような状況では、以下の解決策に従ってください。

BodyStatクラスが再び参照するため、無限再帰が発生します Traineeオブジェクトます

BodyStat

@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinColumn(name="trainee_fk")
private Trainee trainee;

研修生

@OneToMany(mappedBy = "trainee", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@Column(nullable = true)
private Set<BodyStat> bodyStats;

したがって、上記の部分を研修生でコメント/省略する必要があります


1
私の場合、機能していません。github.com/JavaHelper/issue-jackson-bootをご覧ください。
Pra_A

3

私も同じ問題に遭遇しました。@JsonIdentityInfoObjectIdGenerators.PropertyGenerator.class発電機タイプを使用しました。

それが私の解決策です:

@Entity
@Table(name = "ta_trainee", uniqueConstraints = {@UniqueConstraint(columnNames = {"id"})})
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Trainee extends BusinessObject {
...

2
良い答え
LAGRIDA

1
私は同じことを答えます!!! ニース;)
フェリペデジデラーティ

3

@ManyToOneエンティティで@JsonBackReferenceを使用し、@ onetomanyエンティティクラスを含む@JsonManagedReferenceを使用する必要があります。

@OneToMany(
            mappedBy = "queue_group",fetch = FetchType.LAZY,
            cascade = CascadeType.ALL
        )
    @JsonManagedReference
    private Set<Queue> queues;



@ManyToOne(cascade=CascadeType.ALL)
        @JoinColumn(name = "qid")
       // @JsonIgnore
        @JsonBackReference
        private Queue_group queue_group;

子に@ jsonIgnoreアノテーションを付けた場合。子を取得しようとすると、子から親オブジェクトを取得できませんでした。親オブジェクトが来ない理由は、@ jsonignoreによって無視されます。子供から親へ、そして親から子供へ行く方法を教えてください。
Kumaresan Perumal

@JsonIgnoreを使用する必要はありません。上記のアノテーションを使用するだけでなく、ゲッターとセッターを使用して親子のオブジェクトを取得します。Jsonignoreも同じことをしていますが、無限再帰が発生します。あなたがあなたのコードを共有するなら、私はあなたがオブジェクトを取得していない理由を確認できます。私にとっては両方が来るからです。
Shubham

言うつもりだった。親を取るとき。親には子オブジェクトが必要です。子オブジェクトを取得するとき。子供は親と一緒に来るべきです。このシナリオでは機能しません。手伝っていただけませんか?
Kumaresan Perumal

1

注釈hiberbnateなしでDTOパターン作成クラスTraineeDTOを使用でき、Jacksonマッパーを使用してTraineeをTraineeDTOに変換し、エラーメッセージdisapeareにビンゴできます:)


1

プロパティを無視できない場合は、フィールドの可視性を変更してみてください。私たちのケースでは、古いコードがまだ関係のあるエンティティを送信していたため、私の場合、これが修正されました。

    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
    private Trainee trainee;

子に@ jsonIgnoreアノテーションを付けた場合。子を取得しようとすると、子から親オブジェクトを取得できませんでした。親オブジェクトが来ない理由は、@ jsonignoreによって無視されます。子供から親へ、そして親から子供へ行く方法を教えてください。
Kumaresan Perumal

0

私はこの問題を抱えていましたが、エンティティでアノテーションを使用したくなかったので、クラスのコンストラクタを作成することで解決しました。このコンストラクタは、このエンティティを参照するエンティティへの参照を持っていてはなりません。このシナリオを考えてみましょう。

public class A{
   private int id;
   private String code;
   private String name;
   private List<B> bs;
}

public class B{
   private int id;
   private String code;
   private String name;
   private A a;
}

ビューに送信しようとすると、クラスBまたはそれAとともに@ResponseBody無限ループが発生する可能性があります。クラスにコンストラクターを記述して、次のentityManagerようなクエリを作成できます。

"select new A(id, code, name) from A"

これはコンストラクタを持つクラスです。

public class A{
   private int id;
   private String code;
   private String name;
   private List<B> bs;

   public A(){
   }

   public A(int id, String code, String name){
      this.id = id;
      this.code = code;
      this.name = name;
   }

}

ただし、ご覧のとおり、コンストラクターでList bsへの参照を作成しなかったため、このソリューションにはいくつかの制限があります。これは、少なくともバージョン3.6.10.FinalではHibernateがそれを許可していないためです。ビューに両方のエンティティを表示するには、次のようにします。

public A getAById(int id); //THE A id

public List<B> getBsByAId(int idA); //the A id.

このソリューションのもう1つの問題は、プロパティを追加または削除する場合、コンストラクターとすべてのクエリを更新する必要があることです。


0

Spring Data Restを使用している場合、循環参照に関係するすべてのエンティティのリポジトリを作成することで問題を解決できます。


0

私は遅刻したので、すでに長いスレッドになっています。しかし、私もこれを理解するために数時間を費やし、私の事例を別の例として挙げたいと思います。

私はJsonIgnore、JsonIgnoreProperties、BackReferenceの両方のソリューションを試しましたが、不思議なことに、それらがピックアップされなかったようです。

私はLombokを使用し、コンストラクターを作成してtoString(stackoverflowerrorスタックでtoStringを見た)をオーバーライドするため、干渉する可能性があると考えました。

最後に、それはLombokのせいではありませんでした-データベーステーブルからのNetBeansの自動生成を使用して、あまり考えずに-生成されたクラスに追加された注釈の1つは@XmlRootElementでした。それを削除すると、すべてが機能し始めました。しかたがない。


0

重要なのは、@ JsonIgnoreを次のようにセッターメソッドに配置することです。私の場合。

Township.java

@Access(AccessType.PROPERTY)
@OneToMany(fetch = FetchType.LAZY)
@JoinColumn(name="townshipId", nullable=false ,insertable=false, updatable=false)
public List<Village> getVillages() {
    return villages;
}

@JsonIgnore
@Access(AccessType.PROPERTY)
public void setVillages(List<Village> villages) {
    this.villages = villages;
}

Village.java

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "townshipId", insertable=false, updatable=false)
Township township;

@Column(name = "townshipId", nullable=false)
Long townshipId;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.