【问题标题】:Jersey + Jackson deserialization failure with date object日期对象的 Jersey + Jackson 反序列化失败
【发布时间】:2011-06-14 20:41:40
【问题描述】:

我正在同时使用 jersey 和 jackson 来开发我的 REST API,但在反序列化日期字符串时遇到了问题。我在泽西岛注册了一个提供者类:

@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);
    }
}

看来 Jersey 在启动时捡到了它:

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

它可以很好地用于序列化,但是当我尝试反序列化像2010-01-25 00:00:00 这样的字符串时,我遇到了映射错误:

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)

Jersey 似乎仍在使用JacksonJsonProvider 以某种方式处理反序列化。我不确定我做错了什么。我应该如何配置球衣内的杰克逊?谢谢!

【问题讨论】:

  • 我自己想通了。原来我需要在 readFrom() 方法中设置反序列化配置,而不是 writeTo() 方法。呵呵。
  • 为什么会因为“过于本地化”而关闭?与杰克逊在一起的泽西岛是一种常见的情况。
  • @fei 您可以将其添加为答案
  • 我相信 Jackson 默认会使用 ISO-8601 格式(即:2013-04-30T07:00:00.000Z)或过去纪元的数字毫秒。不指定时区的文本日期转换可能会导致问题。当涉及到客户端、服务器和数据库时,日期很容易被破坏。
  • 另外,您可能想查看ObjectMapper.setDateFormat 的JavaDoc。具体如下:“这最好是直接修改SerializationConfig和DeserializationConfig实例。”

标签: java json rest jersey jackson


【解决方案1】:

super.writeTo 方法再次调用 locateMapper(type, mediaType) 并创建一个新的映射器对象实例,因此您配置日期格式的映射器对象永远不会被使用。 您可以在调试模式下确认。

您可以做的是通过创建构造函数来创建自己的映射器对象

 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);}

那你就不需要重写writeTo方法了

【讨论】:

    猜你喜欢
    • 2018-12-26
    • 1970-01-01
    • 1970-01-01
    • 2020-08-12
    • 2021-03-14
    • 1970-01-01
    • 1970-01-01
    • 2014-02-19
    • 2019-04-03
    相关资源
    最近更新 更多