In an earlier post I explained how to avoid parallel JAXB2/Jackson annotations when supporting both XML and JSON web service endpoints. Basically the idea was to configure the Jackson ObjectMapper to understand JAXB2 annotations.
The problem
One of the things that was a little unsatisfactory about that post was that I was using views to generate the XML and JSON representations. We can do that, of course, but a more direct approach to generating the desired data payloads is to use @ResponseBody in conjunction with Spring’s HttpMessageConverters. The idea here is that handler methods simply return the object to be mapped (whether to XML or to JSON), and then HTTP message converters sitting on the app context map the object to XML or JSON. Correspondingly, there are HTTP message converters for both JAXB2 and Jackson (among several others). I say this is more direct because there’s no need to involve a model or a view at all: the controller simply returns the object and the converters do the rest.
In Spring 3.0 this was somewhat challenging to pull off, because both the JAXB2 message converter and the Jackson message converter are able to map the object, and so whichever message converter appears first in the list (the JAXB2 converter, it seems) would always map the object. So we ended up either having to treat JSON as a special case (invoke the ObjectMapper directly), or else just use views after all.
In Spring 3.1 things are a lot better: we can use the @ResponseBody and HTTP message converter approach quite cleanly, owing to an enhancement to @RequestMapping and also to an enhancement to the <mvc:annotation-driven> configuration.
Let’s see how it works.
Implementing the controller
We’ll look at the controller code first:
@RequestMapping(
value = "/{id}.json",
method = RequestMethod.GET,
produces = "application/json")
@ResponseBody
public Person getDetailsAsJson(@PathVariable Long id) {
return personRepo.findOne(id);
}
@RequestMapping(
value = "/{id}.xml",
method = RequestMethod.GET,
produces = "application/xml")
@ResponseBody
public Person getDetailsAsXml(@PathVariable Long id) {
return personRepo.findOne(id);
}
To use the @ResponseBody approach, we obviously need to annotate the handler methods with that annotation, so that’s what we’ve done here. The other thing we do here is return the actual entity (in this case, a Person) from the method instead of returning a logical view name.
We’ve also specified the extension (either .json or .xml) in the value to route requests correctly.
So far, everything we've described was available in Spring 3.0. But notice the new produces element, introduced with Spring 3.1, in the @RequestMapping annotation. This element has two effects. First, it excludes requests with Accepts headers incompatible with the specified media type. Second, it ensures that the generated response is consistent with the specified media type. It’s this second effect that we care about, because this is what allows Spring to figure out which HTTP message converter to use, even when we’re using JAXB2 annotations for both XML and JSON mapping.
Configuration
We need some configuration too. Here are the relevant bits. Be sure you’re using Spring 3.1, that you’ve declared the oxm and mvc namespaces, etc.
<oxm:jaxb2-marshaller id="marshaller">
<oxm:class-to-be-bound name="org.skydingo.skybase.model.Person" />
</oxm:jaxb2-marshaller>
<bean id="jaxbAnnIntrospector" class="org.codehaus.jackson.xc.JaxbAnnotationIntrospector" />
<bean id="jacksonObjectMapper" class="org.codehaus.jackson.map.ObjectMapper">
<property name="serializationConfig.annotationIntrospector" ref="jaxbAnnIntrospector" />
<property name="deserializationConfig.annotationIntrospector" ref="jaxbAnnIntrospector" />
</bean>
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"
p:objectMapper-ref="jacksonObjectMapper" />
</mvc:message-converters>
</mvc:annotation-driven>
The JAXB2 marshaller and Jackson ObjectMapper are the same as they were in my earlier post. The thing that’s different is the <mvc:annotation-driven> definition, and specifically, my inclusion of the new Spring 3.1 <mvc:message-converters> configuration. This allows us to define converters that override the defaults. Here I want to override the default Jackson converter with one that knows about my JAXB2-enabled ObjectMapper.
You don’t need to include XML or JSON views anymore. If you don’t have anything other than the normal JSP view, you can probably get rid of the ContentNegotiatingViewResolver entirely.
The end result
The result is that we can now generate XML and JSON payloads in a simple and consistent fashion. There’s no more need for models and views here (at least with respect to generating XML and JSON), and there’s no need to invoke ObjectMappers directly or anything like that.

