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?
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.
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 :)