tags:

views:

251

answers:

2

I'm using JAXB for quick-and-dirty XML generation. I have a class that represents a tree structure:

@XmlRootElement(name = "element")
public class Element {

  // [...]

  @XmlElementWrapper(name="childs")
  @XmlElementRef
  public List<Element> getChilds() { /*...*/ }
}

I want to restrict the depth up to which the child collection is marshalled. So, for example I'd like to write out just the direct childs of the element I send to the Marshaller but omit their childs.

Is there a standard JAXB way to do this or maybe a callback I can use to disable the marshalling of a property on the fly?

+1  A: 

You can try to use the XmlJavaTypeAdapter annotation and your implementation of XmlAdapter interface.

Superfilin
I already thought of that but wasn't able to figure out how to trigger JAXB marshalling of the childs from inside the Adapter. There is no access to the Marshaller via the XmlAdapter interface, so it seems my options are:1) to instatiate a new one, which can become a big perfomance hit or 2) get access to the current Marshaller - for example using a custom ThreadLocal context class - which I guess isn't safe (or even possible) because it would mean reusing the Marshaller while another object is still being processed.
FRotthowe
You can use a pool of Marshallers and reuse them. In any case there will no more than 2 used at a time as you really need only 2 levels.
Superfilin
I will try to use a pool of marshallers as you suggested. This doesn't feel like a "clean" solution, but at least there's no need for changes to the model classes.
FRotthowe
+1  A: 

If you know that you will not be using your data structure after marshaling or you can easily make a copy of it, I would define the marshaller (http://java.sun.com/javase/6/docs/api/javax/xml/bind/Marshaller.html#marshalEventCallback) callback function:

boolean beforeMarshal(Marshaller);

in your element class. You could use this event callback to track the depth the marshaller has reached. When it reaches your limit depth, just null out the annotated child property. JAXB by default does not produce an element when it encounters a null property, so the marshaller will stop there.

If you want to reuse your structure after marshalling, you need to play games with moving the children you don't want serialized into an un-annotated property and then moving them back into your main property after the marshaller is done:

void afterMmarshal(Marshaller);

This pattern adds a bit of design smell because you have a un-annotated method with a magic signature that is never called from your own code, but it does work.

gibbss
Unfortunately, I need the data structure after marshalling. In fact, the objects are hibernate-mapped: All changes to them may possibly be flushed to the database, so directly modifying them seems a bit too risky.
FRotthowe