How do I set extension to protobuf DynamicMessage

2019-07-16 03:37发布

问题:

I'm constructing DynamicMessage in java from .proto file I loaded during runtime.

My problem is setting extension to such message.

I have:

  • Descriptors.Descriptor of the containing type and DynamicMessage created for it
  • Descriptors.Descriptor of the extension type and DynamicMessage created for it

Now I don't know how to set the extension to the containing message.

The containing descriptor, if I ask for field list, lists only the fields without the fields in the extension. Which makes sense.

The extension descriptor has only the fields from the extending type (it doesn't have the fields from containing type).

Please advice how I can combine these together.

To get to the context you might want to have a look on my previous question on this topic which didn't care about extensions: Protocol buffer objects generated at runtime

EDIT:

In fact I'm looking for analogy of .setExtension of the generated message. I noticed that only GeneratedMessage extends ExtendableMessage but I believe there must be a way :)

回答1:

Extensions are described by FieldDescriptors, just like regular fields, so when using the dynamic interfaces, you actually use exactly the same methods to access either one.

Keep in mind that extensions are actually declared independently from either the extended type or the extension type. For example, this is valid:

message Foo { extensions 1000 to max; }
message Bar { ... }
extend Foo {
  optional Bar ext1 = 1234;
  optional Bar ext2 = 2345;
}

Notice that we declared two extensions to Foo of type Bar. So, simply knowing that you're looking for an extension of type Bar is not good enough -- you have to specify which one.

In any case, the various descriptor types like FileDescriptor and Descriptor have findExtensionByName() methods which can be used to look up an extension descriptor. Note that this method looks for extensions declared within the scope of the descriptor on which you call it -- it does not find extensions to that message type. That is, if you have:

message Foo { extensions 1000 to max; }
message Bar {
  extend Foo {
    optional int32 ext1 = 1234;
  }
}
extend Foo {
    optional int32 ext2 = 2345;
}

In order to find the extension ext1, you would have to call findExtensionByName("ext1") on the Descriptor for Bar, not the descriptor for Foo. To find ext2, you would have to call findExtensionByName("ext2") on the file's FileDescriptor.

You may also want to take a look at the ExtensionRegistry class, which can be used to look up extensions by their fully-qualified name (e.g. "mypackage.Bar.ext1"), but this requires that you first register the descriptors you're interested in, so it might not be terribly helpful.



回答2:

I also tring to find a solution to this in C++ and it seems easier with following code:

const Reflection* reflection = merged_doc_info.GetReflection();<br/>
const FieldDescriptor * ext_fld=reflection->FindKnownExtensionByName("msg.usage");
assert(ext_fld!=0);
reflection->SetUInt32(&merged_doc_info,ext_fld,123);

an altenative way is to simulate how protoc command does, generate lines of java code like

msgBuilder.setExtension(msg.usage, "1");