web-dev-qa-db-fra.com

Spring Boot/Kafka Json Deserialization - Packages sécurisés

Je commence tout juste à utiliser Kafka avec Spring Boot et je souhaite envoyer et consommer des objets JSON.

Je reçois le message d'erreur suivant lorsque je tente d'utiliser un message du sujet Kafka:

org.Apache.kafka.common.errors.SerializationException: Error deserializing key/value for partition dev.orders-0 at offset 9903. If needed, please seek past the record to continue consumption.
Caused by: Java.lang.IllegalArgumentException: The class 'co.orders.feedme.feed.domain.OrderItem' is not in the trusted packages: [Java.util, Java.lang]. If you believe this class is safe to deserialize, please provide its name. If the serialization is only done by a trusted source, you can also enable trust all (*).
at org.springframework.kafka.support.converter.DefaultJackson2JavaTypeMapper.getClassIdType(DefaultJackson2JavaTypeMapper.Java:139) ~[spring-kafka-2.1.5.RELEASE.jar:2.1.5.RELEASE]
at org.springframework.kafka.support.converter.DefaultJackson2JavaTypeMapper.toJavaType(DefaultJackson2JavaTypeMapper.Java:113) ~[spring-kafka-2.1.5.RELEASE.jar:2.1.5.RELEASE]
at org.springframework.kafka.support.serializer.JsonDeserializer.deserialize(JsonDeserializer.Java:218) ~[spring-kafka-2.1.5.RELEASE.jar:2.1.5.RELEASE]
at org.Apache.kafka.clients.consumer.internals.Fetcher.parseRecord(Fetcher.Java:923) ~[kafka-clients-1.0.1.jar:na]
at org.Apache.kafka.clients.consumer.internals.Fetcher.access$2600(Fetcher.Java:93) ~[kafka-clients-1.0.1.jar:na]

J'ai tenté d'ajouter mon package à la liste des packages sécurisés en définissant la propriété suivante dans application.properties:

spring.kafka.consumer.properties.spring.json.trusted.packages = co.orders.feedme.feed.domain

Cela ne semble pas faire de différence. Quelle est la bonne façon d'ajouter mon paquet à la liste des paquets sécurisés pour Kafka JsonDeserializer de Spring?

3
hexkid

Puisque le problème du paquet approuvé est résolu, vous pouvez utiliser le problème de surcharge pour votre prochain problème. 

DefaultKafkaConsumerFactory(Map<String, Object> configs,
            Deserializer<K> keyDeserializer,
            Deserializer<V> valueDeserializer)

 et le "wrapper" JsonDeserializer du printemps kafka

JsonDeserializer(Class<T> targetType, ObjectMapper objectMapper)

En combinant ce qui précède, pour Java, j'ai:

new DefaultKafkaConsumerFactory<>(properties,
                new IntegerDeserializer(),
                new JsonDeserializer<>(Foo.class,
                        new ObjectMapper()
                .registerModules(new KotlinModule(), new JavaTimeModule()).setSerializationInclusion(JsonInclude.Include.NON_NULL)
                .setDateFormat(new ISO8601DateFormat()).configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false))));

Pour l’essentiel, vous pouvez indiquer à l’usine d’utiliser vos propres Deserializers et pour le Json, de fournir votre propre ObjectMapper. Là, vous pouvez enregistrer le module Kotlin, personnaliser les formats de date et autres éléments. 

1
themistoklik

Ok, j'ai lu la documentation un peu plus en détail et j'ai trouvé une réponse à ma question. J'utilise Kotlin pour que la création de mon consommateur ressemble à ceci avec le 

@Bean
fun consumerFactory(): ConsumerFactory<String, FeedItem> {
    val configProps = HashMap<String, Any>()
    configProps[ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG] = bootstrapServers
    configProps[ConsumerConfig.GROUP_ID_CONFIG] = "feedme"
    configProps[ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG] = StringDeserializer::class.Java
    configProps[ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG] = JsonDeserializer::class.Java
    configProps[JsonDeserializer.TRUSTED_PACKAGES] = "co.orders.feedme.feed.domain"
    return DefaultKafkaConsumerFactory(configProps)
}

Maintenant, j'ai juste besoin d'un moyen de remplacer la création de Jackson ObjectMapper dans JsonDeserializer afin qu'il puisse fonctionner avec mes classes de données Kotlin qui n'ont pas de constructeur à zéro argument :)

0
hexkid