Skip to main content

Mapping the same POJOs to different XML representations in JAXB

Posted by kohsuke on January 25, 2007 at 10:41 AM PST

People occasionally need to be able to use the same set of POJOs to match different XML representations. There's a large degree of difference in the complexity — some people just need to be able to produce more or less the same XML files except that they differ in namespaces (this is common when you use namespaces for versioning); some people need to "hide" certain properties in one XML representation but use all properties in another (this happens in versioning as well as access control); and still some others need to be able to handle drastically different-looking yet semantically-similar XMLs (think of RSS vs ATOM.)

I'm going to examine a few possible approaches to this problem today.

One approach that I often recommend is to write SAX filter or StAX filter. SAX version is generally easier to write, and the added bonus is that you can use the same technique both for marshalling and unmarshalling.

Inside the filter implementation, you write the logic to adjust the XML into the "canonical" form that JAXB will understand. For example, changing namespace URIs, adding/removing attributes would be pretty easy with this. This would work pretty efficiently, too, but of course this approach is not a good fit if you need to alter XML representation in a significant way.

You can then set up an XML pipeline so that infoset flows from parser > your filter > unmarshaller. See this for an example.

Another similar approach is to use XSLT. In essence, it's the same technique as the previous approach, except that you can describe more complicated transformation relatively easily. The downside is that for XSLT to work the entire document needs to be first read into memory, so it adds a considerable overhead.

Both of those approachs require you think in terms of XML infoset, which could be a good thing or a bad thing depending on your particular situation.

The third approach is to think in terms of Java objects and more specifically JAXB annotations on them. Normally, the JAXB RI reads JAXB annotations by using reflection, meaning they are loaded from class files. But this behavior is actually pluggable, so the RI allows you to read annotations from anywhere else. You can even programatically synthesize JAXB annotations on-the-fly from other information, and feed that into JAXB. There has been a few discussion of this in the forum and the mailing list.

One useful application of this could be to define your annotation that "hides" a JAXB property. Your AnnotationReader could be mostly just a pass-through to RuntimeInlineAnnotationReader, except that it filters out all the JAXB annotations if your custom annotation is present. So for example, you can write something like:

import org.acme.FilterOut; // your custom annotation
class MyBean {
  @XmlElement
  String abc; // this property always visible
  @XmlElement
  @FilterOut("profile1")
  String def; // this property gets filtered out
}

And your filter annotation reader will recognize @FilterOut and hides @XmlElement (and instead pass @XmlTransient to JAXB), which will cause JAXB to ignore this property. You can create multiple JAXBContexts by using a differently configured filter in this way.

A bit more ambitious approach is started by Lexi as the annox project — it attempts to allow Java annotations (not just JAXB annotations) to be written in an XML file. Then he can write a simple adapter AnnotationReader to read annotations from there. You can then put all your JAXB annotations on external XML files, and you can maintain multiple sets of those for different bindings. It looks like the effort is stalled however, so if you are interested in this, please write to Lexi and encourage him :-)

A further ambitious approach could synthesize the complete JAXB annotations programatically at runtime from other source, like, JPA annotations.

Related Topics >>