जैक्सन JSON और हाइबरनेट JPA मुद्दे के साथ अनंत पुनरावृत्ति


412

जब JSON में एक द्वि-दिशात्मक जुड़ाव वाली JPA ऑब्जेक्ट को बदलने की कोशिश की जाती है, तो मैं प्राप्त करता रहता हूं

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

प्रशिक्षु डीएओ का जेपीए-कार्यान्वयन:

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

जोड़े @Transientको Trainee.bodyStats
२१:२29 पर फिल २

2017 तक, @JsonIgnorePropertiesसबसे साफ समाधान है। की जाँच करें Zammel AlaaEddine का जवाब अधिक जानकारी के लिए।
Utku

इस वसंत की गलती कैसे है ??
नाथन ह्यूजेस

जवाबों:


293

आप @JsonIgnoreचक्र को तोड़ने के लिए उपयोग कर सकते हैं ।


1
@ बेन: वास्तव में मुझे नहीं पता। शायद इसका समर्थन सक्षम नहीं था: wiki.fasterxml.com/JacksonJAXBAnnotations
axtavt

40
चूंकि जैक्सन 1.6 में एक बेहतर समाधान है: आप क्रमांकन के दौरान गेटर्स / सेनेटर्स की अनदेखी किए बिना अनंत पुनरावृत्ति समस्या को हल करने के लिए दो नए एनोटेशन का उपयोग कर सकते हैं। विवरण के लिए नीचे मेरा उत्तर देखें।
कर्ट बॉरबकी

1
@axtavt सही उत्तर के लिए धन्यवाद। Btw, मैं एक और समाधान के साथ आया था: आप बस इस मूल्य के लिए गटर बनाने से बच सकते हैं, इसलिए वसंत JSON बनाते समय इसे एक्सेस करने में सक्षम नहीं होगा (लेकिन मुझे नहीं लगता कि यह हर मामले के लिए उपयुक्त है, इसलिए आपका उत्तर बेहतर है)
शिमोन दानिलोव

11
उपरोक्त सभी समाधानों को एनोटेशन जोड़कर डोमेन ऑब्जेक्ट को बदलने की आवश्यकता है। अगर मैं थर्ड पार्टी क्लासेस को सीरियलाइज़ करूँ तो मेरे पास उन्हें संशोधित करने का कोई तरीका नहीं है। मैं इस मुद्दे से कैसे बच सकता हूं?
जियानवू चेन

2
यह समाधान कुछ स्थितियों में काम नहीं करता है। Jpa के साथ संबंधपरक डेटाबेस में, यदि आप @JsonIgnore"विदेशी कुंजी" में शून्य करेंगे, जब आप इकाई को अपडेट करेंगे ...
स्लिम

628

JsonIgnoreProperties [2017 अपडेट]:

अब आप संपत्तियों के क्रमांकन (क्रमांकन के दौरान) को दबाने के लिए JSONIgnoreProperties का उपयोग कर सकते हैं , या पढ़े गए JSON संपत्तियों के प्रसंस्करण को अनदेखा कर सकते हैं (deserialization के दौरान) । यदि यह वह नहीं है जो आप ढूंढ रहे हैं, तो कृपया नीचे पढ़ते रहें।

(इसे इंगित करने के लिए जैमेल अलाएडाइन के रूप में धन्यवाद)।


JsonManagedReference और JsonBackReference

जैक्सन 1.6 के बाद से आप क्रमांकन के दौरान गेटर्स / सेनेटर्स की अनदेखी किए बिना अनंत पुनरावृत्ति समस्या को हल करने के लिए दो एनोटेशन का उपयोग कर सकते हैं: @JsonManagedReferenceऔर @JsonBackReference

व्याख्या

जैक्सन को अच्छी तरह से काम करने के लिए, रिश्ते के दो पक्षों में से एक को क्रमबद्ध नहीं किया जाना चाहिए, ताकि आपके लूपफ्लोप्रवाह त्रुटि का कारण बनने वाले शिशु लूप से बचें।

