Re: [protobuf] Merging a DynamicMessage into a GeneratedMessage

829 views
Skip to first unread message

Jason Hsueh

unread,
Aug 22, 2012, 1:59:14 PM8/22/12
to Kiran Karra, prot...@googlegroups.com
Is the descriptor you provide to to the DynamicMessage the same exact object as the descriptor for the generated message? It looks like you are only comparing against some descriptorMap, based on the name of the generated type.

If you want to be able to do this, your descriptorMap should simply contain the descriptors of the generated types. You are only allowed to call mergeFrom on two messages that have the same descriptor (compared by identity).


On Thu, Aug 16, 2012 at 9:55 AM, Kiran Karra <kiran...@gmail.com> wrote:
Hi,
I am trying to build a generic deserializer in Java.  We have defined several GPB messages, and the receiver is receiving them, not knowing what kind of message it is.  I take the serialized bytes and use DynamicMessage.parseFrom(descriptor, bytes) (I have the descriptor).

I then take this DynamicMessage and am trying to build a GeneratedMessage from it.   The function below demonstrates how I am doing this:

        public Message getGeneratedMessage(DynamicMessage msg, GeneratedMessage.Builder builder) {
                Descriptor desc = msg.getDescriptorForType();
                System.out.println("Received a DynamicMessage with descriptor = " + desc.getFullName());
                System.out.println("Received GeneratedMessage.Builder with descriptor = " + builder.getDescriptorForType().getFullName());

                if (!msg.getDescriptorForType().equals(descriptorMap.get(builder.getDescriptorForType().getFullName()))) {
                        throw new IllegalArgumentException("Msg was of type " + msg.getDescriptorForType().getFullName() + "; expected type " + builder.getDescriptorForType().getFullName());
                }

                builder.mergeFrom(msg);
                return builder.build();
        }

The program output is showing:
Received a DynamicMessage with descriptor = gpb.SRI
Received GeneratedMessage.Builder with descriptor = gpb.SRI

However..., the mergeFrom method call actually throws the following exception:

java.lang.IllegalArgumentException: mergeFrom(Message) can only merge messages of the same type.
        at com.google.protobuf.AbstractMessage$Builder.mergeFrom(AbstractMessage.java:256)

I'm wondering if anybody has any clues.  The function that I am using to get the generated message from the serialized byte array is:

public DynamicMessage parsePacket(final String name, final String description, byte[] data) throws InvalidProtocolBufferException, IllegalStateException {
                Descriptor descriptor = descriptorMap.get(description);
                DynamicMessage msg = null;
                if (descriptor != null) {

                        msg = DynamicMessage.parseFrom(descriptor, data);
                        return msg;
                }
                else {
                        throw new IllegalStateException("Description does not match any known ProtocolBuffer class types!");
                }
        }

Thanks in advance.

--
You received this message because you are subscribed to the Google Groups "Protocol Buffers" group.
To view this discussion on the web visit https://groups.google.com/d/msg/protobuf/-/jofnQihGNLgJ.
To post to this group, send email to prot...@googlegroups.com.
To unsubscribe from this group, send email to protobuf+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/protobuf?hl=en.


Oliver Jowett

unread,
Aug 23, 2012, 4:25:06 AM8/23/12
to Jason Hsueh, Kiran Karra, prot...@googlegroups.com
On Wed, Aug 22, 2012 at 6:59 PM, Jason Hsueh <jas...@google.com> wrote:
> Is the descriptor you provide to to the DynamicMessage the same exact object
> as the descriptor for the generated message? It looks like you are only
> comparing against some descriptorMap, based on the name of the generated
> type.
>
> If you want to be able to do this, your descriptorMap should simply contain
> the descriptors of the generated types. You are only allowed to call
> mergeFrom on two messages that have the same descriptor (compared by
> identity).

Another gotcha I discovered in this area is that extensions won't be
recognized unless the extension that is registered refers to the same
(by identity) base message descriptor as the descriptor used to
construct the DynamicMessage.

Oliver

Kiran Karra

unread,
Aug 23, 2012, 9:09:03 AM8/23/12
to prot...@googlegroups.com
Hi Jason,
Ok, so when I print out the actual object references for the DynamicMessage and the GeneratedMessage.Builder objects, I get the following:

java.lang.IllegalArgumentException: Msg was withh reference com.google.protobuf.Descriptors$Descriptor@5675d86b; expected object reference com.google.protobuf.Descriptors$Descriptor@1dfe3aa4

Based on your explanation, this would not work.

So I see 2 solutions:
1.) In my descriptor map, I'd put the descriptor of the objects directly, such as SRI.getDescriptor()     <-- I tested this and it worked
2.) I use the descriptor file to generate builders with the same descriptor as the descriptors in the descriptor file, and pass that into the getGeneratedMessage function.  

I'm not sure what the best solution here is, but in the case of solution 1, it seems as though I would need to know ahead of time how many messages I have generated, and add them all into my hashmap manually.  For example, lets say I had SRI, CSN, ABC message types?  Then, I'd have to add into my hashmap 3 entries with descriptors SRI.getDescriptor(), CSN.getDescriptor(), and ABC.getDescriptor().  Seems kind of cumbersome unless I am missing something?

The 2nd solution that I described might be a bit cleaner atleast in terms of implementation, BUT, I don't see anything in the API that can generate a GeneratedMessage.Builder from a Descriptor?  My idea would have been to pass in a GeneratedMessage.Builder object that was geenrated from the descriptor that was read in from the file.

Any suggestions?

Thanks again,
Kiran

Jason Hsueh

unread,
Aug 23, 2012, 1:58:12 PM8/23/12
to Kiran Karra, prot...@googlegroups.com
So, what I left out of the first response was that I don't really see why you need to use DynamicMessage, if you're just going to merge it into a generated message. If your client gives you a builder, why not just parse the data directly into the builder instead of the generated message?

As you mentioned, there is no global pool of Descriptor -> GeneratedMessage. In the Java implementation, it is intended for you to explicitly specify which types you need to know about. You would need to provide this mapping: usually you map from Descriptor to the default instance of the GeneratedMessage.


--
You received this message because you are subscribed to the Google Groups "Protocol Buffers" group.
To view this discussion on the web visit https://groups.google.com/d/msg/protobuf/-/PTG9MxIfpuMJ.

Jason Hsueh

unread,
Aug 23, 2012, 2:02:56 PM8/23/12
to Kiran Karra, prot...@googlegroups.com
Should have been:
why not just parse the data directly into the builder instead of the dynamic message?
Reply all
Reply to author
Forward
0 new messages