Ich bin ein Kafka-Stream App in Java zu schreiben, die von einem Anschluss erstellt Eingang Themen nehmen, das das Schema Registry verwendet und Avro sowohl für den Schlüssel und Wertwandler. Der Verbinder erzeugt das folgende Schema:
key-schema: "int"
value-schema:{
"type": "record",
"name": "User",
"fields": [
{"name": "firstname", "type": "string"},
{"name": "lastname", "type": "string"}
]}
Tatsächlich gibt es mehrere Themen, das Schlüssel-Schema ist immer „int“ und das Wert-Schema ist immer eine Aufzeichnung von irgendeiner Art (Benutzer, Produkt, etc.). Mein Code enthält die folgenden Definitionen
Map<String, String> serdeConfig = Collections.singletonMap("schema.registry.url", schemaRegistryUrl);
Serde<User> userSerde = new SpecificAvroSerde<>();
userSerde.configure(serdeConfig, false);
Zuerst habe ich versucht , das Thema mit etwas raubend wie Consumed.with(Serdes.Integer(), userSerde);
aber das hat nicht funktioniert , weil Serdes.Integer () erwartet 4 Bytes werden ganze Zahlen codiert sind aber avro verwendet eine Codierung mit variabler Länge. Mit Consumed.with(Serdes.Bytes(), userSerde);
gearbeitet , aber ich wollte wirklich int und nicht Bytes , damit ich meinen Code dies geändert
KafkaAvroDeserializer keyDeserializer = new KafkaAvroDeserializer()
KafkaAvroSerializer keySerializer = new KafkaAvroSerializer();
keyDeserializer.configure(serdeConfig, true);
keySerializer.configure(serdeConfig, true);
Serde<Integer> keySerde = (Serde<Integer>)(Serde)Serdes.serdeFrom(keySerializer, keyDeserializer);
Dies machte den Compiler erzeugt eine Warnung (es funktioniert nicht wie das (Serde<Integer>)(Serde)
Casting) , aber es erlaubt mich , zu verwenden
Consumed.with(keySerde, userSerde);
und eine ganze Zahl als Schlüssel erhalten. Dies funktioniert gut und meine App verhält wie erwartet (super !!!). Aber jetzt will ich Standard serde für den Schlüssel / Wert definieren, und ich kann es nicht an der Arbeit.
den Standardwert serde Einstellung ist einfach:
streamsConfiguration.put(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG, SpecificAvroSerde.class);
Allerdings kann ich nicht herausfinden, wie die Standardschlüssel serde zu definieren.
Ich habe es versucht
streamsConfiguration.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, keySerde.getClass().getName());
Erzeugt Laufzeitfehler: Es konnte keine öffentlichen Konstruktor ohne Argumente für org.apache.kafka.common.serialization.Serdes $ WrapperSerde findenstreamsConfiguration.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, SpecificAvroSerde.class);
Erzeugt Laufzeitfehler: java.lang.Integer kann nicht auf org.apache.avro.specific.SpecificRecord gegossen werden
Was vermisse ich? Vielen Dank.
Update (Version 5.5 und höher)
Confluent Version 5.5
bietet native Unterstützung für primitive Typen Avro über PrimitiveAvroSerde
(vgl https://github.com/confluentinc/schema-registry/blob/5.5.x/avro-serde/src/main/java/io/confluent/kafka/streams /serdes/avro/PrimitiveAvroSerde.java )
Original Antwort (Version 5.4 und älter) :
Es ist ein bekannten Probleme. Primitive Avro - Typen funktionieren nicht gut mit Confluent der AvroSerdes, weil der SerDes mit arbeitet GenericAvroRecord
und SpecificAvroRecord
nur.
Vergleichen https://github.com/confluentinc/schema-registry/tree/master/avro-serde/src/main/java/io/confluent/kafka/streams/serdes/avro .
So bauen Sie Serde besitzen basiert auf KafkaAvroSerializer
und KafkaAvroDeserializer
ist der richtige Ansatz. Um dies in die Konfiguration als Standard - Serde zu übergeben, können Sie nicht verwenden , Serdes.serdeFrom
da die Typinformationen aufgrund genrics Typs Löschung verloren.
Sie können jedoch Sie eine eigene Klasse implementieren , die sich Serde
Schnittstelle statt und Ihre benutzerdefinierte Klasse in der Config - Pass:
public class MySerde extends Serde<Integer> {
// use KafkaAvroSerializer and KafkaAvroDeserializer and cast `Object` to `Integer`
}
config.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, MySerde.class);