Jackson JSON ve Hibernate JPA sorunu ile Sonsuz Özyineleme


412

Çift yönlü bir ilişkisi olan bir JPA nesnesini JSON'a dönüştürmeye çalışırken,

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

Tüm bulduğum temelde iki yönlü ilişkilerden kaçınmayı öneren bu konu . Herkes bu bahar hata için bir geçici çözüm için bir fikri var mı?

------ DÜZENLEME 2010-07-24 16:26:22 -------

Kod parçacıkları:

İş Nesnesi 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 ...

İş Nesnesi 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;

Denetleyici:

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

Kursiyer DAO'nun JPA uygulaması:

@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>

Ekle @Transientiçin Trainee.bodyStats.
phil294

2017 itibariyle @JsonIgnorePropertiesen temiz çözüm. Daha fazla bilgi için Zammel AlaaEddine'nin cevabına göz atın .
Utku

Bu baharın hatası nasıl?
Nathan Hughes

Yanıtlar:


293

@JsonIgnoreDöngüyü kırmak için kullanabilirsiniz .


1
@Ben: Aslında bilmiyorum. Belki de desteği etkinleştirilmedi: wiki.fasterxml.com/JacksonJAXBAnnotations
axtavt

40
Jackson 1.6'dan daha iyi bir çözüm var: serileştirme sırasında alıcıları / ayarlayıcıları göz ardı etmeden sonsuz özyineleme sorununu çözmek için iki yeni ek açıklama kullanabilirsiniz. Ayrıntılar için aşağıdaki cevabıma bakın.
Kurt Bourbaki

1
@axtavt Mükemmel cevap için teşekkürler. Btw, başka bir çözümle geldim: sadece bu değer için alıcı oluşturmaktan kaçınabilirsiniz, bu yüzden Bahar JSON oluştururken ona erişemez (ama her duruma uygun olduğunu düşünmüyorum, bu yüzden cevabınız daha iyi)
Semyon Danilov

11
Yukarıdaki tüm çözümlerin ek açıklama ekleyerek alan nesnelerini değiştirmesi gerekir. Eğer onları değiştirmek için hiçbir yolu yok üçüncü taraf sınıfları serileştirmek. Bu sorunu nasıl önleyebilirim?
Jianwu Chen

2
bu çözüm bazı durumlarda işe yaramaz. Jpa ile ilişkisel veritabanında, eğer koyarsanız @JsonIgnorevarlığı güncellediğinizde "yabancı anahtar" null olacak ...
ince

629

JsonIgnoreProperties [2017 Güncellemesi]:

Artık kullanabilirsiniz JsonIgnoreProperties için (seri hale getirme sırasında) özelliklerinin bastırmak serileştirme veya (seri kaldırma sırasında) okumak JSON özelliklerinin işleme görmezden . Aradığınız şey bu değilse, lütfen aşağıda okumaya devam edin.

