├── .github
└── dependabot.yml
├── .gitignore
├── README.md
├── pom.xml
└── src
└── main
├── java
└── com
│ └── codingharbour
│ └── kafka
│ └── protobuf
│ ├── consumer
│ ├── GenericProtobufConsumer.java
│ └── ProtobufConsumer.java
│ └── producer
│ └── ProtobufProducer.java
└── protobuf
└── SimpleMessage.proto
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5 |
6 | version: 2
7 | updates:
8 | - package-ecosystem: "maven" # See documentation for possible values
9 | directory: "/" # Location of package manifests
10 | schedule:
11 | interval: "weekly"
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.idea/*
2 | /target/*
3 | *.iml
4 |
5 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # kafka-protobuf
2 |
3 | > Read the entire tutorial: https://codingharbour.com/apache-kafka/how-to-use-protobuf-with-apache-kafka-and-schema-registry/
4 |
5 | Examples of working with Protobuf (de)serialization
6 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.codingharbour
8 | kafka-protobuf
9 | 1.0-SNAPSHOT
10 |
11 |
12 |
13 | com.google.protobuf
14 | protobuf-java
15 | 3.25.2
16 |
17 |
18 | org.apache.kafka
19 | kafka-clients
20 | 3.6.0
21 |
22 |
23 | io.confluent
24 | kafka-protobuf-serializer
25 | 7.5.2
26 |
27 |
28 |
29 |
30 |
31 | confluent
32 | confluent
33 | https://packages.confluent.io/maven/
34 |
35 |
36 |
37 |
38 |
39 |
40 | org.apache.maven.plugins
41 | maven-compiler-plugin
42 |
43 | 1.8
44 | 1.8
45 |
46 |
47 |
48 | com.github.os72
49 | protoc-jar-maven-plugin
50 | 3.11.4
51 |
52 |
53 | generate-sources
54 |
55 | run
56 |
57 |
58 |
59 | ${project.basedir}/src/main/protobuf
60 |
61 |
62 |
63 | java
64 | main
65 | ${project.basedir}/target/generated-sources/protobuf
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/src/main/java/com/codingharbour/kafka/protobuf/consumer/GenericProtobufConsumer.java:
--------------------------------------------------------------------------------
1 | package com.codingharbour.kafka.protobuf.consumer;
2 |
3 | import com.google.protobuf.Descriptors.FieldDescriptor;
4 | import com.google.protobuf.DynamicMessage;
5 | import io.confluent.kafka.serializers.protobuf.KafkaProtobufDeserializer;
6 | import io.confluent.kafka.serializers.protobuf.KafkaProtobufDeserializerConfig;
7 | import org.apache.kafka.clients.consumer.ConsumerConfig;
8 | import org.apache.kafka.clients.consumer.ConsumerRecord;
9 | import org.apache.kafka.clients.consumer.ConsumerRecords;
10 | import org.apache.kafka.clients.consumer.KafkaConsumer;
11 | import org.apache.kafka.clients.producer.ProducerConfig;
12 | import org.apache.kafka.common.serialization.StringDeserializer;
13 |
14 | import java.time.Duration;
15 | import java.util.Collections;
16 | import java.util.Properties;
17 |
18 | public class GenericProtobufConsumer {
19 | public static void main(String[] args) {
20 | GenericProtobufConsumer protobufConsumer = new GenericProtobufConsumer();
21 | protobufConsumer.readMessages();
22 | }
23 |
24 | public void readMessages() {
25 | Properties properties = new Properties();
26 | properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
27 | properties.put(ConsumerConfig.GROUP_ID_CONFIG, "generic-protobuf-consumer-group");
28 | properties.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");
29 | properties.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false);
30 |
31 | properties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
32 | properties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, KafkaProtobufDeserializer.class);
33 | properties.put(KafkaProtobufDeserializerConfig.SCHEMA_REGISTRY_URL_CONFIG, "http://localhost:8081");
34 |
35 | KafkaConsumer consumer = new KafkaConsumer<>(properties);
36 |
37 | consumer.subscribe(Collections.singleton("protobuf-topic"));
38 |
39 | //poll the record from the topic
40 | while (true) {
41 | ConsumerRecords records = consumer.poll(Duration.ofMillis(100));
42 |
43 | for (ConsumerRecord record : records) {
44 | for (FieldDescriptor field : record.value().getAllFields().keySet()) {
45 | System.out.println(field.getName() + ": " + record.value().getField(field));
46 | }
47 | }
48 | consumer.commitAsync();
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/com/codingharbour/kafka/protobuf/consumer/ProtobufConsumer.java:
--------------------------------------------------------------------------------
1 | package com.codingharbour.kafka.protobuf.consumer;
2 |
3 | import io.confluent.kafka.serializers.protobuf.KafkaProtobufDeserializer;
4 | import io.confluent.kafka.serializers.protobuf.KafkaProtobufDeserializerConfig;
5 | import org.apache.kafka.clients.consumer.ConsumerConfig;
6 | import org.apache.kafka.clients.consumer.ConsumerRecord;
7 | import org.apache.kafka.clients.consumer.ConsumerRecords;
8 | import org.apache.kafka.clients.consumer.KafkaConsumer;
9 | import org.apache.kafka.clients.producer.ProducerConfig;
10 | import org.apache.kafka.common.serialization.StringDeserializer;
11 |
12 | import java.time.Duration;
13 | import java.util.Collections;
14 | import java.util.Properties;
15 |
16 | import static com.codingharbour.protobuf.SimpleMessageProtos.SimpleMessage;
17 |
18 | public class ProtobufConsumer {
19 |
20 | public static void main(String[] args) {
21 | ProtobufConsumer protobufConsumer = new ProtobufConsumer();
22 | protobufConsumer.readMessages();
23 | }
24 |
25 | public void readMessages() {
26 | Properties properties = new Properties();
27 | properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
28 | properties.put(ConsumerConfig.GROUP_ID_CONFIG, "protobuf-consumer-group");
29 | properties.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");
30 | properties.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false);
31 |
32 | properties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
33 | properties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, KafkaProtobufDeserializer.class);
34 |
35 | properties.put(KafkaProtobufDeserializerConfig.SCHEMA_REGISTRY_URL_CONFIG, "http://localhost:8081");
36 | properties.put(KafkaProtobufDeserializerConfig.SPECIFIC_PROTOBUF_VALUE_TYPE, SimpleMessage.class.getName());
37 |
38 | KafkaConsumer consumer = new KafkaConsumer<>(properties);
39 |
40 | consumer.subscribe(Collections.singleton("protobuf-topic"));
41 |
42 | //poll the record from the topic
43 | while (true) {
44 | ConsumerRecords records = consumer.poll(Duration.ofMillis(100));
45 |
46 | for (ConsumerRecord record : records) {
47 | System.out.println("Message content: " + record.value().getContent());
48 | System.out.println("Message time: " + record.value().getDateTime());
49 | }
50 | consumer.commitAsync();
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/com/codingharbour/kafka/protobuf/producer/ProtobufProducer.java:
--------------------------------------------------------------------------------
1 | package com.codingharbour.kafka.protobuf.producer;
2 |
3 | import com.codingharbour.protobuf.SimpleMessageProtos.SimpleMessage;
4 | import io.confluent.kafka.serializers.protobuf.KafkaProtobufSerializer;
5 | import io.confluent.kafka.serializers.protobuf.KafkaProtobufSerializerConfig;
6 | import org.apache.kafka.clients.producer.KafkaProducer;
7 | import org.apache.kafka.clients.producer.Producer;
8 | import org.apache.kafka.clients.producer.ProducerConfig;
9 | import org.apache.kafka.clients.producer.ProducerRecord;
10 | import org.apache.kafka.common.serialization.StringSerializer;
11 |
12 | import java.time.Instant;
13 | import java.util.Properties;
14 |
15 | public class ProtobufProducer {
16 |
17 | public static void main(String[] args) {
18 | ProtobufProducer protobufProducer = new ProtobufProducer();
19 | protobufProducer.writeMessage();
20 | }
21 |
22 | public void writeMessage() {
23 | //create kafka producer
24 | Properties properties = new Properties();
25 | properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
26 | properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
27 | properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, KafkaProtobufSerializer.class);
28 | properties.put(KafkaProtobufSerializerConfig.SCHEMA_REGISTRY_URL_CONFIG, "http://localhost:8081");
29 |
30 | Producer producer = new KafkaProducer<>(properties);
31 |
32 | //prepare the message
33 | SimpleMessage simpleMessage =
34 | SimpleMessage.newBuilder()
35 | .setContent("Hello world")
36 | .setDateTime(Instant.now().toString())
37 | .build();
38 |
39 | System.out.println(simpleMessage);
40 |
41 | //prepare the kafka record
42 | ProducerRecord record
43 | = new ProducerRecord<>("protobuf-topic", null, simpleMessage);
44 |
45 | producer.send(record);
46 | //ensures record is sent before closing the producer
47 | producer.flush();
48 |
49 | producer.close();
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/protobuf/SimpleMessage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package com.codingharbour.protobuf;
4 | option java_outer_classname = "SimpleMessageProtos";
5 |
6 | message SimpleMessage {
7 | string content = 1;
8 | string date_time = 2;
9 | }
--------------------------------------------------------------------------------