public void testParseMessageSet() throws Exception { ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance(); extensionRegistry.add(TestMessageSetExtension1.messageSetExtension); extensionRegistry.add(TestMessageSetExtension2.messageSetExtension); // Set up a RawMessageSet with two known messages and an unknown one. RawMessageSet raw = RawMessageSet.newBuilder() .addItem( RawMessageSet.Item.newBuilder() .setTypeId(TYPE_ID_1) .setMessage( TestMessageSetExtension1.newBuilder().setI(123).build().toByteString()) .build()) .addItem( RawMessageSet.Item.newBuilder() .setTypeId(TYPE_ID_2) .setMessage( TestMessageSetExtension2.newBuilder().setStr("foo").build().toByteString()) .build()) .addItem( RawMessageSet.Item.newBuilder() .setTypeId(UNKNOWN_TYPE_ID) .setMessage(ByteString.copyFromUtf8("bar")) .build()) .build(); ByteString data = raw.toByteString(); // Parse as a TestMessageSet and check the contents. TestMessageSet messageSet = TestMessageSet.parseFrom(data, extensionRegistry); assertEquals(123, messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI()); assertEquals( "foo", messageSet.getExtension(TestMessageSetExtension2.messageSetExtension).getStr()); // Check for unknown field with type LENGTH_DELIMITED, // number UNKNOWN_TYPE_ID, and contents "bar". UnknownFieldSet unknownFields = messageSet.getUnknownFields(); assertEquals(1, unknownFields.asMap().size()); assertTrue(unknownFields.hasField(UNKNOWN_TYPE_ID)); UnknownFieldSet.Field field = unknownFields.getField(UNKNOWN_TYPE_ID); assertEquals(1, field.getLengthDelimitedList().size()); assertEquals("bar", field.getLengthDelimitedList().get(0).toStringUtf8()); }
private void printUnknownFields(final UnknownFieldSet unknownFields, final TextGenerator generator) throws IOException { for (Map.Entry<Integer, UnknownFieldSet.Field> entry : unknownFields.asMap().entrySet()) { final int number = entry.getKey(); final UnknownFieldSet.Field field = entry.getValue(); printUnknownField(number, WireFormat.WIRETYPE_VARINT, field.getVarintList(), generator); printUnknownField(number, WireFormat.WIRETYPE_FIXED32, field.getFixed32List(), generator); printUnknownField(number, WireFormat.WIRETYPE_FIXED64, field.getFixed64List(), generator); printUnknownField(number, WireFormat.WIRETYPE_LENGTH_DELIMITED, field.getLengthDelimitedList(), generator); for (final UnknownFieldSet value : field.getGroupList()) { generator.print(entry.getKey().toString()); if (singleLineMode) { generator.print(" { "); } else { generator.print(" {\n"); generator.indent(); } printUnknownFields(value, generator); if (singleLineMode) { generator.print("} "); } else { generator.outdent(); generator.print("}\n"); } } } }
public void testSerializeMessageSet() throws Exception { // Set up a TestMessageSet with two known messages and an unknown one. TestMessageSet messageSet = TestMessageSet.newBuilder() .setExtension( TestMessageSetExtension1.messageSetExtension, TestMessageSetExtension1.newBuilder().setI(123).build()) .setExtension( TestMessageSetExtension2.messageSetExtension, TestMessageSetExtension2.newBuilder().setStr("foo").build()) .setUnknownFields( UnknownFieldSet.newBuilder() .addField( UNKNOWN_TYPE_ID, UnknownFieldSet.Field.newBuilder() .addLengthDelimited(ByteString.copyFromUtf8("bar")) .build()) .build()) .build(); ByteString data = messageSet.toByteString(); // Parse back using RawMessageSet and check the contents. RawMessageSet raw = RawMessageSet.parseFrom(data); assertTrue(raw.getUnknownFields().asMap().isEmpty()); assertEquals(3, raw.getItemCount()); assertEquals(TYPE_ID_1, raw.getItem(0).getTypeId()); assertEquals(TYPE_ID_2, raw.getItem(1).getTypeId()); assertEquals(UNKNOWN_TYPE_ID, raw.getItem(2).getTypeId()); TestMessageSetExtension1 message1 = TestMessageSetExtension1.parseFrom(raw.getItem(0).getMessage().toByteArray()); assertEquals(123, message1.getI()); TestMessageSetExtension2 message2 = TestMessageSetExtension2.parseFrom(raw.getItem(1).getMessage().toByteArray()); assertEquals("foo", message2.getStr()); assertEquals("bar", raw.getItem(2).getMessage().toStringUtf8()); }
/** * Called by {@code #mergeFieldFrom()} to parse a MessageSet extension. If {@code builder} is * not null, this method will merge MessageSet into the builder. Otherwise, it will merge the * MessageSet into {@code extensions}. */ private static void mergeMessageSetExtensionFromCodedStream( CodedInputStream input, UnknownFieldSet.Builder unknownFields, ExtensionRegistryLite extensionRegistry, Descriptor type, Message.Builder builder, FieldSet<FieldDescriptor> extensions) throws IOException { // The wire format for MessageSet is: // message MessageSet { // repeated group Item = 1 { // required int32 typeId = 2; // required bytes message = 3; // } // } // "typeId" is the extension's field number. The extension can only be // a message type, where "message" contains the encoded bytes of that // message. // // In practice, we will probably never see a MessageSet item in which // the message appears before the type ID, or where either field does not // appear exactly once. However, in theory such cases are valid, so we // should be prepared to accept them. int typeId = 0; ByteString rawBytes = null; // If we encounter "message" before "typeId" ExtensionRegistry.ExtensionInfo extension = null; // Read bytes from input, if we get it's type first then parse it eagerly, // otherwise we store the raw bytes in a local variable. while (true) { final int tag = input.readTag(); if (tag == 0) { break; } if (tag == WireFormat.MESSAGE_SET_TYPE_ID_TAG) { typeId = input.readUInt32(); if (typeId != 0) { // extensionRegistry may be either ExtensionRegistry or // ExtensionRegistryLite. Since the type we are parsing is a full // message, only a full ExtensionRegistry could possibly contain // extensions of it. Otherwise we will treat the registry as if it // were empty. if (extensionRegistry instanceof ExtensionRegistry) { extension = ((ExtensionRegistry) extensionRegistry).findExtensionByNumber(type, typeId); } } } else if (tag == WireFormat.MESSAGE_SET_MESSAGE_TAG) { if (typeId != 0) { if (extension != null && ExtensionRegistryLite.isEagerlyParseMessageSets()) { // We already know the type, so we can parse directly from the // input with no copying. Hooray! eagerlyMergeMessageSetExtension( input, extension, extensionRegistry, builder, extensions); rawBytes = null; continue; } } // We haven't seen a type ID yet or we want parse message lazily. rawBytes = input.readBytes(); } else { // Unknown tag. Skip it. if (!input.skipField(tag)) { break; // End of group } } } input.checkLastTagWas(WireFormat.MESSAGE_SET_ITEM_END_TAG); // Process the raw bytes. if (rawBytes != null && typeId != 0) { // Zero is not a valid type ID. if (extension != null) { // We known the type mergeMessageSetExtensionFromBytes( rawBytes, extension, extensionRegistry, builder, extensions); } else { // We don't know how to parse this. Ignore it. if (rawBytes != null) { unknownFields.mergeField( typeId, UnknownFieldSet.Field.newBuilder().addLengthDelimited(rawBytes).build()); } } } }
/** Called by {@code #mergeFieldFrom()} to parse a MessageSet extension. */ private static void mergeMessageSetExtensionFromCodedStream( final CodedInputStream input, final UnknownFieldSet.Builder unknownFields, final ExtensionRegistryLite extensionRegistry, final Message.Builder builder) throws IOException { final Descriptor type = builder.getDescriptorForType(); // The wire format for MessageSet is: // message MessageSet { // repeated group Item = 1 { // required int32 typeId = 2; // required bytes message = 3; // } // } // "typeId" is the extension's field number. The extension can only be // a message type, where "message" contains the encoded bytes of that // message. // // In practice, we will probably never see a MessageSet item in which // the message appears before the type ID, or where either field does not // appear exactly once. However, in theory such cases are valid, so we // should be prepared to accept them. int typeId = 0; ByteString rawBytes = null; // If we encounter "message" before "typeId" Message.Builder subBuilder = null; FieldDescriptor field = null; while (true) { final int tag = input.readTag(); if (tag == 0) { break; } if (tag == WireFormat.MESSAGE_SET_TYPE_ID_TAG) { typeId = input.readUInt32(); // Zero is not a valid type ID. if (typeId != 0) { final ExtensionRegistry.ExtensionInfo extension; // extensionRegistry may be either ExtensionRegistry or // ExtensionRegistryLite. Since the type we are parsing is a full // message, only a full ExtensionRegistry could possibly contain // extensions of it. Otherwise we will treat the registry as if it // were empty. if (extensionRegistry instanceof ExtensionRegistry) { extension = ((ExtensionRegistry) extensionRegistry).findExtensionByNumber(type, typeId); } else { extension = null; } if (extension != null) { field = extension.descriptor; subBuilder = extension.defaultInstance.newBuilderForType(); final Message originalMessage = (Message) builder.getField(field); if (originalMessage != null) { subBuilder.mergeFrom(originalMessage); } if (rawBytes != null) { // We already encountered the message. Parse it now. subBuilder.mergeFrom(CodedInputStream.newInstance(rawBytes.newInput())); rawBytes = null; } } else { // Unknown extension number. If we already saw data, put it // in rawBytes. if (rawBytes != null) { unknownFields.mergeField( typeId, UnknownFieldSet.Field.newBuilder().addLengthDelimited(rawBytes).build()); rawBytes = null; } } } } else if (tag == WireFormat.MESSAGE_SET_MESSAGE_TAG) { if (typeId == 0) { // We haven't seen a type ID yet, so we have to store the raw bytes // for now. rawBytes = input.readBytes(); } else if (subBuilder == null) { // We don't know how to parse this. Ignore it. unknownFields.mergeField( typeId, UnknownFieldSet.Field.newBuilder().addLengthDelimited(input.readBytes()).build()); } else { // We already know the type, so we can parse directly from the input // with no copying. Hooray! input.readMessage(subBuilder, extensionRegistry); } } else { // Unknown tag. Skip it. if (!input.skipField(tag)) { break; // end of group } } } input.checkLastTagWas(WireFormat.MESSAGE_SET_ITEM_END_TAG); if (subBuilder != null) { builder.setField(field, subBuilder.build()); } }