Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JAXBContext.newInstance variations

Tags:

I am experimenting with the various forms of newInstance method in class JAXBContext (I am using the default Sun JAXB implementation that ships with Oracle JDK 1.7).

It's not clear to me when it's ok to just pass to the newInstance method the concrete classes versus the ObjectFactory class. I should note that I am using JAXB purely for parsing XML files, i.e. only in the XML->Java direction.

Here's the absolutely minimal code that demonstrates my point:

xsd file

<?xml version="1.0" encoding="UTF-8"?>
<schema elementFormDefault="qualified"
    xmlns          ="http://www.w3.org/2001/XMLSchema"
    xmlns:a        ="http://www.example.org/A"
    targetNamespace="http://www.example.org/A">
    <element name="root" type="a:RootType"></element>

    <complexType name="RootType">
       <sequence>
           <element name="value" type="string"></element>
       </sequence>
    </complexType>
</schema>

Given the above XSD, the following JAXBInstance.newInstance invocations succeed in creating a context that can parse a sample a.xml file:

  • jc = JAXBContext.newInstance("example.a");
  • jc = JAXBContext.newInstance(example.a.ObjectFactory.class);
  • jc = JAXBContext.newInstance(example.a.RootType.class, example.a.ObjectFactory.class);

However, passing the example.a.RootType.class alone fails with javax.xml.bind.UnmarshalException at runtime:

jc = JAXBContext.newInstance(example.a.RootType.class); // this fails at runtime.

Can anyone shed some light? The reason I am experimenting on these JAXBContext::newInstance variations is that I've stumbled on this problem where the accepted answer included the option of "building the JAXB context based on individual classes rather than object factories". The sample a.xml and the JAXB Java code I am using follow at the end of the post.

sample a.xml used

<?xml version="1.0" encoding="UTF-8"?>
<a:root xmlns:a="http://www.example.org/A"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.example.org/A A.xsd">
    <a:value>foo</a:value>
</a:root>

JAXB parsing code

public static void main (String args[]) throws JAXBException, FileNotFoundException {
    JAXBContext jc = null;
    message("using package context (press any key:)");
    jc = JAXBContext.newInstance("example.a");
    work(jc); // SUCCEEDS

    message("using Object factory (press any key):");
    jc = JAXBContext.newInstance(example.a.ObjectFactory.class);
    work(jc); // SUCCEEDS

    message("using class enumeration (press any key):");
    try {
        jc = JAXBContext.newInstance(example.a.RootType.class);
        work(jc);  // FAILS
    } catch (javax.xml.bind.UnmarshalException e) {
        e.printStackTrace();
    }

    message("using class enumeration and Object factory too (press any key):");
    jc = JAXBContext.newInstance(example.a.RootType.class, example.a.ObjectFactory.class);
    work(jc); // SUCCEEDS

}

private static void work(JAXBContext jc) throws JAXBException, FileNotFoundException {
    Unmarshaller u = jc.createUnmarshaller();
    RootType root = ((JAXBElement<RootType>)u.unmarshal( new FileInputStream( "a.xml" ))).getValue();
    System.out.println( root.getValue() );
}
like image 447
Marcus Junius Brutus Avatar asked May 31 '13 15:05

Marcus Junius Brutus


People also ask

What is JAXBContext newInstance?

JAXBContext.newInstance( "com.acme.foo:com.acme.bar" ) The JAXBContext instance is initialized from a list of colon separated Java package names. Each java package contains JAXB mapped classes, schema-derived classes and/or user annotated classes.

How do I improve my JAXB performance?

The static helper methods in the JAXB class (JAXB. marshal and JAXB. unmarshall) should be avoided if you need to invoke them repeatedly. Instead, create a JAXBContext instance once and work with the Marshaller and Unmarshaller interfaces.

Is JAXBContext thread safe?

JAXBContext is thread safe and should only be created once and reused to avoid the cost of initializing the metadata multiple times. Marshaller and Unmarshaller are not thread safe, but are lightweight to create and could be created per operation.


1 Answers

JAXB Model Generated from XML Schema

When creating a JAXBContext from a model generated from an XML schema I always recommend doing it on the package name of the generated classes.

JAXBContext jc = JAXBContext.newInstance("example.a");

It is even better to use a newInstance method that takes a ClassLoader parameter. This will save you grief when you move from a Java SE to Java EE environment.

JAXBContext jc = JAXBContext.newInstance("example.a", example.a.ObjectFactory.class.getClassLoader());

When you create the JAXBContext on the package name, the JAXB impl assumes you generated the model from an XML schema and pulls in the ObjectFactory class since it always generates the class annotated with @XmlRegistry with this name.

Starting from a Java Model

This is when I recommend people use the newInstance methods that take classes. When bootstrapping a JAXBContext from JAXB classes there is nothing special about a class called ObjectFactory. The role of the ObjectFactory could be played by any class annotated with @XmlRegistry so it is not automatically looked for. This is why your use case worked when you explictly reference ObjectFactory and failed when you did not.

like image 164
bdoughan Avatar answered Nov 02 '22 20:11

bdoughan