【问题标题】:Spring stream binds to String instead to pojoSpring 流绑定到 String 而不是 pojo
【发布时间】:2019-11-05 10:09:42
【问题描述】:

我们刚刚将 Spring 升级到:

Spring boot: 2.1.0.RELEASE

Spring cloud: Greenwich.SR1

Spring integration kafka: 3.1.0.RELEASE

Spring kafka: 2.2.7.RELEASE

我们正在使用

Kafka 2.1.1

我们有一个主题,可以将不止一种类型的类实例发送到,它们都从同一个抽象类扩展而来。让我们命名为 AbstractMessage 的抽象类,还有 MessageImpl1 和 MessageImpl2 的子类。

我们曾经在消费者中将它作为对象接收(以便在以某种方式接收到错误的类时写入日志),然后使用if(message instanceof MessageImpl){}将其转换为相关的 MessageImpl

升级后,所有消息都绑定到 String 而不是它们的类。

我读到here content-type=application/json 绑定到 pojo,但即使我在输入和输出中都添加了它,它还是绑定到了一个字符串:

spring.cloud.stream.bindings.input.contentType=application/json
spring.cloud.stream.bindings.output.contentType=application/json

尝试直接接收MessageImpl得到这个错误:

原因:com.fasterxml.jackson.databind.exc.InvalidDefinitionException: 不能 构造MessageImpl1 的实例(没有创建者,默认 构造,存在):不能从对象值反序列化(没有委托- 或基于财产的创作者) 在[来源:(字节[])

知道怎么解决吗?

【问题讨论】:

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


    【解决方案1】:

    您是从哪个版本升级的?显示您的代码和配置属性。以前的版本默认使用 Kryo 序列化,现在不赞成使用 JSON,但您的 POJO 需要对 json 友好。

    Kryo 序列化已弃用,但您可以添加转换器。

    the documentation

    提供的 MessageConverters

    如前所述,该框架已经提供了一组 MessageConverters 来处理最常见的用例。以下列表按优先级顺序描述了提供的 MessageConverter(使用第一个工作的 MessageConverter):

    1. ApplicationJsonMessageMarshallingConverter:org.springframework.messaging.converter.MappingJackson2MessageConverter 的变体。在 contentType 为 application/json (DEFAULT) 的情况下,支持将 Message 的有效负载转换为 POJO 或从 POJO 转换。

    2. TupleJsonMessageConverter: DEPRECATED 支持消息的有效负载与 org.springframework.tuple.Tuple 之间的转换。

    3. ByteArrayMessageConverter:在 contentType 为 application/octet-stream 的情况下,支持将 Message 的有效负载从 byte[] 转换为 byte[]。它本质上是一种传递,主要是为了向后兼容而存在。

    4. ObjectStringMessageConverter:当 contentType 为 text/plain 时,支持将任何类型转换为 String。它调用 Object 的 toString() 方法,或者,如果有效负载是 byte[],则调用一个新的 String(byte[])。

    5. JavaSerializationMessageConverter: DEPRECATED 当 contentType 为 application/x-java-serialized-object 时支持基于 java 序列化的转换。

    6. KryoMessageConverter: DEPRECATED 当 contentType 为 application/x-java-object 时支持基于 Kryo 序列化的转换。

    7. JsonUnmarshallingConverter:类似于ApplicationJsonMessageMarshallingConverter。当 contentType 为 application/x-java-object 时,它支持任何类型的转换。它期望将实际类型信息作为属性嵌入到 contentType 中(例如,application/x-java-object;type=foo.bar.Cat)。

    当没有找到合适的转换器时,框架会抛出异常。发生这种情况时,您应该检查您的代码和配置并确保您没有遗漏任何内容(即,确保您通过使用绑定或标头提供了 contentType)。但是,很可能,您发现了一些不常见的情况(例如自定义 contentType),并且当前提供的 MessageConverters 堆栈不知道如何转换。如果是这种情况,您可以添加自定义 MessageConverter。请参阅用户定义的消息转换器。

    【讨论】:

    • 代码中处理程序方法的签名是什么?该方法参数类型是转换是否发生的唯一决定因素。内容类型仅用于在确定需要转换后帮助选择实际转换器。
    • Kryo 没关系;转换器隐含地知道要将数据反序列化到什么。那么,只要反序列化的类有相同的超类,可以是Abstract,就可以将超类作为参数,然后在方法内进行强制转换。
    • 实际上进一步查看您的原始帖子“原因:com.fasterxml.jackson.databind.exc.InvalidDefinitionException:无法构造 MessageImpl1 的实例......” .这仅仅意味着您的 MessageImpl1 不是 JSON 友好的 - 这意味着 json 解析器在反序列化期间无法创建对象的实例。这意味着没有默认构造函数,或者缺少 setter 等来从传入流(表示为 byte[])创建和初始化对象。
    • 这就是我所说的——它以前有效,因为 Kryo 没有这个限制。他要么需要使用 kryo 转换器,要么让他的 Impls JSON 友好。
    猜你喜欢
    • 2014-05-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-05
    相关资源
    最近更新 更多