तो, जैक्सन संदर्भ ( Set<BodyStat> bodyStatsट्रेनी वर्ग में आपका ) का आगे का हिस्सा लेता है , और इसे एक जसन-जैसे भंडारण प्रारूप में परिवर्तित करता है; यह तथाकथित मार्शलिंग प्रक्रिया है। फिर, जैक्सन संदर्भ के पीछे के हिस्से की तलाश करता है (यानी Trainee traineeबॉडीस्टैट क्लास में) और इसे छोड़ देता है, जैसा कि इसे क्रमबद्ध नहीं किया गया है। संबंधों का यह हिस्सा आगे के संदर्भ के डिसेरिएलाइज़ेशन ( अनमरशॉलिंग ) के दौरान फिर से बनाया जाएगा ।

आप अपना कोड इस तरह बदल सकते हैं (मैं बेकार भागों को छोड़ दूंगा):

व्यावसायिक वस्तु 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;

अब यह सब ठीक से काम करना चाहिए।

यदि आप अधिक जानकारी चाहते हैं, तो मैंने अपने ब्लॉग पर कीनफॉर्मेटिक्स पर Json और जैक्सन स्टैकओवरफ़्लो मुद्दों के बारे में एक लेख लिखा ।

संपादित करें:

एक अन्य उपयोगी एनोटेशन जिसे आप देख सकते हैं वह है @JsonIdentityInfo : इसका उपयोग करते हुए, हर बार जैक्सन आपकी वस्तु को क्रमबद्ध करता है, यह इसमें एक आईडी (या आपके चयन की एक और विशेषता) जोड़ देगा, ताकि यह पूरी तरह से "स्कैन" न करे। यह तब उपयोगी हो सकता है जब आपको अधिक परस्पर संबंधित वस्तुओं (उदाहरण के लिए: ऑर्डर -> ऑर्डरलाइन -> उपयोगकर्ता -> ऑर्डर और फिर से) के बीच एक चेन लूप मिला हो।

इस मामले में आप सावधान हो गए हैं, क्योंकि आपको अपनी वस्तु की विशेषताओं को एक से अधिक बार पढ़ने की आवश्यकता हो सकती है (उदाहरण के लिए एक ही विक्रेता को साझा करने वाले अधिक उत्पादों वाले उत्पादों की सूची में), और यह एनोटेशन आपको ऐसा करने से रोकता है। मैं सुझाव देता हूं कि जस्सन की प्रतिक्रिया की जांच करने के लिए हमेशा फायरबग लॉग पर एक नज़र डालें और देखें कि आपके कोड में क्या चल रहा है।

सूत्रों का कहना है:


29
स्पष्ट उत्तर के लिए धन्यवाद। यह @JsonIgnoreबैक रेफरेंस डालने से ज्यादा सुविधाजनक उपाय है ।
उत्क्कू

3
यह निश्चित रूप से इसे करने का सही तरीका है। यदि आप इसे सर्वर साइड पर इस तरह से करते हैं क्योंकि आप वहां जैक्सन का उपयोग करते हैं, तो इससे कोई फर्क नहीं पड़ता कि आप क्लाइंट की तरफ से किस जैसन मैपर का उपयोग करते हैं और आपको बच्चे को पैरेंट लिंक मैनुअल में सेट नहीं करना है। यह सिर्फ काम करता है। धन्यवाद कर्ट
flosk8

1
अच्छा, विस्तृत विवरण और निश्चित रूप से बेहतर और अधिक विवरणात्मक दृष्टिकोण @JsonIgnore
पायोत्र नाउकी

2
धन्यवाद! @JsonIdentityInfo ने चक्रीय संदर्भों के लिए काम किया जिसमें कई अतिव्यापी छोरों में कई संस्थाएं शामिल थीं।
nbb

1
मुझे यह मेरे जीवन के लिए काम करने के लिए नहीं मिल सकता है। मुझे लगता है कि मेरे पास एक समान सेटअप है, लेकिन मुझे स्पष्ट रूप से कुछ गलत मिला है क्योंकि मुझे कुछ भी नहीं मिल सकता है लेकिन अनंत पुनरावृत्ति त्रुटियां:
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 - इस दृष्टिकोण के साथ ही हमें इकाई से जुड़ा डेटा नहीं मिलता है।
प्रात_

@PA है पीएए मुझे लगता है कि इकाई से संबंधित है! तुमने यह क्यों कहा ?
tero17

