提纲:

1.出现的场景。

2.报错内容和代码追踪。

3.原因。

4.三种解决方案。

1.    出现的场景:

  • 服务端提供一个springcloud接口。
  • 客户端通过feign调用该接口,返回值为一个列表的CompanyDTO,DTO中有一个Date对象。
  • 调用出错。

2.    报错如下:

Caused by: org.springframework.http.converter.HttpMessageNotReadableException: Could not read document: Can not deserialize value of type java.util.Date from String "2017-12-08 09:20:53": not a valid representation (error: Failed to parse Date value '2017-12-08 09:20:53': Can not parse date "2017-12-08 09:20:53Z": while it seems to fit format 'yyyy-MM-dd'T'HH:mm:ss.SSS'Z'', parsing fails (leniency? null))at [Source: java.io.PushbackInputStream@2041c1b0; line: 1, column: 554] (through reference chain: com.qts.base.result.ResponseData["data"]->java.util.ArrayList[0]->com.qts.company.api.dto.CompanyDTO["applyRefundTime"]); nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Can not deserialize value of type java.util.Date from String "2017-12-08 09:20:53": not a valid representation (error: Failed to parse Date value '2017-12-08 09:20:53': Can not parse date "2017-12-08 09:20:53Z": while it seems to fit format 'yyyy-MM-dd'T'HH:mm:ss.SSS'Z'', parsing fails (leniency? null))at [Source: java.io.PushbackInputStream@2041c1b0; line: 1, column: 554] (through reference chain: com.qts.base.result.ResponseData["data"]->java.util.ArrayList[0]->com.qts.company.api.dto.CompanyDTO["applyRefundTime"])at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:228)at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:213)at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:95)at org.springframework.cloud.netflix.feign.support.SpringDecoder.decode(SpringDecoder.java:59)at org.springframework.cloud.netflix.feign.support.ResponseEntityDecoder.decode(ResponseEntityDecoder.java:47)at feign.SynchronousMethodHandler.decode(SynchronousMethodHandler.java:165)... 75 more
Caused by: com.fasterxml.jackson.databind.exc.InvalidFormatException: Can not deserialize value of type java.util.Date from String "2017-12-08 09:20:53": not a valid representation (error: Failed to parse Date value '2017-12-08 09:20:53': Can not parse date "2017-12-08 09:20:53Z": while it seems to fit format 'yyyy-MM-dd'T'HH:mm:ss.SSS'Z'', parsing fails (leniency? null))at [Source: java.io.PushbackInputStream@2041c1b0; line: 1, column: 554] (through reference chain: com.qts.base.result.ResponseData["data"]->java.util.ArrayList[0]->com.qts.company.api.dto.CompanyDTO["applyRefundTime"])at com.fasterxml.jackson.databind.exc.InvalidFormatException.from(InvalidFormatException.java:74)at com.fasterxml.jackson.databind.DeserializationContext.weirdStringException(DeserializationContext.java:1410)at com.fasterxml.jackson.databind.DeserializationContext.handleWeirdStringValue(DeserializationContext.java:926)at com.fasterxml.jackson.databind.deser.std.StdDeserializer._parseDate(StdDeserializer.java:822)at com.fasterxml.jackson.databind.deser.std.StdDeserializer._parseDate(StdDeserializer.java:791)at com.fasterxml.jackson.databind.deser.std.DateDeserializers$DateBasedDeserializer._parseDate(DateDeserializers.java:172)at com.fasterxml.jackson.databind.deser.std.DateDeserializers$DateDeserializer.deserialize(DateDeserializers.java:259)at com.fasterxml.jackson.databind.deser.std.DateDeserializers$DateDeserializer.deserialize(DateDeserializers.java:242)at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:499)at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:101)at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:357)at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:148)at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:277)at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:249)at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:26)at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:499)at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:101)at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:357)at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:148)at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3789)at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2913)at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:225)... 80 more
  • 从AbstractJackson2HttpMessageConverter.java:225的readJavaType方法开始。
  • DateDeserializers.java的deserialize中,有一段核心逻辑:this._customFormat.parse(str)。问题来了:_customFormat是从哪里来的?
