Currently I use JSON for the messages in spring kafka and that is pretty easy and works with almost no coding:
@KafkaListener(topics = "foo.t",)
public void receive(Foo payload) {
LOG.info("received payload='{}'", payload);
doMagic(payload);
}
@KafkaListener(topics = "bar.t",)
public void receive(Bar payload) {
LOG.info("received payload='{}'", payload);
doMagic(payload);
}
and little config:
# Kafka Config
spring.kafka.bootstrap-servers=broker.kafka
spring.kafka.consumer.group-id=some-app
spring.kafka.consumer.properties.value.deserializer=org.springframework.kafka.support.serializer.JsonDeserializer
spring.kafka.consumer.properties.spring.json.trusted.packages=com.example.someapp.dto
Which works (great) because the content/type information is encoded in the JSON and thus can be restored from the bytes alone. (There are issues with that as well, but it works) However in protobuf I don't have these meta-information or at least I don't know where to find them.
Question:
Is there a way to declare a generic kafka MessageConverter that works for multiple types, without throwing all the nice abstraction/auto configuration from spring out of the window?
(I would also like to use this for JSON, as encoding the content/data type of the message i the message has both some security and compatibility issues)
I would like to avoid something like this solution: https://stackoverflow.com/a/46670801/4573065 .
Alternatives
Write a message converter/ Deserializer
that tries all kafka classes.
@Override
public T deserialize(String topic, byte[] data) {
try {
return (T) Foo.parse(data);
} catch (Exception e) {
try {
return (T) Bar.parse(data);
} catch (Exception e1) {
throw e
}
}
}
However this will probably negate all performance gains I hope to get by using a binary format.
Another alternative would be to statically map topic->content type however this would still be something error prone or at least hard to make spring configure for you.
EDIT: My producer looks like this:
public void send(String message) {
kafkaTemplate.send("string.t", message);
}