예제 #1
0
  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());
          }
        }
      }
    }
예제 #3
0
    /** 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());
      }
    }