Creating an instance of a message from the descriptor (java)

3,033 views
Skip to first unread message

Kevin Tambascio

unread,
Mar 21, 2010, 8:20:01 PM3/21/10
to Protocol Buffers
Hi,

I'm having trouble getting the following code to work. Using
protoc.exe, I generated a file with the descriptor data using the --
descriptor_set_out file. I've written some Java code to read the
file, and try to instantiate a default instance of one of the objects
in the descriptor, so that I write it out to an XML file using the
protobuf-format-java library.

Here's my code. The variable "descriptorData" contains the binary
content of the descriptor file, without any modifications:

DescriptorProtos.FileDescriptorSet fdSet =
FileDescriptorSet.newBuilder().mergeFrom(descriptorData).build();
FileDescriptorProto fdp = fdSet.getFile(0);

List<DescriptorProto> messageTypes = fdp.getMessageTypeList();
for(DescriptorProto type : messageTypes)
{
System.out.println("Type is: " + type.getName());
FileDescriptor fd = type.getDescriptorForType().getFile();

DynamicMessage dm =
DynamicMessage.getDefaultInstance(type.getDescriptorForType());
System.out.println(XmlFormat.printToString(dm));
}

I've tried numerous combinations of the above code, but each time I
get the following output:

Type is: Type1
<DescriptorProto></DescriptorProto>
Type is: Type2
<DescriptorProto></DescriptorProto>
Type is: Type3
<DescriptorProto></DescriptorProto>
Type is: Type4
<DescriptorProto></DescriptorProto>
Type is: Type5
<DescriptorProto></DescriptorProto>
Type is: Type6
<DescriptorProto></DescriptorProto>

The proto file has Type1, Type2, Type3, etc, defined as messages. The
fact that type.getName() does return the type names from my proto
file, leads me to believe I'm heading in the right direction.
However, the DynamicMessage type that is created (and serialized to
XML) seems to indicate that I'm not passing the right descriptor
instance in to create the object.

Any thoughts?

Thanks,
Kevin

Kenton Varda

unread,
Mar 22, 2010, 4:02:20 PM3/22/10
to Kevin Tambascio, Protocol Buffers
DescriptorProto.getDescriptorForType() returns the Descriptor for DescriptorProto, not for the type which that DescriptorProto is describing.  Remember that DescriptorProto is just a protocol message like any other -- it does not have any special methods that recognize its higher-level meaning.

To convert DescriptorProtos to Descriptors, you need to use FileDescriptor.buildFrom().


--
You received this message because you are subscribed to the Google Groups "Protocol Buffers" group.
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.


Kevin Tambascio

unread,
Mar 22, 2010, 5:42:23 PM3/22/10
to Protocol Buffers
Kenton,

I did make some more progress today, along the lines of what you said
below. I'm seeing an issue where calling
DynamicMessage.getDefaultInstance(type) is not filling in the default
values. This is with 2.3.0 of GPB.

My proto file:

message StringTableEntry
{
required string lang = 1 [default = "en-US"];
required string value = 2 [default = ""];
}

When I instantiate an instance of StringTableEntry, using
DynamicMessage, the required fields are not in the message instance.
From reading the documentation, it sounds like the default values
should show up if I create an object. My code for creation is this:

FileDescriptor fd =
FileDescriptor.buildFrom(fdSet.getFile(0), fds);
List<Descriptor> messageTypes = fd.getMessageTypes();
for(Descriptor type : messageTypes)
{
DynamicMessage dm =
DynamicMessage.newBuilder(type).getDefaultInstanceForType();

//DynamicMessage dm =
DynamicMessage.getDefaultInstance(type);

Map<FieldDescriptor, Object> dmFields =
dm.getAllFields();
for(Entry<FieldDescriptor, Object> entry : dmFields.entrySet())
{
System.out.println("default value for this field: " +
entry.getValue().toString());
entry.setValue("Data");
}

System.out.println(XmlFormat.printToString(dm));
}

