protoreflect

package
v1.36.9 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 9, 2025 License: BSD-3-Clause Imports: 9 Imported by: 126,256

Documentation

Overview

Package protoreflect provides interfaces to dynamically manipulate messages.

This package includes type descriptors which describe the structure of types defined in proto source files and value interfaces which provide the ability to examine and manipulate the contents of messages.

Protocol Buffer Descriptors

Protobuf descriptors (e.g., EnumDescriptor or MessageDescriptor) are immutable objects that represent protobuf type information. They are wrappers around the messages declared in descriptor.proto. Protobuf descriptors alone lack any information regarding Go types.

Enums and messages generated by this module implement Enum and ProtoMessage, where the Descriptor and ProtoReflect.Descriptor accessors respectively return the protobuf descriptor for the values.

The protobuf descriptor interfaces are not meant to be implemented by user code since they might need to be extended in the future to support additions to the protobuf language. The google.golang.org/protobuf/reflect/protodesc package converts between google.protobuf.DescriptorProto messages and protobuf descriptors.

Go Type Descriptors

A type descriptor (e.g., EnumType or MessageType) is a constructor for a concrete Go type that represents the associated protobuf descriptor. There is commonly a one-to-one relationship between protobuf descriptors and Go type descriptors, but it can potentially be a one-to-many relationship.

Enums and messages generated by this module implement Enum and ProtoMessage, where the Type and ProtoReflect.Type accessors respectively return the protobuf descriptor for the values.

The google.golang.org/protobuf/types/dynamicpb package can be used to create Go type descriptors from protobuf descriptors.

Value Interfaces

The Enum and Message interfaces provide a reflective view over an enum or message instance. For enums, it provides the ability to retrieve the enum value number for any concrete enum type. For messages, it provides the ability to access or manipulate fields of the message.

To convert a google.golang.org/protobuf/proto.Message to a protoreflect.Message, use the former's ProtoReflect method. Since the ProtoReflect method is new to the v2 message interface, it may not be present on older message implementations. The github.com/golang/protobuf/proto.MessageReflect function can be used to obtain a reflective view on older messages.

Relationships

The following diagrams demonstrate the relationships between various types declared in this package.

                       ┌───────────────────────────────────┐
                       V                                   │
   ┌────────────── New(n) ─────────────┐                   │
   │                                   │                   │
   │      ┌──── Descriptor() ──┐       │  ┌── Number() ──┐ │
   │      │                    V       V  │              V │
╔════════════╗  ╔════════════════╗  ╔════════╗  ╔════════════╗
║  EnumType  ║  ║ EnumDescriptor ║  ║  Enum  ║  ║ EnumNumber ║
╚════════════╝  ╚════════════════╝  ╚════════╝  ╚════════════╝
      Λ           Λ                   │ │
      │           └─── Descriptor() ──┘ │
      │                                 │
      └────────────────── Type() ───────┘

• An EnumType describes a concrete Go enum type. It has an EnumDescriptor and can construct an Enum instance.

• An EnumDescriptor describes an abstract protobuf enum type.

• An Enum is a concrete enum instance. Generated enums implement Enum.

  ┌──────────────── New() ─────────────────┐
  │                                        │
  │         ┌─── Descriptor() ─────┐       │   ┌── Interface() ───┐
  │         │                      V       V   │                  V
╔═════════════╗  ╔═══════════════════╗  ╔═════════╗  ╔══════════════╗
║ MessageType ║  ║ MessageDescriptor ║  ║ Message ║  ║ ProtoMessage ║
╚═════════════╝  ╚═══════════════════╝  ╚═════════╝  ╚══════════════╝
       Λ           Λ                      │ │  Λ                  │
       │           └──── Descriptor() ────┘ │  └─ ProtoReflect() ─┘
       │                                    │
       └─────────────────── Type() ─────────┘

• A MessageType describes a concrete Go message type. It has a MessageDescriptor and can construct a Message instance. Just as how Go's reflect.Type is a reflective description of a Go type, a MessageType is a reflective description of a Go type for a protobuf message.

• A MessageDescriptor describes an abstract protobuf message type. It has no understanding of Go types. In order to construct a MessageType from just a MessageDescriptor, you can consider looking up the message type in the global registry using the FindMessageByName method on google.golang.org/protobuf/reflect/protoregistry.GlobalTypes or constructing a dynamic MessageType using google.golang.org/protobuf/types/dynamicpb.NewMessageType.

