Support for protocol buffer extensions allowing fields to be added to messages without modifying the original .proto files. This enables third-party extensibility and backwards-compatible schema evolution in the shaded akka.protobufv3.internal package.
Represents a protocol buffer extension with type-safe access to extended fields.
/**
* Represents a protocol buffer extension.
* Provides type-safe access to extension fields in messages.
*/
class Extension<ContainingType extends ExtendableMessage<ContainingType>, Type> {
/** Get the field descriptor for this extension */
Descriptors.FieldDescriptor getDescriptor();
/** Get the message type that contains this extension */
Class<ContainingType> getContainingType();
/** Get the type of this extension's value */
Class<Type> getType();
/** Check if this extension has a default value */
boolean hasDefaultValue();
/** Get the default value for this extension */
Type getDefaultValue();
/** Check if this is a repeated extension */
boolean isRepeated();
/** Check if this extension is packed (for repeated numeric types) */
boolean isPacked();
/** Get the message type for message extensions */
Class<? extends Message> getMessageDefaultInstance();
}Implementation of Extension for generated extension fields.
/**
* Generated implementation of Extension for protocol buffer extensions
* created by the protocol compiler.
*/
static class GeneratedMessage.GeneratedExtension<ContainingType extends Message, Type>
extends Extension<ContainingType, Type> {
/** Get the field number for this extension */
int getNumber();
/** Get the wire type for this extension */
WireFormat.FieldType getLiteType();
/** Check if this extension is lite */
boolean isLite();
/** Create a new instance of the extension */
GeneratedExtension<ContainingType, Type> clone();
}Registry for protocol buffer extensions that enables parsing messages with extension fields.
/**
* Registry for protocol buffer extensions.
* Required when parsing messages that contain extension fields.
*/
class ExtensionRegistry extends ExtensionRegistryLite {
/** Create a new mutable extension registry */
static ExtensionRegistry newInstance();
/** Get the empty extension registry */
static ExtensionRegistry getEmptyRegistry();
/** Add an extension to this registry */
void add(Extension<?, ?> extension);
/** Add an extension with explicit descriptor */
void add(Descriptors.FieldDescriptor type);
/** Add all extensions from another registry */
void addAll(ExtensionRegistry other);
/** Find extension by containing type and field number */
Extension<?, ?> findExtensionByNumber(Descriptors.Descriptor containingType, int fieldNumber);
/** Find immutable extension by field descriptor */
Extension<?, ?> findImmutableExtensionByName(String fullName);
/** Find mutable extension by field descriptor */
Extension<?, ?> findMutableExtensionByName(String fullName);
/** Get an unmodifiable view of this registry */
ExtensionRegistry getUnmodifiable();
/** Create a copy of this registry */
ExtensionRegistry clone();
}Lite version of extension registry with minimal functionality for resource-constrained environments.
/**
* Lite version of extension registry with minimal functionality.
* Used when full extension support is not needed.
*/
class ExtensionRegistryLite {
/** Create a new mutable lite extension registry */
static ExtensionRegistryLite newInstance();
/** Get the empty lite extension registry */
static ExtensionRegistryLite getEmptyRegistry();
/** Add an extension to this registry */
void add(GeneratedMessageLite.GeneratedExtension<?, ?> extension);
/** Add a message extension to this registry */
<ContainingType extends MessageLite> void add(
GeneratedMessageLite.GeneratedExtension<ContainingType, ?> extension);
/** Find extension by containing type and field number */
GeneratedMessageLite.GeneratedExtension<?, ?> findLiteExtensionByNumber(
ExtendableMessageLite<?> containingTypeDefaultInstance, int fieldNumber);
/** Get an unmodifiable view of this registry */
ExtensionRegistryLite getUnmodifiable();
/** Create a copy of this registry */
ExtensionRegistryLite clone();
}Interface for messages that can be extended with additional fields.
/**
* Interface for protocol buffer messages that support extensions.
* Provides methods to access and check extension fields.
*/
interface ExtendableMessage<MessageType extends ExtendableMessage<MessageType>>
extends Message {
/** Check if an extension field is set */
<Type> boolean hasExtension(Extension<MessageType, Type> extension);
/** Get the value of an extension field */
<Type> Type getExtension(Extension<MessageType, Type> extension);
/** Get the count of elements in a repeated extension field */
<Type> int getExtensionCount(Extension<MessageType, List<Type>> extension);
/** Get an element from a repeated extension field */
<Type> Type getExtension(Extension<MessageType, List<Type>> extension, int index);
/** Get all extension fields as a map */
Map<Descriptors.FieldDescriptor, Object> getAllExtensions();
/** ExtendableMessage builder interface */
interface Builder<MessageType extends ExtendableMessage<MessageType>,
BuilderType extends Builder<MessageType, BuilderType>>
extends Message.Builder {
/** Set the value of an extension field */
<Type> BuilderType setExtension(Extension<MessageType, Type> extension, Type value);
/** Add a value to a repeated extension field */
<Type> BuilderType addExtension(Extension<MessageType, List<Type>> extension, Type value);
/** Set an element in a repeated extension field */
<Type> BuilderType setExtension(Extension<MessageType, List<Type>> extension,
int index, Type value);
/** Clear an extension field */
<Type> BuilderType clearExtension(Extension<MessageType, Type> extension);
/** Check if an extension field is set */
<Type> boolean hasExtension(Extension<MessageType, Type> extension);
/** Get the value of an extension field */
<Type> Type getExtension(Extension<MessageType, Type> extension);
/** Get the count of elements in a repeated extension field */
<Type> int getExtensionCount(Extension<MessageType, List<Type>> extension);
/** Get an element from a repeated extension field */
<Type> Type getExtension(Extension<MessageType, List<Type>> extension, int index);
}
}Lite version of extendable message interface with minimal functionality.
/**
* Lite version of extendable message interface.
* Provides basic extension support without full reflection capabilities.
*/
interface ExtendableMessageLite<MessageType extends ExtendableMessageLite<MessageType>>
extends MessageLite {
/** Check if an extension field is set */
<Type> boolean hasExtension(GeneratedMessageLite.GeneratedExtension<MessageType, Type> extension);
/** Get the value of an extension field */
<Type> Type getExtension(GeneratedMessageLite.GeneratedExtension<MessageType, Type> extension);
/** Get the count of elements in a repeated extension field */
<Type> int getExtensionCount(GeneratedMessageLite.GeneratedExtension<MessageType, List<Type>> extension);
/** Get an element from a repeated extension field */
<Type> Type getExtension(GeneratedMessageLite.GeneratedExtension<MessageType, List<Type>> extension,
int index);
/** ExtendableMessageLite builder interface */
interface Builder<MessageType extends ExtendableMessageLite<MessageType>,
BuilderType extends Builder<MessageType, BuilderType>>
extends MessageLite.Builder {
/** Set the value of an extension field */
<Type> BuilderType setExtension(GeneratedMessageLite.GeneratedExtension<MessageType, Type> extension,
Type value);
/** Add a value to a repeated extension field */
<Type> BuilderType addExtension(GeneratedMessageLite.GeneratedExtension<MessageType, List<Type>> extension,
Type value);
/** Clear an extension field */
<Type> BuilderType clearExtension(GeneratedMessageLite.GeneratedExtension<MessageType, Type> extension);
/** Check if an extension field is set */
<Type> boolean hasExtension(GeneratedMessageLite.GeneratedExtension<MessageType, Type> extension);
/** Get the value of an extension field */
<Type> Type getExtension(GeneratedMessageLite.GeneratedExtension<MessageType, Type> extension);
}
}Extensions are typically defined in .proto files and generated as static fields:
// In your .proto file
extend MyMessage {
optional string custom_field = 1001;
repeated int32 custom_numbers = 1002;
}The generated Java code would look like:
// Generated extension fields (example)
// public static final Extension<MyMessage, String> customField =
// GeneratedMessage.newFileScopedGeneratedExtension(String.class, null);
//
// public static final Extension<MyMessage, List<Integer>> customNumbers =
// GeneratedMessage.newFileScopedGeneratedExtension(Integer.class, null);import akka.protobufv3.internal.*;
// Set extension fields in a message (assumes MyMessage and extensions exist)
// MyMessage message = MyMessage.newBuilder()
// .setExtension(MyExtensions.customField, "Hello Extension!")
// .addExtension(MyExtensions.customNumbers, 42)
// .addExtension(MyExtensions.customNumbers, 84)
// .build();
// Read extension fields
// boolean hasCustomField = message.hasExtension(MyExtensions.customField);
// if (hasCustomField) {
// String customValue = message.getExtension(MyExtensions.customField);
// System.out.println("Custom field: " + customValue);
// }
// Read repeated extension
// int count = message.getExtensionCount(MyExtensions.customNumbers);
// for (int i = 0; i < count; i++) {
// Integer number = message.getExtension(MyExtensions.customNumbers, i);
// System.out.println("Custom number " + i + ": " + number);
// }import akka.protobufv3.internal.*;
// Create extension registry
ExtensionRegistry registry = ExtensionRegistry.newInstance();
// Add extensions to registry
// registry.add(MyExtensions.customField);
// registry.add(MyExtensions.customNumbers);
// Parse message with extensions
byte[] data = getMessageBytes();
try {
// MyMessage message = MyMessage.parseFrom(data, registry);
// Extensions will be properly parsed and accessible
// String customValue = message.getExtension(MyExtensions.customField);
} catch (InvalidProtocolBufferException e) {
System.err.println("Failed to parse message with extensions: " + e.getMessage());
}import akka.protobufv3.internal.*;
// Access extensions dynamically using descriptors
// MyMessage message = getMessageWithExtensions();
// Get all extension fields
Map<Descriptors.FieldDescriptor, Object> allExtensions = message.getAllExtensions();
for (Map.Entry<Descriptors.FieldDescriptor, Object> entry : allExtensions.entrySet()) {
Descriptors.FieldDescriptor field = entry.getKey();
Object value = entry.getValue();
System.out.println("Extension field " + field.getName() +
" (number " + field.getNumber() + "): " + value);
}
// Find extension by field number
ExtensionRegistry registry = getExtensionRegistry();
Descriptors.Descriptor messageType = message.getDescriptorForType();
Extension<?, ?> extension = registry.findExtensionByNumber(messageType, 1001);
if (extension != null) {
System.out.println("Found extension: " + extension.getDescriptor().getName());
}import akka.protobufv3.internal.*;
// Create builder and set both regular and extension fields
// MyMessage.Builder builder = MyMessage.newBuilder();
// Set regular fields
// builder.setName("Regular Field");
// builder.setId(123);
// Set extension fields
// builder.setExtension(MyExtensions.customField, "Extension Value");
// builder.addExtension(MyExtensions.customNumbers, 1);
// builder.addExtension(MyExtensions.customNumbers, 2);
// builder.addExtension(MyExtensions.customNumbers, 3);
// Build the message
// MyMessage message = builder.build();
// Verify extensions are set
// System.out.println("Has custom field: " + message.hasExtension(MyExtensions.customField));
// System.out.println("Custom numbers count: " + message.getExtensionCount(MyExtensions.customNumbers));import akka.protobufv3.internal.*;
// Start with a message that has extensions
// MyMessage original = getMessageWithExtensions();
// Create builder from existing message
// MyMessage.Builder builder = original.toBuilder();
// Clear specific extension
// builder.clearExtension(MyExtensions.customField);
// Modify repeated extension
// builder.setExtension(MyExtensions.customNumbers, 0, 999); // Set first element
// builder.addExtension(MyExtensions.customNumbers, 888); // Add new element
// Build modified message
// MyMessage modified = builder.build();import akka.protobufv3.internal.*;
// For lite messages, use ExtensionRegistryLite
ExtensionRegistryLite liteRegistry = ExtensionRegistryLite.newInstance();
// Add lite extensions
// liteRegistry.add(MyLiteExtensions.customLiteField);
// Parse lite message with extensions
byte[] liteData = getLiteMessageBytes();
try {
// MyLiteMessage message = MyLiteMessage.parseFrom(liteData, liteRegistry);
// Access lite extensions
// String value = message.getExtension(MyLiteExtensions.customLiteField);
} catch (InvalidProtocolBufferException e) {
System.err.println("Failed to parse lite message: " + e.getMessage());
}import akka.protobufv3.internal.*;
// Create base registry
ExtensionRegistry baseRegistry = ExtensionRegistry.newInstance();
// baseRegistry.add(CommonExtensions.timestampField);
// baseRegistry.add(CommonExtensions.versionField);
// Create specialized registry
ExtensionRegistry specializedRegistry = ExtensionRegistry.newInstance();
// specializedRegistry.addAll(baseRegistry); // Include base extensions
// specializedRegistry.add(SpecialExtensions.debugField);
// specializedRegistry.add(SpecialExtensions.metadataField);
// Get unmodifiable view for safety
ExtensionRegistry readOnlyRegistry = specializedRegistry.getUnmodifiable();
// Use appropriate registry based on context
// if (isDebugMode()) {
// message = MyMessage.parseFrom(data, specializedRegistry);
// } else {
// message = MyMessage.parseFrom(data, baseRegistry);
// }import akka.protobufv3.internal.*;
try {
// Parse message without proper extension registry
byte[] data = getMessageWithExtensions();
// MyMessage message = MyMessage.parseFrom(data); // Extensions will be in unknown fields
// Access extension (will return default value)
// String customValue = message.getExtension(MyExtensions.customField);
// System.out.println("Custom value: " + customValue); // Will be default/empty
// Check unknown fields for unparsed extensions
UnknownFieldSet unknownFields = message.getUnknownFields();
if (!unknownFields.asMap().isEmpty()) {
System.out.println("Message has unknown fields (possibly extensions)");
}
} catch (InvalidProtocolBufferException e) {
System.err.println("Failed to parse message: " + e.getMessage());
}