SAXException2: A cycle is detected in the object graph. What is the case?
Asked Answered
S

2

7

I have a web-service with Java class files that have been generated with NetBeans based on the database schema I have.

I get strange exceptions sometimes and one of them is this one:

javax.xml.ws.WebServiceException: javax.xml.bind.MarshalException
 - with linked exception:
[com.sun.istack.internal.SAXException2: A cycle is detected in the object graph. This will cause infinitely deep XML: org.mylib.Person[ personId=1 ] ->org.mylib.TeamPerson[ teamPersonPK=org.mylib.teamPersonPK[ teamId=1, personId=1 ] ] -> org.mylib.Person[ personId=1 ]]

I have googled this exception and found some simillar cases but I still cannot understand the problem. I have just generated those classes (Person.java, Team.java, TeamPerson.java) with NetBeans so how can the problem occur?

This happens when I try to get all Persons:

Iterator iter = team.getTeamPersonCollection().iterator();
while(iter.hasNext()) {
            Person person = ((TeamPerson)iter.next()).getPerson();
...
}

EDIT
If I remove the Team reference from TeamPerson I get the following error:

Internal Exception: Exception [EclipseLink-7154] (Eclipse Persistence Services - 2.2.0.v20110202-r8913): org.eclipse.persistence.exceptions.ValidationException
Exception Description: The attribute [teamPersonCollection] in entity class [class org.mylib.Team] has a mappedBy value of [team] which does not exist in its owning entity class [org.mylib.TeamPerson]. If the owning entity class is a @MappedSuperclass, this is invalid, and your attribute should reference the correct subclass.
    at org.eclipse.persistence.exceptions.PersistenceUnitLoadingException.exceptionSearchingForPersistenceResources(PersistenceUnitLoadingException.java:126)

EDIT 2
Parts of the generated classes looks like this:

Team.java

public class Team implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @Basic(optional = false)
    @Column(name = "team_id")
    private Integer teamId;
    @Column(name = "type")
    private String type;
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "team")
    private Collection<TeamPerson> teamPersonCollection;

Person.java

public class Person implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @Basic(optional = false)
    @Column(name = "person_id")
    private Integer personId;
    @Column(name = "name")
    private String name;
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "person")
    private Collection<TeamPerson> teamPersonCollection;

TeamPerson.java

public class TeamPerson implements Serializable {
    private static final long serialVersionUID = 1L;
    @EmbeddedId
    protected TeamPersonPK teamPersonPK;
    @Basic(optional = false)
    @Column(name = "timestamp")
    @Temporal(TemporalType.TIMESTAMP)
    private Date timestamp;
    @JoinColumn(name = "team_id", referencedColumnName = "team_id", insertable = false, updatable = false)
    @ManyToOne(optional = false)
    private Team team;
    @JoinColumn(name = "person_id", referencedColumnName = "person_id", insertable = false, updatable = false)
    @ManyToOne(optional = false)
    private Person person;

TeamPersonPK.java

@Embeddable
public class TeamPersonPK implements Serializable {
    @Basic(optional = false)
    @Column(name = "team_id")
    private int teamId;
    @Basic(optional = false)
    @Column(name = "person_id")
    private int personId;
Sundaysundberg answered 14/5, 2012 at 7:22 Comment(1)
Hi @Rox, did you solve this problem in the end? I got the same!Kaifeng
N
11

The solution is simply to add the annotation : "@XmlTransient" (javax.xml.bind.annotation.XmlTransient) at the getter of the property that causes the cycle.

Nevers answered 8/2, 2013 at 21:14 Comment(2)
The object is required as part of the returned JSON @XmlTransient excludes the it completelyNazareth
the user wants that data to be part of the JSONTound
S
0

Well maybe thats is because your Person class contains the field of type TeamPerson and the TeamPerson contains the field of type Person. And the marshaller is confused un parsing such loop init?

UPD. Maybe you need to change this

@OneToMany(cascade = CascadeType.ALL, mappedBy = "team")
    private Collection<TeamPerson> teamPersonCollection;

to:

@OneToMany(cascade = CascadeType.ALL, mappedBy = "teamId")
    private Collection<TeamPerson> teamPersonCollection;

because field team does not exist in class TeamPerson?

Suitcase answered 14/5, 2012 at 8:22 Comment(2)
If a remove the reference to Team from TeamPerson I get another exception. See my edit above. How can I solve that?Sundaysundberg
I don´t know, the class was generated like that, mappedBy = "team". Don´t ask me why, but if I change to teamId I get a ValidationException: An incompatible mapping has been encountered between [class org.mylib.Person] and [class org.mylib.TeamPerson] This usually occurs when the cardinality of a mapping does not correspond with the cardinality of its backpointer. Any other suggestions?Sundaysundberg

© 2022 - 2024 — McMap. All rights reserved.