• A Message is a reflective view over a concrete message instance. Generated messages implement ProtoMessage, which can convert to a Message. Just as how Go's reflect.Value is a reflective view over a Go value, a Message is a reflective view over a concrete protobuf message instance. Using Go reflection as an analogy, the [ProtoMessage.ProtoReflect] method is similar to calling reflect.ValueOf, and the [Message.Interface] method is similar to calling reflect.Value.Interface.

      ┌── TypeDescriptor() ──┐    ┌───── Descriptor() ─────┐
      │                      V    │                        V
╔═══════════════╗  ╔═════════════════════════╗  ╔═════════════════════╗
║ ExtensionType ║  ║ ExtensionTypeDescriptor ║  ║ ExtensionDescriptor ║
╚═══════════════╝  ╚═════════════════════════╝  ╚═════════════════════╝
      Λ                      │   │ Λ                      │ Λ
      └─────── Type() ───────┘   │ └─── may implement ────┘ │
                                 │                          │
                                 └────── implements ────────┘

• An ExtensionType describes a concrete Go implementation of an extension. It has an ExtensionTypeDescriptor and can convert to/from an abstract Value and a Go value.

• An ExtensionTypeDescriptor is an ExtensionDescriptor which also has an ExtensionType.

• An ExtensionDescriptor describes an abstract protobuf extension field and may not always be an ExtensionTypeDescriptor.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Cardinality

type Cardinality cardinality

Cardinality determines whether a field is optional, required, or repeated.

const (
	Optional Cardinality = 1 // appears zero or one times
	Required Cardinality = 2 // appears exactly one time; invalid with Proto3
	Repeated Cardinality = 3 // appears zero or more times
)

Constants as defined by the google.protobuf.Cardinality enumeration.

func (Cardinality) GoString

func (c Cardinality) GoString() string

GoString returns c as a Go source identifier (e.g., "Optional").

func (Cardinality) IsValid

func (c Cardinality) IsValid() bool

IsValid reports whether the cardinality is valid.

func (Cardinality) String

func (c Cardinality) String() string

String returns c as a proto source identifier (e.g., "optional").

type Descriptor

type Descriptor interface {
	// ParentFile returns the parent file descriptor that this descriptor
	// is declared within. The parent file for the file descriptor is itself.
	//
	// Support for this functionality is optional and may return nil.
	ParentFile() FileDescriptor

	// Parent returns the parent containing this descriptor declaration.
	// The following shows the mapping from child type to possible parent types:
	//
	//	╔═════════════════════╤═══════════════════════════════════╗
	//	║ Child type          │ Possible parent types             ║
	//	╠═════════════════════╪═══════════════════════════════════╣
	//	║ FileDescriptor      │ nil                               ║
	//	║ MessageDescriptor   │ FileDescriptor, MessageDescriptor ║
	//	║ FieldDescriptor     │ FileDescriptor, MessageDescriptor ║
	//	║ OneofDescriptor     │ MessageDescriptor                 ║
	//	║ EnumDescriptor      │ FileDescriptor, MessageDescriptor ║
	//	║ EnumValueDescriptor │ EnumDescriptor                    ║
	//	║ ServiceDescriptor   │ FileDescriptor                    ║
	//	║ MethodDescriptor    │ ServiceDescriptor                 ║
	//	╚═════════════════════╧═══════════════════════════════════╝
	//
	// Support for this functionality is optional and may return nil.
	Parent() Descriptor

	// Index returns the index of this descriptor within its parent.
	// It returns 0 if the descriptor does not have a parent or if the parent
	// is unknown.
	Index() int

	// Syntax is the protobuf syntax.
	Syntax() Syntax // e.g., Proto2 or Proto3

	// Name is the short name of the declaration (i.e., FullName.Name).
	Name() Name // e.g., "Any"

	// FullName is the fully-qualified name of the declaration.
	//
	// The FullName is a concatenation of the full name of the type that this
	// type is declared within and the declaration name. For example,
	// field "foo_field" in message "proto.package.MyMessage" is
	// uniquely identified as "proto.package.MyMessage.foo_field".
	// Enum values are an exception to the rule (see EnumValueDescriptor).
	FullName() FullName // e.g., "google.protobuf.Any"

	// IsPlaceholder reports whether type information is missing since a
	// dependency is not resolved, in which case only name information is known.
	//
	// Placeholder types may only be returned by the following accessors
	// as a result of unresolved dependencies:
	//
	//	╔═══════════════════════════════════╤═════════════════════╗
	//	║ Accessor                          │ Descriptor          ║
	//	╠═══════════════════════════════════╪═════════════════════╣
	//	║ FileImports.FileDescriptor        │ FileDescriptor      ║
	//	║ FieldDescriptor.Enum              │ EnumDescriptor      ║
	//	║ FieldDescriptor.Message           │ MessageDescriptor   ║
	//	║ FieldDescriptor.DefaultEnumValue  │ EnumValueDescriptor ║
	//	║ FieldDescriptor.ContainingMessage │ MessageDescriptor   ║
	//	║ MethodDescriptor.Input            │ MessageDescriptor   ║
	//	║ MethodDescriptor.Output           │ MessageDescriptor   ║
	//	╚═══════════════════════════════════╧═════════════════════╝
	//
	// If true, only Name and FullName are valid.
	// For FileDescriptor, the Path is also valid.
	IsPlaceholder() bool

	// Options returns the descriptor options. The caller must not modify
	// the returned value.
	//
	// To avoid a dependency cycle, this function returns a proto.Message value.
	// The proto message type returned for each descriptor type is as follows:
	//	╔═════════════════════╤══════════════════════════════════════════╗
	//	║ Go type             │ Protobuf message type                    ║
	//	╠═════════════════════╪══════════════════════════════════════════╣
	//	║ FileDescriptor      │ google.protobuf.FileOptions              ║
	//	║ EnumDescriptor      │ google.protobuf.EnumOptions              ║
	//	║ EnumValueDescriptor │ google.protobuf.EnumValueOptions         ║
	//	║ MessageDescriptor   │ google.protobuf.MessageOptions           ║
	//	║ FieldDescriptor     │ google.protobuf.FieldOptions             ║
	//	║ OneofDescriptor     │ google.protobuf.OneofOptions             ║
	//	║ ServiceDescriptor   │ google.protobuf.ServiceOptions           ║
	//	║ MethodDescriptor    │ google.protobuf.MethodOptions            ║
	//	╚═════════════════════╧══════════════════════════════════════════╝
	//
	// This method returns a typed nil-pointer if no options are present.
	// The caller must import the descriptorpb package to use this.
	Options() ProtoMessage
	// contains filtered or unexported methods
}

