138

The question is a bit theoretical, what is the cost of creating JAXB context, marshaller and unmarshaller?

I've found that my code could benefit from keeping the same JAXB context and possibly the same marshaller for all marshaling operations rather than creating context and marshaller on each marshaling.

So what is the cost of creating JAXB context and marshaller/unmarshaller? Is it okay to create context+marshaller for each marshaling operation or it's better to avoid it?

Vladimir
  • 4,782
  • 7
  • 35
  • 56

8 Answers8

285

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.

bdoughan
  • 147,609
  • 23
  • 300
  • 400
  • 7
    great answer. I can be confident now based on your experience as lead on JAXB. – Vladimir Sep 13 '11 at 12:22
  • 7
    I trust you, but is this to be found somewhere in documentation? – Hurda Jan 30 '14 at 22:02
  • 3
    It's documented for the RI: https://jaxb.java.net/guide/Performance_and_thread_safety.html (but not Moxy AFAIK) – Caoilte Aug 24 '14 at 16:33
  • 52
    Please specify this in the Javadoc. It's not satisfactory to have these crucial aspects undocumented. – Thomas W Jun 11 '15 at 23:50
  • 8
    It isn't mentioned in the Javadoc that JAXBContext is thread safe. And just about every example of how to use JAXB, fails to mention that it should be created once and shared across threads. As a result I'm now removing yet another howling resource leak from a live system. Grrrrrrr. – Reg Whitton Dec 07 '16 at 13:30
  • 1
    @Caoilte user guide was moved to https://javaee.github.io/jaxb-v2/doc/user-guide/ch03.html#other-miscellaneous-topics-performance-and-thread-safety – Vlasec Jun 22 '18 at 11:38
  • 1
    @Reg Whiton it's not just a resource leak. At work we found out that concurrent accesses can mess up the Marshaller internally and later cause unreproducible ArrayIndexOutOfBounds exceptions during marshalling. The proplem would persist until restarting the app. At least we realized this before going production... – MauganRa Sep 13 '19 at 20:51
  • 1
    "Marshaller and Unmarshaller [...] are lightweight to create and could be created per operation" - this might be misleading, according to the docs: "creating Unmarshaller could be relatively an expensive operation" for multiple small docs. https://javaee.github.io/jaxb-v2/doc/user-guide/ch06.html – zmx May 18 '21 at 13:13
47

Ideally, you should have a singleton JAXBContext and local instances of Marshaller and Unmarshaller.

JAXBContext instances are thread-safe while Marshaller and Unmarshaller instances are not thread-safe and should never be shared across threads.

catch23
  • 17,519
  • 42
  • 144
  • 217
Sahil Muthoo
  • 12,033
  • 2
  • 29
  • 38
17

It's a pity that this isn't specifically described in the javadoc. What I can tell is that Spring uses a global JAXBContext, shared between threads, whereas it creates a new marshaller for each marshalling operation, with a javadoc comment in the code saying that JAXB marshallers are not necessarily thread-safe.

The same is said on this page:https://javaee.github.io/jaxb-v2/doc/user-guide/ch03.html#other-miscellaneous-topics-performance-and-thread-safety.

I would guess that creating a JAXBContext is a costly operation, because it involves scanning classes and packages for annotations. But measuring it is the best way to know.

Lonzak
  • 9,334
  • 5
  • 57
  • 88
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • Hi @JB, great answer especially your comments on measuring and why JAXBContext is costly. – Vladimir Sep 13 '11 at 12:20
  • 1
    Javadoc has always been weak on the crucial facts of _lifecycle_. It sure gives us trivial repetition of property getters & setters, but as to knowing how/where to get or create an instance, mutation & thread-safety.. it seems to completely miss those most-important factors. Sigh :) – Thomas W Jun 11 '15 at 23:48
4

JAXB 2.2 (JSR-222) has this to say, in section "4.2 JAXBContext":

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.

[..]

JAXBContext class is designed to be immutable and thus threadsafe. Given the amount of dynamic processing that potentially could take place when creating a new instance of JAXBContxt, it is recommended that a JAXBContext instance be shared across threads and reused as much as possible to improve application performance.

Unfortunately, the specification does not make any claims regarding thread-safety of Unmarshaller and Marshaller. So it is best to assume they are not.

Martin Andersson
  • 18,072
  • 9
  • 87
  • 115
3

I solved this problem using:

  • shared thread safe JAXBContext and thread local un/marschallers
  • (so theoretically, there will be as many un/marshaller instances as there are threads which accessed them)
  • with synchronization only on un/marshaller's initialization.
public class MyClassConstructor {
    private final ThreadLocal<Unmarshaller> unmarshallerThreadLocal = new ThreadLocal<Unmarshaller>() {
        protected synchronized Unmarshaller initialValue() {
            try {
                return jaxbContext.createUnmarshaller();
            } catch (JAXBException e) {
                throw new IllegalStateException("Unable to create unmarshaller");
            }
        }
    };
    private final ThreadLocal<Marshaller> marshallerThreadLocal = new ThreadLocal<Marshaller>() {
        protected synchronized Marshaller initialValue() {
            try {
                return jaxbContext.createMarshaller();
            } catch (JAXBException e) {
                throw new IllegalStateException("Unable to create marshaller");
            }
        }
    };

    private final JAXBContext jaxbContext;

