Tuesday, September 10, 2013

Mix JAXBContext for Marshalling

Suppose you have one xml document like this

<product>
  <name>MicroWave</name>
 <extra>
   <!-- undefined xml content from other source -->
 </extra>
</product>
The xml document will be generated by JAXB marshaller(A).

Suppose the XML content enclosed by extra tag is from another JAXB marshaller(B), how can we insert the result from B to the location under Extra.

First, define the extra has the type xsd:anyType. You can do this in schema, annotation. For eclipselink xom, your property will be xml-anyelement instead of the regular xml-element.

Second, define a XmlAdapter which will use the unmarshaller B to convert java object into a org.w3c.dom.Element. The Element will be marshalled in place.

public class ObjectAdapter extends XmlAdapter<Element, Object>
{
 
    @Override
    public Element marshal(Object arg0) throws Exception
    {
        if (arg0==null)
        {
            return null;
        }
        Class<?> cls = arg0.getClass();
        JAXBContext context = JAXBContext.newInstance(cls);
        Marshaller marshaller = context.createMarshaller();

        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        DocumentBuilder db = dbf.newDocumentBuilder();
        Document doc = db.newDocument();
        Element root = doc.createElement("object");
        root.setAttribute("cls", cls.getName());

        marshaller.setProperty("jaxb.fragment", true);
        marshaller.marshal(arg0, root);
       
           return root;
    }

    public Element getFirstElement(Element element)
    {
        for (int i = 0; i < element.getChildNodes().getLength(); i++)
        {
            Node child = element.getChildNodes().item(i);
            if (child.getNodeType() == Node.ELEMENT_NODE)
            {
                return (Element) child;
            }

        }
        return null;
    }

    @Override
    public Object unmarshal(Element element) throws Exception
    {
        if (element==null)
        {
            return null;
        }
        Element firstElement=getFirstElement(element);
        if (firstElement==null)
        {
            return null;
        }
        String clzName = element.getAttribute("cls");
        Class<?> cls = Class.forName(clzName);

        JAXBContext context = JAXBContext.newInstance(cls);
        Unmarshaller um = context.createUnmarshaller();

        Object object = um.unmarshal(firstElement);
        return object;
    }
}

Finally attach the XmlAdapter to property through configuration or annotation.



No comments:

Post a Comment