如果 ResolvableType 已在标头中,则会发生 InvalidDefinitionException

问题描述 投票:0回答:2

我们在项目中使用了 Spring Integration 和 Spring Kafka。 从 Spring-boot 3.1.7 更新到 3.2.1 后,我们在消息序列化期间遇到异常。

鉴于流程:

@Bean
IntegrationFlow sendToKafkaFlow() {
    return IntegrationFlow.from("sendToKafkaFlow.input")
            .transform(Transformers.toJson()) // 1
           // some more handlers/header enricher 
//        .headerFilter(JsonHeaders.RESOLVABLE_TYPE) // 2
            .handle(Kafka.outboundChannelAdapter(kafkaTemplate) //3
                   .topic("someTopic")
            )
            .get();
}

每次我们用这个流程发送消息时,我们都会看到异常:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException:直接自引用导致循环(通过引用链:org.springframework.core.ResolvableType["componentType"]-org.springframework.core.ResolvableType["componentType"] )

步骤 (1) 中的转换器将创建 json__resolvableType 标头。 在 outboundChannelAdapter (3) 中,DefaultKafkaHeaderMapper 用于创建 kafka 标头。一旦此映射器映射 resolvableType,它将产生错误并且不会映射此标头。

    com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Direct self-reference leading to cycle (through reference chain: org.springframework.core.ResolvableType["componentType"]->org.springframework.core.ResolvableType["componentType"])
    at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77)
    at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1308)
(3) at com.fasterxml.jackson.databind.ser.BeanPropertyWriter._handleSelfReference(BeanPropertyWriter.java:948)
(2) at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:726)
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:772)
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178)
(1) at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:732)
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:772)
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178)
    at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:479)
    at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:318)
    at com.fasterxml.jackson.databind.ObjectMapper._writeValueAndClose(ObjectMapper.java:4719)
    at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsBytes(ObjectMapper.java:3987)

据我在调试器中看到的,componentType为空,将被 EmptyInstance (1) 替换。这个 EmptyInstance 也会被分析。 EmptyInstance 本身将再次返回 componentType (2) 的 EmptyInstance。这就导致了自我参照。 (3)

如果我们删除此标头(流程 2),则标头将丢失并且异常消失。

我尝试在 application.yml 中切换失败自引用

spring:   
  jackson:
    serialization:
      fail-on-self-references: false

但这不起作用。 不幸的是,我们经常有这种模式(在不同的应用程序中)。 (转换、做某事、发送到 kafka)。因此,添加 HeaderMapper 的修改或更改流程,在 kafka 模板中进行 json 序列化需要付出一些努力。

还有什么,我们可以尽量避免这种情况直接自引用导致循环可解析类型头异常?

spring-boot spring-integration spring-kafka jackson-databind
2个回答
0
投票

添加

jackson-databind
应该可以解决您的问题。

如果您使用 Maven,请在 pom.xml 文件中尝试此操作:

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.16.1</version>
</dependency>

0
投票

请参阅这家工厂:

  Transformers.toJson(JsonObjectMapper<?, ?> jsonObjectMapper)

这样你就可以注入由 Spring Boot 自动配置的

ObjectMapper

您还可以使用

headerEnricher()
来使用简单的
JsonHeaders.RESOLVABLE_TYPE
内容覆盖
Class
标头:
headers.get(JsonHeaders.RESOLVABLE_TYPE, ResolvableType.class).getRawClass()

© www.soinside.com 2019 - 2024. All rights reserved.