1

I have an existing complex object model that I am trying to marshall to JAXB xml. I don't want to change any of the existing domain classes if possible. I have this snippet working to marshall to a file (using Groovy)

def marshallToFile(Object objectToMarshall, File location){

    def context = JAXBContext.newInstance(objectToMarshall.class)

    def m = context.createMarshaller()
    m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true)

    location.withOutputStream { out ->
        m.marshal(new JAXBElement(new QName("","rootTag"),objectToMarshall.class,objectToMarshall), out)
    }

}

The problem is that the Object Graph is very complex and JAXB tells me com.sun.istack.internal.SAXException2: A cycle is detected in the object graph. This will cause infinitely deep XML: com.example.Object@1eef1eb[Id=100053900] -> com.example.Object@1eef1eb[Id=100053900]

Is there any way to get more information about the detected cycle? Does anyone know of a tool that would help analyze the graph or list it graphically so I can pick out cycles? I have a feeling there are a lot of cycles in this graph (it's old and complex) so any help would be appreciated.

Maybe as an alternative, can you tell JAXB to only go 'n' levels deep or something similar so it doesn't create infinitely deep XML?

Edit:

So with respect to my specific problem... turns out the existing domain object had a Object getThis() and void setThis(Object obj) method defined that was "getting" and "setting" the this self-reference keyword. That is what was causing my cycle. This also highlights the fact that JAXB must use JavaBean method definitions to determine which properties it will marshall (which I was not aware of before).

However, I think the original question still stands, are there any good tools out there for analyzing/viewing the object graph?

FGreg
  • 14,110
  • 10
  • 68
  • 110

2 Answers2

2

Perhaps you could introduce a Marshaller.Listener to trace through the marshalling process and dump object info, for the purpose of diagnosis. See "Marshal Event Callbacks" (parts referencing "External listeners") for more info. This shouldn't require changes to your existing domains.

Brian Henry
  • 3,161
  • 1
  • 16
  • 17
0

You could have your object implement the CycleRecoverable interface to find information about the cycle.

import java.util.*;
import javax.xml.bind.annotation.*;
import com.sun.xml.bind.CycleRecoverable;

@XmlRootElement
public class Department implements CycleRecoverable {

   @XmlAttribute
   public int id;
   public String name;
   public List<Employee> employees = new ArrayList<Employee>();

   public Object onCycleDetected(Context arg0) {
       // Context provides access to the Marshaller being used:
       System.out.println("JAXB Marshaller is: " + cycleRecoveryContext.getMarshaller());

       DepartmentPointer p = new DepartmentPointer();
       p.id = this.id;
       return p;
   }

}

For More Information

bdoughan
  • 147,609
  • 23
  • 300
  • 400