用JAXB转换XML和Java对象时的循环引用问题的解决方法

时间:2021-12-21 20:00:57

    利用JAXB可以实现XML与Java对象之间的转换。在转换时,可能会遇到交叉引用的情况,如果不做处理,提示为:

    A cycle is detected in the object graph. This will cause infinitely deep XML:...

    解决办法有两种:利用com.sun.xml.bind.CycleRecoverable和org.eclipse.persistence.oxm.annotations.XmlInverseReference。

    以一个Student和SClass类为例。它们之间如果建立双向关系时会引起交叉引用。未处理前代码如下:

public class Student{

private String num;
private String name;

private SClass sclass;


public Student(){
super();
}

public Student(String num, String name){
super();
this.num = num;
this.name = name;
}

public SClass getSclass() {
return sclass;
}

public void setSclass(SClass sclass) {
this.sclass = sclass;
}

public String getNum(){
return num;
}

public void setNum(String num){
this.num = num;
}

public String getName(){
return name;
}

public void setName(String name){
this.name = name;
}

}
@XmlRootElementpublic class SClass{private String cnum;private List<Student> students;public SClass(){super();}public SClass(String cnum, List<Student> students){super();this.cnum = cnum;this.students = students;}public void addStudent(Student student){if(!this.students.contains(student)){student.setSclass(this);this.students.add(student);}}public String getCnum(){return cnum;}public void setCnum(String cnum){this.cnum = cnum;}public List<Student> getStudents(){return students;}public void setStudents(List<Student> students){this.students = students;}}

    1. 利用com.sun.xml.bind.CycleRecoverable。

    需要让两个类都实现接口CycleRecoverable的方法onCycleDetected。以Student为例:

public class Student implements CycleRecoverable{

private String num;
private String name;
private SClass sclass;

......
public Object onCycleDetected(Context arg0) {
// TODO Auto-generated method stub
Student student=new Student();
student.setNum(this.getNum());

return student;
}
}
    当遇到循环交叉引用时,JAXB引擎会调用该方法,用return的对象来替换this。这样就可以将引起循环引用问题的关系断开,返回给JAXB。

    这种方法中,如果是使用maven,需加入依赖:

<dependency>
<groupId>javax.xml</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.1</version>
</dependency>

    2. 利用 org.eclipse.persistence.oxm.annotations.XmlInverseReference。

    该方法中,要被引用的部分使用@XmlInverseReference标注。本文例中需要在Student部分加入:

SClass:
private List<Student> students;

Student:
@XmlInverseReference(mappedBy="students")
private SClass sclass;
注意:mappedBy是必须有的属性,其值为引用Student的SClass类的对应field。

特别要注意的是,使用XmlInverseReference时,需要在数据模型类(本例中是Student和SClass)所在package下加入一个jaxb.properties属性文件,里面内容是:

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
    这种方法中,如果是使用maven,需加入依赖:
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.moxy</artifactId>
<version>2.5.0</version>
</dependency>