content: /* Copyright (C) 2016-2018 Alibaba Group Holding Limited
  
  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at
  
      http://www.apache.org/licenses/LICENSE-2.0
  
  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
  ==============================================================================*/
  
  // 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)
   */
  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 {@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;
  
      /**
       * 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.
       */
      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;
  
      @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) {
        if (defaultInstance != null) {
          return new BuilderAdapter(
              defaultInstance.newBuilderForType());
        } else {
          return new BuilderAdapter(builder.newBuilderForField(field));
        }
      }
  
      @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 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.
     *
     * <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(),
          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.
        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 (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 = 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,
              // drop it.
              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 {@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);
    }
  }
  