JAXB creating context and marshallers cost - java

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?

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.

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.

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.

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.

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");
}
}
}

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

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;
}
}

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
**/
}
}

Related

Implementing a JAXBContext Resolver Class: What classes are stored in the list?

I am trying to implement a JAXBContext resolver class. What I don't understand is what types of classes are included in cTypes? I've seen several similar examples, but none explain what the cTypes list is.
#Provider
public class JaxbContextResolver implements ContextResolver<JAXBContext> {
private final JAXBContext context;
private final Set<Class<?>> types;
private final Class<?>[] cTypes = {Flights.class, FlightType.class, AircraftType.class};
public JaxbContextResolver() throws Exception {
this.types = new HashSet<Class<?>>(Arrays.asList(cTypes));
this.context = new JettisonJaxbContext(JettisonConfig.DEFAULT, cTypes);
}
#Override
public JAXBContext getContext(Class<?> objectType) {
return (types.contains(objectType)) ? context : null;
}
}
Your cTypes class list must contains all classes that represents root xml elements (Those that you annotated with #XmlRootElement).
Explanation :
When you create a JAXBContext, you give it a list of classes to bound:
this.context = new JettisonJaxbContext(JettisonConfig.DEFAULT, cTypes);
This will make JAXB able to actually associate an element with a class.
JAXB will automatically bind any classes contained in root element classes (Except the ones annotated #XmlTransient).
Then, when the getContext method is used, it will return the initialized context in your class only if the parameter class has been bound by JAXB to the said context, since your JAXBContext won't be able to use any classes that are not bound.

Convert JAXB class (not its object) to xml template

Is there way one can convert JAXB class (not its object) to xml template.
For example
Below code is taken from http://www.javacodegeeks.com/2011/02/jaxb-generate-xml-xsd.html
public static void main(String[] args) throws JAXBException
{
ObjectFactory factory = new ObjectFactory();
UserT user = factory.createUserT();
user.setUserName("Sanaulla");
ItemT item = factory.createItemT();
item.setItemName("Seagate External HDD");
item.setPurchasedOn("August 24, 2010");
item.setAmount(new BigDecimal("6776.5"));
ItemListT itemList = factory.createItemListT();
itemList.getItem().add(item);
ExpenseT expense = factory.createExpenseT();
expense.setUser(user);
expense.setItems(itemList);
JAXBContext context = JAXBContext.newInstance("generated");
JAXBElement element = factory.createExpenseReport(expense);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty("jaxb.formatted.output",Boolean.TRUE);
marshaller.marshal(element,System.out);
}
In above code object of class Element has been create to marshall. My question is what if I don't have object of JAXB class, will I still be able to generate xml template (with no values)

how do I convert an xml string to an object. I don't know what object ahead of time. Just several possibities

I have a string of that is an XML string and it could correspond to one of several objects that are jaxb generated schema files.
I don't know what object it is ahead of time.
How do convert this XML string to an jaxb xml object? Some type of unmarshalling?
How do I determine which object it is assigned to?
How do I instantiate the object once it is converted from xml string to the object?
You could do something like the following:
Foo
As long as there is a root element associated with your class via an #XmlRootElement or #XmlElementDecl annotation you don't need to specify the type of class that you are unmarshalling (see: http://blog.bdoughan.com/2012/07/jaxb-and-root-elements.html).
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class Foo {
private String bar;
public String getBar() {
return bar;
}
public void setBar(String bar) {
this.bar = bar;
}
}
Demo
To unmarshal from a String simply wrap the String in an instance of StringReader. The unmarshal operation will convert the XML into an instance of your domain class. If you don't know what class you will have to use instanceof or getClass() to determine what type it is.
import java.io.StringReader;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Foo.class);
String xml = "<foo><bar>Hello World</bar></foo>";
StringReader reader = new StringReader(xml);
Unmarshaller unmarshaller = jc.createUnmarshaller();
Object result = unmarshaller.unmarshal(reader);
if(result instanceof Foo) {
Foo foo = (Foo) result;
System.out.println(foo.getBar());
}
}
}
Output
Hello World
Unmarshaller yourunmarshaller = JAXBContext.NewInstance(yourClass).createUnMarshaller();
JAXBElement<YourType> jaxb = (yourunmarshaller).unmarshal(XMLUtils.getStringSource([your object]), [the class of your object].class);
If you have schema files for the XML objects, which you would if you're using JAXB, run a validate on the XML.
Java XML validation against XSD Schema
If you generate objects from XSD, then JAXB generated an ObjectFactory class in the same package as all the type classes.
JAXBContext jaxbContext = JAXBContext.newInstance("your.package.name");
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
Here "your.package.name" stands for the package name of your ObjectFactory class.
The unmarshaller can now convert your XML into objects:
public Object createObjectFromString(String messageBody) throws JAXBException {
return unmarshaller.unmarshal(new StringReader(messageBody));
}
If this is successful, a JAXBElement object will be returned:
try {
JAXBElement jaxbElement= (JAXBElement) createObjectFromString(messageBody);
} catch (JAXBException e) {
// unmarshalling was not successful, take care of the return object
}
If you have a jaxbElement object returned, you can call getValue() for the wrapped object, of getDeclaredType() for it's class.
With this method, you don't need to know the type of the target object in advance.

