Go implementation for protocol buffers providing message serialization, reflection, and code generation
The reflection packages provide powerful runtime introspection and manipulation capabilities for protocol buffer messages. These packages enable working with messages dynamically without compile-time knowledge of their types, building descriptor hierarchies, traversing message structures, and maintaining type registries.
import (
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protodesc"
"google.golang.org/protobuf/reflect/protopath"
"google.golang.org/protobuf/reflect/protorange"
"google.golang.org/protobuf/reflect/protoregistry"
"google.golang.org/protobuf/types/descriptorpb"
)Create file descriptors from FileDescriptorProto messages with dependency resolution.
// NewFile creates a new protoreflect.FileDescriptor from the provided file
// descriptor message. See FileOptions.New for more information.
func NewFile(fd *descriptorpb.FileDescriptorProto, r Resolver) (protoreflect.FileDescriptor, error)
// NewFiles creates a new protoregistry.Files from the provided
// FileDescriptorSet message. See FileOptions.NewFiles for more information.
func NewFiles(fd *descriptorpb.FileDescriptorSet) (*protoregistry.Files, error)Configure file descriptor construction with control over dependency resolution.
// FileOptions configures the construction of file descriptors
type FileOptions struct {
pragma.NoUnkeyedLiterals
// AllowUnresolvable configures New to permissively allow unresolvable
// file, enum, or message dependencies. Unresolved dependencies are replaced
// by placeholder equivalents.
//
// The following dependencies may be left unresolved:
// • Resolving an imported file.
// • Resolving the type for a message field or extension field.
// If the kind of the field is unknown, then a placeholder is used for both
// the Enum and Message accessors on the protoreflect.FieldDescriptor.
// • Resolving an enum value set as the default for an optional enum field.
// If unresolvable, the protoreflect.FieldDescriptor.Default is set to the
// first value in the associated enum (or zero if the also enum dependency
// is also unresolvable). The protoreflect.FieldDescriptor.DefaultEnumValue
// is populated with a placeholder.
// • Resolving the extended message type for an extension field.
// • Resolving the input or output message type for a service method.
//
// If the unresolved dependency uses a relative name,
// then the placeholder will contain an invalid FullName with a "*." prefix,
// indicating that the starting prefix of the full name is unknown.
AllowUnresolvable bool
}
// New creates a new protoreflect.FileDescriptor from the provided file
// descriptor message. The file must represent a valid proto file according to
// protobuf semantics. The returned descriptor is a deep copy of the input.
//
// Any imported files, enum types, or message types referenced in the file are
// resolved using the provided registry. When looking up an import file path,
// the path must be unique. The newly created file descriptor is not registered
// back into the provided file registry.
func (o FileOptions) New(fd *descriptorpb.FileDescriptorProto, r Resolver) (protoreflect.FileDescriptor, error)
// NewFiles creates a new protoregistry.Files from the provided
// FileDescriptorSet message. The descriptor set must include only valid files
// according to protobuf semantics. The returned descriptors are a deep copy of
// the input.
func (o FileOptions) NewFiles(fds *descriptorpb.FileDescriptorSet) (*protoregistry.Files, error)Interface for resolving dependencies during descriptor construction.
// Resolver is the resolver used by NewFile to resolve dependencies
// The enums and messages provided must belong to some parent file, which is also
// registered.
//
// It is implemented by protoregistry.Files.
type Resolver interface {
FindFileByPath(string) (protoreflect.FileDescriptor, error)
FindDescriptorByName(protoreflect.FullName) (protoreflect.Descriptor, error)
}Convert reflection descriptors back to proto message representations.
// ToFileDescriptorProto copies a protoreflect.FileDescriptor into a
// google.protobuf.FileDescriptorProto message
func ToFileDescriptorProto(file protoreflect.FileDescriptor) *descriptorpb.FileDescriptorProto
// ToDescriptorProto copies a protoreflect.MessageDescriptor into a
// google.protobuf.DescriptorProto message
func ToDescriptorProto(message protoreflect.MessageDescriptor) *descriptorpb.DescriptorProto
// ToFieldDescriptorProto copies a protoreflect.FieldDescriptor into a
// google.protobuf.FieldDescriptorProto message
func ToFieldDescriptorProto(field protoreflect.FieldDescriptor) *descriptorpb.FieldDescriptorProto
// ToOneofDescriptorProto copies a protoreflect.OneofDescriptor into a
// google.protobuf.OneofDescriptorProto message
func ToOneofDescriptorProto(oneof protoreflect.OneofDescriptor) *descriptorpb.OneofDescriptorProto
// ToEnumDescriptorProto copies a protoreflect.EnumDescriptor into a
// google.protobuf.EnumDescriptorProto message
func ToEnumDescriptorProto(enum protoreflect.EnumDescriptor) *descriptorpb.EnumDescriptorProto
// ToEnumValueDescriptorProto copies a protoreflect.EnumValueDescriptor into a
// google.protobuf.EnumValueDescriptorProto message
func ToEnumValueDescriptorProto(value protoreflect.EnumValueDescriptor) *descriptorpb.EnumValueDescriptorProto
// ToServiceDescriptorProto copies a protoreflect.ServiceDescriptor into a
// google.protobuf.ServiceDescriptorProto message
func ToServiceDescriptorProto(service protoreflect.ServiceDescriptor) *descriptorpb.ServiceDescriptorProto
// ToMethodDescriptorProto copies a protoreflect.MethodDescriptor into a
// google.protobuf.MethodDescriptorProto message
func ToMethodDescriptorProto(method protoreflect.MethodDescriptor) *descriptorpb.MethodDescriptorProtoRepresent sequences of reflection operations as structured paths through message hierarchies.
// Path is a sequence of protobuf reflection steps applied to some root
// protobuf message value to arrive at the current value
// The first step must be a Root step
type Path []Step
// Index returns the ith step in the path and supports negative indexing
// A negative index starts counting from the tail of the Path such that -1
// refers to the last step, -2 refers to the second-to-last step, and so on
// It returns a zero Step value if the index is out-of-bounds
func (p Path) Index(i int) Step
// String returns a structured representation of the path by concatenating the
// string representation of every path step
func (p Path) String() stringDefine individual steps in a path through a message structure.
// Step is a union where only one step operation may be specified at a time
// The different kinds of steps are specified by the constants defined for the
// StepKind type
type Step struct {
// Has unexported fields.
}
// Root indicates the root message that a path is relative to
// It should always (and only ever) be the first step in a path
func Root(md protoreflect.MessageDescriptor) Step
// FieldAccess describes access of a field within a message
// Extension field accesses are also represented using a FieldAccess and must be
// provided with a protoreflect.FieldDescriptor
func FieldAccess(fd protoreflect.FieldDescriptor) Step
// UnknownAccess describes access to the unknown fields within a message
func UnknownAccess() Step
// ListIndex describes index of an element within a list
func ListIndex(i int) Step
// MapIndex describes index of an entry within a map
// The key type is determined by field descriptor that the map belongs to
func MapIndex(k protoreflect.MapKey) Step
// AnyExpand describes expansion of a google.protobuf.Any message into a
// structured representation of the underlying message
func AnyExpand(md protoreflect.MessageDescriptor) Step
// Kind reports which kind of step this is
func (s Step) Kind() StepKind
// MessageDescriptor returns the message descriptor for Root or AnyExpand
// steps, otherwise it returns nil
func (s Step) MessageDescriptor() protoreflect.MessageDescriptor
// FieldDescriptor returns the field descriptor for FieldAccess steps,
// otherwise it returns nil
func (s Step) FieldDescriptor() protoreflect.FieldDescriptor
// ListIndex returns the list index for ListIndex steps, otherwise it returns 0
func (s Step) ListIndex() int
// MapIndex returns the map key for MapIndex steps, otherwise it returns an
// invalid map key
func (s Step) MapIndex() protoreflect.MapKey
// String returns a string representation of the step
func (s Step) String() string// StepKind identifies the kind of step operation
// Each kind of step corresponds with some protobuf reflection operation
type StepKind int
const (
// RootStep identifies a step as the Root step operation
RootStep StepKind
// FieldAccessStep identifies a step as the FieldAccess step operation
FieldAccessStep
// UnknownAccessStep identifies a step as the UnknownAccess step operation
UnknownAccessStep
// ListIndexStep identifies a step as the ListIndex step operation
ListIndexStep
// MapIndexStep identifies a step as the MapIndex step operation
MapIndexStep
// AnyExpandStep identifies a step as the AnyExpand step operation
AnyExpandStep
)
func (k StepKind) String() stringPair paths with the values at each step for complete traversal state.
// Values is a Path paired with a sequence of values at each step
// The lengths of Values.Path and Values.Values must be identical
// The first step must be a Root step and the first value must be a concrete message value
type Values struct {
Path Path
Values []protoreflect.Value
}
// Len reports the length of the path and values
// If the path and values have differing length, it returns the minimum length
func (p Values) Len() int
// Index returns the ith step and value and supports negative indexing
// A negative index starts counting from the tail of the Values such that -1
// refers to the last pair, -2 refers to the second-to-last pair, and so on
func (p Values) Index(i int) (out struct {
Step Step
Value protoreflect.Value
})
// String returns a humanly readable representation of the path and last value
// Do not depend on the output being stable
func (p Values) String() stringPerform depth-first traversal over message structures with callback-based navigation.
// Range performs a depth-first traversal over reachable values in a message
// See Options.Range for details
func Range(m protoreflect.Message, f func(protopath.Values) error) errorConstants for controlling traversal behavior.
var (
// Break breaks traversal of children in the current value
// It has no effect when traversing values that are not composite types
// (e.g., messages, lists, and maps)
Break = errors.New("break traversal of children in current value")
// Terminate terminates the entire range operation
// All necessary Pop operations continue to be called
Terminate = errors.New("terminate range operation")
)Configure message traversal behavior including ordering and type resolution.
// Options configures traversal of a message value tree
type Options struct {
// Stable specifies whether to visit message fields and map entries
// in a stable ordering. If false, then the ordering is undefined and
// may be non-deterministic.
//
// Message fields are visited in ascending order by field number.
// Map entries are visited in ascending order, where
// boolean keys are ordered such that false sorts before true,
// numeric keys are ordered based on the numeric value, and
// string keys are lexicographically ordered by Unicode codepoints.
Stable bool
// Resolver is used for looking up types when expanding google.protobuf.Any
// messages. If nil, this defaults to using protoregistry.GlobalTypes.
// To prevent expansion of Any messages, pass an empty protoregistry.Types:
//
// Options{Resolver: (*protoregistry.Types)(nil)}
//
Resolver interface {
protoregistry.ExtensionTypeResolver
protoregistry.MessageTypeResolver
}
}
// Range performs a depth-first traversal over reachable values in a message
// The first push and the last pop are to push/pop a protopath.Root step
// If push or pop return any non-nil error (other than Break or Terminate),
// it terminates the traversal and is returned by Range
//
// The rules for traversing a message is as follows:
//
// - For messages, iterate over every populated known and extension field.
// Each field is preceded by a push of a protopath.FieldAccess step,
// followed by recursive application of the rules on the field value,
// and succeeded by a pop of that step. If the message has unknown fields,
// then push an protopath.UnknownAccess step followed immediately by pop of
// that step.
//
// - As an exception to the above rule, if the current message is a
// google.protobuf.Any message, expand the underlying message (if
// resolvable). The expanded message is preceded by a push of a
// protopath.AnyExpand step, followed by recursive application of the
// rules on the underlying message, and succeeded by a pop of that step.
// Mutations to the expanded message are written back to the Any message
// when popping back out.
//
// - For lists, iterate over every element. Each element is preceded by a
// push of a protopath.ListIndex step, followed by recursive application of
// the rules on the list element, and succeeded by a pop of that step.
//
// - For maps, iterate over every entry. Each entry is preceded by a push
// of a protopath.MapIndex step, followed by recursive application of the
// rules on the map entry value, and succeeded by a pop of that step.
//
// Mutations should only be made to the last value, otherwise the effects
// on traversal will be undefined. If the mutation is made to the last value
// during to a push, then the effects of the mutation will affect traversal.
//
// The protopath.Values provided to push functions is only valid until the
// corresponding pop call and the values provided to a pop call is only valid
// for the duration of the pop call itself.
func (o Options) Range(m protoreflect.Message, push, pop func(protopath.Values) error) errorUsage example:
import (
"fmt"
"google.golang.org/protobuf/reflect/protorange"
"google.golang.org/protobuf/reflect/protopath"
)
// Simple traversal
err := protorange.Range(msg.ProtoReflect(), func(p protopath.Values) error {
fmt.Printf("Path: %v, Value: %v\n", p.Path, p.Index(-1).Value)
return nil
})
// Traversal with push/pop callbacks
opts := protorange.Options{Stable: true}
err = opts.Range(msg.ProtoReflect(),
func(p protopath.Values) error {
// Called before visiting
fmt.Printf("Entering: %v\n", p.Path)
return nil
},
func(p protopath.Values) error {
// Called after visiting
fmt.Printf("Leaving: %v\n", p.Path)
return nil
},
)Access the global registry for message types, extension types, and enum types.
// GlobalTypes is a global registry of types
var GlobalTypes *Types
// GlobalFiles is a global registry of files
var GlobalFiles *FilesRegistry for looking up and registering file descriptors.
// Files is a registry for looking up file descriptors
type Files struct {
// Has unexported fields.
}
// NewFiles creates a new file registry
func NewFiles(files ...protoreflect.FileDescriptor) (*Files, error)
// RegisterFile registers the provided file descriptor
// If any descriptor within the file conflicts with the descriptor already
// registered in files, then files is unchanged and an error is returned
func (r *Files) RegisterFile(file protoreflect.FileDescriptor) error
// FindFileByPath looks up a file by the path
// The path must be a proto import path
func (r *Files) FindFileByPath(path string) (protoreflect.FileDescriptor, error)
// FindDescriptorByName looks up a descriptor by its full name
func (r *Files) FindDescriptorByName(name protoreflect.FullName) (protoreflect.Descriptor, error)
// NumFiles reports the number of registered files
func (r *Files) NumFiles() int
// RangeFiles iterates over all registered files
// The iteration order is undefined
func (r *Files) RangeFiles(f func(protoreflect.FileDescriptor) bool)
// NumFilesByPackage reports the number of registered files in a proto package
func (r *Files) NumFilesByPackage(name protoreflect.FullName) int
// RangeFilesByPackage iterates over all registered files in a proto package
// The iteration order is undefined
func (r *Files) RangeFilesByPackage(name protoreflect.FullName, f func(protoreflect.FileDescriptor) bool)Registry for looking up and registering message types, extension types, and enum types.
// Types is a registry for looking up types
type Types struct {
// Has unexported fields.
}
// NewTypes creates a new type registry
func NewTypes(typs ...interface{}) (*Types, error)
// RegisterMessage registers the provided message type
func (r *Types) RegisterMessage(mt protoreflect.MessageType) error
// FindMessageByName looks up a message by its full name
func (r *Types) FindMessageByName(message protoreflect.FullName) (protoreflect.MessageType, error)
// FindMessageByURL looks up a message by a URL identifier
// The URL is of the form "type.googleapis.com/package.Message"
func (r *Types) FindMessageByURL(url string) (protoreflect.MessageType, error)
// RegisterEnum registers the provided enum type
func (r *Types) RegisterEnum(et protoreflect.EnumType) error
// FindEnumByName looks up an enum by its full name
func (r *Types) FindEnumByName(enum protoreflect.FullName) (protoreflect.EnumType, error)
// RegisterExtension registers the provided extension type
func (r *Types) RegisterExtension(xt protoreflect.ExtensionType) error
// FindExtensionByName looks up an extension by its full name
func (r *Types) FindExtensionByName(field protoreflect.FullName) (protoreflect.ExtensionType, error)
// FindExtensionByNumber looks up an extension by field number within some parent message
func (r *Types) FindExtensionByNumber(message protoreflect.FullName, field protoreflect.FieldNumber) (protoreflect.ExtensionType, error)
// NumMessages reports the number of registered messages
func (r *Types) NumMessages() int
// RangeMessages iterates over all registered messages
// The iteration order is undefined
func (r *Types) RangeMessages(f func(protoreflect.MessageType) bool)
// NumEnums reports the number of registered enums
func (r *Types) NumEnums() int
// RangeEnums iterates over all registered enums
// The iteration order is undefined
func (r *Types) RangeEnums(f func(protoreflect.EnumType) bool)
// NumExtensions reports the number of registered extensions
func (r *Types) NumExtensions() int
// RangeExtensions iterates over all registered extensions
// The iteration order is undefined
func (r *Types) RangeExtensions(f func(protoreflect.ExtensionType) bool)
// NumExtensionsByMessage reports the number of registered extensions for a given message
func (r *Types) NumExtensionsByMessage(message protoreflect.FullName) int
// RangeExtensionsByMessage iterates over all registered extensions for a given message
// The iteration order is undefined
func (r *Types) RangeExtensionsByMessage(message protoreflect.FullName, f func(protoreflect.ExtensionType) bool)// NotFound is a sentinel error value to indicate that the type was not found
var NotFound = errors.New("not found")Usage example:
import (
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
)
// Register a message type
registry := &protoregistry.Types{}
err := registry.RegisterMessage((&pb.MyMessage{}).ProtoReflect().Type())
// Look up a message type
mt, err := protoregistry.GlobalTypes.FindMessageByName("example.MyMessage")
if err != nil {
log.Fatal(err)
}
// Create a new instance
msg := mt.New().Interface()The primary interface for reflective message manipulation.
// Message is a reflective view over a concrete message instance
type Message interface {
// Descriptor returns the message descriptor
Descriptor() MessageDescriptor
// Type returns the message type which contains both Go and protobuf type information
Type() MessageType
// New returns a newly allocated and mutable empty message
New() Message
// Interface unwraps the message reflection interface and
// returns the underlying ProtoMessage interface
Interface() ProtoMessage
// Range iterates over every populated field in the message
// The iteration order is undefined
Range(func(FieldDescriptor, Value) bool)
// Has reports whether a field is populated
Has(FieldDescriptor) bool
// Clear clears the field such that a subsequent Has call reports false
Clear(FieldDescriptor)
// Get retrieves the value for a field
Get(FieldDescriptor) Value
// Set stores the value for a field
Set(FieldDescriptor, Value)
// Mutable returns a mutable reference to a composite type
Mutable(FieldDescriptor) Value
// NewField returns a new value that is assignable to the field for the given descriptor
NewField(FieldDescriptor) Value
// WhichOneof reports which field within the oneof is populated, returning nil if none are populated
WhichOneof(OneofDescriptor) FieldDescriptor
// GetUnknown retrieves the entire list of unknown fields
GetUnknown() RawFields
// SetUnknown stores an entire list of unknown fields
SetUnknown(RawFields)
// IsValid reports whether the message is valid
IsValid() bool
}The top-level interface that all generated messages implement.
// ProtoMessage is the top-level interface that all messages must implement
type ProtoMessage interface {
// ProtoReflect returns a reflective view of the message
ProtoReflect() Message
}Represents a value in the protobuf type system.
// Value is a union type that can represent any protobuf value
type Value value
// ValueOf returns a Value for a Go value
func ValueOf(v interface{}) Value
// ValueOfBool returns a new bool value
func ValueOfBool(v bool) Value
// ValueOfInt32 returns a new int32 value
func ValueOfInt32(v int32) Value
// ValueOfInt64 returns a new int64 value
func ValueOfInt64(v int64) Value
// ValueOfUint32 returns a new uint32 value
func ValueOfUint32(v uint32) Value
// ValueOfUint64 returns a new uint64 value
func ValueOfUint64(v uint64) Value
// ValueOfFloat32 returns a new float32 value
func ValueOfFloat32(v float32) Value
// ValueOfFloat64 returns a new float64 value
func ValueOfFloat64(v float64) Value
// ValueOfString returns a new string value
func ValueOfString(v string) Value
// ValueOfBytes returns a new bytes value
func ValueOfBytes(v []byte) Value
// ValueOfEnum returns a new enum value
func ValueOfEnum(v EnumNumber) Value
// ValueOfMessage returns a new message value
func ValueOfMessage(v Message) Value
// ValueOfList returns a new list value
func ValueOfList(v List) Value
// ValueOfMap returns a new map value
func ValueOfMap(v Map) Value
// IsValid reports whether v is populated with a value
func (v Value) IsValid() bool
// Interface returns v as an interface{}
func (v Value) Interface() interface{}
// Bool returns the value as a bool
func (v Value) Bool() bool
// Int returns the value as an int64
func (v Value) Int() int64
// Uint returns the value as a uint64
func (v Value) Uint() uint64
// Float returns the value as a float64
func (v Value) Float() float64
// String returns the value as a string
func (v Value) String() string
// Bytes returns the value as a []byte
func (v Value) Bytes() []byte
// Enum returns the value as an EnumNumber
func (v Value) Enum() EnumNumber
// Message returns the value as a Message
func (v Value) Message() Message
// List returns the value as a List
func (v Value) List() List
// Map returns the value as a Map
func (v Value) Map() Map
// MapKey returns the value as a MapKey
func (v Value) MapKey() MapKey
// Equal reports whether v and w are equal
func (v Value) Equal(w Value) boolThis comprehensive reflection documentation covers all major APIs for working with protocol buffers at runtime through reflection, including descriptor construction, path-based traversal, message introspection, and type registries.
Install with Tessl CLI
npx tessl i tessl/golang-google-golang-org--protobuf