【问题标题】:Send supertype as type information in Kafka JSON Serialization在 Kafka JSON 序列化中发送超类型作为类型信息
【发布时间】:2019-09-09 12:43:33
【问题描述】:

我正在使用 Spring Boot 使用 Kafka 将数据从一个应用程序发送到另一个应用程序。

我的设计使用接口来声明正在发送的数据:

package domain;

interface Data {
    public String getData();
    public void setData(String data);
}

制片人

在源应用程序中,我将此接口实现为 db 实体。

package persistence;

@Data
class DataEntity implements Data {
    private String data;  // lombok generates getter/setters
}

添加实体后,我想使用 KafkaTemplate 将其作为更新发送到 Kafka

@Component
class DataPublisher implements ApplicationListener<DataEvent> {
    @Autowired private KafkaTemplate<String,Data> template;

    // I left out DataEvent which is a straightforward ApplicationEvent override
    @EventListener(classes = DataEvent.class)
    public void onApplicationEvent(DataEvent event) {
        template.send("data", (Data) event.getSource());
    }
}
// triggered by this call in a service
    eventPublisher.publishEvent(new DataEvent(updatedData));

序列化是通过属性完成的

spring:
    kafka:
        consumer:
            value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer
            properties.spring.json.value.default.type: domain.Data

查看kafkacat输出,数据发送正常。

消费者

在接收端我有

@KafkaListener(topics = "data")
public void dataUpdated(@Payload Data data) {
    dataService.updateData(data);
}

导致

原因:java.lang.IllegalArgumentException:类“persistence.DataEntity”不在受信任的包中[...]

我完全理解——序列化程序发送一个persistence.DataEntity 对象,但客户端需要一个domain.Data 对象。但这就是设计的本意;我希望客户只知道域包,而不是它的persistence 实现。 (作为一个附带问题,我在哪里可以看到这种类型的标头?它不在编码的 json AFAICT 中,我错过了什么?)

所以问题是:如何强制 Spring JsonDeserializer 发送 domain.Data 作为序列化数据类型?

我确实在序列化程序类中找到了一个 TYPE_MAPPING 属性,但它唯一的文档是它“将 [s] 类型映射添加到类型映射器:'foo:com.Foo,bar:com.Bar'”没有解释任何东西,我找不到示例用法。

编辑:

我确实添加了

spring.kafka.producer.properties.spring.json.type.mapping=domain.Data:persistence.DataEntity

到生产者的属性,但这没有帮助。

【问题讨论】:

    标签: java spring spring-boot apache-kafka spring-kafka


    【解决方案1】:

    the documentation

    您必须提供双方的映射。

    但是,您应该使用BytesDeserializerBytesJsonMessageConverter,而不是使用JsonDeserializer(只需添加一个@Bean,Boot 就会将其连接到容器工厂)。

    这样框架会自动转换成参数类型。

    再次,请参阅the documentation

    【讨论】:

    • 我也读过那部分,但仍然没有完全明白。所以我以token为代表,将其映射到每一侧的不同类型?等我回到我的机器上试试看。
    • 好的,所以我确实将spring.kafka.producer.properties.spring.json.type.mapping=data:persistence.DataEntity 添加到了生产者并将spring.kafka.consumer.properties.spring.json.type.mapping=data:domain.Data 添加到了消费者,但我仍然在消费者身上得到“类'persistence.DataEntity'不在受信任的包中”一边。
    • 对;您还必须将包添加到反序列化器的受信任包中。这是为了保护您免受恶意行为。
    • 是的,但我想反序列化为 domain.Datadomain is 在受信任的包中。为什么它甚至提到了persistence 包?我假设它永远不会到达消费者,因为我已经使用了该类型的令牌。
    • 您的映射似乎没有以某种方式应用;要么在调试器中运行它以找出原因,要么发布一个展示该行为的小示例应用程序。有一个 test case here 表明它有效。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-16
    • 2013-10-18
    相关资源
    最近更新 更多