Jaxb Creating Context and Marshallers Cost

JAXB creating context and marshallers cost

Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB 2 (JSR-222) expert group.

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.

JAXB one Marshaller instance and Unmarshaller instance per application

Caching Marschaller and Unmarshaller is not a good idea. Cache the JAXBContext instead.

JAXBContext may be reused to create marshallers and unmarshallers.

Marshaller and Unmarshaller instances are NOT (necessarily) thread-safe or reusable.

I'll look for the references and update the answer.

Here's the reference:

The JAXBContext class is thread safe, but the Marshaller,
Unmarshaller, and Validator classes are not thread safe.

Related answer:

JAXB creating context and marshallers cost

How do I improve performance of application that uses the JAXBContext.newInstance operation?

A JAXB implementation (Metro, EclipseLink MOXy, Apache JaxMe, etc) typically initializes its metadata during the JAXBContext.newInstance call. All OXM tools need to initialize mapping metadata at some point and try to minimize the cost of this operation. Since it is impossible to do it with zero cost, it is best to only do it once. Instances of JAXBContext are thread safe, so yes you only need to create it once.

From the JAXB 2.2 Specification, Section 4.2 JAXB Context:

To avoid the overhead involved in
creating a JAXBContext instance, a
JAXB application is encouraged to
reuse a JAXBContext instance. An
implementation of abstract class
JAXBContext is required to be
thread-safe, thus, multiple threads in
an application can share the same
JAXBContext instance.

Instances of Marshaller and Unmarshaller are not thread safe and must not be shared among threads, they are lightweight to create.

JAXB Marshaller indentation

This annoying issue could be fixed by applying javax Transformer to the output.

import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.StreamResult;

Object jaxbElement = // The object you want to marshall using jaxb.

JAXBContext context = JAXBContext.newInstance(jaxbElement.getClass());
Marshaller marshaller = context.createMarshaller();
OutputStream out = // Here your destination, FileOutStream, ByteOutStream etc
DOMResult domResult = new DOMResult();
marshaller.marshal(jaxbElement, domResult);

Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
transformer.transform(new DOMSource(domResult.getNode()), new StreamResult(out));

JAXB marshalling superclass

I'm not sure how you're configuring the JAXB context or marshaller but the following:-

public static void main(String[] args) throws Exception
{

Employee employee = new Employee();
employee.setId(1);
employee.setName("Ralph");

JAXBContext context = JAXBContext.newInstance(Employee.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(employee, System.out);

}

gives:-

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<employee>
<name>Ralph</name>
<id>1</id>
</employee>

JAXB and marshalling

Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.

The behaviour you are seeing will differ upon which implemenation of JAXB you are using. The MOXy implementation will give you the result you are looking for. I will demonstrate below.

JAVA MODEL

Below is the Java model that will be used for this example. The package level @XmlSchema annotation will be used to specify the namespace qualfication in each of the packages (see: http://blog.bdoughan.com/2010/08/jaxb-namespaces.html).

forum13408684.a.A

package forum13408684.a;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class A {

}

forum13408684.a.package-info

@XmlSchema(namespace="A", elementFormDefault=XmlNsForm.QUALIFIED)
package forum13408684.a;

import javax.xml.bind.annotation.*;

forum13408684.b.B

package forum13408684.a;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class B {

}

forum13408684.b.package-info

@XmlSchema(namespace="B", elementFormDefault=XmlNsForm.QUALIFIED)
package forum13408684.b;

import javax.xml.bind.annotation.*;

DEMO CODE

package forum13408684;

import javax.xml.bind.*;
import forum13408684.a.A;
import forum13408684.b.B;

public class Demo {

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

Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(new A(), System.out);
marshaller.marshal(new B(), System.out);
}

}

OUTPUT

JAXB Reference Implementation

The output below matches what you described in your question:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<a xmlns="A" xmlns:ns2="B"/>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:b xmlns="A" xmlns:ns2="B"/>

EclipseLink JAXB (MOXy)

If you specify MOXy as your JAXB provider (see: http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html) you will get the output you are looking for.

<?xml version="1.0" encoding="UTF-8"?>
<a xmlns="A"/>
<?xml version="1.0" encoding="UTF-8"?>
<ns0:b xmlns:ns0="B"/>


Related Topics



Leave a reply



Submit