Java HTML / XML How to - Marshall an objectgraph with Java XML binding to a specific depth








Question

We would like to know how to marshall an objectgraph with Java XML binding to a specific depth.

Answer

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
//from w w w  .ja v a 2  s .c  om
public class Main {

  public static void main(String[] args) throws Exception {
    JAXBContext jc = JAXBContext.newInstance(Root.class);

    Root rootA = new Root();
    rootA.setName("A");

    Root rootB = new Root();
    rootB.setName("B");
    rootA.setChild(rootB);

    Root rootC = new Root();
    rootC.setName("C");
    rootB.setChild(rootC);

    Root rootD = new Root();
    rootD.setName("D");
    rootC.setChild(rootD);

    Root rootE = new Root();
    rootE.setName("E");
    rootD.setChild(rootE);

    Marshaller marshaller = jc.createMarshaller();
    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

    DepthListener depthListener = new DepthListener(3);
    marshaller.setListener(depthListener);
    marshaller.setAdapter(new RootAdapter(depthListener));
    marshaller.marshal(rootA, System.out);
  }

}

class DepthListener extends Marshaller.Listener {

  private int targetDepth;
  private int currentDepth = 0;

  public DepthListener(int depth) {
    this.targetDepth = depth;
  }

  @Override
  public void beforeMarshal(Object source) {
    currentDepth++;
  }

  @Override
  public void afterMarshal(Object source) {
    currentDepth--;
  }

  public boolean isMarshalDepth() {
    return currentDepth <= targetDepth;
  }

}

class RootAdapter extends XmlAdapter<Root, Root> {

  private DepthListener depthListener;

  public RootAdapter() {
  }

  public RootAdapter(DepthListener depthListener) {
    this.depthListener = depthListener;
  }

  @Override
  public Root unmarshal(Root root) throws Exception {
    return root;
  }

  @Override
  public Root marshal(Root root) throws Exception {
    if (depthListener != null && !depthListener.isMarshalDepth()) {
      return null;
    }
    return root;
  }

}

@XmlRootElement
@XmlJavaTypeAdapter(RootAdapter.class)
@XmlType(propOrder = { "name", "child" })
class Root {

  private String name;
  private Root child;

  public String getName() {
    return name;
  }

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

  public Root getChild() {
    return child;
  }

  public void setChild(Root report) {
    this.child = report;
  }

}