jaxb exception management in property setters of unmarshalled class

When I unmarshal an Xml node to a property, the setMyProperty is called.
The code of the property setter may raise an exception:what happens in this case?
The behaviour that I have observed: if the exception is an unchecked exception, then it is swallowed by jaxb "internals" and that property ignored. If the RuntimeException is changed in a Exception (so checked and added to the throws clause of the property setter) it causes the unmarshal to fail.
The question is: is this a behaviour you can rely on?
thanks in advance
Agostino
PS: Ok "swallowed" is not the correct word, because it actually is managed in the "best possible way", unmarshalling correctly the rest of the document. Nevertheless the unmarshall caller is not notified that an exception has happen.
PS: A simple test case, just in case :-)
package test.jaxb;
import java.io.File;
import javax.xml.bind.*;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class SZL {
public static void main(String [] args) throws JAXBException {
SZL test = new SZL();
test.myProp = "test-value";
test.setMyProp2("test-value-2");
JAXBContext jc = JAXBContext.newInstance(SZL.class);
File f = new File("SZL.xml");
Marshaller m = jc.createMarshaller();
m.marshal(test, f);
test = null;
Unmarshaller um = jc.createUnmarshaller();
test = (SZL)um.unmarshal(f);
System.out.println("The RuntimeException has been swallowed");
System.out.println(test.myProp);
System.out.println(test.myProp2);
}
private String myProp;
public void setMyProp(String myProp) {
throw new RuntimeException();
//this.myProp = myProp;
}
public String getMyProp() {return myProp;}
private String myProp2;
public void setMyProp2(String myProp2){
this.myProp2 = myProp2;
}
public String getMyProp2() {return myProp2;}
}
This behaviour is not guaranteed to be portable across all JAXB implementations (Metro, EclipseLink MOXy, Apache JaxMe, etc).
For example the exception is not swallowed in EclipseLink JAXB (MOXy). Note I'm the MOXy lead, and a member of the JAXB (JSR-222) expert group.

JAXB marshals XML differently to OutputStream vs. StringWriter

