Summary
Add support for binding to raw Apache Kafka records (KafkaRecord type) in the Java worker, enabling users to access full Kafka message metadata (topic, partition, offset, key/value as raw bytes, headers, timestamp, leader epoch).
This is the Java implementation of Azure/azure-functions-kafka-extension#612. The host-side Kafka Extension 4.3.1 and .NET Isolated Worker (PR #3356) are already complete.
Background
The host-side Kafka Extension (4.3.1) serializes IKafkaEventData to Protobuf and sends it as ParameterBindingData with:
source: "AzureKafkaRecord"
content_type: "application/x-protobuf"
content: Protobuf-encoded KafkaRecordProto
Currently, Java users can only bind to String, byte[], or Map<String, String> — they cannot access structured metadata like headers, timestamps, or partition info.
Protobuf Schema (shared across all languages)
message KafkaRecordProto {
string topic = 1;
int32 partition = 2;
int64 offset = 3;
optional bytes key = 4;
optional bytes value = 5;
KafkaTimestampProto timestamp = 6;
repeated KafkaHeaderProto headers = 7;
optional int32 leader_epoch = 8;
reserved 9 to 15;
}
message KafkaTimestampProto {
int64 unix_timestamp_ms = 1;
int32 type = 2; // 0=NotAvailable, 1=CreateTime, 2=LogAppendTime
}
message KafkaHeaderProto {
string key = 1;
optional bytes value = 2;
}
Required Changes
Part A: New POJO types (in azure-functions-java-library)
| File |
Description |
KafkaRecord.java |
Main POJO: topic, partition, offset, key (byte[]), value (byte[]), timestamp, headers, leaderEpoch (Integer) |
KafkaHeader.java |
Header: key (String) + value (byte[]) + getValueAsString() helper |
KafkaTimestamp.java |
Timestamp: unixTimestampMs (long) + type (enum) + getDateTime() -> OffsetDateTime |
KafkaTimestampType.java |
Enum: NotAvailable(0), CreateTime(1), LogAppendTime(2) |
No annotation changes needed — existing @KafkaTrigger works as-is.
Part B: Worker-side Protobuf deserializer (in azure-functions-java-worker)
| File |
Change |
KafkaRecordProto.proto |
New: Add proto schema, configure protobuf-maven-plugin for code generation |
RpcModelBindingDataSource.java |
Modify: Add content_type dispatch — application/json -> existing JSON path, application/x-protobuf -> new Protobuf deserialization |
KafkaRecordProtoDeserializer.java |
New: Map KafkaRecordProto -> KafkaRecord POJO |
Note: protobuf-java 3.25.5 is already in pom.xml. Maven protobuf plugin setup is needed for .proto compilation.
Part C: No changes to azure-functions-java-additions
KafkaRecord is a data container, not an Azure SDK client — the SdkType/Hydrator pattern is not applicable.
User Experience
// Existing (continues to work)
@FunctionName("ExistingTrigger")
public void run(@KafkaTrigger(...) String message) { }
// NEW: Full record access
@FunctionName("KafkaRecordTrigger")
public void run(
@KafkaTrigger(name = "record", topic = "my-topic",
brokerList = "%BrokerList%", consumerGroup = "$Default")
KafkaRecord record,
final ExecutionContext context) {
context.getLogger().info("Topic: " + record.getTopic());
context.getLogger().info("Partition: " + record.getPartition());
context.getLogger().info("Offset: " + record.getOffset());
context.getLogger().info("Key: " + new String(record.getKey()));
context.getLogger().info("Timestamp: " + record.getTimestamp().getDateTime());
for (KafkaHeader header : record.getHeaders()) {
context.getLogger().info("Header: " + header.getKey() + " = " + header.getValueAsString());
}
}
// NEW: Batch mode
@FunctionName("KafkaBatchTrigger")
public void run(
@KafkaTrigger(..., cardinality = Cardinality.MANY)
KafkaRecord[] records) { ... }
Breaking Changes
None. This is purely additive. All existing binding types (String, byte[], POJO) continue to work.
Implementation Order
- POJO types in
java-library (no dependency on host release)
- Protobuf deserializer in
java-worker (requires host extension 4.3.1 NuGet — already released)
Related Issues
Summary
Add support for binding to raw Apache Kafka records (
KafkaRecordtype) in the Java worker, enabling users to access full Kafka message metadata (topic, partition, offset, key/value as raw bytes, headers, timestamp, leader epoch).This is the Java implementation of Azure/azure-functions-kafka-extension#612. The host-side Kafka Extension 4.3.1 and .NET Isolated Worker (PR #3356) are already complete.
Background
The host-side Kafka Extension (4.3.1) serializes
IKafkaEventDatato Protobuf and sends it asParameterBindingDatawith:source:"AzureKafkaRecord"content_type:"application/x-protobuf"content: Protobuf-encodedKafkaRecordProtoCurrently, Java users can only bind to
String,byte[], orMap<String, String>— they cannot access structured metadata like headers, timestamps, or partition info.Protobuf Schema (shared across all languages)
Required Changes
Part A: New POJO types (in
azure-functions-java-library)KafkaRecord.javaKafkaHeader.javagetValueAsString()helperKafkaTimestamp.javagetDateTime()-> OffsetDateTimeKafkaTimestampType.javaNo annotation changes needed — existing
@KafkaTriggerworks as-is.Part B: Worker-side Protobuf deserializer (in
azure-functions-java-worker)KafkaRecordProto.protoprotobuf-maven-pluginfor code generationRpcModelBindingDataSource.javacontent_typedispatch —application/json-> existing JSON path,application/x-protobuf-> new Protobuf deserializationKafkaRecordProtoDeserializer.javaKafkaRecordProto->KafkaRecordPOJONote:
protobuf-java3.25.5 is already in pom.xml. Maven protobuf plugin setup is needed for.protocompilation.Part C: No changes to
azure-functions-java-additionsKafkaRecordis a data container, not an Azure SDK client — the SdkType/Hydrator pattern is not applicable.User Experience
Breaking Changes
None. This is purely additive. All existing binding types (
String,byte[], POJO) continue to work.Implementation Order
java-library(no dependency on host release)java-worker(requires host extension 4.3.1 NuGet — already released)Related Issues