or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

compiler-protogen.mdcore.mdencoding.mdindex.mdreflection.mdruntime.mdtesting.mdtypes-descriptorpb.mdtypes-dynamicpb.mdtypes-known.mdtypes-pluginpb.md
tile.json

types-dynamicpb.mddocs/

Dynamic Message Handling

The dynamicpb package creates protocol buffer messages using runtime type information, enabling work with message types that are only known at runtime. Dynamic messages implement the same interfaces as generated messages and can be used with all standard proto package functions.

Package Import

import (
    "google.golang.org/protobuf/types/dynamicpb"
    "google.golang.org/protobuf/reflect/protoreflect"
    "google.golang.org/protobuf/reflect/protoregistry"
    "google.golang.org/protobuf/proto"
)

Dynamic Message Creation

Message Construction

Create new dynamic messages from message descriptors.

// NewMessage creates a new message with the provided descriptor
func NewMessage(desc protoreflect.MessageDescriptor) *Message

Usage example:

import (
    "google.golang.org/protobuf/types/dynamicpb"
    "google.golang.org/protobuf/reflect/protoregistry"
)

// Look up a message descriptor
md, err := protoregistry.GlobalFiles.FindDescriptorByName("example.MyMessage")
if err != nil {
    log.Fatal(err)
}

// Create a dynamic message
msg := dynamicpb.NewMessage(md.(protoreflect.MessageDescriptor))

// Use the message with standard proto operations
data, err := proto.Marshal(msg)

Dynamic Message Type

The Message type represents a dynamically constructed protocol buffer message.

// A Message is a dynamically constructed protocol buffer message
//
// Message implements the google.golang.org/protobuf/proto.Message interface,
// and may be used with all standard proto package functions such as Marshal,
// Unmarshal, and so forth.
//
// Message also implements the protoreflect.Message interface. See the
// protoreflect package documentation for that interface for how to get and set
// fields and otherwise interact with the contents of a Message.
//
// Reflection API functions which construct messages, such as NewField, return
// new dynamic messages of the appropriate type. Functions which take messages,
// such as Set for a message-value field, will accept any message with a
// compatible type.
//
// Operations which modify a Message are not safe for concurrent use.
type Message struct {
    // Has unexported fields.
}

// ProtoReflect implements the protoreflect.ProtoMessage interface
func (m *Message) ProtoReflect() protoreflect.Message

// ProtoMessage implements the legacy message interface
func (m *Message) ProtoMessage()

// Reset clears the message to be empty, but preserves the dynamic message type
func (m *Message) Reset()

// String returns a string representation of a message
func (m *Message) String() string

// Descriptor returns the message descriptor
func (m *Message) Descriptor() protoreflect.MessageDescriptor

// Type returns the message type
func (m *Message) Type() protoreflect.MessageType

// New returns a newly allocated empty message with the same descriptor
// See protoreflect.Message for details
func (m *Message) New() protoreflect.Message

// Interface returns the message
// See protoreflect.Message for details
func (m *Message) Interface() protoreflect.ProtoMessage

// IsValid reports whether the message is valid
// See protoreflect.Message for details
func (m *Message) IsValid() bool

Field Access Methods

Reflective field manipulation for dynamic messages.

// Range visits every populated field in undefined order
// See protoreflect.Message for details
func (m *Message) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool)

// Has reports whether a field is populated
// See protoreflect.Message for details
func (m *Message) Has(fd protoreflect.FieldDescriptor) bool

// Get returns the value of a field
// See protoreflect.Message for details
func (m *Message) Get(fd protoreflect.FieldDescriptor) protoreflect.Value

// Set stores a value in a field
// See protoreflect.Message for details
func (m *Message) Set(fd protoreflect.FieldDescriptor, v protoreflect.Value)

// Clear clears a field
// See protoreflect.Message for details
func (m *Message) Clear(fd protoreflect.FieldDescriptor)

// Mutable returns a mutable reference to a repeated, map, or message field
// See protoreflect.Message for details
func (m *Message) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value