Descriptor provides a set of accessors that are common to every descriptor. Each descriptor type wraps the equivalent google.protobuf.XXXDescriptorProto, but provides efficient lookup and immutability.

Each descriptor is comparable. Equality implies that the two types are exactly identical. However, it is possible for the same semantically identical proto type to be represented by multiple type descriptors.

For example, suppose we have t1 and t2 which are both an MessageDescriptor. If t1 == t2, then the types are definitely equal and all accessors return the same information. However, if t1 != t2, then it is still possible that they still represent the same proto type (e.g., t1.FullName == t2.FullName). This can occur if a descriptor type is created dynamically, or multiple versions of the same proto type are accidentally linked into the Go binary.

type Enum

type Enum interface {
	// Descriptor returns enum descriptor, which contains only the protobuf
	// type information for the enum.
	Descriptor() EnumDescriptor

	// Type returns the enum type, which encapsulates both Go and protobuf
	// type information. If the Go type information is not needed,
	// it is recommended that the enum descriptor be used instead.
	Type() EnumType

	// Number returns the enum value as an integer.
	Number() EnumNumber
}

Enum is a reflection interface for a concrete enum value, which provides type information and a getter for the enum number. Enum does not provide a mutable API since enums are commonly backed by Go constants, which are not addressable.

type EnumDescriptor

type EnumDescriptor interface {
	Descriptor

	// Values is a list of nested enum value declarations.
	Values() EnumValueDescriptors

	// ReservedNames is a list of reserved enum names.
	ReservedNames() Names
	// ReservedRanges is a list of reserved ranges of enum numbers.
	ReservedRanges() EnumRanges

	// IsClosed reports whether this enum uses closed semantics.
	// See https://protobuf.dev/programming-guides/enum/#definitions.
	// Note: the Go protobuf implementation is not spec compliant and treats
	// all enums as open enums.
	IsClosed() bool
	// contains filtered or unexported methods
}

EnumDescriptor describes an enum and corresponds with the google.protobuf.EnumDescriptorProto message.

Nested declarations: EnumValueDescriptor.

type EnumDescriptors

type EnumDescriptors interface {
	// Len reports the number of enum types.
	Len() int
	// Get returns the ith EnumDescriptor. It panics if out of bounds.
	Get(i int) EnumDescriptor
	// ByName returns the EnumDescriptor for an enum named s.
	// It returns nil if not found.
	ByName(s Name) EnumDescriptor
	// contains filtered or unexported methods
}

EnumDescriptors is a list of enum declarations.

type EnumNumber

type EnumNumber int32

EnumNumber is the numeric value for an enum.

type EnumRanges

