Jersey + Jackson deserialization failure with date

2019-04-25 02:56发布

问题:

I'm using jersey and jackson together to develop my REST API, and I'm having a problem when deserializing a date string. I have register a provider class in Jersey:

@Provider
public class MyJsonProvider extends JacksonJsonProvider {
    public static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
    @Override
    public void writeTo(Object value, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String,Object> httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException {
        ObjectMapper mapper = locateMapper(type, mediaType);
        // Enable human readable date format
        SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
        mapper.getDeserializationConfig().setDateFormat(sdf);
        mapper.getSerializationConfig().setDateFormat(sdf);
        // Enable JAXB annotation, with Jackson annotation being the preferred one.
        AnnotationIntrospector primary = new JacksonAnnotationIntrospector();
        AnnotationIntrospector secondary = new JaxbAnnotationIntrospector();
        AnnotationIntrospector introspector = new AnnotationIntrospector.Pair(primary, secondary);
        mapper.getDeserializationConfig().setAnnotationIntrospector(introspector);
        mapper.getSerializationConfig().setAnnotationIntrospector(introspector);
        super.writeTo(value, type, genericType, annotations, mediaType, httpHeaders, entityStream);
    }
}

And it seems like Jersey picked it up during start up:

Jan 24, 2011 2:53:23 PM com.sun.jersey.api.core.ScanningResourceConfig logClasses
INFO: Provider classes found:
  class com.mypackage.MyJsonProvider

And it works fine for serialization, but when I tried to deserialize a string like 2010-01-25 00:00:00, I'm getting a mapping error:

SEVERE: Servlet.service() for servlet JerseyWebApplication threw exception
org.codehaus.jackson.map.JsonMappingException: Can not construct instance of java.util.Date from String value '2010-01-25 00:00:00': not a valid representation (error: Can not parse date "2010-01-25 00:00:00": not compatible with any of standard forms ("yyyy-MM-dd'T'HH:mm:ss.SSSZ", "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", "EEE, dd MMM yyyy HH:mm:ss zzz", "yyyy-MM-dd"))
 at [Source: org.apache.catalina.connector.CoyoteInputStream@6a3d899a; line: 3, column: 37]
    at org.codehaus.jackson.map.JsonMappingException.from(JsonMappingException.java:159)
    at org.codehaus.jackson.map.deser.StdDeserializationContext.weirdStringException(StdDeserializationContext.java:222)
    at org.codehaus.jackson.map.deser.StdDeserializer._parseDate(StdDeserializer.java:283)
    at org.codehaus.jackson.map.deser.DateDeserializer.deserialize(DateDeserializer.java:26)
    at org.codehaus.jackson.map.deser.DateDeserializer.deserialize(DateDeserializer.java:17)
    at org.codehaus.jackson.map.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:135)
    at org.codehaus.jackson.map.deser.SettableBeanProperty$MethodProperty.deserializeAndSet(SettableBeanProperty.java:221)
    at org.codehaus.jackson.map.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:391)
    at org.codehaus.jackson.map.deser.BeanDeserializer.deserialize(BeanDeserializer.java:286)
    at org.codehaus.jackson.map.ObjectMapper._readValue(ObjectMapper.java:1568)
    at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:788)
    at org.codehaus.jackson.jaxrs.JacksonJsonProvider.readFrom(JacksonJsonProvider.java:398)
    at com.sun.jersey.spi.container.ContainerRequest.getEntity(ContainerRequest.java:454)

It seems like Jersey is still using JacksonJsonProvider to handle the deserialization somehow. I'm not sure what I am doing wrong. How should I configure the jackson within jersey? Thanks!

回答1:

super.writeTo method calls locateMapper(type, mediaType) again and creates a new instance of mapper object so the mapper object on which you configure the dateformat is never used. You can confirm in debug mode.

What you can do is create your own mapper object by creating a constructor

 MyJsonProvider(){

     ObjectMapper mapper = new ObjectMapper();
    // Enable human readable date format
    SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
    mapper.getDeserializationConfig().setDateFormat(sdf);
    mapper.getSerializationConfig().setDateFormat(sdf);
    // Enable JAXB annotation, with Jackson annotation being the preferred one.
    AnnotationIntrospector primary = new JacksonAnnotationIntrospector();
    AnnotationIntrospector secondary = new JaxbAnnotationIntrospector();
    AnnotationIntrospector introspector = new AnnotationIntrospector.Pair(primary, secondary);
    mapper.getDeserializationConfig().setAnnotationIntrospector(introspector);
    mapper.getSerializationConfig().setAnnotationIntrospector(introspector);
   super(mapper);}

Then you dont need to override the writeTo method