(Bunu işaret ettiği için As Zammel AlaaEddine'e teşekkürler).


JsonManagedReference ve JsonBackReference

Jackson 1.6'dan beri, serileştirme sırasında alıcıları / ayarlayıcıları göz ardı etmeden sonsuz özyineleme sorununu çözmek için iki ek açıklama kullanabilirsiniz: @JsonManagedReferenceve @JsonBackReference.

açıklama

Jackson'ın iyi çalışması için, yığın akışı hatasına neden olan sonsuz döngüden kaçınmak için ilişkinin iki tarafından biri serileştirilmemelidir.

Böylece, Jackson referansın ( Set<BodyStat> bodyStatsTrainee sınıfında) ileri kısmını alır ve json benzeri bir depolama biçimine dönüştürür; bu sözde marşaling sürecidir. Daha sonra, Jackson referansın arka kısmını arar (yani Trainee traineeBodyStat sınıfında) ve diziselleştirmeden olduğu gibi bırakır. İlişkinin bu kısmı , ileri başvurunun serileştirilmesi ( uyumsuzlaştırılması ) sırasında yeniden yapılandırılacaktır .

Kodunuzu bu şekilde değiştirebilirsiniz (yararsız kısımları atlarım):

İş Nesnesi 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;

İş Nesnesi 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;

Şimdi her şey düzgün çalışmalı.

Daha fazla bilgi istiyorsanız , blogum Keenformatics hakkında Json ve Jackson Stackoverflow sorunları hakkında bir makale yazdım .

DÜZENLE:

Kontrol edebileceğiniz bir diğer yararlı ek açıklama @JsonIdentityInfo : bunu kullanarak, Jackson nesnenizi her serileştirdiğinde, ona bir kimlik (veya seçtiğiniz başka bir özellik) ekleyecektir, böylece her seferinde tamamen "taramayacak". Bu, daha fazla ilişkili nesneler arasında bir zincir döngünüz olduğunda yararlı olabilir (örneğin: Order -> OrderLine -> Kullanıcı -> Order ve tekrar).

Bu durumda dikkatli olmalısınız, çünkü nesnenizin özelliklerini bir kereden fazla okumanız gerekebilir (örneğin aynı satıcıyı paylaşan daha fazla ürün içeren bir ürün listesinde) ve bu ek açıklama bunu yapmanızı engeller. Json yanıtını kontrol etmek ve kodunuzda neler olduğunu görmek için her zaman firebug günlüklerine göz atmanızı öneririm.

Kaynaklar:


29
Açık cevap için teşekkürler. Bu, @JsonIgnoregeri referans yapmaktan daha uygun bir çözümdür .
Utku Özdemir

3
Bunu yapmanın kesinlikle doğru yolu budur. Sunucu tarafında bu şekilde yaparsanız, Jackson'ı orada kullandığınız için, istemci tarafında hangi json eşleştiricisini kullandığınız önemli değildir ve çocuğu ebeveyn bağlantı kılavuzuna ayarlamanız gerekmez. Sadece çalışıyor. Thanks Kurt
flosk8

1
Güzel, ayrıntılı bir açıklama ve kesinlikle daha iyi ve daha açıklayıcı bir yaklaşım @JsonIgnore.
Piotr Nowicki

2
Teşekkürler! @JsonIdentityInfo, çakışan birçok döngüde birden çok varlığı içeren döngüsel referanslar için çalıştı.
n00b

1
Bunu hayatım boyunca çalıştıramadım. Ben oldukça benzer bir kurulum var sanırım, ama sonsuz tekrarlama hataları dışında bir şey alamadım çünkü açıkçası yanlış bir şey var:
swv

103

Yeni @JsonIgnoreProperties ek açıklaması diğer seçeneklerle ilgili sorunların çoğunu çözer.

@Entity

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

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

Buradan kontrol edin. Tıpkı belgelerde olduğu gibi çalışır:
http://springquay.blogspot.com/2016/01/new-approach-to-solve-json-recursive.html


@tero - Bu yaklaşımla varlıkla ilgili veriler de elde edilmez.
Pra_A

@ PAA HEY PAA Ben varlık ile ilişkili olduğunu düşünüyorum! neden böyle söyledin?
tero17

1
@ tero17 2'den fazla dersiniz olduğunda sonsuz özyinelemeyi nasıl yönetirsiniz? Örneğin: Sınıf A -> Sınıf B -> Sınıf C -> Sınıf A. Şanssız JsonIgnoreProperties ile denedim
Villat

@Villat bu çözmek için başka bir sorun, bunun için yeni bir talep açmanızı öneririm.
tero17

Kod örneği için +1, bir Jackson newbie olarak @JsonIgnoreProperties kullanımı JavaDoc
Wecherowski

47

Ayrıca, Jackson 2.0+ kullanarak @JsonIdentityInfo . Bu benim hazırda daha sınıflar için çok daha iyi çalıştı @JsonBackReferenceve @JsonManagedReferencebenim için sorunlar vardı ve sorunu çözmedi. Bunun gibi bir şey ekleyin:

@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 {

ve işe yaramalı.


"Bu çok daha iyi çalıştı" açıklayabilir misiniz? Yönetilen referansla ilgili bir sorun mu var?
Utku Özdemir

@ UtkuÖzdemir @JsonIdentityInfoYukarıdaki cevabımda detaylar ekledim .
Kurt Bourbaki

1
bu şimdiye kadar bulduğumuz en iyi çözümdür, çünkü "@JsonManagedReference" kullandığımızda get yöntemi herhangi bir stackoverflow hatası olmadan değerleri başarıyla döndürdü. Ancak, postayı kullanarak veri kaydetmeye çalıştığımızda, 415 hatası (desteklenmeyen medya hatası)
döndürdü

1
@JsonIdentityInfoVarlıklarıma ek açıklama ekledim ancak özyineleme sorununu çözmüyor. Sadece @JsonBackReferenceve @JsonManagedReferenceçözer, ancak bunlar eşlenmiş özellikleri JSON'dan kaldırır.
Oleg Abrazhaev



9

Bu benim için gayet iyi çalıştı. Üst sınıfa başvuruda belirttiğiniz alt sınıfa @JsonIgnore ek açıklamasını ekleyin.

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

2
Bence @JsonIgnorebu özellik istemci tarafına alınmasını yok sayar. Bu özelliğe çocuğuyla (çocuğu varsa) ihtiyacım olursa ne olur?
Khasan 24-7

6

Şimdi serileştirirken Hazırda Bekleme tembel başlatma sorunlarını ele almak için özel olarak tasarlanmış bir Jackson modülü (Jackson 2 için) var.

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

Sadece bağımlılığı ekleyin (Hazırda Bekletme 3 ve Hazırda Bekletme 4 için farklı bağımlılıklar olduğunu unutmayın):

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

ve Jackson'ın ObjectMapper'ını başlatırken modülü kaydedin:

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

Belgeler şu anda harika değil. Kullanılabilir seçenekler için Hibernate4Module koduna bakın .


O zaman problemi çözmek, çünkü ilginç görünüyor. Ben OP ile aynı sorunu var ve yukarıdaki dahil tüm hileler işe yaramadı.
user1567291

6

Benim için iyi çalışıyor Jackson ile çalışırken Json Infinite Recursion sorununu çözün

OneToMany ve ManyToOne Mapping'de yaptığım şey bu

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


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

Bahar önyükleme uygulamasında hazırda bekleme eşleme kullandım
Prabu M

Merhaba Yazar, Güzel öğreticiler ve harika gönderiler için teşekkürler. Ancak buldum @JsonManagedReference, @JsonBackReferencesize ilişkili veri @OneToManyve @ManyToOnesenaryo @JsonIgnorePropertiesvermez , ayrıca kullanırken ilişkili varlık verilerini atlar. Bunu nasıl çözebilirim?
Pra_A

5

Benim için en iyi çözüm, @JsonViewher senaryo için özel filtreler kullanmak ve oluşturmaktır. Ayrıca kullanabilirsiniz @JsonManagedReferenceve @JsonBackReferenceancak bu, sahibin her zaman sahip olan tarafa atıfta bulunduğu ve asla tersi olmayan tek bir duruma sabit kodlanmış bir çözümdür. Özelliğe farklı bir şekilde yeniden açıklama eklemeniz gereken başka bir serileştirme senaryosunuz varsa, bunu yapamazsınız.

Sorun

İki sınıf kullanalım Companyve Employeearalarında döngüsel bağımlılığın olduğu yerler:

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

Ve ObjectMapper( Spring Boot ) kullanarak serileştirmeye çalışan test sınıfı :

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

Bu kodu çalıştırırsanız şunları elde edersiniz:

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

`@ JsonView` Kullanarak Çözüm

@JsonViewfiltreleri kullanmanızı ve nesneleri serileştirirken hangi alanların ekleneceğini seçmenizi sağlar. Filtre, tanımlayıcı olarak kullanılan bir sınıf başvurusudur. Önce filtreleri oluşturalım:

public class Filter {

    public static interface EmployeeData {};

    public static interface CompanyData extends EmployeeData {};

} 

Unutmayın, filtreler, @JsonViewek açıklama içeren alanları belirtmek için kullanılan kukla sınıflardır, böylece istediğiniz ve ihtiyacınız olanı oluşturabilirsiniz. Eylemde görelim, ama önce Companysınıfımıza açıklama eklememiz gerekiyor :

public class Company {

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

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

    public Employee getEmployee() {
        return employee;
    }
}

ve serileştiricinin Görünümü kullanması için Testi değiştirin:

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

Şimdi bu kodu çalıştırırsanız, Sonsuz Özyineleme sorunu çözülür, çünkü yalnızca ek açıklama eklenmiş nitelikleri serileştirmek istediğinizi açık bir şekilde söylediniz. @JsonView(Filter.CompanyData.class) .

İçindeki şirket için geri referansa ulaştığında, Employeeaçıklamalı olmadığını kontrol eder ve serileştirmeyi yok sayar. Ayrıca REST API'leriniz aracılığıyla hangi verileri göndermek istediğinizi seçmek için güçlü ve esnek bir çözümünüz de vardır.

Spring ile REST Kontrolörleri yöntemlerinizi istediğiniz @JsonViewfiltreyle açıklayabilirsiniz ve serileştirme dönen nesneye şeffaf olarak uygulanır.

Kontrol etmeniz gerektiğinde kullanılan ithalatlar şunlardır:

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
Bu, özyinelemeleri çözmek için birçok alternatif çözümü açıklayan güzel bir makaledir: baeldung.com/…
Hugo Baés

5

Cevap @JsonIgnoreProperties .

Bunun gibi bir şey kullanın ::

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

Jhipster'ın oluşturduğu kodda bunu kullandığını gördüğüm gibi güvenle kullanın
ifelse.codes

Cevap için teşekkürler. Ancak buldum @JsonManagedReference, @JsonBackReferencesize ilişkili veri @OneToManyve @ManyToOnesenaryo @JsonIgnorePropertiesvermez , ayrıca kullanırken ilişkili varlık verilerini atlar. Bunu nasıl çözebilirim?
Pra_A

4

Benim durumumda ilişki değiştirmek için yeterliydi:

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

için:

@OneToMany
private List<Town> towns;

başka bir ilişki olduğu gibi kaldı:

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

2
Bence Kurt'un çözümünü kullanmak daha iyi. Çünkü JoinColumn çözümü referanssız veri ölü gövdelerinde sonlanabilir.
flosk8

1
Aslında bana yardımcı olan tek şey bu. Üstten başka hiçbir çözüm işe yaramadı. Hala emin değilim neden ...
Deniss M.

4

Her yerde com.fasterxml.jackson kullandığınızdan emin olun . Bunu bulmak için çok zaman harcadım.

<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>

Sonra @JsonManagedReferenceve kullanın @JsonBackReference.

Son olarak, modelinizi JSON'a serileştirebilirsiniz:

import com.fasterxml.jackson.databind.ObjectMapper;

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

4

@JsonIgnore kullanabilirsiniz , ancak bu, Yabancı Anahtar ilişkisi nedeniyle erişilebilen json verilerini yok sayar . Bu nedenle, yabancı anahtar verilerini (çoğu zaman ihtiyaç duyduğumuz) reqiure ederseniz, @JsonIgnore size yardımcı olmaz. Bu durumda lütfen aşağıdaki çözümü takip edin.

tekrar Stajyer nesnesine atıfta bulunan BodyStat sınıfı nedeniyle Sonsuz özyineleme alıyorsunuz

Bodystat

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

Stajyer

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

Bu nedenle, yorumuna sahip / kısmen yukarıda ihmal Stajyer


1
Benim durumumda, çalışmıyor. Eğer bir göz atın misiniz: github.com/JavaHelper/issue-jackson-boot ?
Pra_A

3

Ben de aynı problemle karşılaştım. Kullandığım @JsonIdentityInfo'nin ObjectIdGenerators.PropertyGenerator.classjeneratör türü.

Bu benim çözümüm:

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

2
İyi cevap
LAGRIDA

1
Ben aynı şeyi cevap !!! Nice;)
Felipe Desiderati

3

@ManyToOne varlık ile @JsonBackReference ve @onetomany içeren varlık sınıflarıyla @JsonManagedReference kullanmalısınız.

@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;

Çocuğa @ jsonIgnore ek açıklaması koyarsam. Çocuktan ebeveyn nesnesi alamadım. Çocuğu almaya çalıştığımda. Ana nesne neden gelmiyorsa, @ jsonignore tarafından yoksayılır. bana çocuktan ebeveyne ve ebeveynden çocuğa geçmenin yolunu söyle.
Kumaresan Perumal

@JsonIgnore kullanmanıza gerek yok sadece yukarıdaki ek açıklamaları kullanın ve Ebeveyn ve çocuğun nesnelerini almak için Getters ve setters kullanarak. ve Jsonignore da aynı şeyi yapıyor ancak sonsuz özyineleme yaratacak. Kodunuzu paylaşırsanız, neden nesne almadığınızı kontrol edebilirim. Çünkü benim için ikisi de geliyor.
Shubham

Demek istedim ki. bir ebeveyn alırken. Ebeveyn çocuk nesnesiyle birlikte gelmelidir. alt nesne alırken. Çocuk bir ebeveynle gelmelidir. Bu senaryoda çalışmıyor. Lütfen bana yardım eder misiniz?
Kumaresan Perumal

1

herhangi bir açıklama hiberbnate olmadan DTO desen oluşturmak sınıf TraineeDTO kullanabilirsiniz ve Trainee TraineeDTO dönüştürmek ve hata mesajı hayal kırıklığı bingo jackson mapper kullanabilirsiniz :)


