When Fegin calls, Jackson time conversion exception problem solved

Recently, I found a problem when using fegin to call. Many time formats jackson does not support when converting strings to dates, and will report errors.
The error message is as follows:

feign.codec.DecodeException: Error while extracting response for type [com.inforun.common.core.domain.R<java.util.List<com.inforun.common.base.domain.TTaskTime>>] and content type [application/json;charset=UTF-8]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `java.util.Date` from String "23:59:59": not a valid representation (error: Failed to parse Date value '23:59:59': Unparseable date: "23:59:59"); nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `java.util.Date` from String "23:59:59": not a valid representation (error: Failed to parse Date value '23:59:59': Unparseable date: "23:59:59")
 at [Source: (PushbackInputStream); line: 1, column: 82] (through reference chain: com.inforun.common.core.domain.R["data"]->java.util.ArrayList[0]->com.inforun.common.base.domain.TTaskTime["endTime"])

I only need the time and the date, and it doesn’t work when converting. I found out after checking the information on the Internet that jackson only supports the following types

"yyyy-MM-dd'T'HH:mm:ss.SSSZ";

"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";

"yyyy-MM-dd";

"EEE, dd MMM yyyy HH:mm:ss zzz";

long类型的时间戳

These types obviously do not include the format I passed in, so I can only figure out a solution by myself. There are two ways to solve it.

1. The annotation solution is to add annotations to a single class,
insert image description here
but this method can only be used for a small number. If there are many, it will be troublesome to add one by one, so I did not use this method.

2. Custom type converter method
We can write a custom time type converter and use the time type converter to convert the format we need, so that there is no need to add annotations one by one, which is more convenient.

import cn.hutool.core.date.DateUtil;

import java.text.DateFormat;
import java.text.FieldPosition;
import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Date;

public class MyDateFormat extends DateFormat {
    
    
    private DateFormat dateFormat;
    private SimpleDateFormat format1 = new SimpleDateFormat("yyy-MM-dd HH:mm:ss");
    private SimpleDateFormat format2 = new SimpleDateFormat("yyy-MM-dd");
    private SimpleDateFormat format3 = new SimpleDateFormat("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 {
    
    
            // 先按我的规则1来
            date = format1.parse(source, pos);
        } catch (Exception e) {
    
    
            //方式1不行方式2
            try {
    
    
                date = format2.parse(source, pos);
            } catch (Exception e1) {
    
    
                //方式2不行方式3
                try {
    
    
                    date = format3.parse(source, pos);
                } catch (Exception e2) {
    
    
                    // 不行,那就按原先的规则吧
                    date = dateFormat.parse(source, pos);
                }
            }
        }
        return date;
    }    // 主要还是装饰这个方法

    @Override
    public Date parse(String source) throws ParseException {
    
    
        Date date = null;
        try {
    
    
            //先按照自己的规则来,动态筛查
            date = DateUtil.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);
    }
}

This is a custom conversion class. In fact, we still use a single conversion. I used the Hutool tool class for a single conversion here. It can automatically identify some commonly used time types, so that you can save yourself. Let's configure it down.

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.inforun.common.security.config.jackson.MyDateFormat;
import com.inforun.common.security.interceptor.HeaderInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.text.DateFormat;

public class WebMvcConfig implements WebMvcConfigurer
{
    
    

    @Bean
    public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(){
    
    

        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        ObjectMapper objectMapper = new ObjectMapper();
        //添加此配置
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        converter.setObjectMapper(objectMapper);
        DateFormat dateFormat = objectMapper.getDateFormat();
        objectMapper.setDateFormat(new MyDateFormat(dateFormat));
        return converter;
    }
}

Even if it is completed so far, there will be no problem when converting again. You can give it a try.

Guess you like

Origin blog.csdn.net/qq_45699784/article/details/131044965
Recommended