• feign请求返回值反序列LocalDateTime异常记录


    前言

    最近项目组用feign调用远程服务,消费端报了如下一个异常
    feign-localDateTime异常.png
    从异常信息可以得出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

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

    总结

    异常信息很重要,源码很重要,官网同样重要

  • 相关阅读:
    sql-DDL, DML 常用语句
    7.8 Structured Streaming
    7.7 输出操作
    7.6 转换操作
    7.5 高级数据源---Kafka
    7.4 基本输入源
    7.3 DStream操作
    7.2 Spark Streaming
    7.1 流计算概述
    6.3 使用Spark SQL读写数据库
  • 原文地址:https://www.cnblogs.com/linyb-geek/p/15064781.html
Copyright © 2020-2023  润新知