This post is about my initial attempts to get Jersey and Moxy working the way I want. See part 3 for the full analysis of why I was having trouble and my eventual solution.
Jersey is an implementation of JAX-RS, the Java standard for REST web services. To this you can add JAXB, which allows your REST services to use declarative metadata to map domain objects to a wire format, typically either JSON or XML.
The downside of the JAXB reference implementation is that the metadata is expressed as annotations on the domain model. Personally, I think that this kind of mapping is definitely a cross-cutting concern and is to be kept out of the domain model source code at all costs. Moxy comes to the rescue! You can plug Moxy in as your JAXB provider, replacing the reference implementation entirely, and Moxy supports externalizing the mapping metadata to an XML file. So, how to get it working?
The Jersey documentation is very simple and to the point. To use Moxy for JSON binding, just place the appropriate jar on the classpath – see instructions. You can then use a custom JAXB context resolver to set Moxy up with a mapping file, and away you go.
The documentation for using Moxy for XML binding is even simpler. The simplest way is:
… use the standard JAXB mechanisms to define the JAXBContextFactory from which a JAXBContext instance would be obtained (for more on this topic, read JavaDoc on JAXBContext)…
That boils down to putting a jaxb.properties file alongside your model, as documented here.
The alternative mechanism is to manually configure Jersey, registering and configuring the MoxyXmlFeature.
However, neither mechanism actually works. It appears that, while Jerseys Moxy JSON feature registers a MessageBodyWriter to handle JSON writes, the XML feature does not do anything of the sort, instead falling back onto Jersey’s default XML MessageBodyWriter. Unfortunately, the default XML writer appears to completely ignore any registered ContextResolvers you’ve registered. Thus, while you can marshall a completely unannotated domain object to JSON, if you try to marshall the same object to XML you’ll get an exception.
See https://bitbucket.org/jmetcher/resttest for a small project showing Jersey setup strictly according to the documentation. Check out the master branch for the basic setup.
The solution is to register your own custom MessageBodyWriter, as described here. Sadly, as far as I can tell this is 100% missing from the documentation. Check out the MBW branch of the above project to see what it looks like with the recommended MessageBodyWriter approach. Unfortunately, this doesn’t work either. It appears that, contrary to about a dozen examples dotted around the web, injection of the ContextResolver does not work, as you’ll see by the NPE if you run that code.