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

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

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

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

public class PageResult<T> {
	private int total = 0;

	private List<T> list = null;

	public int getTotal() {
		return total;
	}

	public void setTotal(int total) {
		this.total = total;
	}

	public List<T> getList() {
		return list;
	}

	public void setList(List<T> list) {
		this.list = list;
	}

	public PageResult(int total, List<T> list) {
		this.total = total;
		this.list = list;

	}

}

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

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

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

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

"yyyy-MM-dd'T'HH:mm:ss.SSSZ"
"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"

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

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

/**
 * @author: admin
 * @date: 2019/05/17 
 * @description: 时间格式-使用装饰模式创建一个支持yyyy-MM-dd HH:mm:ss格式
 */
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;
    }

    @Override
    public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) {
        return dateFormat.format(date, toAppendTo, fieldPosition);
    }

    @Override
    public 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;
    }

    /**
     * 主要还是装饰这个方法
     * @param source
     * @return
     * @throws ParseException
     */
    @Override
    public 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中也有用到
     */
    @Override
    public Object clone() {
        Object format = dateFormat.clone();
        return new MyDateFormat((DateFormat) format);
    }
}

 

添加bean:

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

参考文章:

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


版权声明:本文为m0_37772518原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
THE END
< <上一篇
下一篇>>