type EnumRanges interface {
	// Len reports the number of ranges in the list.
	Len() int
	// Get returns the ith range. It panics if out of bounds.
	Get(i int) [2]EnumNumber // start inclusive; end inclusive
	// Has reports whether n is within any of the ranges.
	Has(n EnumNumber) bool
	// contains filtered or unexported methods
}

EnumRanges represent a list of enum number ranges.

type EnumType

type EnumType interface {
	// New returns an instance of this enum type with its value set to n.
	New(n EnumNumber) Enum

	// Descriptor returns the enum descriptor.
	//
	// Invariant: t.Descriptor() == t.New(0).Descriptor()
	Descriptor() EnumDescriptor
}

EnumType encapsulates an EnumDescriptor with a concrete Go implementation.

type EnumValueDescriptor

type EnumValueDescriptor interface {
	Descriptor

	// Number returns the enum value as an integer.
	Number() EnumNumber
	// contains filtered or unexported methods
}

EnumValueDescriptor describes an enum value and corresponds with the google.protobuf.EnumValueDescriptorProto message.

All other proto declarations are in the namespace of the parent. However, enum values do not follow this rule and are within the namespace of the parent's parent (i.e., they are a sibling of the containing enum). Thus, a value named "FOO_VALUE" declared within an enum uniquely identified as "proto.package.MyEnum" has a full name of "proto.package.FOO_VALUE".

type EnumValueDescriptors

type EnumValueDescriptors interface {
	// Len reports the number of enum values.
	Len() int
	// Get returns the ith EnumValueDescriptor. It panics if out of bounds.
	Get(i int) EnumValueDescriptor
	// ByName returns the EnumValueDescriptor for the enum value named s.
	// It returns nil if not found.
	ByName(s Name) EnumValueDescriptor
	// ByNumber returns the EnumValueDescriptor for the enum value numbered n.
	// If multiple have the same number, the first one defined is returned
	// It returns nil if not found.
	ByNumber(n EnumNumber) EnumValueDescriptor
	// contains filtered or unexported methods
}

EnumValueDescriptors is a list of enum value declarations.

type ExtensionDescriptor

type ExtensionDescriptor = FieldDescriptor

ExtensionDescriptor is an alias of FieldDescriptor for documentation.

type ExtensionDescriptors

type ExtensionDescriptors interface {
	// Len reports the number of fields.
	Len() int
	// Get returns the ith ExtensionDescriptor. It panics if out of bounds.
	Get(i int) ExtensionDescriptor
	// ByName returns the ExtensionDescriptor for a field named s.
	// It returns nil if not found.
	ByName(s Name) ExtensionDescriptor
	// contains filtered or unexported methods
}

ExtensionDescriptors is a list of field declarations.

type ExtensionType

type ExtensionType interface {
	// New returns a new value for the field.
	// For scalars, this returns the default value in native Go form.
	New() Value

	// Zero returns a new value for the field.
	// For scalars, this returns the default value in native Go form.
	// For composite types, this returns an empty, read-only message, list, or map.
	Zero() Value

	// TypeDescriptor returns the extension type descriptor.
	TypeDescriptor() ExtensionTypeDescriptor

	// ValueOf wraps the input and returns it as a Value.
	// ValueOf panics if the input value is invalid or not the appropriate type.
	//
	// ValueOf is more extensive than protoreflect.ValueOf for a given field's
	// value as it has more type information available.
	ValueOf(any) Value

	// InterfaceOf completely unwraps the Value to the underlying Go type.
	// InterfaceOf panics if the input is nil or does not represent the
	// appropriate underlying Go type. For composite types, it panics if the
	// value is not mutable.
	//
	// InterfaceOf is able to unwrap the Value further than Value.Interface
	// as it has more type information available.
	InterfaceOf(Value) any

	// IsValidValue reports whether the Value is valid to assign to the field.
	IsValidValue(Value) bool

	// IsValidInterface reports whether the input is valid to assign to the field.
	IsValidInterface(any) bool
}

ExtensionType encapsulates an ExtensionDescriptor with a concrete Go implementation. The nested field descriptor must be for a extension field.

While a normal field is a member of the parent message that it is declared within (see [Descriptor.Parent]), an extension field is a member of some other target message (see [FieldDescriptor.ContainingMessage]) and may have no relationship with the parent. However, the full name of an extension field is relative to the parent that it is declared within.

For example:

syntax = "proto2";
package example;
message FooMessage {
	extensions 100 to max;
}
message BarMessage {
	extends FooMessage { optional BarMessage bar_field = 100; }
}

Field "bar_field" is an extension of FooMessage, but its full name is "example.BarMessage.bar_field" instead of "example.FooMessage.bar_field".