    private MyClassConstructor(){
        try {
            jaxbContext = JAXBContext.newInstance(Entity.class);
        } catch (JAXBException e) {
            throw new IllegalStateException("Unable to initialize");
        }
    }
}
peeeto
  • 65
  • 1
  • 4
  • 8
    ThreadLocal will introduce other subtile problems, without benefit. Just keep a single JAXBContext (that's the costly part) and create a new Unmarshaller whenever required. – ymajoros Feb 03 '14 at 09:12
  • `ThreadLocal#initialValue` should not be synchronised here. It uses only the thread safe `JAXBContext` object. – Lii Jun 24 '21 at 11:37
2

Even better!! Based on the good solution from the post above, create the context just-once in the constructor, and save it instead of the class.

Replace the line:

  private Class clazz;

with this one:

  private JAXBContext jc;

And the main constructor with this one:

  private Jaxb(Class clazz)
  {
     this.jc = JAXBContext.newInstance(clazz);
  }

so in the getMarshaller/getUnmarshaller you can remove this line:

  JAXBContext jc = JAXBContext.newInstance(clazz);

This improvement makes, in my case, that processing times drops from 60~70ms to just 5~10ms

tbarderas
  • 55
  • 6
  • How big was the xml file you were parsing. Do you see significant improvement with very large xml files? – John Jul 06 '15 at 13:38
  • 1
    it's not really a matter of big xml files (mines goes from just 2-3kb up to +6mb) , but instead a matter of a very large number of xml files (we're talking here of about 10,000 xml requests per minute); in that case creating the context just once gaining those little ms makes a huge difference – tbarderas Sep 14 '15 at 14:55
1

I usually solve problems like this with a ThreadLocal class pattern. Given the fact that you need a different marshaller for each Class, you can combine it with a singleton-map pattern.

To save you 15 minutes, of work. Here follows my implementation of a thread-safe Factory for Jaxb Marshallers and Unmarshallers.

It allows you to access the instances as follows ...

Marshaller m = Jaxb.get(SomeClass.class).getMarshaller();
Unmarshaller um = Jaxb.get(SomeClass.class).getUnmarshaller();

And the code you will need is a little Jaxb class that looks as follows:

public class Jaxb
{
  // singleton pattern: one instance per class.
  private static Map<Class,Jaxb> singletonMap = new HashMap<>();
  private Class clazz;

  // thread-local pattern: one marshaller/unmarshaller instance per thread
  private ThreadLocal<Marshaller> marshallerThreadLocal = new ThreadLocal<>();
  private ThreadLocal<Unmarshaller> unmarshallerThreadLocal = new ThreadLocal<>();

  // The static singleton getter needs to be thread-safe too, 
  // so this method is marked as synchronized.
  public static synchronized Jaxb get(Class clazz)
  {
    Jaxb jaxb =  singletonMap.get(clazz);
    if (jaxb == null)
    {
      jaxb = new Jaxb(clazz);
      singletonMap.put(clazz, jaxb);
    }
    return jaxb;
  }

  // the constructor needs to be private, 
  // because all instances need to be created with the get method.
  private Jaxb(Class clazz)
  {
     this.clazz = clazz;
  }

  /**
   * Gets/Creates a marshaller (thread-safe)
   * @throws JAXBException
   */
  public Marshaller getMarshaller() throws JAXBException
  {
    Marshaller m = marshallerThreadLocal.get();
    if (m == null)
    {
      JAXBContext jc = JAXBContext.newInstance(clazz);
      m = jc.createMarshaller();
      marshallerThreadLocal.set(m);
    }
    return m;
  }

  /**
   * Gets/Creates an unmarshaller (thread-safe)
   * @throws JAXBException
   */
  public Unmarshaller getUnmarshaller() throws JAXBException
  {
    Unmarshaller um = unmarshallerThreadLocal.get();
    if (um == null)
    {
      JAXBContext jc = JAXBContext.newInstance(clazz);
      um = jc.createUnmarshaller();
      unmarshallerThreadLocal.set(um);
    }
    return um;
  }
}
bvdb
  • 22,839
  • 10
  • 110
  • 123
  • 10
    ThreadLocal will introduce other subtile problems, without benefit. Just keep a single JAXBContext (that's the costly part) and create a new Unmarshaller whenever required. – ymajoros Feb 03 '14 at 09:12
  • You actually don't need separate JAXBContexts since you can pass in multiple classes. So, if you can predict which classes are going to be marshalled, you can create a single shared one. Also, the JAXB spec requires them to be threadsafe already. – MauganRa Sep 13 '19 at 20:59
1

Creating JAXBContext within a enum and accessing it within application Thread to create Marshaller/Unmarshaller will suffice.

public enum MyApplicationJAXBContext {

    REQ(Request.class), RESP(Response.class);

    private final JAXBContext jaxbContext;

    MyApplicationJAXBContext(Class contextClass) {

        try {
            jaxbContext = JAXBContext.newInstance(contextClass);
        } catch (JAXBException e) 
            throw new RunTimeException(e);
           // Lets caller decide what to do ?
        }
    }

    public JAXBContext getJaxbContext() {
        return jaxbContext;
    }
}


public class MyAppCallable implements Callable<Response> {

private final Request req;
public MyAppCallable(Request req) {
    this.req = req;
}


public Response call() {

Marshaller marshaller = MyApplicationJAXBContext.REQ.getJaxbContext().createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
// Anything else you want to configure properties
Unmarshaller unmarshaller = MyApplicationJAXBContext.RESP.getJaxbContext().createUnmarshaller();

/** 
All other logic you want to do after req/rsp usage and return Response
**/

}

}