jmetcher
jmetcher

Reputation: 98

Jersey + Moxy + JAXB - how to marshal XML without annotations

In http://blog.bdoughan.com/2013/06/moxy-is-new-default-json-binding.html about halfway down there's a heading "Customizing the JSON-Binding". How do you similarly customize the XML binding?

There seem to be fundamental differences between the way Jersey handles Moxy JSON binding and the XML equivalent. If I follow the instructions in the Jersey documentation for creating a custom JAXBContext resolver to configure Moxy's mapping file, that resolver fires in the JSON case but not in the XML case. See https://bitbucket.org/jmetcher/resttest/ for a very small project demonstrating this.

I have the correct jaxb.properties file in place, and I'm building with the jersey-media-moxy module. I can get the identical Moxy JAXB setup working in standalone mode, I just can't get Jersey to take any notice of it.

The debugging I've done indicates that the only way to get this to work is to create a custom MessageBodyWriter. The jersey-media-moxy module registers a JSON MessageBodyWriter which will then invoke any registered ContextResolvers. It does not register an equivalent MessageBodyWriter for XML, and Jersey's default MBW's seem to completely ignore registered ContextResolvers.

Howver, the fact that the need to create a custom MessageBodyWriter is completely missing from the docs and nearly every example seems to indicate that I'm missing something fundamental.

I'd provide links to more info but I don't seem to have the rep to do much at all on SO.

EDIT: More info in response to comments:

Moxy is certainly being picked up as the JAXB provider. I can see this in the debugger.

Jersey version is 2.9, EclipseLink version is 2.5. Java 7.

The ContextResolver approach works fine for JSON. So does the approach of registering MoxyXMLFeature in an Application class. In both cases, the correct context configured with the right mapping file is used. In the XML case, it seems that Jersey never even attempts to create a context.

IF, however, I add an @XmlRootElement annotation to the class I'm trying to marshal, it all works. Even with no other annotations, the class can be marshaled to both XML and JSON according to the oxm mapping file. I've updated the bitbucket project to show this.

So, I can work around the issue either by creating a custom MBW or providing an annotated root class. I guess at this point I'm to work out what the best or recommended approach would be so I can log a documentation patch.

Upvotes: 2

Views: 2715

Answers (2)

jmetcher
jmetcher

Reputation: 98

It is indeed the case that the only way to marshal an unannotated domain model to XML using Jersey + Moxy is to register your own provider (aka MessageBodyWriter/MessageBodyReader).

Marshalling an unannotated model is supported Moxy functionality. However, Jersey's default JAXB providers mask this functionality by requiring that the model is annotated before they will pass off control to Moxy. The JSON case is implemented differently and does not have this restriction.

See http://lagod.id.au/blog/?p=472 for a fully worked example.

Doc bug reported: https://java.net/jira/browse/JERSEY-2552

Upvotes: 1

bdoughan
bdoughan

Reputation: 149017

To have Jersey pick up MOXy as the JAXB provider, you simply need to add the jaxb.properties file with the correct entry (see: http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html) in the same package as your domain model. In the case of JAX-RS if a ContextResolver is not specified this package needs to be the one that corresponds to the parameter to, or return type from from the method in your service mapped with JAX-RS annotations.

Note:

There was a bug in an earlier version of Jersey that prevented MOXy from being picked up as the default JAXB provider, in that case you could:

  1. Upgrade to a newer version of Jersey.
  2. Create a ContextResolver to return an instance of a MOXy JAXBContext (see: http://blog.bdoughan.com/2011/04/moxys-xml-metadata-in-jax-rs-service.html)

In the case of the ContextResolver you could use code to directly create the MOXy JAXBContext instead of leveraging a jaxb.properites file. Refer to option #2 in the answer I linked to below:

Upvotes: 1

Related Questions