March 9, 2011

Handling Duplicate @XmlRootElement Declarations

The following post was inspired by an answer I gave to a question on Stack Overflow (feel free to up vote).  The problem arose from a JAXBContext being created on classes derived from two schemas that both use the same root element.  The solution is to supply type of object to the unmarshal operation.


Java Model


Our Java model will consist of two classes.  Both classes have the same @XmlRootElement declaration.

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name="A")
public class A1 {    
}

and

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name="A")
public class A2 {    
}

XML

For this example the XML document is quite simple as all we care about is the root element.

<A/>

Demo Code

In this example the root element name does not uniquely map to a Java class.  We need to supply the type of object we want to the unmarshal operation.  Since the A1 class does supply an @XmlRootElement annotation there is nothing special that has to be done for the marshal operation.

import java.io.File;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;

public class Demo {

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

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xmlFile = new File("input.xml");
        StreamSource xmlSource = new StreamSource(xmlFile);
        A1 a1 = unmarshaller.unmarshal(xmlSource, A1.class).getValue();

        Marshaller marshaller = jc.createMarshaller();
        marshaller.marshal(a1, System.out);
    }
}

4 comments:

  1. Hi Blaise We are using JAXB to generate the classes used and the generator complains/fails due to the identical root elements. Is there a workaround that will enable the classes to be generated using, for instance, the binding.jxb configuration file?

    ReplyDelete
  2. Hey, great help. But how do you use createUnmarshaller, which is protected?

    ReplyDelete