【问题标题】:How to override Jackson ObjectMapper configuration for Spring Cloud Stream?如何覆盖 Spring Cloud Stream 的 Jackson ObjectMapper 配置?
【发布时间】:2021-10-24 20:04:27
【问题描述】:

在 Spring Boot/Spring Cloud Stream 应用程序中,我们使用 Kafka binder。我注意到在反序列化包含ZonedDateTime 属性的Kafka 消息时,即使序列化形式包含时区(例如20210101084239+0200),Jackson 也会自动更改时区(到UTC)。 经过一番研究,我发现这是一个可以禁用的默认反序列化功能,因此我在我的 @Configuration 类之一中添加了以下内容:

    @Bean
    public Jackson2ObjectMapperBuilderCustomizer objectMapperCustomizer() {
        return builder ->  {
            builder.featuresToDisable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE);
            //... other custom config...
        };

但这不起作用,大概是因为 Spring Cloud Stream(或 Kafka binder)使用的 ObjectMapper 不是从应用程序上下文中配置的 Jackson2ObjectMapperBuilder 构造的:-(。

经过更多研究,我发现有人声称有必要覆盖 Spring Messaging 的 MappingJackson2MessageConverter,因为它会创建自己的 ObjectMapper。所以我添加了这个:

    @Bean
    public MappingJackson2MessageConverter springMessagingJacksonConverter() {
        MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
        converter.getObjectMapper().configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, false);

        return converter;
    }

不幸的是,这仍然不起作用。我仍然在反序列化 ZonedDateTime 对象,忽略 JSON 值中的时区信息。

那么 Spring Cloud Stream Kafka binder 使用的 ObjectMapper 是由什么 bean 创建的,如何自定义其配置?

【问题讨论】:

    标签: spring-boot jackson spring-kafka spring-cloud-stream


    【解决方案1】:

    正如下面的讨论 cmets 和 here 中所述,Spring Cloud Stream 中存在一个错误,即它没有在应使用的地方使用 Spring 应用程序上下文中的 ObjectMapper

    话虽如此,解决方法是定义您自己的Serde<> @Bean,它调用JsonSerde<> 构造函数,该构造函数采用从应用上下文注入的ObjectMapper。例如:

    @Configuration
    public class MyConfig {
        @Bean
        public Serde<SomeClass> someClassSerde(ObjectMapper jsonMapper) {
            return new JsonSerde<SomeClass>(SomeClass.class, jsonMapper);
        }
    }
    

    此解决方法的缺点是您必须针对要在消息中序列化/反序列化的每种目标类型执行此操作。

    【讨论】:

      【解决方案2】:

      请看spring boot reference

      如果您想完全替换默认的 ObjectMapper,请定义该类型的 @Bean 并将其标记为 @Primary,或者,如果您更喜欢基于构建器的方法,请定义 Jackson2ObjectMapperBuilder @Bean。请注意,在任何一种情况下,这样做都会禁用 ObjectMapper 的所有自动配置。

      【讨论】:

      • Jackson2ObjectMapperBuilderCustomizer 与那些类似,但允许您自定义而不是完全替换 ObjectMapper 构建器。这就是我已经做的,我知道它正在被使用,因为我在ObjectMapper 实例中看到它,我注入我自己的类。但是 Spring Cloud Stream/Kafka 出于某种原因没有使用它。
      • 您能否提出问题 - github.com/spring-cloud/spring-cloud-stream/issues 并参考此讨论?我看到AbstractMessageChannelBinderBindingServiceBindingsLifecycleController 等都在创建 ObjectMapper 的新实例,而他们确实需要来自 AC 的实例
      • @OlegZhurakousky 现在有什么解决方法吗?我必须添加一个 mix-in 来支持某些第三方类型的反序列化。
      • 对于消息转换器,我们确实从 AC 中提取 ObjetMapper,所以我不确定这些其他类如何影响您。也许如果您可以创建一个最小的小项目来重现问题并将其推送到某处的guthub,我们可以查看是否有潜在的解决方法
      • 组装一个最小的项目来演示需要一些时间。同时,这里是杰克逊未能反序列化 LocalDateRange 的堆栈跟踪(我已经为 AC ObjectMapper 添加了一个 mixin)gist.github.com/erizzo/cb5b8b0756bdc3f6323df9117a8f782c
      猜你喜欢
      • 1970-01-01
      • 2016-01-28
      • 1970-01-01
      • 2018-05-27
      • 1970-01-01
      • 2016-06-21
      • 2012-10-17
      • 2021-04-03
      • 1970-01-01
      相关资源
      最近更新 更多