1

Özelliği yok sayamıyorsanız, alanın görünürlüğünü değiştirmeyi deneyin. Bizim durumumuzda, eski kod hala ilişki ile varlık gönderme vardı, bu yüzden benim durumumda, bu düzeltme oldu:

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

Çocuğa @ jsonIgnore ek açıklaması koyarsam. Çocuktan ebeveyn nesnesi alamadım. Çocuğu almaya çalıştığımda. Ana nesne neden gelmiyorsa, @ jsonignore tarafından yoksayılır. bana çocuktan ebeveyne ve ebeveynden çocuğa geçmenin yolunu söyle.
Kumaresan Perumal

0

Bu sorunu yaşadım, ancak varlıklarımda ek açıklama kullanmak istemedim, bu yüzden sınıfım için bir kurucu oluşturarak çözdüm, bu kurucunun bu varlığa referans veren varlıklara bir referansı olmamalıdır. Diyelim ki bu senaryo.

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

Eğer görünüme sınıfını göndermeye çalışırsanız Bya Aile @ResponseBodybuna sonsuz bir döngüye neden olabilir. Sınıfınıza bir kurucu yazabilir ve bunun entityManagergibi bir sorgu oluşturabilirsiniz .

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

Bu, kurucu ile sınıftır.

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

}

