19

I use the JAXBContext.newInstance operation in my JBoss based web application. This operation, as I understand, is very heavyweight. I only require two unique instances of the Marshaller class.

My initial proposal is to have a static initializer block that will initialize these two instances only once upon the class loading:

public class MyWebApp {
    private static Marshaller requestMarshaller;
    private static Marshaller responseMarshaller;

    static {
        try {
            // one time instance creation
            requestMarshaller = JAXBContext.newInstance(Request.class).createMarshaller();
            responseMarshaller = JAXBContext.newInstance(Response.class).createMarshaller();
        } catch (JAXBException e) {
            e.printStackTrace();
        }
    }

    private void doSomething() {
            requestMarshaller.marshall(...);
            responseMarshaller.marshall(...);
            ...
    }

}

If this is a reasonable solution then I guess I'll have answered my own question, but I would like to know if this is the correct way to do this?

ryan
  • 5,039
  • 13
  • 35
  • 42

5 Answers5

29

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.

bdoughan
  • 147,609
  • 23
  • 300
  • 400
10

JAXBContext should always be static, it is thread safe.

Marshallers and Unmarshallers are cheap and not thread safe. You should create once JAXBContext and create marshallers/unmarshallers for every operation

public class MyWebApp {
    private static JAXBContext jaxbContext;

    static {
        try {
            // one time instance creation
            jaxbContext = JAXBContext.newInstance(Request.class, Response.class);
        } catch (JAXBException e) {
            throw new IllegalStateException(e);
        }
    }

    private void doSomething() {                
            jaxbContext.createMarshaller().marshall(...);
            ...
    }

}

Use same marshaller to marshall everything (add all classes when you create the context).

cocorossello
  • 1,289
  • 1
  • 17
  • 30
  • 2
    Just a comment: You should not reuse marshallers/unmarshallers, they are not thread safe. Just create them each time, it's very fast – cocorossello Jun 03 '15 at 11:04
  • 2
    I think the suggested solution here is spot-on, and very helpful, but I don't believe the code example is illustrating the point made in the text that you shouldn't be calling JAXBContext.newInstance() every time you need a Marshaller. Shouldn't the line in doSomething() be `requestMarshaller = jaxbContext.createMarshaller();`? – rscarter Sep 23 '15 at 18:14
4

I recently did some performance testing with JAXBContext.newInstance and the result is documented here .

http://app-inf.blogspot.com/2012/10/performance-tuning-logging-right-way.html

When called by one thread, using a fairly large schema with ~195 classes generated, it took ~400ms to finish. When called by 20 threads simultaneously, it caused cpu contentions, and took up to ~5000ms to finish. The creation of marshaller and object serialization of a small object only too ~14ms.

0

One can use javax.xml.bind.JAXB. It has direct Marshal and unmarshal methods. So you don't have to worry about instance creation of JAXB.

e.g. JAXB.unmarshal(inputStream/inputFile, outputClassExpected) or JAXB.marshal(jaxbObject, xmlOutputFile/xmlOutputStream)

sandeep kale
  • 321
  • 2
  • 10
  • 1
    Did you see this in the javadoc of class [javax.xml.bind.JAXB](https://docs.oracle.com/javase/8/docs/api/javax/xml/bind/JAXB.html)? *Generally speaking, the performance is not necessarily optimal. It is expected that people who need to write performance critical code will use the rest of the JAXB API directly.* – Thomas Fritsch Sep 11 '17 at 16:19
  • @ThomasFritsch, Yes. The performance may be a concern for critical projects. This has to be checked if it's the case. May be writing own marshaller/un-marshaller will help. – sandeep kale Sep 14 '17 at 12:07
  • 1
    In my case JAXB.marshall uses it's own cache implementation of the context. Oracle JDK 8. So it turns out to be faster that using the Jaxb API and not caching the context – Filip Mar 14 '19 at 15:15
-1

You should create single JAXBContext object per bean class. see this

Nitin
  • 2,701
  • 2
  • 30
  • 60