When instantiating the object, using either the commented or
uncommented out lines of code above, fails to contain the required
fields with their default values. If I poke around the 'type'
variable in the debugger, I can see that the 2 fields are in the
descriptor, and the default values are there as well. But the
instance of the message does not contain those two fields
(dmFields.entrySet() returns null, and the code inside the
"for(Entry<FieldDescriptor, Object> entry : dmFields.entrySet())" loop
does not execute).

It seems like I could write a routine to set the default values based
on the Descriptor data, but I think that getDefaultInstance should do
that for me.

Thoughts?

Thanks,
Kevin


On Mar 22, 4:02 pm, Kenton Varda <ken...@google.com> wrote:
> DescriptorProto.getDescriptorForType() returns the Descriptor for
> DescriptorProto, not for the type which that DescriptorProto is describing.
>  Remember that DescriptorProto is just a protocol message like any other --
> it does not have any special methods that recognize its higher-level
> meaning.
>
> To convert DescriptorProtos to Descriptors, you need to use
> FileDescriptor.buildFrom().
>
> On Sun, Mar 21, 2010 at 5:20 PM, Kevin Tambascio

> <kevin.tambas...@gmail.com>wrote:

> > protobuf+u...@googlegroups.com<protobuf%2Bunsubscribe@googlegroups.c om>

Kenton Varda

unread,
Mar 22, 2010, 7:07:53 PM3/22/10
to Kevin Tambascio, Protocol Buffers
"required" means "If this field is not explicitly set before build() is called, or if parseFrom() parses a message missing this field, throw an exception.".  It does NOT mean "Automatically fill in this field.".  Please point me at any documentation which suggests the latter meaning so I can fix it.

The default value is the value returned by the field's getter when the field has not been explicitly assigned any other value.

getAllFields() only returns field which have been explicitly set.

To unsubscribe from this group, send email to protobuf+u...@googlegroups.com.

Kevin Tambascio

unread,
Mar 22, 2010, 7:56:20 PM3/22/10
to Protocol Buffers
Kenton,

This description in the MessageLite documentation is what led me to
believe the default values would be there. I figured I was
misinterpreting the documentation, or the meaning behind the default
value:

getDefaultInstanceForType

MessageLite getDefaultInstanceForType()
Get an instance of the type with all fields set to their default
values. This may or may not be a singleton. This differs from the
getDefaultInstance() method of generated message classes in that this
method is an abstract method of the MessageLite interface whereas
getDefaultInstance() is a static method of a specific class. They
return the same thing.

http://code.google.com/apis/protocolbuffers/docs/reference/java/index.html

Thanks for your help,
Kevin


On Mar 22, 7:07 pm, Kenton Varda <ken...@google.com> wrote:
> "required" means "If this field is not explicitly set before build() is
> called, or if parseFrom() parses a message missing this field, throw an
> exception.".  It does NOT mean "Automatically fill in this field.".  Please
> point me at any documentation which suggests the latter meaning so I can fix
> it.
>
> The default value is the value returned by the field's getter when the field
> has not been explicitly assigned any other value.
>
> getAllFields() only returns field which have been explicitly set.
>
> On Mon, Mar 22, 2010 at 2:42 PM, Kevin Tambascio

> <kevin.tambas...@gmail.com>wrote:

> > <protobuf%2Bunsubscr...@googlegroups.c om>

Kenton Varda

unread,
Mar 22, 2010, 7:59:46 PM3/22/10
to Kevin Tambascio, Protocol Buffers
Yeah, I can see how that is misleading (though it does not mention "required" fields -- it claims all fields).  It should say "Get an instance of the type with no fields set.  Because no fields are set, all getters for singular fields will return default values and repeated fields will appear empty.".

To unsubscribe from this group, send email to protobuf+u...@googlegroups.com.

Kenton Varda

unread,
Mar 22, 2010, 8:02:06 PM3/22/10
to Kevin Tambascio, Protocol Buffers
Reply all
Reply to author
Forward
0 new messages