// NewField returns a new value for assignable to the field of a given descriptor
// See protoreflect.Message for details
func (m *Message) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value

// WhichOneof reports which field in a oneof is populated, returning nil if none are populated
// See protoreflect.Message for details
func (m *Message) WhichOneof(od protoreflect.OneofDescriptor) protoreflect.FieldDescriptor

Unknown Fields

Manage unknown fields in dynamic messages.

// GetUnknown returns the raw unknown fields
// See protoreflect.Message for details
func (m *Message) GetUnknown() protoreflect.RawFields

// SetUnknown sets the raw unknown fields
// See protoreflect.Message for details
func (m *Message) SetUnknown(r protoreflect.RawFields)

Internal Methods

// ProtoMethods is an internal detail of the protoreflect.Message interface
// Users should never call this directly
func (m *Message) ProtoMethods() *protoiface.Methods

Usage example:

// Create a dynamic message
msg := dynamicpb.NewMessage(messageDescriptor)

// Get field descriptor
fields := messageDescriptor.Fields()
nameField := fields.ByName("name")
valueField := fields.ByName("value")

// Set field values
msg.Set(nameField, protoreflect.ValueOfString("example"))
msg.Set(valueField, protoreflect.ValueOfInt32(42))

// Check if field is set
if msg.Has(nameField) {
    name := msg.Get(nameField).String()
    fmt.Println("Name:", name)
}

// Iterate over all fields
msg.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
    fmt.Printf("Field %s: %v\n", fd.Name(), v)
    return true
})

// Marshal to wire format
data, err := proto.Marshal(msg)

Dynamic Type Construction

Message Type Creation

Create message types from message descriptors.

// NewMessageType creates a new MessageType with the provided descriptor
//
// MessageTypes created by this package are equal if their descriptors
// are equal. That is, if md1 == md2, then NewMessageType(md1) ==
// NewMessageType(md2).
func NewMessageType(desc protoreflect.MessageDescriptor) protoreflect.MessageType

Usage example:

md, _ := protoregistry.GlobalFiles.FindDescriptorByName("example.MyMessage")
mt := dynamicpb.NewMessageType(md.(protoreflect.MessageDescriptor))

// Create instances
msg := mt.New().Interface()

Enum Type Creation

Create enum types from enum descriptors.

// NewEnumType creates a new EnumType with the provided descriptor
//
// EnumTypes created by this package are equal if their descriptors are equal.
// That is, if ed1 == ed2, then NewEnumType(ed1) == NewEnumType(ed2).
//
// Enum values created by the EnumType are equal if their numbers are equal.
func NewEnumType(desc protoreflect.EnumDescriptor) protoreflect.EnumType

Extension Type Creation

Create extension types from extension descriptors.

// NewExtensionType creates a new ExtensionType with the provided descriptor
//
// Dynamic ExtensionTypes with the same descriptor compare as equal. That is,
// if xd1 == xd2, then NewExtensionType(xd1) == NewExtensionType(xd2).
//
// The InterfaceOf and ValueOf methods of the extension type are defined as:
//
//     func (xt extensionType) ValueOf(iv any) protoreflect.Value {
//         return protoreflect.ValueOf(iv)
//     }
//
//     func (xt extensionType) InterfaceOf(v protoreflect.Value) any {
//         return v.Interface()
//     }
//
// The Go type used by the proto.GetExtension and proto.SetExtension functions
// is determined by these methods, and is therefore equivalent to the Go
// type used to represent a protoreflect.Value. See the protoreflect.Value
// documentation for more details.
func NewExtensionType(desc protoreflect.ExtensionDescriptor) protoreflect.ExtensionType

Dynamic Type Registry

Types Registry

A collection of dynamically constructed descriptors with concurrent-safe lookup methods.

// A Types is a collection of dynamically constructed descriptors
// Its methods are safe for concurrent use
//
// Types implements protoregistry.MessageTypeResolver and
// protoregistry.ExtensionTypeResolver. A Types may be used as a
// google.golang.org/protobuf/proto.UnmarshalOptions.Resolver.
type Types struct {
    // Has unexported fields.
}