I apologize if this has been answered, but the search terms I have been using (i.e. JAXB #XmlAttribute condensed or JAXB XML marshal to String different results) aren't coming up with anything.
I am using JAXB to un/marshal objects annotated with #XmlElement and #XmlAttribute annotations. I have a formatter class which provides two methods -- one wraps the marshal method and accepts the object to marshal and an OutputStream, the other just accepts the object and returns the XML output as a String. Unfortunately, these methods do not provide the same output for the same objects. When marshaling to a file, simple object fields internally marked with #XmlAttribute are printed as:
<element value="VALUE"></element>
while when marshaling to a String, they are:
<element value="VALUE"/>
I would prefer the second format for both cases, but I am curious as to how to control the difference, and would settle for them being the same regardless. I even created one static marshaller that both methods use to eliminate different instance values. The formatting code follows:
/** Marker interface for classes which are listed in jaxb.index */
public interface Marshalable {}
/** Local exception class */
public class XMLMarshalException extends BaseException {}
/** Class which un/marshals objects to XML */
public class XmlFormatter {
private static Marshaller marshaller = null;
private static Unmarshaller unmarshaller = null;
static {
try {
JAXBContext context = JAXBContext.newInstance("path.to.package");
marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
unmarshaller = context.createUnmarshaller();
} catch (JAXBException e) {
throw new RuntimeException("There was a problem creating a JAXBContext object for formatting the object to XML.");
}
}
public void marshal(Marshalable obj, OutputStream os) throws XMLMarshalException {
try {
marshaller.marshal(obj, os);
} catch (JAXBException jaxbe) {
throw new XMLMarshalException(jaxbe);
}
}
public String marshalToString(Marshalable obj) throws XMLMarshalException {
try {
StringWriter sw = new StringWriter();
return marshaller.marshal(obj, sw);
} catch (JAXBException jaxbe) {
throw new XMLMarshalException(jaxbe);
}
}
}
/** Example data */
#XmlType
#XmlAccessorType(XmlAccessType.FIELD)
public class Data {
#XmlAttribute(name = value)
private String internalString;
}
/** Example POJO */
#XmlType
#XmlRootElement(namespace = "project/schema")
#XmlAccessorType(XmlAccessType.FIELD)
public class Container implements Marshalable {
#XmlElement(required = false, nillable = true)
private int number;
#XmlElement(required = false, nillable = true)
private String word;
#XmlElement(required = false, nillable = true)
private Data data;
}
The result of calling marshal(container, new FileOutputStream("output.xml")) and marshalToString(container) are as follows:
Output to file
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:container xmlns:ns2="project/schema">
<number>1</number>
<word>stackoverflow</word>
<data value="This is internal"></data>
</ns2:container>
and
Output to String
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:container xmlns:ns2="project/schema">
<number>1</number>
<word>stackoverflow</word>
<data value="This is internal"/>
</ns2:container>
Looks like this might be a "bug" in JAXB. Looking at the source, the calls for marshal() create different writers based on the output/writer type parameter:
public void marshal(Object obj, OutputStream out, NamespaceContext inscopeNamespace) throws JAXBException {
write(obj, createWriter(out), new StAXPostInitAction(inscopeNamespace,serializer));
}
public void marshal(Object obj, XMLStreamWriter writer) throws JAXBException {
write(obj, XMLStreamWriterOutput.create(writer,context), new StAXPostInitAction(writer,serializer));
}
The implementations of the writers is different with regards to how they handle "empty elements". The above code is from:
jaxb-ri\runtime\src\com\sun\xml\bind\v2\runtime\MarshallerImpl.java.
The two writers you are creating are:
jaxb-ri\runtime\src\com\sun\xml\bind\v2\runtime\output\UTF8XmlOutput.java
jaxb-ri\runtime\src\com\sun\xml\bind\v2\runtime\output\XMLStreamWriterOutput.java
The good news is that JAXB is a specification with more than one implementation (just like JPA). If one implementation is not meeting your needs, others are available such as EclipseLink JAXB (MOXy):
http://www.eclipse.org/eclipselink/moxy.php
I don't know why JAXB is doing this - or even if it is JAXB - if JAXB is outputting XML via a SAXContentHandler for example, then it has no direct control over how close tags are produced.
To get consistent behaviour, you could wrap your OutputStream in a OutputStreamWriter, e.g.
public void marshal(Marshalable obj, OutputStream os) throws XMLMarshalException {
try {
marshaller.marshal(obj, new OutputStreamWriter(os, "UTF-8"));
} catch (JAXBException jaxbe) {
throw new XMLMarshalException(jaxbe);
}
}
Along the same lines, you might see what happens if you wrap the StringWriter in a PrintWriter. Maybe there is some custom code that detects StringWriter to tries to keep the output short as possible. Sounds unlikely, but I have no other explanation.

Categories