解决jackson反序列化失败InvalidFormatException:Can not deserialize value of type java.util.Date
作者:huangyaa729
今天调试接口的时候碰到了这个问题,String 转Date类型时
反序列化失败
caused by: com.fasterxml.jackson.databind.exc.InvalidFormatException:
Can not deserialize value of type java.util.Date from String
“2018-12-25 10:07:49”: not a valid representation (error: Failed to
parse Date value ‘2018-12-25 10:07:49’: Can not parse date “2018-12-25
10:07:49Z”: while it seems to fit format
‘yyyy-MM-dd’T’HH:mm:ss.SSS’Z’’, parsing fails (leniency? null))
首先尝试了 @DateTimeFormat注解,发现没有效果,仍然报错;
然后试了下@JsonFormat注解,接口正常;
在印象中,@DateTimeFormat是入参时进行数据格式化转换,@JsonFormat是出参进行格式话转换,为啥突然不行了呢。
通过一番搜索,找到了如下解释
一般都是使用@DateTimeFormat把传给后台的时间字符串转成Date,使用@JsonFormat把后台传出的Date转成时间字符串,但是@DateTimeFormat只会在类似@RequestParam的请求参数(url拼接的参数才生效,如果是放到RequestBody中的form-data也是无效的)上生效,如果@DateTimeFormat放到@RequestBody下是无效的。
在@RequestBody中则可以使用@JsonFormat把传给后台的时间字符串转成Date,也就是说@JsonFormat其实既可以把传给后台的时间字符串转成Date也可以把后台传出的Date转成时间字符串。
至于为啥没效果,没有细说,从报错的分析来看应该是反序列话的方式不同,导致@DateTimeFormat注解不能生效。
另附原因与多种解决方式
原因
fastjson默认使用的序列化格式:
public static String DEFFAULT_DATE_FORMAT = “yyyy-MM-dd HH:mm:ss”;
jackson默认支持的日期反序列格式:
(“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”))
jackjson解析框架在解析实体类里面是date数据类型的数据时的默认格式是:UTC类型,即yyyy-MM-dd’T’HH:mm:ss.SSS
并且默认为+8时区,即时间基础上加8小时,
Springboot使用的默认json解析框架是jackjson框架
解决办法一
重写jackson反序列化
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import java.io.IOException; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; /** * @version 1.0.0 * @description 重写反序列化 * @date 2018/12/25 9:51 **/ public class CustomJsonDateDeserializer extends JsonDeserializer<Date> { @Override public Date deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String date = jp.getText(); try { return format.parse(date); } catch (ParseException e) { throw new RuntimeException(e); } } }
在需要的date属性上添加注解:
@JsonDeserialize(using = CustomJsonDateDeserializer.class) private Date txnTime;
使用这种方式,需要重写上面反序列化抽象类
解决办法二
使用@JsonFormat注解指定所需的接收格式,不需要重写反序列化:
//GMT+8表示时区,东八区,需加上时区,shape 默认是JsonFormat.Shape.ANY, @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") private Date txnTime;
解决办法三
如果排除了jackjson框架则使用fastjson注解,不要重写反序列化
@JSONField(format = “yyyy-MM-dd HH:mm:ss”) private Date txnTime;
需要添加的依赖:
<!-- fastjson --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.32</version> </dependency> <!-- jackson--> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.6.4</version> </dependency>
最后介绍一种全局修改接收时间格式的方式
用MappingJackson2HttpMessageConverter配置在Application.Java启动类,指定接收格式,本人不推荐使用,因为这是全局性的,不是很灵活,因此了解即可
@Bean public MappingJackson2HttpMessageConverter getMappingJackson2HttpMessageConverter() { MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter(); //设置日期格式 ObjectMapper objectMapper = new ObjectMapper(); SimpleDateFormat smt = new SimpleDateFormat("yyyy-MM-dd"); objectMapper.setDateFormat(smt); mappingJackson2HttpMessageConverter.setObjectMapper(objectMapper); //设置中文编码格式 List<MediaType> list = new ArrayList<MediaType>(); list.add(MediaType.APPLICATION_JSON_UTF8); mappingJackson2HttpMessageConverter.setSupportedMediaTypes(list); return mappingJackson2HttpMessageConverter; }
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。