前言
最近项目组用feign调用近程服务,生产端报了如下一个异样
从异样信息能够得出localdatime反序列化出了异样,而这个异样又是因为jackson无奈解决导致。因而咱们能够为jackson的ObjectMapper适配一下
解决办法
1、在pom.xml引入
<dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-jsr310</artifactId> <version>${jackson.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-jdk8</artifactId> <version>${jackson.version}</version> </dependency>
注: jackson-datatype-jsr310这是用来反对jsr310标准的工夫,jackson-datatype-jdk8用来反对新的特定于JDK8的类型,例如Optional
2、替换默认的ObjectMapper
@Configurationpublic class LocalDateTimeConfig { public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; @Bean public ObjectMapper objectMapper() { ObjectMapper objectMapper = new ObjectMapper(); objectMapper.registerModule(new Jdk8Module()); objectMapper.setDateFormat(new SimpleDateFormat(DEFAULT_DATE_TIME_FORMAT)); objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8")); objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); objectMapper.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE); JavaTimeModule javaTimeModule = new JavaTimeModule(); javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT))); javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT))); objectMapper.registerModule(javaTimeModule).registerModule(new ParameterNamesModule()); return objectMapper; }
疑难点:为什么替换了默认的ObjectMapper后,feign就能够解决LocalDateTime
答案就在
@Configuration(proxyBeanMethods = false)public class FeignClientsConfiguration { @Autowired private ObjectFactory<HttpMessageConverters> messageConverters; @Bean @ConditionalOnMissingBean public Decoder feignDecoder() { return new OptionalDecoder( new ResponseEntityDecoder(new SpringDecoder(this.messageConverters))); }}
而messageConverters默认的转换器是依据HttpMessageConvertersAutoConfiguration而来
@Configuration(proxyBeanMethods = false)@ConditionalOnClass(HttpMessageConverter.class)@Conditional(NotReactiveWebApplicationCondition.class)@AutoConfigureAfter({ GsonAutoConfiguration.class, JacksonAutoConfiguration.class, JsonbAutoConfiguration.class })@Import({ JacksonHttpMessageConvertersConfiguration.class, GsonHttpMessageConvertersConfiguration.class, JsonbHttpMessageConvertersConfiguration.class })public class HttpMessageConvertersAutoConfiguration { static final String PREFERRED_MAPPER_PROPERTY = "spring.http.converters.preferred-json-mapper"; @Bean @ConditionalOnMissingBean public HttpMessageConverters messageConverters(ObjectProvider<HttpMessageConverter<?>> converters) { return new HttpMessageConverters(converters.orderedStream().collect(Collectors.toList())); }
ObjectProvider具备提早加载的性能,会依据理论状况加载。springboot的web模块默认会引入Jackson相干包。官网上有这么一段话
这个就阐明默认的HttpMessageConverter为MappingJackson2HttpMessageConverter,而MappingJackson2HttpMessageConverter会利用objectMapper来进行序列化和反序列化
下面的的话用代码整顿如下
public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; @Bean public Decoder feignDecoder() { return new ResponseEntityDecoder(new SpringDecoder(messageConverters())); } public ObjectFactory<HttpMessageConverters> messageConverters() { return () -> new HttpMessageConverters(mappingJackson2HttpMessageConverter()); } public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() { return new MappingJackson2HttpMessageConverter(objectMapper()); } public ObjectMapper objectMapper() { ObjectMapper objectMapper = new ObjectMapper(); objectMapper.registerModule(new Jdk8Module()); objectMapper.setDateFormat(new SimpleDateFormat(DEFAULT_DATE_TIME_FORMAT)); objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8")); objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); objectMapper.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE); JavaTimeModule javaTimeModule = new JavaTimeModule(); javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT))); javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT))); objectMapper.registerModule(javaTimeModule).registerModule(new ParameterNamesModule()); return objectMapper; }
总结
异样信息很重要,源码很重要,官网同样重要