Given a Spring MVC controller:
@RequestMapping(method = RequestMethod.POST consumes = RestApiConstants.JSON, produces = RestApiConstants.JSON)
@ResponseBody
public CustomerDto post(@RequestBody final CustomerDto dto) {
// save it
}
When posting a dto to this controller, the Jackson mapper is missing the @class
property:
2014-11-07 14:20:55 ERROR ... Probably Jackson Mapper has failed.
org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON: Unexpected token (END_OBJECT), expected FIELD_NAME: missing property '@class' that is to contain type id (for class com.our.package.CustomerDto)
at [Source: java.io.PushbackInputStream@66be55c7; line: 1, column: 988]; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Unexpected token (END_OBJECT), expected FIELD_NAME: missing property '@class' that is to contain type id (for class com.our.package.CustomerDto)
at [Source: java.io.PushbackInputStream@66be55c7; line: 1, column: 988]
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:208)
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:200)
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(AbstractMessageConverterMethodArgumentResolver.java:138)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.readWithMessageConverters(RequestResponseBodyMethodProcessor.java:181)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:104)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:77)
...
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Unexpected token (END_OBJECT), expected FIELD_NAME: missing property '@class' that is to contain type id (for class com.our.package.CustomerDto)
at [Source: java.io.PushbackInputStream@66be55c7; line: 1, column: 988]
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:164)
at com.fasterxml.jackson.databind.DeserializationContext.wrongTokenException(DeserializationContext.java:784)
...
The CustomerDto is defined as a specific subtype of an abstract super class PartnerDto:
@JsonSubTypes({
@Type(Customer.class),
@Type(Supplier.class)
})
@JsonTypeInfo(use = Id.CLASS, include = As.PROPERTY, property = "@class")
public abstract class PartnerDto {
// ...
}
public class CustomerDto extends PartnerDto {
// ...
}
RestyGwt posts this CustomerDto:
{
"name": "Testname",
"age": 50,
...
}
But Spring expects this:
{
"@class": "com.our.package.CustomerDto",
"name": "Testname",
"age": 50,
...
}
This problem occurs since we moved Spring and RestyGwt to use the Jackson 2 mapper (Spring 4.1.1.RELEASE, RestyGWT 2.0-SNAPSHOT, Jackson 2.3.2). It worked with older versions (Spring 4.0.7.RELEASE, RestyGWT 1.4, Jackson 1.9.13).
How could I handle that?
I've created a pull request for resty gwt with a failing unit test.
https://github.com/resty-gwt/resty-gwt/pull/212
Problem occurs when creating a JsonEncoder for a concrete implementation instead of the common super type.