Ancak bu çözüm hakkında bazı daralmalar ben bir başvuru yapmadığını yapıcı içinde, gördüğünüz gibi, orada List bs hazırda buna izin vermez çünkü bu en azından içinde olduğu versiyon 3.6.10.Final ihtiyacım nedenle zaman her iki objeyi bir görünümde göstermek için aşağıdakileri yapıyorum.

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

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

Bu çözümle ilgili diğer sorun, bir özellik ekler veya kaldırırsanız kurucunuzu ve tüm sorgularınızı güncellemenizdir.


0

Spring Data Rest kullanıyorsanız, döngüsel referanslarda yer alan her bir Varlık için Depolar oluşturularak sorun çözülebilir.


0

Ben geç geliyorum ve zaten çok uzun bir iplik. Ama bunu anlamaya çalışmak için birkaç saat geçirdim ve davamı başka bir örnek olarak vermek istiyorum.

Hem JsonIgnore, JsonIgnoreProperties hem de BackReference çözümlerini denedim, ama garip bir şekilde alınmamış gibi oldu.

Lombok'u kullandım ve belki de müdahale ettiğini düşündüm, çünkü yapıcılar oluşturuyor ve String'i geçersiz kılıyor (stackoverflowerror yığınında gördüm).

Sonunda Lombok'un hatası değildi - çok düşünmeden, veritabanı tablolarından otomatik NetBeans nesli JPA varlıklarını kullandım - ve oluşturulan sınıflara eklenen ek açıklamalardan biri @XmlRootElement idi. Kaldırdığımda her şey çalışmaya başladı. Oh iyi.


0

Amaç @JsonIgnore ayarlayıcı yöntemine aşağıdaki gibi yerleştirmektir. benim durumumda.

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;
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.