By Supporting XML and JSON web service endpoints... | Web Services | Syngu February 22, 2012 - 11:43 pm
[...] Shows how to use Spring 3.1 enhancements to overcome some challenges when trying to implement RESTful services in a clean way. Web Services Read the original post on DZone… [...]
By madytyoo February 23, 2012 - 5:29 am
Very useful, thanks for sharing.
Madytyoo
By pankajtandon February 23, 2012 - 2:30 pm
I’ve been looking for this clarification for the past week! I just couldn’t figure out which messageConverter would be used if both are declared.
Thanks for the excellent post!
By Willie Wheeler February 23, 2012 - 8:56 pm
You’re very welcome–glad you found it useful.
By pankajtandon February 24, 2012 - 8:53 am
Another point to note is that in Spring 3.1, not only are we allowed to specify messageConverters inside of the mvc:annnotion-driven element, we are *requierd* to!
I found this out the hard way when I determined that if I declared my converters in a list to RequestMappingHandlerAdapter
<bean class=”org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter”>
<property name=”messageConverters”>
<util:list id=”beanList”>
<ref bean=”stringHttpMessageConverter”/>
<ref bean=”marshallingHttpMessageConverter”/>
</util:list>
</property>
</bean>
AND
I specified
<mvc:annotation-driven />
.. the messageConverters made available to AbstractMessageConverterMethodProcessor is the list of converters specified by the mvc:annotation-driven. The ones defined explicitly in the adapter are ignored.
So…. IFF mvc:annotation-driven is used AND a different converter is needed (other than what the namespace configures), then we MUST use the nested syntax offered by the 3.1 namespace. Else, don’t use the namespace at all and use the adapter.
Pankaj
By DanielSawano February 24, 2012 - 3:55 pm
I think it could be worth mentioning that one very nice alternative is to let the Accept header in the client request control wether the output should be JSON or XML. That way you could still use the same URL and there is no need for any extra configuration. Just an @XmlRootElement on your POJO.
By Willie Wheeler February 24, 2012 - 4:20 pm
Great point Daniel. In my particular case, I’m interested in making it easy for people to see the payload in the browser, where different browsers send different Accept headers. But if there’s no such requirement, then the Accept header is probably even more elegant than extensions.
By Willie Wheeler April 27, 2012 - 12:02 pm
By the way, just saw this:
http://software.sawano.se/2012/03/combining-json-and-xml-in-restful-web.html
Nice post.
By Daniel Sawano May 12, 2012 - 1:39 pm
Thank you Willie! Glad you liked it.
By Eugen Paraschiv February 25, 2012 - 3:01 pm
I have a quick question about the request mappings. Since this subject maps right on the concepts of REST, I was wondering why you chose to add the mime type in the request mapping directly, instead of letting the client choose based on the Accept Header. In a RESTful architecture, there would be a single Resource with a single URI, which would be served in different Representations, based on the request (Accept headers), instead of having 2 different URIs for the 2 representations of the same Resource.
Very useful info,
Thanks.
Eugen.
By Willie Wheeler February 25, 2012 - 9:16 pm
Hey Eugen, good to see you again. The answer is in my response above to Daniel. Basically I’m diverging from the purist approach because I want the XML and JSON representations to be visible in the web browser should the user open them there. If there were a way to specify the Accept header value in the link then that would be great, but alas, there isn’t.
By Joseph March 10, 2012 - 10:22 am
Thanks a lot for this example Willie, but I have yet another question/concern. In your spring config you’re having to use the namespace to explicitly configure the domain object class (or classes) that you need for spring to transform to XML in your controller methods.
My goal is to not use any additional oxm config. All I want to do is use the standard config (no sub-elements). Also have a single controller method for the resource and let the client submit an Accept header for which format of the response they want.
Mind you, I’ve already done this with Spring MVC 3.0, but my problem is that if I place @XmlRootElement at the top of any of my domain classes, the objects of that class get serialized as XML *IF* I don’t specify a “application/json” Accept header. If I simply comment out the @XmlRootElement, then the default format becomes JSON. This is really annoying.
I’m wondering if you know of a way in Spring 3.1 (with its new options) to make JSON the default serialization mechanism, EVEN IF a domain class is annotated with @XmlRootElement. So if client doesn’t send an Accept header, the controller simply serializes the response in JSON. But if client does send Accept=application/xml, then XML would be returned.
Thanks in advance.
-Jac
By Willie Wheeler March 10, 2012 - 2:29 pm
Hi Jac (Joseph?),
I’m not totally sure that I’m understanding your question(s), but let me give it a shot.
First, to the question about not having to use additional configuration to explicitly configure domain object classes–I assume you are talking about the <oxm:class-to-be-bound> definitions here. See http://springinpractice.com/2011/12/29/its-back-the-classpathscanningjaxb2marshaller/ for a way to avoid this.
As far as making JSON the default instead of XML, there is something you can try, though I haven’t myself tried it. Maybe you can control the order by providing the HTTP message converters in the desired order in the <mvc:message-converters> definition. You might need to set the register-defaults attribute false to avoid having the default message converters influencing things.
Anyway, give that a try and let us know if it works. :-)
Willie
By Joseph March 11, 2012 - 7:16 pm
Let me see if I can more succinct…
In Spring 3.0 I had to do very little in the way of configuration to get the exact same controller method to return both JSON and XML format of my response object using @ResponseBody.
I put 2 lines in myapp-servlet.xml:
I put @ResponseBody in my controller method
I put @XmlRootElement at the top of my response object.
That’s it. With just the above if I set Accept=application/json, I get JSON. If I set it to application/xml, I get XML.
The only annoying thing about this setup is that if I don’t specify an Accept header, the default serialized form is XML. There seems to be no way (that I’ve found) to tell Spring MVC to make the default JSON, so if no Accept is set, then JSON is returned.
What I was asking you in my earlier reply is this: Is there anything in Spring 3.1 that lets me specify as little config as above, yet allow me to set the default format to JSON?
Hope this is a bit more clear. Thanks again for your help. Your post has been very helpful.
-Jac
By Joseph March 11, 2012 - 7:42 pm
Oh BTW, I’m very interested in Spring 3.1′s “no-xml-config” ability. I’m trying to get rid of the myapp-servlet.xml.
I’ve created this class:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter
Obviously I had to put the following in my web.xml:
contextClass
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
contextConfigLocation
app.main.web
So I assume from your last reply that I should now take a look at modifying the order of the message converters in the over-ridden configureMessageConverters (List<HttpMessageConverter> converters)?
Thanks again.
-Jac
By Willie Wheeler March 15, 2012 - 7:40 am
Reordering the message converters is just a guess on my part–I haven’t actually looked into it. But yes, that’s what I’d try first. I’d be interested to hear if that works, or if there’s a better way to do it.
By Joseph March 25, 2012 - 11:01 pm
Well I finally got something figured out with this whole thing.
At first I tried extending my WebConfig class (as I said, I’m trying to use all-Java config, no XML) from WebMvcConfigurerAdapter with @EnableWebMvc annotation. Well, even though it’s got the method configureMessageConverters() I wasn’t able to modify its default behavior in any way.
I tried configuring message converters in every order possible. Nope, it turns out once you specify @EnableWebMvc, you lose control. If you annotate any of your POJOs with @XmlRootElement, all of a sudden XML becomes the default format when returning them with @ResponseBody. That’s a very odd choice by the Spring guys. Of course, you can remove @XmlRootElement to get default format to return back to JSON, but from that point on your client’s requests with Accept=application/xml will be met with 406 NOT_ACCEPTABLE.
Ok, so I was left with only one last option…
@Configuration
public class WebConfig extends WebMvcConfigurationSupport
…and in the configureMessageConverters():
converters.add (new Jaxb2RootElementHttpMessageConverter ());
converters.add (new MappingJacksonHttpMessageConverter ());
Notice 2 changes…. I now extend from WebMvcConfigurationSupport, and of course, no @EnableWebMvc.
Then in my controller …
@RequestMapping (value=”/{userId}”, method = RequestMethod.GET,
produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
public @ResponseBody WebApiResponse getUser (@PathVariable String userId)
With the above, when I make a request to:
GET /myapp/users/{userId}
(no Accept header)
I get back JSON by default! Yipee!!! And I still have both my WebApiResponse and my User class annotated with @XmlRootElement. So when I simply pass in Accept=application/xml header…. violah! XML comes back.
And BTW, what controls which format is the default when no Accept header is specified? The order you define the “produces” attr on your controller method. Notice I specified JSON first, then XML. All I had to do was switch it and XML became my default format. On this one the Spring guys followed the Jersey/JAX-RS guys, which is definitely a good thing.
This is what I’ve been wanting to do this whole time. I just wish it wasn’t as difficult as it was. The @EnableWebMvc should’ve been something that did everything for you and then allowed surgical customization, but unfortunately it just isn’t like that. Oh well, at least there’s a way without having to implement the whole mess from scratch.
Once again, thanks a bunch for your post. It was very helpful. I hope this is also helpful to someone.
Cheers,
-Jac
By Willie Wheeler March 27, 2012 - 12:33 am
Thanks Jac for taking the time to post this follow-up. No doubt it will help somebody in the future.
By gerardribas March 20, 2012 - 9:03 am
Hi Willie!
Do you have this code in github? I have some problems with spring 3.1 implementing rest and your code is helpful for me to resolve this.
Thanks!
Gerard.
By Willie Wheeler March 23, 2012 - 9:43 am
Hey Gerard, I do. Try this link:
https://github.com/williewheeler/zkybase/blob/master/service/src/main/java/org/zkybase/web/controller/AbstractCrudController.java
(At some point that link may break since I plan to refactor the controllers, but for now it should work.)
By gerardribas March 23, 2012 - 9:49 am
Thanks Willie!
By BryanM April 5, 2012 - 1:51 am
Willie, please delete my previous post. I’ve cloned your project and pulled it down and then used the Eclipse Maven plug.
I’m new to Spring and I’m looking to create end-points running on Google App Engine which will return structures as JSON to be consumed by mobile phone apps. I’m wondering if the method and system you’ve pointed out is stateless or if sessions of some sort will be created as I’d imagine is the case when using the MVC model.
By Willie Wheeler April 5, 2012 - 9:28 am
Hi Bryan. Previous post deleted. And the techniques involved work in both stateful and stateless scenarios. That is true of the MVC architecture generally–it is not inherently stateful.
By BryanM April 6, 2012 - 10:49 am
Willie,
Thanks for your reply. I appreciate it.
By Just a Joe July 19, 2012 - 2:21 pm
While the mapping you have is clear and straightforward, it sort-of violates DRY as the methods are pretty much duplicated. I am quite certain you don’t need to do this. Rather you can write:
@RequestMapping(
value = “/{id}”,
method = RequestMethod.GET)
@ResponseBody
public Person getDetails(@PathVariable Long id) {
return personRepo.findOne(id);
}
and while the converter registration may need to change a bit, if you request json in the request header, then you get back json. If you request xml, then you get back xml….