记录一次Feign调用报JSON parse error的错(1、no suitable constructor found,2、Failed to parse Date)

柔光的暖阳◎ 2022-01-26 16:36 927阅读 0赞

在项目改造SpringCloud的时候,业务端调用服务端的时候,报JSON parse error的错。

  1. feign.codec.DecodeException: JSON parse error: Can not construct instance of com.example.model.PageResult:
  2. no suitable constructor found, can not deserialize from Object value (missing default constructor or creator, or perhaps need to add/enable type information?);
  3. nested exception is com.fasterxml.jackson.databind.JsonMappingException:
  4. Can not construct instance of com.example.model.PageResult: no suitable constructor found,
  5. can not deserialize from Object value (missing default constructor or creator, or perhaps need to add/enable type information?)
  6. at [Source: java.io.PushbackInputStream@3f8f1df2; line: 1, column: 52] (through reference chain: com.example.model.HttpResult["data"])

后来找到原因,是因为我的PageResult存在有参构造器却没有无参构造器。

  1. public class PageResult<T> {
  2. private int total = 0;
  3. private List<T> list = null;
  4. public int getTotal() {
  5. return total;
  6. }
  7. public void setTotal(int total) {
  8. this.total = total;
  9. }
  10. public List<T> getList() {
  11. return list;
  12. }
  13. public void setList(List<T> list) {
  14. this.list = list;
  15. }
  16. public PageResult(int total, List<T> list) {
  17. this.total = total;
  18. this.list = list;
  19. }
  20. }

加个无参构造器就好了。后来发现,Jackson需要创建一个类的实例,为了做到这一点,它需要类有一个无参构造函数。反序列化时,java类需要无参构造函数。

后来加上无参构造器,又报时间格式的错。

  1. feign.codec.DecodeException: JSON parse error:
  2. Can not deserialize value of type java.util.Date from String "2019-04-01 16:49:41":
  3. not a valid representation (error: Failed to parse Date value '2019-04-01 16:49:41':
  4. Can not parse date "2019-04-01 16:49:41": while it seems to fit format 'yyyy-MM-dd'T'HH:mm:ss.SSS', parsing fails (leniency? null));
  5. nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException:
  6. Can not deserialize value of type java.util.Date from String "2019-04-01 16:49:41":
  7. not a valid representation (error: Failed to parse Date value '2019-04-01 16:49:41': Can not parse date "2019-04-01 16:49:41":
  8. while it seems to fit format 'yyyy-MM-dd'T'HH:mm:ss.SSS', parsing fails (leniency? null))
  9. at [Source: java.io.PushbackInputStream@5ed6e6e5; line: 1, column: 150] (through reference chain:
  10. com.djcps.example.model.HttpResult["data"]->com.example.model.PageResult["list"]->java.util.ArrayList[0]->com.example.model.response.ResQueryRegisterUser["createtime"])

原因是,jackson支持的时间格式有限的,它只支持:

  1. "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
  2. "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
  3. "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
  4. "EEE, dd MMM yyyy HH:mm:ss zzz"
  5. "yyyy-MM-dd"

而我用的是yyyy-MM-dd’T’HH:mm:ss

解决的办法是,自定义jackson解析时间格式yyy-MM-dd HH:mm:ss

  1. /**
  2. * @author: admin
  3. * @date: 2019/05/17
  4. * @description: 时间格式-使用装饰模式创建一个支持yyyy-MM-dd HH:mm:ss格式
  5. */
  6. public class MyDateFormat extends DateFormat {
  7. private DateFormat dateFormat;
  8. private SimpleDateFormat format1 = new SimpleDateFormat("yyy-MM-dd HH:mm:ss");
  9. public MyDateFormat(DateFormat dateFormat) {
  10. this.dateFormat = dateFormat;
  11. }
  12. @Override
  13. public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) {
  14. return dateFormat.format(date, toAppendTo, fieldPosition);
  15. }
  16. @Override
  17. public Date parse(String source, ParsePosition pos) {
  18. Date date = null;
  19. try {
  20. date = format1.parse(source, pos);
  21. } catch (Exception e) {
  22. date = dateFormat.parse(source, pos);
  23. }
  24. return date;
  25. }
  26. /**
  27. * 主要还是装饰这个方法
  28. * @param source
  29. * @return
  30. * @throws ParseException
  31. */
  32. @Override
  33. public Date parse(String source) throws ParseException {
  34. Date date = null;
  35. try {
  36. // 自定义原则
  37. date = format1.parse(source);
  38. } catch (Exception e) {
  39. // 自定义原则异常就按原先的规则
  40. date = dateFormat.parse(source);
  41. }
  42. return date;
  43. }
  44. /**
  45. * 这里装饰clone方法的原因是因为clone方法在jackson中也有用到
  46. */
  47. @Override
  48. public Object clone() {
  49. Object format = dateFormat.clone();
  50. return new MyDateFormat((DateFormat) format);
  51. }
  52. }

添加bean:

  1. @Bean
  2. public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(){
  3. ObjectMapper mapper = jackson2ObjectMapperBuilder.build();
  4. // ObjectMapper为了保障线程安全性,里面的配置类都是一个不可变的对象
  5. // 所以这里的setDateFormat的内部原理其实是创建了一个新的配置类
  6. DateFormat dateFormat = mapper.getDateFormat();
  7. mapper.setDateFormat(new MyDateFormat(dateFormat));
  8. return new MappingJackson2HttpMessageConverter(mapper);
  9. }

参考文章:

https://blog.csdn.net/thomescai/article/details/80019641

发表评论

表情:
评论列表 (有 0 条评论,927人围观)

还没有评论,来说两句吧...

相关阅读