7

I'm having trouble mapping a JSON Post to a particular Java Object to save it via Hibernate

Headers of the Ajax call are correctly set...

Accept          application/json
Content-Type    application/json; charset=UTF-8

and the HTTP-Method is POST

Here comes my configuration...

My Spring MVC function mapping looks like this

@RequestMapping(value = {"/save.json"},method = RequestMethod.POST)
public ModelMap save(@RequestBody Seizure seizureObj,Model model) {
   ...
}

in my container xml I have a ContentNegotiatingViewResolver like this

<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
    <property name="mediaTypes">
        <map>
            <entry key="html" value="text/html" />
            <entry key="json" value="application/json" />
        </map>
    </property>
    <property name="viewResolvers">
        <list>
            <bean id="viewResolver"
                class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                <property name="prefix" value="/WEB-INF/assets/" />
                <property name="suffix" value=".jsp" />
            </bean>
        </list>
    </property>
    <property name="defaultViews">
        <list>
            <bean
                class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
                <property name="prefixJson" value="false" />
                <property name="objectMapper" ref="jacksonObjectMapper" />
            </bean>
        </list>
    </property>
</bean>

in my container xml the part for jackson

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapterConfigurer"
    init-method="init">

    <property name="messageConverters">
        <list>
            <bean id="marshallingHttpMessageConverter"
                class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"
          >
          <property name="objectMapper" ref="jacksonObjectMapper" />
          </bean>
        </list>
    </property>
</bean> 

<bean id="jacksonObjectMapper" class="org.codehaus.jackson.map.ObjectMapper" /> 

I have

  • jackson-core-asl-1.8.5
  • jackson-mapper-asl-1.8.5

in my /lib folder

and Jackson works for a simple case like this

public class Simple {
  private int id;

  public int getId() {
    return id;
  }

  public void setId(int id) {
    this.id = id;
  }   
}

@RequestMapping(value = {"/saveSimple.json"},method = RequestMethod.POST)
public ModelMap save(@RequestBody Simple simple,Model model) {
   ...
}

when I test it with curl

 curl -v -H "Accept: application/json" -H "Content-type: application/json" -X POST -d '{"id":1}'  http://<URL>/saveSimple.json

No problems, but if I test it with the Hibernate object I get the message

415 Unsupported Media Type

any ideas.

Jeremy S.
  • 6,423
  • 13
  • 48
  • 67

4 Answers4

14

StanMax lead my in the right direction...

First I had to set the @JsonManagedReference and @JsonBackReference right. I set the ManagedReference to the attribute which represents the ONE of of the ONE-to-MANY relationship, but apparently you have to set it to the MANY attribute (the collection)

see the description here http://wiki.fasterxml.com/JacksonFeatureBiDirReferences

@JsonBackReference is the "back" part of reference: it will be omitted from serialization, and re-constructed during deserialization of forward reference.

  • Annotated property must be of bean type

The problem in my case was that I didn't send sufficient information in my JSON POST to match the Hibernate requirements.

This resulted in an Exception that the proper fields to create a Hibernate object out of my JSON POST, were not present.

I created a test url where I created the Object mapper myself and tried to de-serialize JSON by hand. This throw the right error message.

It seems to my that Spring unfortunately throws the 415 "Unsupported Media Type" exception which is a bit misleading.

So for the future. Try it out by hand first (see example included) and than go on.

 ModelMap map = new ModelMap();
 logger.info("HibernateAware");
 HibernateAwareObjectMapper mapper = new HibernateAwareObjectMapper();
 String jsonInput = 
 "{" +
   "\"id\":\"1\"," +
   "\"matCountry\":{" +
     "\"id\":\"1\"" +
   "}" +
 "}";
 Seizure seizure = mapper.readValue(jsonInput, Seizure.class); // this line throw the exception

Hope this helps someone.

Regards JS

Community
  • 1
  • 1
Jeremy S.
  • 6,423
  • 13
  • 48
  • 67
4

One thing you can try is to figure out if the problem is with Jackson's data binding (fails to serialize hibernate object) or something else. This can be done by manually constructing ObjectMapper, checking to see if 'mapper.serializeValueAsString()' works or throws an exception.

There is a good chance it has to do with Jackson handling of lazily-loaded properties; if so, you may need to use jackson hibernate module as it can handle Hibernate-specific details.

StaxMan
  • 113,358
  • 34
  • 211
  • 239
  • I get the error message ``'defaultReference': back reference type (java.util.Set) not compatible with managed type ()`` – Jeremy S. Aug 23 '11 at 08:01
2

I had the same problem. After reading through how MappingJacksonHttpMessageConverter works I realized that I had not initialized it properly. So I used the following in my rest-servlet.xml and it worked..

<bean id="jsonHttpMessageConverter"  class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" />
    <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
    <property name="mediaTypes">
        <map>
            <entry key="json" value="application/json" />
        </map>
    </property>

    <property name="defaultViews">
        <list>
            <bean
                class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
                <property name="objectMapper">
                    <ref bean="JacksonObjectMapper" />
                </property>
            </bean>
        </list>
    </property>
    <property name="favorPathExtension" value="false" />
    <property name="favorParameter" value="true" />
    <property name="useNotAcceptableStatusCode" value="true" />
</bean>

<bean id="JacksonObjectMapper" class="org.codehaus.jackson.map.ObjectMapper" />
Gautam
  • 21
  • 1
0

I had a similar problem, which was due to the fact that one of my classes had a map with a non-primitive key type. I was able to @JsonIgnore to this field to work around the problem.

matt forsythe
  • 3,863
  • 1
  • 19
  • 29