// NewTypes creates a new Types registry with the provided files
// The Files registry is retained, and changes to Files will be reflected in Types
// It is not safe to concurrently change the Files while calling Types methods
func NewTypes(f *protoregistry.Files) *Types

Message Type Lookup

Find message types in the dynamic registry.

// FindMessageByName looks up a message by its full name
// e.g. "google.protobuf.Any"
//
// This returns (nil, protoregistry.NotFound) if not found
func (t *Types) FindMessageByName(name protoreflect.FullName) (protoreflect.MessageType, error)

// FindMessageByURL looks up a message by a URL identifier
// See documentation on google.protobuf.Any.type_url for the URL format
//
// This returns (nil, protoregistry.NotFound) if not found
func (t *Types) FindMessageByURL(url string) (protoreflect.MessageType, error)

Enum Type Lookup

Find enum types in the dynamic registry.

// FindEnumByName looks up an enum by its full name
// e.g., "google.protobuf.Field.Kind"
//
// This returns (nil, protoregistry.NotFound) if not found
func (t *Types) FindEnumByName(name protoreflect.FullName) (protoreflect.EnumType, error)

Extension Type Lookup

Find extension types in the dynamic registry.

// FindExtensionByName looks up an extension field by the field's full name
// Note that this is the full name of the field as determined by where the
// extension is declared and is unrelated to the full name of the message being
// extended
//
// This returns (nil, protoregistry.NotFound) if not found
func (t *Types) FindExtensionByName(name protoreflect.FullName) (protoreflect.ExtensionType, error)

// FindExtensionByNumber looks up an extension field by the field number within
// some parent message, identified by full name
//
// This returns (nil, protoregistry.NotFound) if not found
func (t *Types) FindExtensionByNumber(message protoreflect.FullName, field protoreflect.FieldNumber) (protoreflect.ExtensionType, error)

Usage example:

import (
    "google.golang.org/protobuf/types/dynamicpb"
    "google.golang.org/protobuf/reflect/protoregistry"
)

// Create a dynamic types registry
files := protoregistry.GlobalFiles
types := dynamicpb.NewTypes(files)

// Look up a message type
mt, err := types.FindMessageByName("google.protobuf.Any")
if err != nil {
    log.Fatal(err)
}

// Create a new instance
msg := mt.New()

// Use as UnmarshalOptions.Resolver
opts := proto.UnmarshalOptions{
    Resolver: types,
}
err = opts.Unmarshal(data, msg.Interface())

Common Use Cases

Working with Unknown Message Types

// Load file descriptors from a FileDescriptorSet
fds := &descriptorpb.FileDescriptorSet{}
err := proto.Unmarshal(descriptorData, fds)

files, err := protodesc.NewFiles(fds)
types := dynamicpb.NewTypes(files)

// Create message from type URL
mt, err := types.FindMessageByURL("type.googleapis.com/example.MyMessage")
msg := mt.New().Interface()

// Unmarshal data into dynamic message
err = proto.Unmarshal(wireData, msg)

// Access fields dynamically
md := msg.ProtoReflect().Descriptor()
field := md.Fields().ByName("my_field")
value := msg.ProtoReflect().Get(field)

Dynamic Message Construction

// Get descriptor for a message type
md, _ := protoregistry.GlobalFiles.FindDescriptorByName("example.MyMessage")
msgDesc := md.(protoreflect.MessageDescriptor)

// Create dynamic message
msg := dynamicpb.NewMessage(msgDesc)

// Build message programmatically
fields := msgDesc.Fields()
for i := 0; i < fields.Len(); i++ {
    fd := fields.Get(i)
    // Set default values or read from configuration
    switch fd.Kind() {
    case protoreflect.StringKind:
        msg.Set(fd, protoreflect.ValueOfString("default"))
    case protoreflect.Int32Kind:
        msg.Set(fd, protoreflect.ValueOfInt32(0))
    }
}

This documentation covers the complete API for working with dynamic protocol buffer messages at runtime, including message creation, field manipulation, type construction, and dynamic type registries.