1
@ tero17 जब आप 2 से अधिक कक्षाएं लेते हैं तो आप अनंत पुनरावृत्ति का प्रबंधन कैसे करते हैं? उदाहरण के लिए: क्लास A -> क्लास B -> क्लास C -> क्लास A. मैंने किस्मत के बिना JsonIgnoreProperties के साथ प्रयास किया
विराट

@Villat यह हल करने के लिए एक और समस्या है, मैं उसके लिए एक नई मांग खोलने का सुझाव देता हूं।
tero17

कोड नमूने के लिए +1, जैक्सन के नौसिखिया के रूप में @JsonIgnoreProperties का उपयोग JavaDoc
Wecherowski

47

इसके अलावा, जैक्सन 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 {

और यह काम करना चाहिए।


क्या आप कृपया समझा सकते हैं "यह बहुत बेहतर काम किया"? क्या प्रबंधित संदर्भ में कोई समस्या है?
उत्कु irzdemir

@ Utku inzdemir मैंने @JsonIdentityInfoअपने उत्तर के बारे में विवरण जोड़ा ।
कर्ट बॉरबकी

1
यह अब तक मिला सबसे अच्छा समाधान है, क्योंकि जब हमने "@JsonManagedReference" का उपयोग किया था, तो प्राप्त विधि ने बिना किसी स्टैकओवरफ़्लो त्रुटि के मूल्यों को सफलतापूर्वक लौटा दिया। लेकिन, जब हमने पोस्ट का उपयोग करके डेटा को बचाने का प्रयास किया, तो उसने 415 की त्रुटि (असमर्थित मीडिया त्रुटि)
लौटा दी

1
मैंने @JsonIdentityInfoअपनी संस्थाओं में एनोटेशन जोड़ा है, लेकिन यह रिकर्सन समस्या का समाधान नहीं करता है। केवल @JsonBackReferenceऔर @JsonManagedReferenceसोल्व होते हैं, लेकिन उन्हें JSON से मैप किए गए गुण हटा दिए जाते हैं।
ओलेग अब्राहेव

19

इसके अलावा, जैक्सन 1.6 को द्वि-दिशात्मक संदर्भों को संभालने के लिए समर्थन है ... जो ऐसा लगता है कि आप क्या देख रहे हैं ( इस ब्लॉग प्रविष्टि में इस विशेषता का भी उल्लेख है)

और जुलाई 2011 तक, " जैकसन-मॉड्यूल-हाइबरनेट " भी है, जो हाइबरनेट वस्तुओं से निपटने के कुछ पहलुओं में मदद कर सकता है, हालांकि जरूरी नहीं कि यह विशेष रूप से (जिसमें एनोटेशन की आवश्यकता होती है)।


लिंक मर चुके हैं, क्या आपको उन्हें अपडेट करने या अपना जवाब संपादित करने में कोई आपत्ति नहीं है।
GetMeARemoteJob


9

यह मेरे लिए पूरी तरह से ठीक है। उस चाइल्ड क्लास पर एनोटेशन @JsonIgnore जोड़ें जहां आप मूल वर्ग के संदर्भ का उल्लेख करते हैं।

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

2
मुझे लगता है कि @JsonIgnoreग्राहक पक्ष को पुनः प्राप्त करने से इस विशेषता को अनदेखा करता है। क्या होगा यदि मुझे अपने बच्चे के साथ इस विशेषता की आवश्यकता है (यदि उसके पास बच्चा है)?
खसान 24-7

6

अब एक जैक्सन मॉड्यूल है (जैक्सन 2 के लिए) विशेष रूप से सीरियस करते समय हाइबरनेट आलसी इनिशियलाइज़ेशन समस्याओं को संभालने के लिए डिज़ाइन किया गया है।

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

बस निर्भरता जोड़ें (ध्यान दें कि हाइबरनेट 3 और हाइबरनेट 4 के लिए अलग-अलग निर्भरताएं हैं):

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

और जैक्सन के ऑब्जेक्टमैपर को इंटिग्रेट करते समय मॉड्यूल को पंजीकृत करें:

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

वर्तमान में प्रलेखन महान नहीं है। उपलब्ध विकल्पों के लिए Hibernate4Module कोड देखें ।


तब क्या समस्या हल होती है, क्योंकि यह दिलचस्प लगती है। मैं ओपी के रूप में एक ही मुद्दा है और ऊपर सहित सभी चालें काम नहीं किया है।
user1567291

6

मेरे लिए काम करना ठीक है काम जैक्सन के साथ काम करते समय जसन अनंत पुनर्संरचना समस्या का समाधान करें

यह मैंने OneToMany और ManyToOne मैपिंग में किया है

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


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

मैंने स्प्रिंग बूट एप्लिकेशन में हाइबरनेट मैपिंग का इस्तेमाल किया है
प्रबु एम

हाय लेखक, अच्छा ट्यूटोरियल और महान पदों के लिए धन्यवाद। हालाँकि मैंने पाया है कि @JsonManagedReference, @JsonBackReferenceआपको संबंधित इकाई डेटा को छोड़ते समय, डेटा @OneToManyऔर @ManyToOneपरिदृश्य से संबंधित डेटा नहीं देता है @JsonIgnoreProperties। इसे कैसे हल करें?
प्रात_

5

मेरे लिए सबसे अच्छा समाधान @JsonViewप्रत्येक परिदृश्य के लिए विशिष्ट फ़िल्टर का उपयोग करना और बनाना है। आप भी उपयोग कर सकते हैं @JsonManagedReferenceऔर @JsonBackReference, हालांकि, यह केवल एक स्थिति के लिए एक हार्डकोड समाधान है, जहां मालिक हमेशा मालिक पक्ष का संदर्भ देता है, और कभी विपरीत नहीं। यदि आपके पास एक और क्रमांकन परिदृश्य है, जहां आपको विशेषता को अलग से पुन: एनोटेट करने की आवश्यकता है, तो आप नहीं कर पाएंगे।

मुसीबत

चलो दो वर्गों का उपयोग करते हैं, 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;
    }
}

