github.com/bakjos/protoreflect@v1.9.2/dynamic/message_factory.go (about) 1 package dynamic 2 3 import ( 4 "reflect" 5 "sync" 6 7 "github.com/golang/protobuf/proto" 8 9 "github.com/bakjos/protoreflect/desc" 10 ) 11 12 // MessageFactory can be used to create new empty message objects. A default instance 13 // (without extension registry or known-type registry specified) will always return 14 // dynamic messages (e.g. type will be *dynamic.Message) except for "well-known" types. 15 // The well-known types include primitive wrapper types and a handful of other special 16 // types defined in standard protobuf definitions, like Any, Duration, and Timestamp. 17 type MessageFactory struct { 18 er *ExtensionRegistry 19 ktr *KnownTypeRegistry 20 } 21 22 // NewMessageFactoryWithExtensionRegistry creates a new message factory where any 23 // dynamic messages produced will use the given extension registry to recognize and 24 // parse extension fields. 25 func NewMessageFactoryWithExtensionRegistry(er *ExtensionRegistry) *MessageFactory { 26 return NewMessageFactoryWithRegistries(er, nil) 27 } 28 29 // NewMessageFactoryWithKnownTypeRegistry creates a new message factory where the 30 // known types, per the given registry, will be returned as normal protobuf messages 31 // (e.g. generated structs, instead of dynamic messages). 32 func NewMessageFactoryWithKnownTypeRegistry(ktr *KnownTypeRegistry) *MessageFactory { 33 return NewMessageFactoryWithRegistries(nil, ktr) 34 } 35 36 // NewMessageFactoryWithDefaults creates a new message factory where all "default" types 37 // (those for which protoc-generated code is statically linked into the Go program) are 38 // known types. If any dynamic messages are produced, they will recognize and parse all 39 // "default" extension fields. This is the equivalent of: 40 // NewMessageFactoryWithRegistries( 41 // NewExtensionRegistryWithDefaults(), 42 // NewKnownTypeRegistryWithDefaults()) 43 func NewMessageFactoryWithDefaults() *MessageFactory { 44 return NewMessageFactoryWithRegistries(NewExtensionRegistryWithDefaults(), NewKnownTypeRegistryWithDefaults()) 45 } 46 47 // NewMessageFactoryWithRegistries creates a new message factory with the given extension 48 // and known type registries. 49 func NewMessageFactoryWithRegistries(er *ExtensionRegistry, ktr *KnownTypeRegistry) *MessageFactory { 50 return &MessageFactory{ 51 er: er, 52 ktr: ktr, 53 } 54 } 55 56 // NewMessage creates a new empty message that corresponds to the given descriptor. 57 // If the given descriptor describes a "known type" then that type is instantiated. 58 // Otherwise, an empty dynamic message is returned. 59 func (f *MessageFactory) NewMessage(md *desc.MessageDescriptor) proto.Message { 60 var ktr *KnownTypeRegistry 61 if f != nil { 62 ktr = f.ktr 63 } 64 if m := ktr.CreateIfKnown(md.GetFullyQualifiedName()); m != nil { 65 return m 66 } 67 return NewMessageWithMessageFactory(md, f) 68 } 69 70 // NewDynamicMessage creates a new empty dynamic message that corresponds to the given 71 // descriptor. This is like f.NewMessage(md) except the known type registry is not 72 // consulted so the return value is always a dynamic message. 73 // 74 // This is also like dynamic.NewMessage(md) except that the returned message will use 75 // this factory when creating other messages, like during de-serialization of fields 76 // that are themselves message types. 77 func (f *MessageFactory) NewDynamicMessage(md *desc.MessageDescriptor) *Message { 78 return NewMessageWithMessageFactory(md, f) 79 } 80 81 // GetKnownTypeRegistry returns the known type registry that this factory uses to 82 // instantiate known (e.g. generated) message types. 83 func (f *MessageFactory) GetKnownTypeRegistry() *KnownTypeRegistry { 84 if f == nil { 85 return nil 86 } 87 return f.ktr 88 } 89 90 // GetExtensionRegistry returns the extension registry that this factory uses to 91 // create dynamic messages. The registry is used by dynamic messages to recognize 92 // and parse extension fields during de-serialization. 93 func (f *MessageFactory) GetExtensionRegistry() *ExtensionRegistry { 94 if f == nil { 95 return nil 96 } 97 return f.er 98 } 99 100 type wkt interface { 101 XXX_WellKnownType() string 102 } 103 104 var typeOfWkt = reflect.TypeOf((*wkt)(nil)).Elem() 105 106 // KnownTypeRegistry is a registry of known message types, as identified by their 107 // fully-qualified name. A known message type is one for which a protoc-generated 108 // struct exists, so a dynamic message is not necessary to represent it. A 109 // MessageFactory uses a KnownTypeRegistry to decide whether to create a generated 110 // struct or a dynamic message. The zero-value registry (including the behavior of 111 // a nil pointer) only knows about the "well-known types" in protobuf. These 112 // include only the wrapper types and a handful of other special types like Any, 113 // Duration, and Timestamp. 114 type KnownTypeRegistry struct { 115 excludeWkt bool 116 includeDefault bool 117 mu sync.RWMutex 118 types map[string]reflect.Type 119 } 120 121 // NewKnownTypeRegistryWithDefaults creates a new registry that knows about all 122 // "default" types (those for which protoc-generated code is statically linked 123 // into the Go program). 124 func NewKnownTypeRegistryWithDefaults() *KnownTypeRegistry { 125 return &KnownTypeRegistry{includeDefault: true} 126 } 127 128 // NewKnownTypeRegistryWithoutWellKnownTypes creates a new registry that does *not* 129 // include the "well-known types" in protobuf. So even well-known types would be 130 // represented by a dynamic message. 131 func NewKnownTypeRegistryWithoutWellKnownTypes() *KnownTypeRegistry { 132 return &KnownTypeRegistry{excludeWkt: true} 133 } 134 135 // AddKnownType adds the types of the given messages as known types. 136 func (r *KnownTypeRegistry) AddKnownType(kts ...proto.Message) { 137 r.mu.Lock() 138 defer r.mu.Unlock() 139 if r.types == nil { 140 r.types = map[string]reflect.Type{} 141 } 142 for _, kt := range kts { 143 r.types[proto.MessageName(kt)] = reflect.TypeOf(kt) 144 } 145 } 146 147 // CreateIfKnown will construct an instance of the given message if it is a known type. 148 // If the given name is unknown, nil is returned. 149 func (r *KnownTypeRegistry) CreateIfKnown(messageName string) proto.Message { 150 msgType := r.GetKnownType(messageName) 151 if msgType == nil { 152 return nil 153 } 154 155 if msgType.Kind() == reflect.Ptr { 156 return reflect.New(msgType.Elem()).Interface().(proto.Message) 157 } else { 158 return reflect.New(msgType).Elem().Interface().(proto.Message) 159 } 160 } 161 162 func isWellKnownType(t reflect.Type) bool { 163 if t.Implements(typeOfWkt) { 164 return true 165 } 166 if msg, ok := reflect.Zero(t).Interface().(proto.Message); ok { 167 name := proto.MessageName(msg) 168 _, ok := wellKnownTypeNames[name] 169 return ok 170 } 171 return false 172 } 173 174 // GetKnownType will return the reflect.Type for the given message name if it is 175 // known. If it is not known, nil is returned. 176 func (r *KnownTypeRegistry) GetKnownType(messageName string) reflect.Type { 177 var msgType reflect.Type 178 if r == nil { 179 // a nil registry behaves the same as zero value instance: only know of well-known types 180 t := proto.MessageType(messageName) 181 if t != nil && isWellKnownType(t) { 182 msgType = t 183 } 184 } else { 185 if r.includeDefault { 186 msgType = proto.MessageType(messageName) 187 } else if !r.excludeWkt { 188 t := proto.MessageType(messageName) 189 if t != nil && isWellKnownType(t) { 190 msgType = t 191 } 192 } 193 if msgType == nil { 194 r.mu.RLock() 195 msgType = r.types[messageName] 196 r.mu.RUnlock() 197 } 198 } 199 200 return msgType 201 }