Spring boot Spring云流反序列化来自Kafka主题的无效JSON

Spring boot Spring云流反序列化来自Kafka主题的无效JSON,spring-boot,apache-kafka,spring-cloud-stream,embedded-kafka,Spring Boot,Apache Kafka,Spring Cloud Stream,Embedded Kafka,我正在努力将Spring Cloud Streams与Kafka binder集成。目标是我的应用程序使用主题中的json并将其反序列化为Java对象。我使用的是功能型方法,而不是命令式方法。我的代码使用结构良好的json输入 另一方面,当我发送无效的json时,我希望触发错误日志记录方法。这在某些测试用例中有效,在另一个测试用例中不起作用。我的应用程序反序列化json,即使它无效并触发包含逻辑的方法,而不是错误日志记录方法 我无法解决框架为什么反序列化一些非结构化json输入的问题 @Buil

我正在努力将Spring Cloud Streams与Kafka binder集成。目标是我的应用程序使用主题中的json并将其反序列化为Java对象。我使用的是功能型方法,而不是命令式方法。我的代码使用结构良好的json输入

另一方面,当我发送无效的json时,我希望触发错误日志记录方法。这在某些测试用例中有效,在另一个测试用例中不起作用。我的应用程序反序列化json,即使它无效并触发包含逻辑的方法,而不是错误日志记录方法

我无法解决框架为什么反序列化一些非结构化json输入的问题

@Builder
@吸气剂
@塞特
@AllArgsConstructor
@诺尔格构装师
公共级卡夫卡文崔克酒店{
@JsonProperty(value=“传输\元数据”,必需=true)
@非空
私有传输元数据传输元数据;
@JsonProperty(value=“payload”,required=true)
@非空
专用有效载荷;
}
@组件
公共类令牌事件消费者{
@豆子
消费者(){
返回事件->{
log.info(“从Kafka{}消耗的Kafka事件数据”,事件);
};
}
}
@配置
@Slf4j
公共类CloudStreamErrorHandler{
@ServiceActivator(inputChannel=“errorChannel”)
公共无效句柄错误(ErrorMessage ErrorMessage){
error(“错误消息为{}”,errorMessage);
}
}
@EmbeddedKafka(主题={“批处理中”},分区=3)
@TestPropertySource(属性={“spring.kafka.producer.bootstrap servers=${spring.embedded.kafka.brokers}”,
“spring.kafka.consumer.bootstrap servers=${spring.embedded.kafka.brokers}”,
“spring.cloud.stream.kafka.binder.brokers=${spring.embedded.kafka.brokers}”})
@SpringBootTest(webEnvironment=SpringBootTest.webEnvironment.RANDOM\u端口)
@ActiveProfiles(“测试”)
@Slf4j
公共类KafkaTokenConsumerTest{
私有静态字符串TOPIC=“批处理输入”;
@自动连线
私人嵌入卡夫卡布洛克嵌入卡夫卡布洛克;
@自动连线
私人卡夫卡模板卡夫卡模板;
@自动连线
卡夫卡列斯汀私人登记处;
@自动连线
私有对象映射器对象映射器;
@间谍
卡夫卡文坦德勒工厂卡夫卡文坦德勒工厂;
@间谍
CloudStreamErrorHandler CloudStreamErrorHandler;
@之前
无效设置(){
对于(MessageListenerContainer MessageListenerContainer:endpointRegistry.getListenerContainers()){
ContainerTestUtils.waitForAssignment(messageListenerContainer,embeddedKafkaBroker.getPartitionsPerTopic());
}
}
//这个方法通过了
@试验
public void rejectedCorruptedMessage()引发ExecutionException、InterruptedException{
kafkaTemplate.send(主题“{{”).get();//同步调用
CountDownLatch闩锁=新的CountDownLatch(1);
等待(5L,时间单位秒);
//这个框架试了两次,不知道为什么
验证(cloudStreamErrorHandler,times(2)).handleError(isA(ErrorMessage.class));
}
//这种方法失败了
@试验
public void rejectedCorruptedMessage2()引发ExecutionException、InterruptedException{
kafkaTemplate.send(主题“{}”).get();//同步调用
CountDownLatch闩锁=新的CountDownLatch(1);
等待(5L,时间单位秒);
//这个框架试了两次,不知道为什么
验证(cloudStreamErrorHandler,times(2)).handleError(isA(ErrorMessage.class));
}
}
rejectCorruptedMessage测试方法中的json会触发
handleError(ErrorMessage ErrorMessage)
方法,这是预期的,因为它是无效的json。另一方面,
JSON在ToKeEngEngestCuffor类中的<强> > Read CurraseMeule2>/Stult>测试方法,触发器<代码>消费类()/代码>方法中,这不是预期的行为,但是,我得到的KAFKEvestRead对象具有空值。

< P>杰克逊不认为这是无效的JSON,它忽略了尾随<代码> }。并将
{}
解码为空对象

公共类SO67804599应用{
公共静态void main(字符串[]args)引发异常{
ObjectMapper mapper=新的ObjectMapper();
JavaType=mapper.constructType(Foo.class);
对象foo=mapper.readerFor(foo.class.readValue(“{”bar\“:\”baz\“}”);
系统输出打印项次(foo);
foo=mapper.readerFor(foo.class.readValue(“{}”);
系统输出打印项次(foo);
}
公共静态类Foo{
弦杆;
公共字符串getBar(){
返回此.bar;
}
公共空心立根杆(弦杆){
这个.bar=bar;
}
@凌驾
公共字符串toString(){
返回“Foo[bar=“+this.bar+”]”;
}
}
}

您应该在生产者端使用
StringSerializer
,因为您发送的是原始json;
JsonSerializer
将有效负载转换为有效的JSON字符串。新配置如下:spring.deserializer.key.delegate.class=org.springframework.kafka.support.serializer.jsondeselizer.spring.deserializer.value.delegate.class=org.springframework.kafka.support.serializer.jsondeselizerspring.json.value.default.type=com.batikan.api.v1.kafka.event.consumer.KafkaEventRecord spring.json.use.type.headers=false,但问题仍在继续。当我发送{{{}有效负载时,我收到org.springframework.kafka.support.serializer.DeserializationException,我收到了带有空字段的KafkaEventRecord对象。我看到你是新来的-不要在注释中添加这样的内容;它不会很好地呈现;而是编辑问题并注释你已经这样做了。你误读了我的注释,我相信问题出在发送端。看起来Jackson只是
spring.cloud.stream.kafka.bindings.consumer-in-0.consumer.configuration.spring.deserializer.key.delegate.class=org.apache.kafka.common.serialization.StringDeserializer
spring.cloud.stream.kafka.bindings.consumer-in-0.consumer.configuration.spring.deserializer.value.delegate.class=org.springframework.kafka.support.serializer.JsonDeserializer
spring.cloud.stream.kafka.bindings.consumer-in-0.consumer.configuration.key.deserializer=org.springframework.kafka.support.serializer.ErrorHandlingDeserializer
spring.cloud.stream.kafka.bindings.consumer-in-0.consumer.configuration.value.deserializer=org.springframework.kafka.support.serializer.ErrorHandlingDeserializer

// Producer only for testing purpose
spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer
spring.kafka.producer.value-serializer=org.springframework.kafka.support.serializer.JsonSerializer
Foo [bar=baz]
Foo [bar=null]