You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by st...@apache.org on 2017/07/07 05:00:54 UTC
[20/51] [partial] hbase git commit: Revert "HBASE-17056 Remove
checked in PB generated files Selective add of dependency on" Revert for now.
Build unstable and some interesting issues around CLASSPATH
http://git-wip-us.apache.org/repos/asf/hbase/blob/6786b2b6/hbase-protocol-shaded/src/main/java/org/apache/hadoop/hbase/shaded/com/google/protobuf/MessageLiteToString.java
----------------------------------------------------------------------
diff --git a/hbase-protocol-shaded/src/main/java/org/apache/hadoop/hbase/shaded/com/google/protobuf/MessageLiteToString.java b/hbase-protocol-shaded/src/main/java/org/apache/hadoop/hbase/shaded/com/google/protobuf/MessageLiteToString.java
new file mode 100644
index 0000000..eea6db5
--- /dev/null
+++ b/hbase-protocol-shaded/src/main/java/org/apache/hadoop/hbase/shaded/com/google/protobuf/MessageLiteToString.java
@@ -0,0 +1,239 @@
+// 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 org.apache.hadoop.hbase.shaded.com.google.protobuf;
+
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+/**
+ * Helps generate {@link String} representations of {@link MessageLite} protos.
+ */
+// TODO(dweis): Fix map fields.
+final class MessageLiteToString {
+
+ private static final String LIST_SUFFIX = "List";
+ private static final String BUILDER_LIST_SUFFIX = "OrBuilderList";
+ private static final String BYTES_SUFFIX = "Bytes";
+
+ /**
+ * Returns a {@link String} representation of the {@link MessageLite} object. The first line of
+ * the {@code String} representation representation includes a comment string to uniquely identify
+ * the objcet instance. This acts as an indicator that this should not be relied on for
+ * comparisons.
+ *
+ * <p>For use by generated code only.
+ */
+ static String toString(MessageLite messageLite, String commentString) {
+ StringBuilder buffer = new StringBuilder();
+ buffer.append("# ").append(commentString);
+ reflectivePrintWithIndent(messageLite, buffer, 0);
+ return buffer.toString();
+ }
+
+ /**
+ * Reflectively prints the {@link MessageLite} to the buffer at given {@code indent} level.
+ *
+ * @param buffer the buffer to write to
+ * @param indent the number of spaces to indent the proto by
+ */
+ private static void reflectivePrintWithIndent(
+ MessageLite messageLite, StringBuilder buffer, int indent) {
+ // Build a map of method name to method. We're looking for methods like getFoo(), hasFoo(), and
+ // getFooList() which might be useful for building an object's string representation.
+ Map<String, Method> nameToNoArgMethod = new HashMap<String, Method>();
+ Map<String, Method> nameToMethod = new HashMap<String, Method>();
+ Set<String> getters = new TreeSet<String>();
+ for (Method method : messageLite.getClass().getDeclaredMethods()) {
+ nameToMethod.put(method.getName(), method);
+ if (method.getParameterTypes().length == 0) {
+ nameToNoArgMethod.put(method.getName(), method);
+
+ if (method.getName().startsWith("get")) {
+ getters.add(method.getName());
+ }
+ }
+ }
+
+ for (String getter : getters) {
+ String suffix = getter.replaceFirst("get", "");
+ if (suffix.endsWith(LIST_SUFFIX) && !suffix.endsWith(BUILDER_LIST_SUFFIX)) {
+ String camelCase = suffix.substring(0, 1).toLowerCase()
+ + suffix.substring(1, suffix.length() - LIST_SUFFIX.length());
+ // Try to reflectively get the value and toString() the field as if it were repeated. This
+ // only works if the method names have not be proguarded out or renamed.
+ Method listMethod = nameToNoArgMethod.get("get" + suffix);
+ if (listMethod != null && listMethod.getReturnType().equals(List.class)) {
+ printField(
+ buffer,
+ indent,
+ camelCaseToSnakeCase(camelCase),
+ GeneratedMessageLite.invokeOrDie(listMethod, messageLite));
+ continue;
+ }
+ }
+
+ Method setter = nameToMethod.get("set" + suffix);
+ if (setter == null) {
+ continue;
+ }
+ if (suffix.endsWith(BYTES_SUFFIX)
+ && nameToNoArgMethod.containsKey(
+ "get" + suffix.substring(0, suffix.length() - "Bytes".length()))) {
+ // Heuristic to skip bytes based accessors for string fields.
+ continue;
+ }
+
+ String camelCase = suffix.substring(0, 1).toLowerCase() + suffix.substring(1);
+
+ // Try to reflectively get the value and toString() the field as if it were optional. This
+ // only works if the method names have not be proguarded out or renamed.
+ Method getMethod = nameToNoArgMethod.get("get" + suffix);
+ Method hasMethod = nameToNoArgMethod.get("has" + suffix);
+ // TODO(dweis): Fix proto3 semantics.
+ if (getMethod != null) {
+ Object value = GeneratedMessageLite.invokeOrDie(getMethod, messageLite);
+ final boolean hasValue = hasMethod == null
+ ? !isDefaultValue(value)
+ : (Boolean) GeneratedMessageLite.invokeOrDie(hasMethod, messageLite);
+ // TODO(dweis): This doesn't stop printing oneof case twice: value and enum style.
+ if (hasValue) {
+ printField(
+ buffer,
+ indent,
+ camelCaseToSnakeCase(camelCase),
+ value);
+ }
+ continue;
+ }
+ }
+
+ if (messageLite instanceof GeneratedMessageLite.ExtendableMessage) {
+ Iterator<Map.Entry<GeneratedMessageLite.ExtensionDescriptor, Object>> iter =
+ ((GeneratedMessageLite.ExtendableMessage<?, ?>) messageLite).extensions.iterator();
+ while (iter.hasNext()) {
+ Map.Entry<GeneratedMessageLite.ExtensionDescriptor, Object> entry = iter.next();
+ printField(buffer, indent, "[" + entry.getKey().getNumber() + "]", entry.getValue());
+ }
+ }
+
+ if (((GeneratedMessageLite<?, ?>) messageLite).unknownFields != null) {
+ ((GeneratedMessageLite<?, ?>) messageLite).unknownFields.printWithIndent(buffer, indent);
+ }
+ }
+
+ private static boolean isDefaultValue(Object o) {
+ if (o instanceof Boolean) {
+ return !((Boolean) o);
+ }
+ if (o instanceof Integer) {
+ return ((Integer) o) == 0;
+ }
+ if (o instanceof Float) {
+ return ((Float) o) == 0f;
+ }
+ if (o instanceof Double) {
+ return ((Double) o) == 0d;
+ }
+ if (o instanceof String) {
+ return o.equals("");
+ }
+ if (o instanceof ByteString) {
+ return o.equals(ByteString.EMPTY);
+ }
+ if (o instanceof MessageLite) { // Can happen in oneofs.
+ return o == ((MessageLite) o).getDefaultInstanceForType();
+ }
+ if (o instanceof java.lang.Enum<?>) { // Catches oneof enums.
+ return ((java.lang.Enum<?>) o).ordinal() == 0;
+ }
+
+ return false;
+ }
+
+ /**
+ * Formats a text proto field.
+ *
+ * <p>For use by generated code only.
+ *
+ * @param buffer the buffer to write to
+ * @param indent the number of spaces the proto should be indented by
+ * @param name the field name (in lower underscore case)
+ * @param object the object value of the field
+ */
+ static final void printField(StringBuilder buffer, int indent, String name, Object object) {
+ if (object instanceof List<?>) {
+ List<?> list = (List<?>) object;
+ for (Object entry : list) {
+ printField(buffer, indent, name, entry);
+ }
+ return;
+ }
+
+ buffer.append('\n');
+ for (int i = 0; i < indent; i++) {
+ buffer.append(' ');
+ }
+ buffer.append(name);
+
+ if (object instanceof String) {
+ buffer.append(": \"").append(TextFormatEscaper.escapeText((String) object)).append('"');
+ } else if (object instanceof ByteString) {
+ buffer.append(": \"").append(TextFormatEscaper.escapeBytes((ByteString) object)).append('"');
+ } else if (object instanceof GeneratedMessageLite) {
+ buffer.append(" {");
+ reflectivePrintWithIndent((GeneratedMessageLite<?, ?>) object, buffer, indent + 2);
+ buffer.append("\n");
+ for (int i = 0; i < indent; i++) {
+ buffer.append(' ');
+ }
+ buffer.append("}");
+ } else {
+ buffer.append(": ").append(object.toString());
+ }
+ }
+
+ private static final String camelCaseToSnakeCase(String camelCase) {
+ StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < camelCase.length(); i++) {
+ char ch = camelCase.charAt(i);
+ if (Character.isUpperCase(ch)) {
+ builder.append("_");
+ }
+ builder.append(Character.toLowerCase(ch));
+ }
+ return builder.toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/hbase/blob/6786b2b6/hbase-protocol-shaded/src/main/java/org/apache/hadoop/hbase/shaded/com/google/protobuf/MessageOrBuilder.java
----------------------------------------------------------------------
diff --git a/hbase-protocol-shaded/src/main/java/org/apache/hadoop/hbase/shaded/com/google/protobuf/MessageOrBuilder.java b/hbase-protocol-shaded/src/main/java/org/apache/hadoop/hbase/shaded/com/google/protobuf/MessageOrBuilder.java
new file mode 100644
index 0000000..59d5e2f
--- /dev/null
+++ b/hbase-protocol-shaded/src/main/java/org/apache/hadoop/hbase/shaded/com/google/protobuf/MessageOrBuilder.java
@@ -0,0 +1,143 @@
+// 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 org.apache.hadoop.hbase.shaded.com.google.protobuf;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Base interface for methods common to {@link Message} and
+ * {@link Message.Builder} to provide type equivalency.
+ *
+ * @author jonp@google.com (Jon Perlow)
+ */
+public interface MessageOrBuilder extends MessageLiteOrBuilder {
+
+ // (From MessageLite, re-declared here only for return type covariance.)
+ @Override
+ Message getDefaultInstanceForType();
+
+ /**
+ * Returns a list of field paths (e.g. "foo.bar.baz") of required fields
+ * which are not set in this message. You should call
+ * {@link MessageLiteOrBuilder#isInitialized()} first to check if there
+ * are any missing fields, as that method is likely to be much faster
+ * than this one even when the message is fully-initialized.
+ */
+ List<String> findInitializationErrors();
+
+ /**
+ * Returns a comma-delimited list of required fields which are not set
+ * in this message object. You should call
+ * {@link MessageLiteOrBuilder#isInitialized()} first to check if there
+ * are any missing fields, as that method is likely to be much faster
+ * than this one even when the message is fully-initialized.
+ */
+ String getInitializationErrorString();
+
+ /**
+ * Get the message's type's descriptor. This differs from the
+ * {@code getDescriptor()} method of generated message classes in that
+ * this method is an abstract method of the {@code Message} interface
+ * whereas {@code getDescriptor()} is a static method of a specific class.
+ * They return the same thing.
+ */
+ Descriptors.Descriptor getDescriptorForType();
+
+ /**
+ * Returns a collection of all the fields in this message which are set
+ * and their corresponding values. A singular ("required" or "optional")
+ * field is set iff hasField() returns true for that field. A "repeated"
+ * field is set iff getRepeatedFieldCount() is greater than zero. The
+ * values are exactly what would be returned by calling
+ * {@link #getField(Descriptors.FieldDescriptor)} for each field. The map
+ * is guaranteed to be a sorted map, so iterating over it will return fields
+ * in order by field number.
+ * <br>
+ * If this is for a builder, the returned map may or may not reflect future
+ * changes to the builder. Either way, the returned map is itself
+ * unmodifiable.
+ */
+ Map<Descriptors.FieldDescriptor, Object> getAllFields();
+
+ /**
+ * Returns true if the given oneof is set.
+ * @throws IllegalArgumentException if
+ * {@code oneof.getContainingType() != getDescriptorForType()}.
+ */
+ boolean hasOneof(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);
+
+ /**
+ * 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);
+
+ /**
+ * 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.
+ */
+ Object getField(Descriptors.FieldDescriptor field);
+
+ /**
+ * Gets the number of elements of a repeated field. This is exactly
+ * equivalent to calling the generated "Count" accessor method corresponding
+ * to the field.
+ * @throws IllegalArgumentException The field is not a repeated field, or
+ * {@code field.getContainingType() != getDescriptorForType()}.
+ */
+ int getRepeatedFieldCount(Descriptors.FieldDescriptor field);
+
+ /**
+ * Gets an element of a repeated field. 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.
+ * @throws IllegalArgumentException The field is not a repeated field, or
+ * {@code field.getContainingType() != getDescriptorForType()}.
+ */
+ Object getRepeatedField(Descriptors.FieldDescriptor field, int index);
+
+ /** Get the {@link UnknownFieldSet} for this message. */
+ UnknownFieldSet getUnknownFields();
+}
http://git-wip-us.apache.org/repos/asf/hbase/blob/6786b2b6/hbase-protocol-shaded/src/main/java/org/apache/hadoop/hbase/shaded/com/google/protobuf/MessageReflection.java
----------------------------------------------------------------------
diff --git a/hbase-protocol-shaded/src/main/java/org/apache/hadoop/hbase/shaded/com/google/protobuf/MessageReflection.java b/hbase-protocol-shaded/src/main/java/org/apache/hadoop/hbase/shaded/com/google/protobuf/MessageReflection.java
new file mode 100644
index 0000000..99a3377
--- /dev/null
+++ b/hbase-protocol-shaded/src/main/java/org/apache/hadoop/hbase/shaded/com/google/protobuf/MessageReflection.java
@@ -0,0 +1,990 @@
+// 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 org.apache.hadoop.hbase.shaded.com.google.protobuf;
+
+import org.apache.hadoop.hbase.shaded.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.
+ *
+ * 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();
+ 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) {
+ 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.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);
+ }
+}