卡夫卡的JsonDeserializer不适用于java.util.Map

时间:2019-05-14 10:28:03

标签: java apache-kafka spring-kafka

我正在使用JsonDeserializer反序列化自定义对象,但是在用@KafkaListener注释的方法中,获取Map字段为null的对象。

public ConsumerFactory<String, BizWebKafkaTopicMessage> consumerFactory(String groupId) {
  Map<String, Object> props = new HashMap<>();
  props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapAddress);
  props.put(ConsumerConfig.GROUP_ID_CONFIG, groupId);
  return new DefaultKafkaConsumerFactory<>(props, new StringDeserializer(), new JsonDeserializer<>(BizWebKafkaTopicMessage.class));
}

我的BizWebKafkaTopicMessage是

@Data
public class BizWebKafkaTopicMessage {

    // Elastic Search Index Name
    private String indexName;

    // ElasticSearch Index's type name
    private String indexType;

    // Source document to be used
    private Map<String, Object> source; <=== This is being delivered as null.

    // ElasticSearch document primary id
    private Long id;
}

和侦听器方法 listenToKafkaMessages

@KafkaListener(topics = "${biz-web.kafka.message.topic.name}", groupId = "${biz-web.kafka.message.group.id}")
public void listenToKafkaMessages(BizWebKafkaTopicMessage message) {
............................................
............................................
         // Here message.source is null
............................................
............................................
}

listenToKafkaMessages方法中,消息参数看起来像这样

message.indexName = 'neeraj';
message.indexType = 'jain';
message.id = 123;
message.source = null;

1 个答案:

答案 0 :(得分:2)

我强烈怀疑这是您价值的多态性,而不是Maps本身。

Spring在引擎盖下使用Jackson进行序列化/反序列化-默认情况下,Jackson(序列化)在处理Object实例时不对序列化的类进行编码。

为什么?好吧,这会导致糟糕的兼容性问题,例如您在1年前将一个对象(Really MyPojoV1.class)序列化到数据库中,然后又将其读出-但是您的代码不再有MyPojoV1.class,因为事情进展了...如果移动MyPojoV1,它甚至可能导致问题在应用程序生存期内的任何地方都可以使用其他软件包!

因此,在反序列化时,杰克逊不知道将该对象反序列化到哪个类。

一个骇人听闻的主意是在某处运行以下命令:

ObjectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

或者更好/更春季的方式是:

@Configuration
public class JacksonConfiguration {

 @Bean
 public ObjectMapper objectMapper() {
    ObjectMapper mapper = new ObjectMapper();
    #Your Configuration Here for example  mapper.configure(DeserializationFeature.something, true);

    return mapper;
 }
}

最后值得一提的是,任意反序列化类通常会带来很大的安全风险。 Java中存在一些类,它们根据其字段中的值执行命令行甚至基于反射的逻辑(Jackson会很乐意为您填充)。因此,有人可以制作JSON,以便您反序列化为一个类,该类基本上执行value = {}字段中的任何命令。

您可以在此处阅读有关漏洞利用的更多信息-尽管我知道它可能与您无关,因为您的Kafka集群及其生产者可能固有地处于您的“受信任范围”内: https://www.nccgroup.trust/globalassets/our-research/us/whitepapers/2018/jackson_deserialization.pdf