4

I'm trying to make it so my Spring rest application can handle both xml and json responses, but it seems like adding a Jaxb message converter has broken my json mapping.

@Bean
public MappingJackson2HttpMessageConverter jsonConverter() {
    MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
    SimpleModule simpleModule = new SimpleModule();
    simpleModule.addSerializer(String.class, new StringSerializer());
    ObjectMapper mapper = new ObjectMapper()
        .registerModule(simpleModule);
    converter.setObjectMapper(mapper);
    return converter;
}

@Bean
public Jaxb2RootElementHttpMessageConverter jaxbConverter() {
    return new Jaxb2RootElementHttpMessageConverter();
}

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    converters.add(jsonConverter());
    converters.add(jaxbConverter());
}

If I comment out the second and third methods there, everything starts working again (except the xml mapping of course!). With those there, though, I get screwed up stuff, like serializing a List<String> results in [APPLEORANGEBANANA], where apple, orange, and banana are separate strings in the list.

If I directly use a jackson object mapper to map to json, it doesn't have that issue, but using the @ResponseBody annotation to automatically serialize to json I have this issue.

Anyone have any ideas?

CorayThan
  • 17,174
  • 28
  • 113
  • 161
  • I think maybe my issue is the `configureMessageConverters` method by itself. Take that out and both seem like they work. (Working through a hibernate exception right now to make sure they actually do.) – CorayThan Sep 06 '13 at 05:58

4 Answers4

5

This is how I did it.

@RequestMapping(method = RequestMethod.GET, value = "/accounts/{accountId}", produces = {APPLICATION_XML_VALUE, APPLICATION_JSON_VALUE})
@ResponseBody
@ResponseStatus(value = HttpStatus.OK)
public Account getAccount(@PathVariable String accountId) {
    return new Account(); // populate Account VO and send
}

and in the XML file

<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager" >
    <mvc:message-converters register-defaults="false">
       <ref bean="xmlConverter"/>
       <ref bean="jsonConverter"/>
    </mvc:message-converters>
</mvc:annotation-driven> 

 <!-- XML MessageConverter -->
 <bean id="xmlConverter" class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
  <constructor-arg ref="jaxbMarshaller"/>
  <property name="supportedMediaTypes" value="application/xml" />
 </bean> 

<!-- JSON MessageConverter -->
 <bean id="jsonConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
 </bean>

<!-- JAXB Classes to be marshalled -->
<bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
    <property name="packagesToScan">
   <list>
    <value>com.test.*</value>
    <value>com.*.test</value>
  </list>
  </property>
</bean>
spal
  • 731
  • 3
  • 9
  • 20
  • 1
    I'm pretty sure your MarshallingHttpMessageConverter is just a more manual way of doing it than Jaxb2RootElementHttpMessageConverter. Other than that what you have looks just like what I have so far as I can see, except I'm using Java configuration. – CorayThan Sep 06 '13 at 05:38
0

I removed the configureMessageConverters and it picked up both of the converters automatically and neither has an issue.

CorayThan
  • 17,174
  • 28
  • 113
  • 161
0

Happened the very same to me. Twice :-)

In one case, a simple converters.clear() before adding my converters solved the problem. Looks like Spring adds some converters by default. using XML to inject them deletes the one implicitly set by Spring, while adding them explicitly from code doesn't.

In the other case the problem was that the correct headers had be set in the request, that is the content-type and accept. In the request mappings, then, I had to specify the "consumes" and "produces" parameters, mapping respectively the two headers.

public class MyRequestHandler {
     ...

     @RequestMapping(... , consumes={ MediaType.APPLICATION_JSON_VALUE, produces = { MediaType.APPLICATION_JSON_VALUE } }
     public ResponseEntity<MyResultClass> doSomething(...) { ... }

     ...
}

This solved the problem for me.

Stefano Cazzola
  • 1,597
  • 1
  • 20
  • 36
0

When you override configureMessageConverters, it will not add Default Message Converters. Try below code.

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    converters.add(jsonConverter());
    converters.add(jaxbConverter());
    super.addDefaultHttpMessageConverters();
}
c.sankhala
  • 850
  • 13
  • 27