Monday, February 14, 2011

Embedding XML within JAXB Objects

If a JAXB object contains a String element of un-parsed XML, it can be a little tricky to represent.

First, you need to stop JAXB from attempting to unmarshal the embedded XML. This is done by intercepting the call to unmarshal the element in order to gain access to raw DOM node that JAXB has constructed. From here, it's simply a matter of converting the node into a String, which is written to a field. As you'd expect, for marshalling you need to do the opposite, turning the XML String into a DOM node. However, you must wrap your XML in a dummy, root tag prior to returning it. For example:

The above code utilizes a utility class to wrap basic W3C XML parsing. It's not doing anything special, but, if you're curious, the source is available here.

Your code should now be able to marshal/unmarshal embedded XML to a String field. This works fine and dandy as long as your XML does not contain namespaces. Namespaces pose a couple of problems. First, if the namespaces aren't declared at the root of the document, JAXB will blowup while parsing. Second, if there is a declared, but unused, namespace, JAXB will not preserve it.

The first problem can be solved by scanning your XML prior to unmarshalling, and attaching any namespace declarations that are discovered to the root node. This can be done in a variety of ways. I have a solution that's based on DOM4J that's available in my commons project here.

The second issue is really only a problem if something else in your application is depending on having certain namespaces defined. Unfortunately, JAXB does not have a simple flag to toggle between behaviors, but there is a way to preserve unused namespaces. You have to create a SAXSource, set a couple of namespace related flags on it, and feed it to your unmarshaller. It should look something like this:

JAXB has more than its fair share of quirks, but at least you can force it to do just about anything.

Saturday, February 5, 2011

JAXB Packing Bug

It appears to be a little known fact that Java 1.6 includes a JAXB implementation -- no need for external libraries. However, the version that's currently bundled has an annoying bug related to how it packs lists. Let's say that your XML contains a list of items that you'd like to unmarshal and represent internally as a map. One might thing that all you'd have to do is the following:

And what you'll end up with is an empty map. Here's what happened:
  1. Something.getList() is called and returns null.
  2. JAXB creates a new ArrayList, and passes it to Something.setList(). At this point there is nothing in the list.
  3. JAXB unmarshals all of the items, appending them to the list.
I'm sure you see the problem. Fortunately, there is a solution. The latest version of JAXB (available here) has fixed the problem. It follows the same flow described above, but with one additional step. It calls Something.setList() a second time after populating the list.

Upgrading your version of JAXB is a two step process.
  1. Put the new jars on your classpath or install them to your Maven repository.
  2. Prior to unmarshalling, call: System.setProperty("javax.xml.bind.JAXBContext", "com.sun.xml.bind.v2.ContextFactory");

Wednesday, February 2, 2011

Domain Model Marshalling

I have been attempting to marshal/unmarshal arbitrary parts of a complex domain model, and was unable to find an adequate solution for the cyclic reference problem anywhere.

Failed solutions:

  • JAXB's Unofficial Guide has some good suggestions, but they require a fixed parent-child relationship.
  • Castor handles cycles out of the box, but there's data loss in that it refuses to preserve back references.
  • This guy has an interesting solution that handles marshalling extremely well, but, at least just going off the code posted, unmashalling will never work.

Here's my hacky, yet functional, solution:

First, define an abstract class as follows:

All of your domain objects must extend this class. It provides the IDs that will essentially be used as surrogate keys when your objects are marshalled. As you go through your classes extending Marshallable, annotate all of your properties with @XmlIDREF. For example:

Now, when JAXB marshals these objects it's going to simply insert references, which solves the cycle problem. However, it creates a new containment issue. If you were to marshal your objects now, you'd generate a well formed XML tree full of references that point nowhere. I'm not convinced this is the best solution, but here's my crack at the issue of containment.

You'll need to wrap every object that you marshal in this wrapper. It flattens the entire graph so that ever instance of Marshallable is a sibling.

Here's an example marshal:

Here's an example unmarshal:

It isn't pretty, but that should do the trick.