3

I am having one issue with Spring MVC and its json support. I make one ajax call to get some data and I want to get that data in json format including the root value. I am also using JABX annotations in the entities because those are used for some REST API.

I have read that to get the root value included with Jackson, I should use this method:

this.configure(org.codehaus.jackson.map.DeserializationConfig.Feature.UNWRAP_ROOT_VALUE, true);

So I created one objectMapper which extends the codehaus one and looks like this:

public class JaxbJacksonObjectMapper extends ObjectMapper {

    public JaxbJacksonObjectMapper() {
        final AnnotationIntrospector introspector = new JaxbAnnotationIntrospector();

        this.configure(org.codehaus.jackson.map.DeserializationConfig.Feature.UNWRAP_ROOT_VALUE, true);
        super.getDeserializationConfig().withAnnotationIntrospector(introspector);

        this.configure(org.codehaus.jackson.map.SerializationConfig.Feature.WRAP_ROOT_VALUE, true);
        super.getSerializationConfig().withAnnotationIntrospector(introspector);
    }
}

For Spring to use this mapper I have configured the following lines:

<beans:bean id="customObjectMapper" class="com.test.package.config.JaxbJacksonObjectMapper" />

<beans:bean id="jsonMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
    <beans:property name="objectMapper" ref="customObjectMapper" />
</beans:bean>

<beans:bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
    <beans:property name="messageConverters">
        <beans:list>
            <beans:ref bean="jsonMessageConverter"/>
        </beans:list>
    </beans:property>
</beans:bean>

And my entities look like this:

@XmlRootElement(name = "collection")
public class Issuers {
    private List<Issuer> issuers;
}

The problem is that when Spring 3.1 returns the Issuers json object to the browser it does not include the collection root element.

Any idea how to solve this issue?

Thanks!

Mualig
  • 1,444
  • 1
  • 19
  • 42
Enrique Cordero
  • 33
  • 1
  • 1
  • 6

4 Answers4

3

It seems that the method withAnnotiationIntrospector does not set AnnotiationIntrospector. It's returns new DeserializationConfig/SerializationConfig object instead (with correct AnnotiationIntrospector).

So, my version of JaxbJacksonObjectMapper:

public class JaxbJacksonObjectMapper extends ObjectMapper {

    public JaxbJacksonObjectMapper() {
        super();

        final AnnotationIntrospector introspector = new JaxbAnnotationIntrospector();

        this.configure(org.codehaus.jackson.map.DeserializationConfig.Feature.UNWRAP_ROOT_VALUE, true);
        this.configure(org.codehaus.jackson.map.SerializationConfig.Feature.WRAP_ROOT_VALUE, true);

        this.setDeserializationConfig(this.getDeserializationConfig().withAnnotationIntrospector(introspector));
        this.setSerializationConfig(this.getSerializationConfig().withAnnotationIntrospector(introspector));

    }
}

Now it support @XmlRootElement, @XmlTransient and other.

Mualig
  • 1,444
  • 1
  • 19
  • 42
Vladimir
  • 39
  • 2
0

Alternative to this use following one statement:

setAnnotationIntrospector(introspector);

instead following two statements,

super.getDeserializationConfig().setAnnotationIntrospector(introspector);
super.getSerializationConfig().setAnnotationIntrospector(introspector);
Ankur
  • 5,086
  • 19
  • 37
  • 62
0

Wrap your "Issuers" in a generic holder-object. That's what I do when working with Jackson and Spring.

class JSONResponse {

    private Object collection;

    public JSONResponse(Object collection) {
        this.collection = collection;
    }
    public Object getCollection() {
        return collection;
    }
}

...

@RequestMappin(...)
@ResponseBody
public Object someHandler(...) {
    ...
    return new JSONResponse(issuers);
}
pap
  • 27,064
  • 6
  • 41
  • 46
  • That could be one option, thanks. But I would like to get a cleaner solution so that I wouldn't need to change it in every single request. But in the worst case... – Enrique Cordero Mar 01 '12 at 13:47
  • It seems that the spring configuration was not right. That did not override the messageconverters, so it was not taking the Mapper that I wrote. To override those, the right spring config is: ` ` – Enrique Cordero Mar 01 '12 at 14:52
  • Now I am getting the root element, but it is not taking the name given in the jabx annotation, but the name of the class. Any idea how to solve that issue? That must be related to some problem in the Jackson mapper that I created... – Enrique Cordero Mar 01 '12 at 14:52
0

It seems that the spring configuration was not right. That did not override the messageconverters, so it was not taking the Mapper that I wrote.

To override those, the right spring config is:

    <annotation-driven>
    <message-converters>
        <beans:bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
            <beans:property name="objectMapper"  ref="customObjectMapper" />
        </beans:bean>
    </message-converters>
</annotation-driven>

Now I am getting the root element, but it is not taking the name given in the jabx annotation, but the name of the class.

It seems that the new method (withAnnotiationIntrospector) does not work as it should, or I am missing something. But if use the deprecated one, I get the proper root name defined in the JABX label.

    public JaxbJacksonObjectMapper() {
    final AnnotationIntrospector introspector = new JaxbAnnotationIntrospector();

    this.configure(org.codehaus.jackson.map.SerializationConfig.Feature.WRAP_ROOT_VALUE, true);
    this.configure(org.codehaus.jackson.map.DeserializationConfig.Feature.UNWRAP_ROOT_VALUE, true);

    // When using the non deprecated method (withAnnotationIntrospector),
    // there are problems with JAXB/JSON parser so don't use right now

    super.getDeserializationConfig().setAnnotationIntrospector(introspector);
    super.getSerializationConfig().setAnnotationIntrospector(introspector);
}
Enrique Cordero
  • 33
  • 1
  • 1
  • 6