JAXB is a Java binding tool. It generates Java code from a schema and you are able to transform from those classes into XML matching the processed schema and back. Note, that you cannot use your own objects, you have to use what is generated.In this post I will provide an alternative answer to that question.
Java Model
We will use the following model for this example. The classes represent customer data. The get/set methods have been omitted to save space.
Customer
package comparison; import java.util.ArrayList; import java.util.List; public class Customer { private long id; private String name; private Address address; private List<phonenumber> phoneNumbers; public Customer() { phoneNumbers = new ArrayList<PhoneNumber>(); } }
Address
package comparison; public class Address { private String city; private String street; }
PhoneNumber
package comparison; public class PhoneNumber { private String type; private String number; }
Customer Data
The following instance of Customer will be marshalled to XML using both JAXB and XStream.
package comparison; public class Data { public static Customer CUSTOMER; static { CUSTOMER = new Customer(); CUSTOMER.setId(123); CUSTOMER.setName("Jane Doe"); Address address = new Address(); address.setStreet("1 A Street"); address.setCity("Any Town"); CUSTOMER.setAddress(address); PhoneNumber workPhoneNumber = new PhoneNumber(); workPhoneNumber.setType("work"); workPhoneNumber.setNumber("555-WORK"); CUSTOMER.getPhoneNumbers().add(workPhoneNumber); PhoneNumber cellPhoneNumber = new PhoneNumber(); cellPhoneNumber.setType("cell"); cellPhoneNumber.setNumber("555-CELL"); CUSTOMER.getPhoneNumbers().add(cellPhoneNumber); } }
Marshal Code
This is the code we will use to convert the objects to XML.
XStream
The following code will be used to marshal the instance of Customer to an OutputStream. The XStream code is quite compact.
package comparison.xstream; import com.thoughtworks.xstream.XStream; import static comparison.Data.CUSTOMER; public class XStreamDemo { public static void main(String[] args) { XStream xstream = new XStream(); xstream.autodetectAnnotations(true); xstream.toXML(CUSTOMER, System.out); } }
JAXB
The following code will be used to marshal the instance of Customer to an OutputStream. A couple of differences are already apparent:
- A JAXBContext needs to be initialized on the binding metadata before the marshal operation can occur.
- Unlike XStream JAXB does not format the XML by default, so we will enable this feature.
- With no metadata specified we need to supply JAXB with a root element name (and namespace).
package comparison.jaxb; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBElement; import javax.xml.bind.Marshaller; import javax.xml.namespace.QName; import comparison.Customer; import static comparison.Data.CUSTOMER; public class JAXBDemo { public static void main(String[] args) throws Exception { JAXBContext jc = JAXBContext.newInstance(Customer.class); Marshaller marshaller = jc.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); JAXBElement<Customer> jaxbElement = new JAXBElement<Customer>(new QName("customer"), Customer.class, CUSTOMER); marshaller.marshal(jaxbElement, System.out); } }
<customer> <id>123</id> <address> <city>Any Town</city> <street>1 A Street</street> </address> <name>Jane Doe</name> <phoneNumbers> <number>555-WORK</number> <type>work</type> </phoneNumbers> <phoneNumbers> <number>555-CELL</number> <type>cell</type> </phoneNumbers> </customer>
@XmlAccessorType(XmlAccessType.FIELD) package comparison; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType;
import java.util.ArrayList; import java.util.List; import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamImplicit; @XStreamAlias("customer") public class Customer { private long id; private String name; private Address address; @XStreamImplicit(itemFieldName="phone-number") private List<PhoneNumber> phoneNumbers; public Customer() { phoneNumbers = new ArrayList<PhoneNumber>(); } }
import java.util.ArrayList; import java.util.List; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class Customer { private long id; private String name; private Address address; @XmlElement(name="phone-number") private List<PhoneNumber> phoneNumbers; public Customer() { phoneNumbers = new ArrayList<PhoneNumber>(); } }
Note: The JAXB Marshal code can now be simplified since we no longer need to supply the root element information:
package comparison.jaxb; import javax.xml.bind.JAXBContext; import javax.xml.bind.Marshaller; import comparison.Customer; import static comparison.Data.CUSTOMER; public class JAXBDemo { public static void main(String[] args) throws Exception { JAXBContext jc = JAXBContext.newInstance(Customer.class); Marshaller marshaller = jc.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.marshal(CUSTOMER, System.out); } }
XML Output
At this point the same XML is being produced by XStream and JAXB.
<customer> <id>123</id> <name>Jane Doe</name> <address> <city>Any Town</city> <street>1 A Street</street> </address> <phone-number> <type>work</type> <number>555-WORK</number> </phone-number> <phone-number> <type>cell</type> <number>555-CELL</number> </phone-number> </customer>
package comparison; import java.util.ArrayList; import java.util.List; import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamAsAttribute; import com.thoughtworks.xstream.annotations.XStreamImplicit; @XStreamAlias("customer") public class Customer { @XStreamAsAttribute private long id; private String name; private Address address; @XStreamImplicit(itemFieldName="phone-number") private List<PhoneNumber> phoneNumbers; public Customer() { phoneNumbers = new ArrayList<PhoneNumber>(); } }
package comparison; import java.util.ArrayList; import java.util.List; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class Customer { @XmlAttribute private long id; private String name; private Address address; @XmlElement(name="phone-number") private List<PhoneNumber> phoneNumbers; public Customer() { phoneNumbers = new ArrayList<PhoneNumber>(); } }
<customer id="123"> <name>Jane Doe</name> <address> <city>Any Town</city> <street>1 A Street</street> </address> <phone-number> <type>work</type> <number>555-WORK</number> </phone-number> <phone-number> <type>cell</type> <number>555-CELL</number> </phone-number> </customer>We can reference the converter on the phoneNumbers property using @XStreamConverter.
package comparison; import java.util.ArrayList; import java.util.List; import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamAsAttribute; import com.thoughtworks.xstream.annotations.XStreamConverter; import com.thoughtworks.xstream.annotations.XStreamImplicit; @XStreamAlias("customer") public class Customer { @XmlAttribute private long id; private String name; private Address address; @XStreamImplicit(itemFieldName="phone-number") @XStreamConverter(PhoneNumberConverter.class) private List<PhoneNumber> phoneNumbers; public Customer() { phoneNumbers = new ArrayList<PhoneNumber>(); } }
The converter can be implemented as follows:
package comparison; import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; public class PhoneNumberConverter implements Converter { public boolean canConvert(Class clazz) { return PhoneNumber.class == clazz; } public void marshal(Object object, HierarchicalStreamWriter hsw, MarshallingContext mc) { PhoneNumber phoneNumber = (PhoneNumber) object; hsw.addAttribute("type", phoneNumber.getType()); hsw.setValue(phoneNumber.getNumber()); } public Object unmarshal(HierarchicalStreamReader hsr, UnmarshallingContext uc) { PhoneNumber phoneNumber = new PhoneNumber(); phoneNumber.setType(hsr.getAttribute("type")); phoneNumber.setNumber(hsr.getValue()); return phoneNumber; } }
JAXB
For JAXB we will use the @XmlAttribute and @XmlValue annotations on the PhoneNumber class.
package comparison; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlValue; public class PhoneNumber { @XmlAttribute private String type; @XmlValue private String number; }
XML Output:
The XML output is the same for both JAXB and XStream.
<customer id="123"> <name>Jane Doe</name> <address> <street>1 A Street</street> <city>Any Town</city> </address> <phone-number type="work">555-WORK</phone-number> <phone-number type="cell">555-CELL</phone-number> </customer>
package comparison.xstream; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.converters.reflection.FieldDictionary; import com.thoughtworks.xstream.converters.reflection.SortableFieldKeySorter; import com.thoughtworks.xstream.converters.reflection.Sun14ReflectionProvider; import com.thoughtworks.xstream.io.xml.QNameMap; import com.thoughtworks.xstream.io.xml.StaxDriver; import comparison.Address; import static comparison.Data.CUSTOMER; public class XStreamDemo { public static void main(String[] args) { QNameMap nsm = new QNameMap(); nsm.setDefaultNamespace("http://www.example.com"); StaxDriver staxDriver = new StaxDriver(nsm); SortableFieldKeySorter sorter = new SortableFieldKeySorter(); sorter.registerFieldOrder(Address.class, new String[] { "street", "city"}); FieldDictionary fieldDictionary = new FieldDictionary(sorter); Sun14ReflectionProvider reflectionProvider = new Sun14ReflectionProvider(fieldDictionary); XStream xstream = new XStream(reflectionProvider, staxDriver); xstream.autodetectAnnotations(true); xstream.toXML(CUSTOMER, System.out); } }
Note: With this change I lost XML formatting, the following was produced.
<customer xmlns="http://www.example.com" id="123"><name>Jane Doe</name><address><street>1 A Street</street><city>Any Town</city></address><phone-number type="work">555-WORK</phone-number><phone-number type="cell">555-CELL</phone-number></customer>
@XmlAccessorType(XmlAccessType.FIELD) @XmlSchema(namespace="http://www.example.com", elementFormDefault=XmlNsForm.QUALIFIED) package comparison; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlNsForm; import javax.xml.bind.annotation.XmlSchema;
The following XML was produced
<customer xmlns="http://www.example.com" id="123"> <name>Jane Doe</name> <address> <street>1 A Street</street> <city>Any Town</city> </address> <phone-number type="work">555-WORK</phone-number> <phone-number type="cell">555-CELL</phone-number> </customer>
Nicely done.
ReplyDeleteBlaise,
ReplyDeletethanks for this comprehensive summary, really great.
One addition where I personally found JAXB to be superior to xstream is when you apply model transformations (as opposed to simple type conversions).
I think that JAXB's XmlAdapter is much simpler to deal with than xstream's custom mappers. I often see XSLT being used with xstream instead, but than you're using an additional language (and one which many java developers find cumbersome).
Thanks again,
Wolfgang
Wolfgang,
ReplyDeleteI agree on XmlAdapter, it is my favourite JAXB feature. It was actually the topic of my first blog post XmlAdapter - JAXB's Secret Weapon.
-Blaise
Excellent post, also note that JAXB now comes bundled on JDK, so the use of XStream gets a bit unneeded if the xml to be marshaled/unmarshaled are simple enough
ReplyDeletesombriks,
ReplyDeleteIn this example JAXB handled the XML better than XStream. This was especially true WRT namespace handling. For more information on JAXB's namespace support see:
- JAXB & Namespaces
XStream does have the converter concept, but JAXB has the much more powerful XmlAdapter feature:
- XmlAdapter - JAXB's Secret Weapon
Plus since JAXB is a spec, individual implementations can offer their own extensions such as MOXy's XPath based mapping:
- XPath Based Mapping
- XPath Based Mapping - Geocode Example
JAXB is not only a standard part of Java SE 6, but the default binding layer for two Java EE Web Service standards JAX-WS & JAX-RS. JAXB is the enterprise Java binding layer.
-Blaise
Blaise,
ReplyDeleteI guess the XStream FAQ primarily just needs an update for JAXB 2.0 ;-)
My experience with XStream is that it's great for serializing/deserializing arbitrary object graphs, but it's very hard to make the xml comply to some given schema. JAXB is at times more heavy-weight, but much more powerful as well.
But both by 95% serve the same purpose. I even started a little adapter class that uses XStream as an JAXB implementation... it's yet not much more than a proof of concept, though:
https://messageapi.dev.java.net/source/browse/messageapi/trunk/adapter/src/main/java/com/oneandone/consumer/messageapi/xstream
One thing that annoys me, though, is that the JDK "reference implementation" does not seem to comply to the standard paragraph 8.5.4, which says that Maps have to be supported. MOXy does, but the RI does not... or am I getting something wrong?
-Rüdiger
Rüdiger,
ReplyDeleteThe XStream FAQ definitely needs to be updated for JAXB 2.0 :).
To be fair XStream has times when it is more heavy weight. This can be seen in this post:
- A field dictionary had to be created to control the order of elements.
- A converter need to be created to map an object to simple content.
- The driver had to be changed to apply namespaces.
WRT 95%:
- XStream cannot generate classes from XML Schema. There FAQ recommends using XMLBeans for this purpose.
- XStream cannot generate an XML schema from Java classes
- XStream is not a Web Service binding layer.
- XStream does not cover 100% of XML schema concepts.
- XStream cannot preserve the XML infoset.
Section 8.5.4 of the JAXB spec clearly states that java.util.Map (and its subtypes) must be supported. This is probably a bug in the reference implementation, you can report this here:
- https://jaxb.dev.java.net/issues/
Don't forgot that JAXB implementations are free to go beyond the specification. Below are some of the EclipseLink MOXy extensions:
- XPath base mapping
- XML metadata file
- JPA entity mapping support
-Blaise
It looks like XStream can map inheritance better than JAXB.
ReplyDeletehttp://www.natpryce.com/articles/000766.html
Can JAXB do the same?
Andrew,
ReplyDeleteI read the article "Mapping Inheritance Cleanly with XStream", and it demonstrates how to write a converter to represent multiple classes as the same XML element. The JAXB equivalent would be to write an XmlAdapter.
- XmlAdapter - JAXB's Secret Weapon
The following posts demonstrate how to easily represent object inheritance in JAXB by leveraging existing XML schema concepts:
- JAXB and Inheritance - Using the xsi:type Attribute
- JAXB and Inheritance - Using Substitution Groups
-Blaise
Nice post. I was really happy with XStream, but JAXB looks cool for those cases also.
ReplyDeleteBy the way, int the XML output, in XStram you can "map" the qualified name to an alias: xstream.alias("customer", Customer.class);
Nice post. I too was under the impression that to use JAXB, you needed to start out with a schema, generate the java classes, etc. Was this ever the case? Either way, the tutorial you just went through needs to be front and center on Oracle's JAXB main page. It's great to know that JAXB can handle the hard stuff, but it's more important to get the word out how easy it is to use JAXB for the easy stuff. I mean, come on, one of the alternate libraries was probably named "Simple" for a reason. :)
ReplyDeleteThanks Ken,
ReplyDeleteJAXB 1 required that you start with an XML schema and generate standard interfaces backed by vendor specific implementation classes.
JAXB 2 moved to POJOs with standard annotations, making the classes portable between JAXB implementations. But somehow the stigma still persisted. It could be because JAXB still offers a schema to Java compiler to generate classes from an XML schema as a convenience mechanism.
I have also writted a post comparing Simple and JAXB. For that example they are both easy to use. The difference is in all the extra feaures that JAXB implementations (Metro, MOXy, JaxMe, etc) have:
- http://bdoughan.blogspot.com/2010/10/how-does-jaxb-compare-to-simple.html
-Blaise
Blaise,
ReplyDeleteThis is a very informative blog. I'm trying to decide between XStream and JAXB. It was useful to see that you don't have to use an XML schema with JAXB. I'm not a fan of annotations. I just don't like to pollute my code with it. Personal taste...
You can configure XStream to do your second example by registering aliases. Can this be done in JAXB without annotations? Also, can the examples in JAXB be done without using annotations? Are they required?
Hi Manuel,
ReplyDeleteJAXB as defined in the specification (JSR-222) requires annotations. However individual implementations may offer extensions to this.
EclipseLink MOXy (I'm the tech lead)
We offer an XML representation of the metadata. An example of it can be seen here:
- Extending JAXB - Representing Metadata as XML
Metro JAXB (The reference implementation)
Can leverage Annox and JAXBIntroductions to get an XML representation of the metadata. With a few lines of code MOXy can also be adapted to work with these formats.
- http://jaxb.java.net/
Other JAXB implementations such as JaxMe may address the use case in other ways.
One of the advantages of JAXB is that it is a standard with multiple implementations. This avoids the vendor lockin you get with a library like XStream.
-Blaise
Interesting post. I am after XML serialization/deserialization of Java object tree. Is there a way to do this using JAXB without tinkering with XmlAdapter or explicit mappings?
ReplyDeleteBlaise,
ReplyDeleteExcellent post!
I wonder if you can recommend an approach for handling evoloving classes. Class A, version1 is used at first. Then some of the clients update to Class A version2 (which introduces a new field). But other clients do not upgrade yet. They have the Class A version1 on their classpath. They should be able to read the xml representation of Class A version2 (by just ignoring the new field).
What's the best way to accomplish that? Can JAXB 'ignore' fields if the class does not have them? Can XStream? I saw that XMT can be used to read version1 with version2 code. But I'm talking about reading version2 with version1 code.
Any help would be great.
Hi Alex,
ReplyDeleteJAXB can be used to marshal an object to XML without the use of any metadata. JAXB metadata only needs to be supplied to override the default behavior. For an example see:
- http://wiki.eclipse.org/EclipseLink/Examples/MOXy/GettingStarted/TheBasics
-Blaise
Hi Anonymous,
ReplyDeleteRegarding evolving classes, JAXB handles this case easily. When JAXB finds an element/attribute it does not recognize it is simply ignored.
From the XStream FAQ if XStream finds an element/attribute it does not recognize an exception is thrown:
"If a field is removed from the class, deserializing an old version that contains that field will cause an exception."
-Blaise
Hmm, I looked at it some time ago, but at the time Java 6 bundled jaxb could not do the following:
ReplyDelete- If an object tree I serialize/deserialize has fields of interface types JAXB would not do it OOB
- If a field is declared as base class, but is assigned a subclass jaxb marshall/unmarshall looses this
- If I have multiple fields in the object tree that point to the same object instance, after jaxb unmarshalling they will become two independent instances.
- Java proxy serialization another issue
Is there an easy way to address all this without creating adapters?
Hi Alex,
ReplyDeleteThe JAXB specification does not define behavior for interfaces, but this is handled in EclipseLink JAXB (MOXy):
- MOXy JAXB - Map Interfaces to XML
JAXB does support inheritance. You need to ensure that the JAXBContext is aware of the subclasses:
- JAXB and Inheritance - Using the xsi:type Attribute
- JAXB and Inheritance - Using Substitution Groups
To handle shared references you do need to supply JAXB metadata to handle this:
- JAXB and Shared References: @XmlID and @XmlIDREF
For proxy serialization, refer to the post about mapping to interfaces.
-Blaise
Hi, what about performance comparison?
ReplyDeleteHi byF,
ReplyDeleteI do not have a performance comparison for JAXB and XStream. JAXB should be faster since if offers and initialization stage where the metadata can be optimized before unmarshalling/marshalling is done.
-Blaise
Hi, Blaise,
ReplyDeleteHave you used Jaxb in a OSGI/bundle environment? Do you know if it is supported on Felix?
I am facing a weird problem where the same code executes fine in a standalone java project, but complains that it does not see @XmlRootElement when this code runs in a bundle (in Felix) when it really is there.
Thanks in advance!
Hi Xianguan,
ReplyDeleteMost of the work I have done with JAXB and OSGi has been with Equinox.
In your manifest you will need to ensure that you are importing all the JAXB packages. You will also need to ensure that JAXB is available as a bundle. GlassFish provides one, and one is available in EclipseLink.
EclipseLink JAXB (MOXy) is also available as an OSGi bundle and can be obtained from the download site:
- http://www.eclipse.org/eclipselink/downloads/
-Blaise
thanks for the answer, Blaise. Really appreciate it.
ReplyDeleteDoes Xstream support multiple namespaces...??
ReplyDeleteWe can always set QnameMap.setDefaultNamespace() to set a default namesapce for the entire xml..but vat if I have to use more than one namespace in the same xml?
For specifics on how/if XStream handles multiple namespaces you will need to contact someone on that project.
ReplyDeleteJAXB implementations (Metro, EclipseLink MOXy, Apache JaxMe) have an elegant solution for this:
- JAXB & Namespaces
-Blaise
Hi there - Great information. WIth respect to speed, in my own testing I've seen JAXB outperform XStream on the order of 5 to 1. I'd be interested how it shook out with other peoples' use cases.
ReplyDeleteBlaZe, you are the man. This page helped me tremendously decide between JAXB and XStream. It has so much useful information (annotations esp.). I could totally build my marshalling strategy without creating any XSD etc...beautiful.
ReplyDeleteHi Amit,
ReplyDeleteI hope that means you chose JAXB :).
-Blaise
Hello Blaise
ReplyDeletePlease, as I implement the @xmlInverseReference of JAXB in XStream ?
Thanks
Hi Odete,
ReplyDeleteI am not aware if XStream has an equivalent of @XmlInverseReference. I'm the EclipseLink JAXB (MOXy) lead, and am more than happy to help you with MOXy (or any JAXB implementation), but I can't spend any cycles helping with XStream.
-Blaise
Hello Blaise,
ReplyDeleteIs there any possibility in JAXB to marshall all Object of a given ClassZ (e.g. the Date or a CustomClass) depending on some dynamic data (e.g date format, which changes for each object instance)?
With @XmlAdapter I will have to annotate all properties of type ClassZ with @XmlAdapter and constructing and adapter supposes other 2(or 3) classes.
The following may help:
ReplyDelete1. You can use the @XmlSchemaType at the field/property level to specify the XML representation of data:
- JAXB and Date/Time Properties
2. You can register an XmlAdapter for all classes of a particular type at the package level:
- JAXB and Joda-Time: Dates and Times
3. You can set initialized instances of XmlAdapter on Marshaller and Unmarshaller. The following answer I gave to a question on Stack Overflow demonstrates this concept in action:
- http://stackoverflow.com/questions/7278406/serialize-a-jaxb-object-via-its-id/7285517#7285517
-Blaise
Blaise,
ReplyDeleteI have been using JAXB (in a Jersey Restful application) and so far I have been quite happy ! I just have this new requirement come up where I need to convert a List of HashMaps to xml. Each map contains a key value pairs of a database row (so for example the list will have 2 hashmaps for 2 rows {{FNAME=John, LNAME=Smith, AGE=35},{firstName=Mary, lastName=Maria, age=45}}.
I have written a MapAdapter based on your post http://blog.bdoughan.com/2010/07/xmladapter-jaxbs-secret-weapon.html but I don't quite like the xml I get. I get this
JOHN
35
SMITH
MARY
45
MARIA
but I would like this instead
ALEX
42
TRUMP
...
....
I haven't been able to do that in JAXB but I have been able to with XStream custom converters!!!! But for just this one case, I don't want to start XSTream as well. Can I achieve the desired result with JAXB ?
Hi,
DeleteIt appears as though your XML samples did not survive the formatting restrictions of the comment section. Would you mind sending me the details through my contact page?
- http://blog.bdoughan.com/p/contact_01.html
-Blaise
Hi Blaise,
ReplyDeleteExcellent blog!! Your blogs have been quite informative and helpful!!
Is there a way to suppress certain field names in JAXB or Moxy? Comparable to what XStream's addImplicitCollection achieves?
Thanks!
Hi,
DeleteI'm happy to hear you are enjoying the blog and are finding it useful.
XStream will include a wrapper element for the collection and then you can use addImplicitCollection to remove it. JAXB (JSR-222) implementations by default do not add a wrapper element unless you use @XmlElementWrapper:
- JAXB & Collection Properties
Also if there is a property you want to be excluded from the XML representation you can use @XmlTransient, or you can use @XmlAccessorType(XmlAccessType.NONE) so that only explicitly annotated properties are converted to/from XML:
- Using JAXB's @XmlAccessorType to Configure Field or Property Access
-Blaise
Hi Blaise,
ReplyDeleteThis is really good blog with examples.
I would like save/retrieve some user defined objects into a file.
I don't know really which one should I use?
I initially thought of using XMLEncoder and XMLDecoder. I heard that it is not thread safe and it doesn't support some types like Enum etc.
I am looking at JAXB, Is JAXB heavy for this?
Are there any less weight solutions for this requirement.
JAXB is not a "heavy weight" solution. An implementation is included in the JRE starting with Java SE 6. JAXB is configuration by exception meaning you only need to add annotations to your domain model where you want to override the default mapping behaviour.
Delete-Blaise
Hi Blaise,
ReplyDeleteNice article.
Any thoughts on using Jibx instead of JAXB?
My requirement is simple to create the XML from POJO and reverse i.e. POJO from XML.
What would we your suggestion for this?
Tahnks
AC
Hi AC,
DeleteI'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group, so I won't even pretend to be impartial wrt that question.
JAXB is the standard for XML binding with multiple open source implementations. Because it is the standard an implementation has been included in Java SE 6. It is the standard binding layer for JAX-WS (SOAP based services) and JAX-RS (RESTful services) meaning JAXB will work in any Java EE application server (WebLogic, GlassFish, WebSphere, JBoss, etc).
There are risks with using proprietary XML binding solutions in that you don't know when they will disappear. XStream for example didn't have a release between December 2008 and August 2011. And XMLBeans hasn't had a release since December 2009. JAXB is part of Java and will continue to evolve along with it.
You may want to check out the following question on Quora:
- What, if any, are the advantages of JiBX over JAXB?
-Blaise
Nice article.
ReplyDeleteAfter reading your article and some other article I am more incline toward the JAXB compare to other XML Binding technology available.
JAXB can be used for both Marshalling and Unmarshalling, Correct?
Can we use your approach mentioned above if we directly want to start from POJO to create XML?
Thanks
Jha
Hi Jha,
DeleteYes JAXB (JSR-222) can be used for both Marshalling (object-to-XML), and unmarshalling (XML-to-object). You can definitely start with POJO and create XML. You might find the following tutorial helpful:
- http://wiki.eclipse.org/EclipseLink/Examples/MOXy/GettingStarted
-Blaise
Hi Blaise,
DeleteAny thoughts on Performance of JAXB? What I mean is, Is it OK to use in J2EE app?
Any issue with MultiThreading? I read somewhere that JAXBContext class is thread safe and Marshal/Unmarshal classes or not?
I know there shouldn't be any issue as it's build for keeping WebServices in mind but just wanted to know your opinion.
What is your thought on this?
Thanks
Jha
Hi Jha,
DeleteJAXB (JSR-222) is the default binding layer for both JAX-WS (SOAP) and JAX-RS (RESTful) Web Services. This means that a JAXB implementation is included with every Java EE application server and is used by countless Java EE applications.
- EclipseLink MOXy is the JAXB Provider in WebLogic Server 12c
- Creating a RESTful Web Service - Part 1/5
JAXBContext is thread safe and can be shared, Marshaller/Unmarshaller and not thread safe (but are light-weight). When JAXB is used in a JAX-WS or JAX-RS application all this management is done for you.
-Blaise
Hi Blaise,
ReplyDeleteThanks for your reply.
Depending upon structure of XML, Do I need to create the Classes also?
Also, Is it possible in JAxb to create the dynamic Element? For example
Rest all the tag has the name based on what you define in POJO attribute. What about if the tag name it self is dynamic?
Thanks
Jha
Hi Jha,
DeleteSome content was lost from your comment due to the limitations of the comment section. Feel free to send me a message through my "Contact Me" link at the top of this page.
-Blaise
I like JAXB in that it's mature, well-documented, and fast. It's lack of support for immutable objects (no final, default ctor required) and required getters/setters make it far more verbose than XStream for every case I've run across. I wish it wasn't so, I find XStream very slow. But, XStream lets my code be my code, no need to mutate it to fit a persistence library. Also, I've seen jaxb just silently fail too often when ingesting XML and null fields abound.
ReplyDeleteHi Jason,
DeleteThe ability to support multi-arg constructors would definitely be a welcome addition to JAXB (JSR-222). As a workaround I suggest using XmlAdapters to handle this use case.
- JAXB and Immutable Objects
JAXB does not require that you have get/set methods. Simply specify @XmlAccessorType(XmlAccessType.FIELD) and JAXB will use your fields.
- Using JAXB's @XmlAccessorType to Configure Field or Property Access
JAXB doesn't really silently fail. By default it is very tolerant of poorly formed XML. If you want to see where the errors occur simply set a ValidationEventHandler on your Unmarshaller.
XStream requires that your Java model pretty closely resemble the XML structure. If you want true separation check out the path based mapping we have in EclipseLink JAXB (MOXy)
- XPath Based Mapping - Geocode Example
-Blaise
Thanks for the reply! I've had to switch over to JAXB due to XStream just performing far too slowly (60 seconds vs 500 ms) for my JNLP app (something to do with class loading/scanning I'm sure - no compression on my war/jar though).
DeleteI'll definitely check out MOXy :) I do hope JAXB gets multi(or single!)-arg ctor support. Writing an adapter for all these classes isn't feasible. I've set the ValidationEventHandler up and that works nicely. Thanks!
One more question (ha, as if there is ever just one more!). In XStream I was able to, using different instances of XStream, write out the same attributes with a different name. For instance, I have a class called "DistanceProperty" with a "private double distance". In one use case I want the attribute to be labelled "distance" in XML in another I want it to be labelled "height". I googled high and low but it looks like there isn't out-of-the-box support for this with JAXB. I'd like to set the attribute name at runtime somehow. Is this possible?
ReplyDeleteHi Jason,
DeleteIf you are using EclipseLink MOXy as your JAXB provider you can a mapping file to accomplish this use case:
- Extended JAXB - Representing Metadata as XML
- Mapping Objects to Multiple XML Schemas - Weather Example
-Blaise
Great article. Nicely compares JAXB and XStream.
ReplyDeleteHello.. In JAXB I dont find a way to serialize a dynamic Object. I would choose xstream then.
ReplyDeleteDepends what you mean by a dynamic Object. EclipseLink JAXB (MOXy) offers a lot of useful extensions:
Deletejava.lang.reflect.Proxy Mechanism
MOXy can map to interfaces where the underlying implementation is handled by Java's reflection APIs:
- MOXy JAXB - Map Interfaces to XML
Extensible Objects
MOXy supports virtual properties on static models. This is very useful when building multi-tenant applications:
- MOXy Extensible Models - Multi-Tenant Example
No Domain Classes Whatsoever
With MOXy's Dynamic JAXB you don't need any domain classes at all. This can be bootstrapped from an XML schema or MOXy's external mapping document. Below is an example.
- MOXy's Object Graphs & Dynamic JAXB
Great Job!! Enjoyed the reading.
ReplyDelete