protected Date _parseDate(JsonParser p, DeserializationContext ctxt) throws IOException {if (this._customFormat != null) {JsonToken t = p.getCurrentToken();if (t == JsonToken.VALUE_STRING) {String str = p.getText().trim();if (str.length() == 0) {return (Date)this.getEmptyValue(ctxt);}DateFormat var5 = this._customFormat;synchronized(this._customFormat) {Date var10000;try {var10000 = this._customFormat.parse(str);//重点} catch (ParseException var8) {return (Date)ctxt.handleWeirdStringValue(this.handledType(), str, "expected format \"%s\"", new Object[]{this._formatString});}return var10000;}}}return super._parseDate(p, ctxt);}
  • DateBasedDeserializer中的_customFormat,通过ctxt.getConfig()获取,DeserializationContext是配置的上下文。
  • protected abstract static class DateBasedDeserializer<T> extends StdScalarDeserializer<T> implements ContextualDeserializer {protected final DateFormat _customFormat;protected final String _formatString;protected abstract DateDeserializers.DateBasedDeserializer<T> withDateFormat(DateFormat var1, String var2);public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) throws JsonMappingException {if (property != null) {Value format = this.findFormatOverrides(ctxt, property, this.handledType());if (format != null) {TimeZone tz = format.getTimeZone();Locale loc;if (format.hasPattern()) {String pattern = format.getPattern();loc = format.hasLocale() ? format.getLocale() : ctxt.getLocale();SimpleDateFormat df = new SimpleDateFormat(pattern, loc);if (tz == null) {tz = ctxt.getTimeZone();}df.setTimeZone(tz);return this.withDateFormat(df, pattern);}if (tz != null) {DateFormat df = ctxt.getConfig().getDateFormat();//重点Object df;if (df.getClass() == StdDateFormat.class) {loc = format.hasLocale() ? format.getLocale() : ctxt.getLocale();StdDateFormat std = (StdDateFormat)df;std = std.withTimeZone(tz);std = std.withLocale(loc);df = std;} else {df = (DateFormat)df.clone();((DateFormat)df).setTimeZone(tz);}return this.withDateFormat((DateFormat)df, this._formatString);}}}return this;}}
  • 我们看下getDateFormat的具体实现,最终是通过MapperConfig中的BaseSettings获取。
    public final DateFormat getDateFormat() {return this._base.getDateFormat();}

3.具体原因是Jason只支持一下几种格式:

"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"  

4.解决方案:

既然默认的序列化不支持这样的格式,那就手动设置一下。

4.1设置客户端的DateFormat。

public class MyDateFormat extends DateFormat {private DateFormat dateFormat;private SimpleDateFormat format1 = new SimpleDateFormat("yyy-MM-dd HH:mm:ss");public MyDateFormat(DateFormat dateFormat) {this.dateFormat = dateFormat;}@Overridepublic StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) {return dateFormat.format(date, toAppendTo, fieldPosition);}@Overridepublic Date parse(String source, ParsePosition pos) {Date date = null;try {date = format1.parse(source, pos);} catch (Exception e) {date = dateFormat.parse(source, pos);}return date;}// 主要还是装饰这个方法@Overridepublic Date parse(String source) throws ParseException {Date date = null;try {// 先按我的规则来date = format1.parse(source);} catch (Exception e) {// 不行,那就按原先的规则吧date = dateFormat.parse(source);}return date;}// 这里装饰clone方法的原因是因为clone方法在jackson中也有用到@Overridepublic Object clone() {Object format = dateFormat.clone();return new MyDateFormat((DateFormat) format);}
}

并在启动的时候加入。

@Configuration
public class WebConfig {@Autowiredprivate Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder;@Beanpublic MappingJackson2HttpMessageConverter MappingJsonpHttpMessageConverter() {ObjectMapper mapper = jackson2ObjectMapperBuilder.build();// ObjectMapper为了保障线程安全性,里面的配置类都是一个不可变的对象// 所以这里的setDateFormat的内部原理其实是创建了一个新的配置类DateFormat dateFormat = mapper.getDateFormat();mapper.setDateFormat(new MyDateFormat(dateFormat));MappingJackson2HttpMessageConverter mappingJsonpHttpMessageConverter = new MappingJackson2HttpMessageConverter(mapper);return mappingJsonpHttpMessageConverter;}
}

4.2解决方案2

可以通过代码,那就可以通过配置。。。

#spring.mvc.date-format=yyyy-MM-dd HH:mm:ss
#spring.jackson.time-zone=GMT+8
#spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
#spring.jackson.deserialization.accept_empty_string_as_null_object=true

4.3解决方案3

在字段的setter上加上注解,这种方法比较麻烦。

public class DateJsonDeserializer extends JsonDeserializer<Date> {/*** @see JsonDeserializer#deserialize(JsonParser,*      DeserializationContext)*/@Overridepublic Date deserialize(JsonParser parser, DeserializationContext context)throws IOException, JsonProcessingException {try {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");return sdf.parse(parser.getValueAsString());} catch (Exception e) {e.printStackTrace();}return null;}}

然后在DTO的字段上增加注解:

    @JsonDeserialize(using = DateJsonDeserializer.class)private Date applyRefundTime;

参考文章:

https://blog.csdn.net/qq906627950/article/details/79503801

http://wujiu.iteye.com/blog/2244537

springcloud采坑-jason序列化中的Date对象相关推荐

  1. javascript 无法修改 数组中对象_如何使用JavaScript中的Date对象

    Date对象是一个内置函数,我们可以使用Date对象来显示日期,本篇文章就来给大家分享一篇有关于Date对象的使用方法. 内置函数我们可以使用new来创建 var 对象名称= new object() ...

  2. js中的Date对象 及 将时间戳转换为yy-mm-dd hh:mm:ss格式的方法

    文章目录 Date 创建 Date对象的方法 get时间 set时间 转字符串 将时间戳转换为yy-mm-dd hh:mm:ss格式的方法 Date Date 对象用于处理日期和时间. 创建 日期对象 ...

  3. SpringCloud采坑之Feign服务间调用默认返回xml

    2019独角兽企业重金招聘Python工程师标准>>> 日前在使用SpringCloud的时候,需要用到服务间的调用,采用Feign进行调用,但是默认返回了xml格式的数据,比较坑爹 ...

  4. JavaScript中的Date对象在Safari与IOS中的“大坑”

    最近小编在做一个会议室预定的功能,这个功能就像在买电影票时选择座位一样,看看会议室的哪个时间段空闲,有什么设备等等.由于我做的是APP,APP既要兼容Android,又要兼容IOS,刚开始的开发与调试 ...

  5. MyBatis动态SQL底层原理分析 与 JavaScript中的Date对象,以及UTC、GMT、时区的关系...

    http://fangjian0423.github.io/categories/mybatis/ http://xtutu.me/the-date-object-in-js/

  6. json Date对象在js中的处理办法

    我们在程序用往往通过ajax方式返回json数据,json中包含Date对象时,在js中是Object对象.可以方式获取: 1.new Date(yourJsonDate.time); //你用你的返 ...

  7. 探索 Java 中的 Date, Calendar, TimeZone 和Timestamp

    探索 Java 中的 Date, Calendar, TimeZone 和Timestamp java 2010-12-31 08:56:49 阅读8 评论0  字号:大中小 订阅 对象 宋晟 (sh ...

  8. JavaScript常用工具Date对象和Math介绍介绍

    Date对象 JavaScript中使用Date对象来表示时间. //创建一个时间对象,时间是当前时间 var cur = new Date();//根据表达式创建指定时间的时间对象,格式是 月/日/ ...

  9. javascript中的Data()对象

    javascript中的Data()对象 关于月份的英文 一月 Jan. January二月 Feb. February三月 Mar. March四月 Apr. April五月 May. May六月 ...

最新文章

  1. 上手!深度学习最常见的26个模型练习项目汇总
  2. 【高并发】高并发分布式锁架构解密,不是所有的锁都是分布式锁!!
  3. 常见的数据库端口及查询方法
  4. 第十六届智能车竞赛线上全国总决赛远程组委会监督腾讯会议
  5. 新手如何学drupal?
  6. Effective Java之优先使用标准的异常(六十)
  7. 外媒:字节跳动是谷歌云存储第二大客户 但所存数据远不及苹果
  8. Java-压缩指针compressedOops
  9. java多线程基础篇第一篇-JMM
  10. CKeditor4.7.3标准版图片上传及相关配置
  11. 2008服务器系统安装哪个版本好,Windows Server 2008和Windows Server 2008 R2哪个更好,其中可选的安装版本那个最高级,都有什么用?...
  12. 视频教程-OCJP认证考试复习课-其他
  13. Zigbee协议栈无线通信系统
  14. 移动端混合式App开发框架
  15. android 广播监听截屏,Android 应用监听截屏操作
  16. 笔记:盖洛普《伟大管理的12要素》中的12原则
  17. MySQL:explain结果中Extra:Impossible WHERE noticed after reading const tables
  18. EXCEL-日常技巧整理-2-单元格拆分后原数据填充
  19. 利用局域网将电脑上的文件快速下载到手机上
  20. c语言转义字符(c语言转义字符是什么意思)

热门文章

  1. jQuery源码分析系列(一)初识jQuery
  2. 篮球记分牌c语言程序和报告,跪求:设计一款篮球记分牌,包括C语言程序和proteus的仿真图,最好附带设计报告.。邮箱liuzhonghuaol@126.com。...
  3. python import文件后 core dumped_python numpy包调用core dumped、Linux VDSO机制
  4. 浙商银行计算机专业笔试考什么,浙商银行笔试题目汇总
  5. Linux下通过CCID协议与USB设备进行交互经验总结
  6. opta球员大数据预测胜负_数据分析视角下的世界杯冠军预测
  7. cesium加载entity图片缩放_教你使用最简单粗暴的js方法实现图片最小边展示
  8. qq音乐html5测试性格,根据你的听歌习惯测试你的性格
  9. 苹果IOS14版本自建服务器无法下载解决方法
  10. 9个妙招教你玩转微信