JsonDeserializer Кафки не работает для java.util.Map - PullRequest
0 голосов
/ 14 мая 2019

Я использую JsonDeserializer для десериализации моего пользовательского объекта, но в моем методе, помеченном @KafkaListener, получаем объект с полем карты как ноль.

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 Ответ

2 голосов
/ 21 мая 2019

Я сильно подозреваю, что это полиморфный характер вашей ценности, а не Карты как таковой.

Spring использует Джексона под колпаком для своей сериализации / десериализации - и по умолчанию Джексон (в сериализации) при обработке экземпляров объекта не кодирует, какой класс он сериализует.

Почему? Ну, это делает для плохих проблем совместимости, например. вы сериализовали объект (действительно MyPojoV1.class) в базу данных 1 год назад, а затем позже прочитали его - но ваш код больше не имеет 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 существуют классы, которые выполняют командную строку или даже логику, основанную на отражении, в зависимости от значения в своих полях (которое Джексон с радостью заполнит для вас). Следовательно, кто-то может создать JSON таким образом, чтобы вы десериализовали его в класс, который в основном выполняет любую команду из поля value = {}.

Вы можете прочитать больше об эксплойтах здесь - хотя я признаю, что это может не касаться вас, поскольку ваш кластер Kafka и его производители могут по своей природе находиться в пределах ваших «доверенных границ»: https://www.nccgroup.trust/globalassets/our-research/us/whitepapers/2018/jackson_deserialization.pdf

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...