और परीक्षण वर्ग जो ObjectMapper( स्प्रिंग बूट ) का उपयोग करके क्रमबद्ध करने की कोशिश करता है :

@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 द्वारा कौन सा डेटा भेजना है, यह चुनने के लिए आपके पास एक शक्तिशाली और लचीला समाधान है।

वसंत के साथ आप अपने बाकी कंट्रोलर के तरीकों को वांछित के साथ एनोटेट कर सकते हैं @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/…
ह्यूगो बैस

5

@JsonIgnoreProperties जवाब है।

कुछ इस तरह का प्रयोग करें ::

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

विश्वासपूर्वक इसका उपयोग करें क्योंकि मैंने देखा है कि जिप्स्टर अपने उत्पन्न कोड में इसका उपयोग करता है
ifelse.codes

जवाब के लिए धन्यवाद। हालाँकि मैंने पाया है कि @JsonManagedReference, @JsonBackReferenceआपको संबंधित इकाई डेटा को छोड़ते समय, डेटा @OneToManyऔर @ManyToOneपरिदृश्य से संबंधित डेटा नहीं देता है @JsonIgnoreProperties। इसे कैसे हल करें?
प्रात_

4

मेरे मामले में यह संबंध बदलने के लिए पर्याप्त था:

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

सेवा:

@OneToMany
private List<Town> towns;

एक और रिश्ता जैसा था वैसा ही रहा:

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

2
मुझे लगता है कि कर्ट के समाधान का उपयोग करना बेहतर है। क्योंकि JoinColumn सॉल्यूशन अपरिचित डेटा डेड बॉडी में खत्म हो सकता है।
flosk8

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

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

3

मैं भी उसी समस्या से मिला। मैं प्रयोग किया जाता @JsonIdentityInfoहै ObjectIdGenerators.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

आपको @JanyBackReference का उपयोग @ManyToOne इकाई के साथ और @JsonManagedReference को @onetomany के साथ इकाई वर्गों के साथ करना चाहिए।

@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 द्वारा नजरअंदाज किया जाता है। मुझे बच्चे से माता-पिता और बच्चे से माता-पिता तक पहुंचने का रास्ता बताएं।
कुमारसन पेरुमल

@JsonIgnore का उपयोग करने की कोई आवश्यकता नहीं है, बस उपरोक्त एनोटेशन का उपयोग करें और माता-पिता और बच्चे के objets प्राप्त करने के लिए गेटर्स और सेटर का उपयोग करके। और Jsonignore भी ऐसा ही कर रहा है लेकिन यह अनंत पुनरावृत्ति पैदा करेगा। यदि आप अपना कोड साझा करते हैं तो मैं जांच सकता हूं कि आपको ऑब्जेक्ट क्यों नहीं मिल रहे हैं। क्योंकि मेरे लिए दोनों आ रहे हैं।
शुभम

