// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// 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)
/** * Reflection utility methods shared by both mutable and immutable messages. * * @author liujisi@google.com (Pherl Liu) */
class MessageReflection { static void writeMessageTo( Message message, Map<FieldDescriptor, Object> fields, CodedOutputStream output, boolean alwaysWriteRequiredFields) throws IOException { final boolean isMessageSet = message.getDescriptorForType().getOptions().getMessageSetWireFormat(); 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, Map<FieldDescriptor, Object> fields) { int size = 0; final boolean isMessageSet = message.getDescriptorForType().getOptions().getMessageSetWireFormat(); 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()) { 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 this.missingFields with the full "path" of each missing required field in the given message.
/** * 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.
/** 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.
/** * 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 field.getContainingType() != getDescriptorForType().
/** * 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 MessageOrBuilder.getField(FieldDescriptor) would return.
/** * 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.
/** * 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 MessageOrBuilder.getRepeatedField(FieldDescriptor, int) would return.
Throws:
/** * 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 setRepeatedField, but appends the value as a new element.
Throws:
/** * 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 oneof.getContainingType() != getDescriptorForType().
/** * 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.
/** * 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.
/** 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.
/** * 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.
/** * 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.
/** * 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;
Returns the UTF8 validation level for the field.
/** Returns the UTF8 validation level for the field. */
WireFormat.Utf8Validation getUtf8Validation(Descriptors.FieldDescriptor descriptor);
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.
/** * 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);
Returns an empty 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.
/** * Returns an empty 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 newEmptyTargetForField( Descriptors.FieldDescriptor descriptor, Message defaultInstance);
Finishes the merge and returns the underlying object.
/** Finishes the merge and returns the underlying object. */
Object finish(); } static class BuilderAdapter implements MergeTarget { private final Message.Builder builder; @Override public Descriptors.Descriptor getDescriptorForType() { return builder.getDescriptorForType(); } public BuilderAdapter(Message.Builder builder) { this.builder = builder; } @Override public Object getField(Descriptors.FieldDescriptor field) { return builder.getField(field); } @Override public boolean hasField(Descriptors.FieldDescriptor field) { return builder.hasField(field); } @Override public MergeTarget setField(Descriptors.FieldDescriptor field, Object value) { builder.setField(field, value); return this; } @Override public MergeTarget clearField(Descriptors.FieldDescriptor field) { builder.clearField(field); return this; } @Override public MergeTarget setRepeatedField( Descriptors.FieldDescriptor field, int index, Object value) { builder.setRepeatedField(field, index, value); return this; } @Override 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); } @Override public ContainerType getContainerType() { return ContainerType.MESSAGE; } @Override public ExtensionRegistry.ExtensionInfo findExtensionByName( ExtensionRegistry registry, String name) { return registry.findImmutableExtensionByName(name); } @Override public ExtensionRegistry.ExtensionInfo findExtensionByNumber( ExtensionRegistry registry, Descriptors.Descriptor containingType, int fieldNumber) { return registry.findImmutableExtensionByNumber(containingType, fieldNumber); } @Override 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(); } @Override 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(); } @Override 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(); } @Override public MergeTarget newMergeTargetForField( Descriptors.FieldDescriptor field, Message defaultInstance) { Message.Builder subBuilder; 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); } } return new BuilderAdapter(subBuilder); } @Override public MergeTarget newEmptyTargetForField( Descriptors.FieldDescriptor field, Message defaultInstance) { Message.Builder subBuilder; if (defaultInstance != null) { subBuilder = defaultInstance.newBuilderForType(); } else { subBuilder = builder.newBuilderForField(field); } return new BuilderAdapter(subBuilder); } @Override public WireFormat.Utf8Validation getUtf8Validation(Descriptors.FieldDescriptor descriptor) { if (descriptor.needsUtf8Check()) { return WireFormat.Utf8Validation.STRICT; } // TODO(liujisi): support lazy strings for repeated fields. if (!descriptor.isRepeated() && builder instanceof GeneratedMessage.Builder) { return WireFormat.Utf8Validation.LAZY; } return WireFormat.Utf8Validation.LOOSE; } @Override 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; } @Override public Descriptors.Descriptor getDescriptorForType() { throw new UnsupportedOperationException("getDescriptorForType() called on FieldSet object"); } @Override public Object getField(Descriptors.FieldDescriptor field) { return extensions.getField(field); } @Override public boolean hasField(Descriptors.FieldDescriptor field) { return extensions.hasField(field); } @Override public MergeTarget setField(Descriptors.FieldDescriptor field, Object value) { extensions.setField(field, value); return this; } @Override public MergeTarget clearField(Descriptors.FieldDescriptor field) { extensions.clearField(field); return this; } @Override public MergeTarget setRepeatedField( Descriptors.FieldDescriptor field, int index, Object value) { extensions.setRepeatedField(field, index, value); return this; } @Override 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; } @Override public ContainerType getContainerType() { return ContainerType.EXTENSION_SET; } @Override public ExtensionRegistry.ExtensionInfo findExtensionByName( ExtensionRegistry registry, String name) { return registry.findImmutableExtensionByName(name); } @Override public ExtensionRegistry.ExtensionInfo findExtensionByNumber( ExtensionRegistry registry, Descriptors.Descriptor containingType, int fieldNumber) { return registry.findImmutableExtensionByNumber(containingType, fieldNumber); } @Override 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(); } @Override 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(); } @Override 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(); } @Override public MergeTarget newMergeTargetForField( Descriptors.FieldDescriptor descriptor, Message defaultInstance) { throw new UnsupportedOperationException("newMergeTargetForField() called on FieldSet object"); } @Override public MergeTarget newEmptyTargetForField( Descriptors.FieldDescriptor descriptor, Message defaultInstance) { throw new UnsupportedOperationException("newEmptyTargetForField() called on FieldSet object"); } @Override public WireFormat.Utf8Validation getUtf8Validation(Descriptors.FieldDescriptor descriptor) { if (descriptor.needsUtf8Check()) { return WireFormat.Utf8Validation.STRICT; } // TODO(liujisi): support lazy strings for ExtesnsionSet. return WireFormat.Utf8Validation.LOOSE; } @Override 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.

Params:
  • tag – The tag, which should have already been read.
  • unknownFields – If not null, unknown fields will be merged to this UnknownFieldSet, otherwise unknown fields will be discarded.
Returns:true unless the tag is an end-group tag.
/** * Parses a single field into MergeTarget. The target can be Message.Builder, FieldSet or * MutableMessage. * * <p>Package-private because it is used by GeneratedMessage.ExtendableMessage. * * @param tag The tag, which should have already been read. * @param unknownFields If not null, unknown fields will be merged to this {@link * UnknownFieldSet}, otherwise unknown fields will be discarded. * @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(), /* isPacked= */ false)) { packed = false; } else if (field.isPackable() && wireType == FieldSet.getWireFormatForFieldType(field.getLiteType(), /* isPacked= */ true)) { packed = true; } else { unknown = true; // Unknown wire type. } if (unknown) { // Unknown field or wrong wire type. Skip. if (unknownFields != null) { return unknownFields.mergeFieldFrom(tag, input); } else { return input.skipField(tag); } } 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(); if (field.getFile().supportsUnknownEnumValue()) { target.addRepeatedField( field, field.getEnumType().findValueByNumberCreatingIfUnknown(rawValue)); } else { final Object value = field.getEnumType().findValueByNumber(rawValue); // If the number isn't recognized as a valid value for this enum, // add it to the unknown fields. if (value == null) { if (unknownFields != null) { unknownFields.mergeVarintField(fieldNumber, rawValue); } } else { target.addRepeatedField(field, value); } } } } else { while (input.getBytesUntilLimit() > 0) { final Object value = WireFormat.readPrimitiveField( input, field.getLiteType(), target.getUtf8Validation(field)); 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(); if (field.getFile().supportsUnknownEnumValue()) { value = field.getEnumType().findValueByNumberCreatingIfUnknown(rawValue); } else { value = field.getEnumType().findValueByNumber(rawValue); // If the number isn't recognized as a valid value for this enum, // add it to the unknown fields. if (value == null) { if (unknownFields != null) { unknownFields.mergeVarintField(fieldNumber, rawValue); } return true; } } break; default: value = WireFormat.readPrimitiveField( input, field.getLiteType(), target.getUtf8Validation(field)); break; } if (field.isRepeated()) { target.addRepeatedField(field, value); } else { target.setField(field, value); } } return true; }
Called by #mergeFieldFrom() to parse a MessageSet extension into MergeTarget.
/** 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 != 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); } }