// Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. // http://code.google.com/p/protobuf/ // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package com.google.protobuf; import com.google.protobuf.Descriptors.FieldDescriptor; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.TreeMap; /** * Reflection utility methods shared by both mutable and immutable messages. * * @author liujisi@google.com (Pherl Liu) */ class MessageReflection { static void writeMessageTo(Message message, CodedOutputStream output, boolean alwaysWriteRequiredFields) throws IOException { final boolean isMessageSet = message.getDescriptorForType().getOptions().getMessageSetWireFormat(); Map<FieldDescriptor, Object> fields = message.getAllFields(); if (alwaysWriteRequiredFields) { fields = new TreeMap<FieldDescriptor, Object>(fields); for (final FieldDescriptor field : message.getDescriptorForType().getFields()) { if (field.isRequired() && !fields.containsKey(field)) { fields.put(field, message.getField(field)); } } } for (final Map.Entry<Descriptors.FieldDescriptor, Object> entry : fields.entrySet()) { final Descriptors.FieldDescriptor field = entry.getKey(); final Object value = entry.getValue(); if (isMessageSet && field.isExtension() && field.getType() == Descriptors.FieldDescriptor.Type.MESSAGE && !field.isRepeated()) { output.writeMessageSetExtension(field.getNumber(), (Message) value); } else { FieldSet.writeField(field, value, output); } } final UnknownFieldSet unknownFields = message.getUnknownFields(); if (isMessageSet) { unknownFields.writeAsMessageSetTo(output); } else { unknownFields.writeTo(output); } } static int getSerializedSize(Message message) { int size = 0; final boolean isMessageSet = message.getDescriptorForType().getOptions().getMessageSetWireFormat(); for (final Map.Entry<Descriptors.FieldDescriptor, Object> entry : message.getAllFields().entrySet()) { final Descriptors.FieldDescriptor field = entry.getKey(); final Object value = entry.getValue(); if (isMessageSet && field.isExtension() && field.getType() == Descriptors.FieldDescriptor.Type.MESSAGE && !field.isRepeated()) { size += CodedOutputStream.computeMessageSetExtensionSize( field.getNumber(), (Message) value); } else { size += FieldSet.computeFieldSize(field, value); } } final UnknownFieldSet unknownFields = message.getUnknownFields(); if (isMessageSet) { size += unknownFields.getSerializedSizeAsMessageSet(); } else { size += unknownFields.getSerializedSize(); } return size; } static String delimitWithCommas(List<String> parts) { StringBuilder result = new StringBuilder(); for (String part : parts) { if (result.length() > 0) { result.append(", "); } result.append(part); } return result.toString(); } @SuppressWarnings("unchecked") static boolean isInitialized(MessageOrBuilder message) { // Check that all required fields are present. for (final Descriptors.FieldDescriptor field : message .getDescriptorForType() .getFields()) { if (field.isRequired()) { if (!message.hasField(field)) { return false; } } } // Check that embedded messages are initialized. for (final Map.Entry<Descriptors.FieldDescriptor, Object> entry : message.getAllFields().entrySet()) { final Descriptors.FieldDescriptor field = entry.getKey(); if (field.getJavaType() == Descriptors.FieldDescriptor.JavaType.MESSAGE) { if (field.isRepeated()) { for (final Message element : (List<Message>) entry.getValue()) { if (!element.isInitialized()) { return false; } } } else { if (!((Message) entry.getValue()).isInitialized()) { return false; } } } } return true; } private static String subMessagePrefix(final String prefix, final Descriptors.FieldDescriptor field, final int index) { final StringBuilder result = new StringBuilder(prefix); if (field.isExtension()) { result.append('(') .append(field.getFullName()) .append(')'); } else { result.append(field.getName()); } if (index != -1) { result.append('[') .append(index) .append(']'); } result.append('.'); return result.toString(); } private static void findMissingFields(final MessageOrBuilder message, final String prefix, final List<String> results) { for (final Descriptors.FieldDescriptor field : message.getDescriptorForType().getFields()) { if (field.isRequired() && !message.hasField(field)) { results.add(prefix + field.getName()); } } for (final Map.Entry<Descriptors.FieldDescriptor, Object> entry : message.getAllFields().entrySet()) { final Descriptors.FieldDescriptor field = entry.getKey(); final Object value = entry.getValue(); if (field.getJavaType() == Descriptors.FieldDescriptor.JavaType.MESSAGE) { if (field.isRepeated()) { int i = 0; for (final Object element : (List) value) { findMissingFields((MessageOrBuilder) element, subMessagePrefix(prefix, field, i++), results); } } else { if (message.hasField(field)) { findMissingFields((MessageOrBuilder) value, subMessagePrefix(prefix, field, -1), results); } } } } } /** * Populates {@code this.missingFields} with the full "path" of each missing * required field in the given message. */ static List<String> findMissingFields( final MessageOrBuilder message) { final List<String> results = new ArrayList<String>(); findMissingFields(message, "", results); return results; } static interface MergeTarget { enum ContainerType { MESSAGE, EXTENSION_SET } /** * Returns the descriptor for the target. */ public Descriptors.Descriptor getDescriptorForType(); public ContainerType getContainerType(); public ExtensionRegistry.ExtensionInfo findExtensionByName( ExtensionRegistry registry, String name); public ExtensionRegistry.ExtensionInfo findExtensionByNumber( ExtensionRegistry registry, Descriptors.Descriptor containingType, int fieldNumber); /** * Obtains the value of the given field, or the default value if it is not * set. For primitive fields, the boxed primitive value is returned. For * enum fields, the EnumValueDescriptor for the value is returned. For * embedded message fields, the sub-message is returned. For repeated * fields, a java.util.List is returned. */ public Object getField(Descriptors.FieldDescriptor field); /** * Returns true if the given field is set. This is exactly equivalent to * calling the generated "has" accessor method corresponding to the field. * * @throws IllegalArgumentException The field is a repeated field, or {@code * field.getContainingType() != getDescriptorForType()}. */ boolean hasField(Descriptors.FieldDescriptor field); /** * Sets a field to the given value. The value must be of the correct type * for this field, i.e. the same type that * {@link Message#getField(Descriptors.FieldDescriptor)} * would return. */ MergeTarget setField(Descriptors.FieldDescriptor field, Object value); /** * Clears the field. This is exactly equivalent to calling the generated * "clear" accessor method corresponding to the field. */ MergeTarget clearField(Descriptors.FieldDescriptor field); /** * Sets an element of a repeated field to the given value. The value must * be of the correct type for this field, i.e. the same type that {@link * Message#getRepeatedField(Descriptors.FieldDescriptor, int)} would return. * * @throws IllegalArgumentException The field is not a repeated field, or * {@code field.getContainingType() != * getDescriptorForType()}. */ MergeTarget setRepeatedField(Descriptors.FieldDescriptor field, int index, Object value); /** * Like {@code setRepeatedField}, but appends the value as a new element. * * @throws IllegalArgumentException The field is not a repeated field, or * {@code field.getContainingType() != * getDescriptorForType()}. */ MergeTarget addRepeatedField(Descriptors.FieldDescriptor field, Object value); /** * Returns true if the given oneof is set. * * @throws IllegalArgumentException if * {@code oneof.getContainingType() != getDescriptorForType()}. */ boolean hasOneof(Descriptors.OneofDescriptor oneof); /** * Clears the oneof. This is exactly equivalent to calling the generated * "clear" accessor method corresponding to the oneof. */ MergeTarget clearOneof(Descriptors.OneofDescriptor oneof); /** * Obtains the FieldDescriptor if the given oneof is set. Returns null * if no field is set. */ Descriptors.FieldDescriptor getOneofFieldDescriptor(Descriptors.OneofDescriptor oneof); /** * Parse the input stream into a sub field group defined based on either * FieldDescriptor or the default instance. */ Object parseGroup(CodedInputStream input, ExtensionRegistryLite registry, Descriptors.FieldDescriptor descriptor, Message defaultInstance) throws IOException; /** * Parse the input stream into a sub field message defined based on either * FieldDescriptor or the default instance. */ Object parseMessage(CodedInputStream input, ExtensionRegistryLite registry, Descriptors.FieldDescriptor descriptor, Message defaultInstance) throws IOException; /** * Parse from a ByteString into a sub field message defined based on either * FieldDescriptor or the default instance. There isn't a varint indicating * the length of the message at the beginning of the input ByteString. */ Object parseMessageFromBytes( ByteString bytes, ExtensionRegistryLite registry, Descriptors.FieldDescriptor descriptor, Message defaultInstance) throws IOException; /** * Read a primitive field from input. Note that builders and mutable * messages may use different Java types to represent a primtive field. */ Object readPrimitiveField( CodedInputStream input, WireFormat.FieldType type, boolean checkUtf8) throws IOException; /** * Returns a new merge target for a sub-field. When defaultInstance is * provided, it indicates the descriptor is for an extension type, and * implementations should create a new instance from the defaultInstance * prototype directly. */ MergeTarget newMergeTargetForField( Descriptors.FieldDescriptor descriptor, Message defaultInstance); /** * Finishes the merge and returns the underlying object. */ Object finish(); } static class BuilderAdapter implements MergeTarget { private final Message.Builder builder; public Descriptors.Descriptor getDescriptorForType() { return builder.getDescriptorForType(); } public BuilderAdapter(Message.Builder builder) { this.builder = builder; } public Object getField(Descriptors.FieldDescriptor field) { return builder.getField(field); } @Override public boolean hasField(Descriptors.FieldDescriptor field) { return builder.hasField(field); } public MergeTarget setField(Descriptors.FieldDescriptor field, Object value) { builder.setField(field, value); return this; } public MergeTarget clearField(Descriptors.FieldDescriptor field) { builder.clearField(field); return this; } public MergeTarget setRepeatedField( Descriptors.FieldDescriptor field, int index, Object value) { builder.setRepeatedField(field, index, value); return this; } public MergeTarget addRepeatedField( Descriptors.FieldDescriptor field, Object value) { builder.addRepeatedField(field, value); return this; } @Override public boolean hasOneof(Descriptors.OneofDescriptor oneof) { return builder.hasOneof(oneof); } @Override public MergeTarget clearOneof(Descriptors.OneofDescriptor oneof) { builder.clearOneof(oneof); return this; } @Override public Descriptors.FieldDescriptor getOneofFieldDescriptor(Descriptors.OneofDescriptor oneof) { return builder.getOneofFieldDescriptor(oneof); } public ContainerType getContainerType() { return ContainerType.MESSAGE; } public ExtensionRegistry.ExtensionInfo findExtensionByName( ExtensionRegistry registry, String name) { return registry.findImmutableExtensionByName(name); } public ExtensionRegistry.ExtensionInfo findExtensionByNumber( ExtensionRegistry registry, Descriptors.Descriptor containingType, int fieldNumber) { return registry.findImmutableExtensionByNumber(containingType, fieldNumber); } public Object parseGroup(CodedInputStream input, ExtensionRegistryLite extensionRegistry, Descriptors.FieldDescriptor field, Message defaultInstance) throws IOException { Message.Builder subBuilder; // When default instance is not null. The field is an extension field. if (defaultInstance != null) { subBuilder = defaultInstance.newBuilderForType(); } else { subBuilder = builder.newBuilderForField(field); } if (!field.isRepeated()) { Message originalMessage = (Message) getField(field); if (originalMessage != null) { subBuilder.mergeFrom(originalMessage); } } input.readGroup(field.getNumber(), subBuilder, extensionRegistry); return subBuilder.buildPartial(); } public Object parseMessage(CodedInputStream input, ExtensionRegistryLite extensionRegistry, Descriptors.FieldDescriptor field, Message defaultInstance) throws IOException { Message.Builder subBuilder; // When default instance is not null. The field is an extension field. if (defaultInstance != null) { subBuilder = defaultInstance.newBuilderForType(); } else { subBuilder = builder.newBuilderForField(field); } if (!field.isRepeated()) { Message originalMessage = (Message) getField(field); if (originalMessage != null) { subBuilder.mergeFrom(originalMessage); } } input.readMessage(subBuilder, extensionRegistry); return subBuilder.buildPartial(); } public Object parseMessageFromBytes(ByteString bytes, ExtensionRegistryLite extensionRegistry, Descriptors.FieldDescriptor field, Message defaultInstance) throws IOException { Message.Builder subBuilder; // When default instance is not null. The field is an extension field. if (defaultInstance != null) { subBuilder = defaultInstance.newBuilderForType(); } else { subBuilder = builder.newBuilderForField(field); } if (!field.isRepeated()) { Message originalMessage = (Message) getField(field); if (originalMessage != null) { subBuilder.mergeFrom(originalMessage); } } subBuilder.mergeFrom(bytes, extensionRegistry); return subBuilder.buildPartial(); } public MergeTarget newMergeTargetForField(Descriptors.FieldDescriptor field, Message defaultInstance) { if (defaultInstance != null) { return new BuilderAdapter( defaultInstance.newBuilderForType()); } else { return new BuilderAdapter(builder.newBuilderForField(field)); } } public Object readPrimitiveField( CodedInputStream input, WireFormat.FieldType type, boolean checkUtf8) throws IOException { return FieldSet.readPrimitiveField(input, type, checkUtf8); } public Object finish() { return builder.buildPartial(); } } static class ExtensionAdapter implements MergeTarget { private final FieldSet<Descriptors.FieldDescriptor> extensions; ExtensionAdapter(FieldSet<Descriptors.FieldDescriptor> extensions) { this.extensions = extensions; } public Descriptors.Descriptor getDescriptorForType() { throw new UnsupportedOperationException( "getDescriptorForType() called on FieldSet object"); } public Object getField(Descriptors.FieldDescriptor field) { return extensions.getField(field); } public boolean hasField(Descriptors.FieldDescriptor field) { return extensions.hasField(field); } public MergeTarget setField(Descriptors.FieldDescriptor field, Object value) { extensions.setField(field, value); return this; } public MergeTarget clearField(Descriptors.FieldDescriptor field) { extensions.clearField(field); return this; } public MergeTarget setRepeatedField( Descriptors.FieldDescriptor field, int index, Object value) { extensions.setRepeatedField(field, index, value); return this; } public MergeTarget addRepeatedField( Descriptors.FieldDescriptor field, Object value) { extensions.addRepeatedField(field, value); return this; } @Override public boolean hasOneof(Descriptors.OneofDescriptor oneof) { return false; } @Override public MergeTarget clearOneof(Descriptors.OneofDescriptor oneof) { // Nothing to clear. return this; } @Override public Descriptors.FieldDescriptor getOneofFieldDescriptor(Descriptors.OneofDescriptor oneof) { return null; } public ContainerType getContainerType() { return ContainerType.EXTENSION_SET; } public ExtensionRegistry.ExtensionInfo findExtensionByName( ExtensionRegistry registry, String name) { return registry.findImmutableExtensionByName(name); } public ExtensionRegistry.ExtensionInfo findExtensionByNumber( ExtensionRegistry registry, Descriptors.Descriptor containingType, int fieldNumber) { return registry.findImmutableExtensionByNumber(containingType, fieldNumber); } public Object parseGroup(CodedInputStream input, ExtensionRegistryLite registry, Descriptors.FieldDescriptor field, Message defaultInstance) throws IOException { Message.Builder subBuilder = defaultInstance.newBuilderForType(); if (!field.isRepeated()) { Message originalMessage = (Message) getField(field); if (originalMessage != null) { subBuilder.mergeFrom(originalMessage); } } input.readGroup(field.getNumber(), subBuilder, registry); return subBuilder.buildPartial(); } public Object parseMessage(CodedInputStream input, ExtensionRegistryLite registry, Descriptors.FieldDescriptor field, Message defaultInstance) throws IOException { Message.Builder subBuilder = defaultInstance.newBuilderForType(); if (!field.isRepeated()) { Message originalMessage = (Message) getField(field); if (originalMessage != null) { subBuilder.mergeFrom(originalMessage); } } input.readMessage(subBuilder, registry); return subBuilder.buildPartial(); } public Object parseMessageFromBytes(ByteString bytes, ExtensionRegistryLite registry, Descriptors.FieldDescriptor field, Message defaultInstance) throws IOException { Message.Builder subBuilder = defaultInstance.newBuilderForType(); if (!field.isRepeated()) { Message originalMessage = (Message) getField(field); if (originalMessage != null) { subBuilder.mergeFrom(originalMessage); } } subBuilder.mergeFrom(bytes, registry); return subBuilder.buildPartial(); } public MergeTarget newMergeTargetForField( Descriptors.FieldDescriptor descriptor, Message defaultInstance) { throw new UnsupportedOperationException( "newMergeTargetForField() called on FieldSet object"); } public Object readPrimitiveField( CodedInputStream input, WireFormat.FieldType type, boolean checkUtf8) throws IOException { return FieldSet.readPrimitiveField(input, type, checkUtf8); } public Object finish() { throw new UnsupportedOperationException( "finish() called on FieldSet object"); } } /** * Parses a single field into MergeTarget. The target can be Message.Builder, * FieldSet or MutableMessage. * * Package-private because it is used by GeneratedMessage.ExtendableMessage. * * @param tag The tag, which should have already been read. * @return {@code true} unless the tag is an end-group tag. */ static boolean mergeFieldFrom( CodedInputStream input, UnknownFieldSet.Builder unknownFields, ExtensionRegistryLite extensionRegistry, Descriptors.Descriptor type, MergeTarget target, int tag) throws IOException { if (type.getOptions().getMessageSetWireFormat() && tag == WireFormat.MESSAGE_SET_ITEM_TAG) { mergeMessageSetExtensionFromCodedStream( input, unknownFields, extensionRegistry, type, target); return true; } final int wireType = WireFormat.getTagWireType(tag); final int fieldNumber = WireFormat.getTagFieldNumber(tag); final Descriptors.FieldDescriptor field; Message defaultInstance = null; if (type.isExtensionNumber(fieldNumber)) { // 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) { final ExtensionRegistry.ExtensionInfo extension = target.findExtensionByNumber((ExtensionRegistry) extensionRegistry, type, fieldNumber); if (extension == null) { field = null; } else { field = extension.descriptor; defaultInstance = extension.defaultInstance; if (defaultInstance == null && field.getJavaType() == Descriptors.FieldDescriptor.JavaType.MESSAGE) { throw new IllegalStateException( "Message-typed extension lacked default instance: " + field.getFullName()); } } } else { field = null; } } else if (target.getContainerType() == MergeTarget.ContainerType.MESSAGE) { field = type.findFieldByNumber(fieldNumber); } else { field = null; } boolean unknown = false; boolean packed = false; if (field == null) { unknown = true; // Unknown field. } else if (wireType == FieldSet.getWireFormatForFieldType( field.getLiteType(), false /* isPacked */)) { packed = false; } else if (field.isPackable() && wireType == FieldSet.getWireFormatForFieldType( field.getLiteType(), true /* isPacked */)) { packed = true; } else { unknown = true; // Unknown wire type. } if (unknown) { // Unknown field or wrong wire type. Skip. return unknownFields.mergeFieldFrom(tag, input); } if (packed) { final int length = input.readRawVarint32(); final int limit = input.pushLimit(length); if (field.getLiteType() == WireFormat.FieldType.ENUM) { while (input.getBytesUntilLimit() > 0) { final int rawValue = input.readEnum(); final Object value = field.getEnumType().findValueByNumber(rawValue); if (value == null) { // If the number isn't recognized as a valid value for this // enum, drop it (don't even add it to unknownFields). return true; } target.addRepeatedField(field, value); } } else { while (input.getBytesUntilLimit() > 0) { final Object value = target.readPrimitiveField(input, field.getLiteType(), field.needsUtf8Check()); target.addRepeatedField(field, value); } } input.popLimit(limit); } else { final Object value; switch (field.getType()) { case GROUP: { value = target .parseGroup(input, extensionRegistry, field, defaultInstance); break; } case MESSAGE: { value = target .parseMessage(input, extensionRegistry, field, defaultInstance); break; } case ENUM: final int rawValue = input.readEnum(); value = field.getEnumType().findValueByNumber(rawValue); // If the number isn't recognized as a valid value for this enum, // drop it. if (value == null) { unknownFields.mergeVarintField(fieldNumber, rawValue); return true; } break; default: value = target.readPrimitiveField(input, field.getLiteType(), field.needsUtf8Check()); break; } if (field.isRepeated()) { target.addRepeatedField(field, value); } else { target.setField(field, value); } } return true; } /** * Called by {@code #mergeFieldFrom()} to parse a MessageSet extension into * MergeTarget. */ private static void mergeMessageSetExtensionFromCodedStream( CodedInputStream input, UnknownFieldSet.Builder unknownFields, ExtensionRegistryLite extensionRegistry, Descriptors.Descriptor type, MergeTarget target) 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 = target.findExtensionByNumber( (ExtensionRegistry) extensionRegistry, 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, target); 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, target); } else { // We don't know how to parse this. Ignore it. if (rawBytes != null) { unknownFields.mergeField(typeId, UnknownFieldSet.Field.newBuilder() .addLengthDelimited(rawBytes).build()); } } } } private static void mergeMessageSetExtensionFromBytes( ByteString rawBytes, ExtensionRegistry.ExtensionInfo extension, ExtensionRegistryLite extensionRegistry, MergeTarget target) throws IOException { Descriptors.FieldDescriptor field = extension.descriptor; boolean hasOriginalValue = target.hasField(field); if (hasOriginalValue || ExtensionRegistryLite.isEagerlyParseMessageSets()) { // If the field already exists, we just parse the field. Object value = target.parseMessageFromBytes( rawBytes, extensionRegistry,field, extension.defaultInstance); target.setField(field, value); } else { // Use LazyField to load MessageSet lazily. LazyField lazyField = new LazyField( extension.defaultInstance, extensionRegistry, rawBytes); target.setField(field, lazyField); } } private static void eagerlyMergeMessageSetExtension( CodedInputStream input, ExtensionRegistry.ExtensionInfo extension, ExtensionRegistryLite extensionRegistry, MergeTarget target) throws IOException { Descriptors.FieldDescriptor field = extension.descriptor; Object value = target.parseMessage(input, extensionRegistry, field, extension.defaultInstance); target.setField(field, value); } }