मेरे कहने का मतलब। जब माता-पिता ले रहे हों। माता-पिता को बाल वस्तु के साथ आना चाहिए। बच्चे की वस्तु लेते समय। बच्चे को माता-पिता के साथ आना चाहिए। यह इस परिदृश्य में काम नहीं कर रहा है। क्या कृपा करके आप मेरी सहायता करेंगे?
कुमारसन पेरुमल

1

आप डीटीओ पैटर्न का उपयोग करके क्लास ट्रेनीडेओटी को बिना किसी एनोटेशन हाइबरनेट के बना सकते हैं और आप ट्रेनी को ट्रेनीडीटीओ में परिवर्तित करने के लिए जैकसन मैपर का उपयोग कर सकते हैं और त्रुटि संदेश नापसंद करने के लिए बिंगो :)


1

यदि आप संपत्ति की उपेक्षा नहीं कर सकते, तो क्षेत्र की दृश्यता को संशोधित करने का प्रयास करें। हमारे मामले में, हमारे पास पुराने कोड अभी भी संबंधों के साथ संस्थाओं को जमा कर रहे थे, इसलिए मेरे मामले में, यह तय था:

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

अगर मैंने बच्चे में @ jsonIgnore एनोटेशन डाला। मुझे बच्चे से अभिभावक वस्तु नहीं मिल सकी। जब मैं बच्चे को लेने की कोशिश करता हूं। पैरेंट ऑब्जेक्ट क्यों नहीं आ रहा है, इसे @ jsonignore द्वारा नजरअंदाज किया जाता है। मुझे बच्चे से माता-पिता और बच्चे से माता-पिता तक पहुंचने का रास्ता बताएं।
कुमारसन पेरुमल

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

}

हालाँकि, इस समाधान के बारे में कुछ अड़चनें हैं, जैसा कि आप देख सकते हैं, कंस्ट्रक्टर में मैंने लिस्ट bs का संदर्भ नहीं दिया है क्योंकि यह हाइबरनेट इसे अनुमति नहीं देता है, कम से कम संस्करण 3.6.10.Final में , इसलिए जब मुझे आवश्यकता हो दोनों संस्थाओं को एक दृश्य में दिखाने के लिए मैं निम्नलिखित कार्य करता हूं।

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

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

इस समाधान के साथ दूसरी समस्या यह है कि यदि आप कोई संपत्ति जोड़ते या हटाते हैं तो आपको अपने कंस्ट्रक्टर और अपने सभी प्रश्नों को अपडेट करना होगा।


0

यदि आप स्प्रिंग डेटा रेस्ट का उपयोग कर रहे हैं, तो चक्रीय संदर्भों में शामिल प्रत्येक इकाई के लिए रिपॉजिटरी बनाकर समस्या का समाधान किया जा सकता है।


0

मैं देर से आने वाला हूं और यह पहले से ही इतना लंबा धागा है। लेकिन मैंने कुछ घंटे बिताए, यह भी पता लगाने की कोशिश कर रहा हूं, और अपने मामले को एक और उदाहरण के रूप में देना चाहूंगा।

मैंने JsonIgnore, JsonIgnoreProperties और BackReference सॉल्यूशंस दोनों की कोशिश की, लेकिन अजीब तरह से यह ऐसा था जैसे वे उठाए नहीं गए थे।

मैंने लोम्बोक का इस्तेमाल किया और सोचा कि शायद यह हस्तक्षेप करता है, क्योंकि यह कंस्ट्रक्टर बनाता है और स्ट्राइडिंग को ओवरराइड करता है (स्टैकओवरफ्लॉवर स्टैक में स्टर्लिंग को देखा)।

अंत में यह लोम्बोक की गलती नहीं थी - मैंने डेटाबेस तालिकाओं से जेपीए संस्थाओं की स्वचालित नेटबीन्स पीढ़ी का इस्तेमाल किया, बिना ज्यादा सोचे-समझे, और उत्पन्न वर्ग में जोड़े गए एनोटेशन में से एक @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;
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.