Status: New
Owner: liuj...@google.com
Labels: Type-Defect Priority-Medium
New issue 568 by t...@squareup.com: DynamicMessage.Builder#setField allows
enum values to be set for enum fields, instead of EnumValueDescriptors only
http://code.google.com/p/protobuf/issues/detail?id=568
What steps will reproduce the problem?
Consider this test:
@Test(expected = IllegalArgumentException.class) public void
dynamicMessageSetFieldToValue() {
// This should throw IllegalArgumentException, but doesn't!
DynamicMessage dynamicMessage = DynamicMessage.newBuilder(descriptor)
.setField(fieldDescriptor, MyEnum.ONE).build();
// Throws ClassCastException when casting MyEnum.ONE to
EnumValueDescriptor.
dynamicMessage.toString();
}
With this protocol buffer enum and message:
enum MyEnum {
ONE = 1;
}
message MyEnumMessage {
optional MyEnum my_enum = 1;
}
What is the expected output? What do you see instead?
I would expect that DynamicMessage.Builder.setField throws if you try to
set a field to an enum value, instead of the EnumValueDescriptor for the
value.
What I see instead, is that setField happily accepts the enum value, but
then toString on the message blows up with a ClassCastException because it
tries to cast the enum value to an EnumValueDescriptor.
Additionally, apart from the TextFormat implementation, the following makes
me believe EnumValueDescriptor is the type it should accept:
- roundtripping the erroneous DynamicMessage through the serialized form
coalesces the enum value to a EnumValueDescriptor, and
- the reflection API (setField) on GeneratedMessage does throw
IllegalArgumentException if you try to set an enum field to the enum value,
instead of the EnumValueDescriptor.
What version of the product are you using? On what operating system?
Mac OS X 10.8.5, protocol buffers 2.4.1. From inspecting source I'm pretty
sure this issue still exists: FieldSet#verifyType still does only
an "instanceof Internal.EnumLite" check, and ProtocolMessageEnum still
extends Internal.EnumLite.
---
Here are more tests that show the inconsistency. The fourth test is the one
quoted above, and the only test that fails in the code snippet below.
public class ProtocolMessageEnumTest {
static final Descriptors.Descriptor descriptor =
MyEnumMessage.getDescriptor();
static final Descriptors.FieldDescriptor fieldDescriptor =
descriptor.findFieldByName("my_enum");
@Test public void generatedMessageSetMyEnum() {
MyEnumMessage message =
MyEnumMessage.newBuilder().setMyEnum(MyEnum.ONE).build();
assertThat(message.getMyEnum()).isEqualTo(MyEnum.ONE);
assertThat(message.getField(fieldDescriptor)).isEqualTo(MyEnum.ONE.getValueDescriptor());
}
@Test(expected = IllegalArgumentException.class) public void
generatedMessageSetFieldToValue() {
// Throws IllegalArgumentException because EnumValueDescriptor is
expected.
MyEnumMessage message = MyEnumMessage.newBuilder()
.setField(fieldDescriptor, MyEnum.ONE).build();
}
@Test public void generatedMessageSetFieldToValueDescriptor() {
MyEnumMessage message = MyEnumMessage.newBuilder()
.setField(fieldDescriptor, MyEnum.ONE.getValueDescriptor()).build();
assertThat(message.getMyEnum()).isEqualTo(MyEnum.ONE);
assertThat(message.getField(fieldDescriptor)).isEqualTo(MyEnum.ONE.getValueDescriptor());
}
@Test(expected = IllegalArgumentException.class) public void
dynamicMessageSetFieldToValue() {
// This should throw IllegalArgumentException, but doesn't!
DynamicMessage dynamicMessage = DynamicMessage.newBuilder(descriptor)
.setField(fieldDescriptor, MyEnum.ONE).build();
// Throws ClassCastException when casting MyEnum.ONE to
EnumValueDescriptor.
dynamicMessage.toString();
}
@Test public void dynamicMessageSetFieldToValueDescriptor() {
DynamicMessage dynamicMessage = DynamicMessage.newBuilder(descriptor)
.setField(fieldDescriptor, MyEnum.ONE.getValueDescriptor()).build();
dynamicMessage.toString();
}
@Test public void generatedMessageToDynamicMessage() throws
InvalidProtocolBufferException {
MyEnumMessage message =
MyEnumMessage.newBuilder().setMyEnum(MyEnum.ONE).build();
DynamicMessage dynamicMessage = DynamicMessage.parseFrom(descriptor,
message.toByteString());
assertThat(message.getMyEnum()).isEqualTo(MyEnum.ONE);
assertThat(message.getField(fieldDescriptor)).isEqualTo(MyEnum.ONE.getValueDescriptor());
assertThat(dynamicMessage.getField(fieldDescriptor)).isEqualTo(MyEnum.ONE.getValueDescriptor());
}
@Test public void dynamicMessageSetFieldToValueToDynamicMessage() throws
InvalidProtocolBufferException {
DynamicMessage dynamicMessage1 = DynamicMessage.newBuilder(descriptor)
.setField(fieldDescriptor, MyEnum.ONE).build();
DynamicMessage dynamicMessage2 =
DynamicMessage.parseFrom(descriptor,
dynamicMessage1.toByteString());
assertThat(dynamicMessage1.getField(fieldDescriptor)).isEqualTo(MyEnum.ONE);
assertThat(dynamicMessage2.getField(fieldDescriptor)).isEqualTo(MyEnum.ONE.getValueDescriptor());
}
}
--
You received this message because this project is configured to send all
issue notifications to this address.
You may adjust your notification preferences at:
https://code.google.com/hosting/settings
--
You received this message because you are subscribed to the Google Groups "Protocol
Buffers" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to protobuf+unsubscr...@googlegroups.com.
To post to this group, send email to protobuf@googlegroups.com.
Visit this group at http://groups.google.com/group/protobuf.
For more options, visit https://groups.google.com/groups/opt_out.