Index: third_party/protobuf/java/src/main/java/com/google/protobuf/MessageReflection.java |
diff --git a/third_party/protobuf/java/src/main/java/com/google/protobuf/MessageReflection.java b/third_party/protobuf/java/src/main/java/com/google/protobuf/MessageReflection.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..de4bfd3ef3014d539b825c1d31e9668ac6703aad |
--- /dev/null |
+++ b/third_party/protobuf/java/src/main/java/com/google/protobuf/MessageReflection.java |
@@ -0,0 +1,952 @@ |
+// 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; |
+ |
+ public Descriptors.Descriptor getDescriptorForType() { |
+ return builder.getDescriptorForType(); |
+ } |
+ |
+ public BuilderAdapter(Message.Builder builder) { |
+ this.builder = builder; |
+ } |
+ |
+ public Object getField(Descriptors.FieldDescriptor field) { |
+ return builder.getField(field); |
+ } |
+ |
+ @Override |
+ public boolean hasField(Descriptors.FieldDescriptor field) { |
+ return builder.hasField(field); |
+ } |
+ |
+ public MergeTarget setField(Descriptors.FieldDescriptor field, |
+ Object value) { |
+ builder.setField(field, value); |
+ return this; |
+ } |
+ |
+ public MergeTarget clearField(Descriptors.FieldDescriptor field) { |
+ builder.clearField(field); |
+ return this; |
+ } |
+ |
+ public MergeTarget setRepeatedField( |
+ Descriptors.FieldDescriptor field, int index, Object value) { |
+ builder.setRepeatedField(field, index, value); |
+ return this; |
+ } |
+ |
+ public MergeTarget addRepeatedField( |
+ Descriptors.FieldDescriptor field, Object value) { |
+ builder.addRepeatedField(field, value); |
+ return this; |
+ } |
+ |
+ @Override |
+ public boolean hasOneof(Descriptors.OneofDescriptor oneof) { |
+ return builder.hasOneof(oneof); |
+ } |
+ |
+ @Override |
+ public MergeTarget clearOneof(Descriptors.OneofDescriptor oneof) { |
+ builder.clearOneof(oneof); |
+ return this; |
+ } |
+ |
+ @Override |
+ public Descriptors.FieldDescriptor getOneofFieldDescriptor(Descriptors.OneofDescriptor oneof) { |
+ return builder.getOneofFieldDescriptor(oneof); |
+ } |
+ |
+ public ContainerType getContainerType() { |
+ return ContainerType.MESSAGE; |
+ } |
+ |
+ public ExtensionRegistry.ExtensionInfo findExtensionByName( |
+ ExtensionRegistry registry, String name) { |
+ return registry.findImmutableExtensionByName(name); |
+ } |
+ |
+ public ExtensionRegistry.ExtensionInfo findExtensionByNumber( |
+ ExtensionRegistry registry, Descriptors.Descriptor containingType, |
+ int fieldNumber) { |
+ return registry.findImmutableExtensionByNumber(containingType, |
+ fieldNumber); |
+ } |
+ |
+ public Object parseGroup(CodedInputStream input, |
+ ExtensionRegistryLite extensionRegistry, |
+ Descriptors.FieldDescriptor field, Message defaultInstance) |
+ throws IOException { |
+ Message.Builder subBuilder; |
+ // When default instance is not null. The field is an extension field. |
+ if (defaultInstance != null) { |
+ subBuilder = defaultInstance.newBuilderForType(); |
+ } else { |
+ subBuilder = builder.newBuilderForField(field); |
+ } |
+ if (!field.isRepeated()) { |
+ Message originalMessage = (Message) getField(field); |
+ if (originalMessage != null) { |
+ subBuilder.mergeFrom(originalMessage); |
+ } |
+ } |
+ input.readGroup(field.getNumber(), subBuilder, extensionRegistry); |
+ return subBuilder.buildPartial(); |
+ } |
+ |
+ public Object parseMessage(CodedInputStream input, |
+ ExtensionRegistryLite extensionRegistry, |
+ Descriptors.FieldDescriptor field, Message defaultInstance) |
+ throws IOException { |
+ Message.Builder subBuilder; |
+ // When default instance is not null. The field is an extension field. |
+ if (defaultInstance != null) { |
+ subBuilder = defaultInstance.newBuilderForType(); |
+ } else { |
+ subBuilder = builder.newBuilderForField(field); |
+ } |
+ if (!field.isRepeated()) { |
+ Message originalMessage = (Message) getField(field); |
+ if (originalMessage != null) { |
+ subBuilder.mergeFrom(originalMessage); |
+ } |
+ } |
+ input.readMessage(subBuilder, extensionRegistry); |
+ return subBuilder.buildPartial(); |
+ } |
+ |
+ public Object parseMessageFromBytes(ByteString bytes, |
+ ExtensionRegistryLite extensionRegistry, |
+ Descriptors.FieldDescriptor field, Message defaultInstance) |
+ throws IOException { |
+ Message.Builder subBuilder; |
+ // When default instance is not null. The field is an extension field. |
+ if (defaultInstance != null) { |
+ subBuilder = defaultInstance.newBuilderForType(); |
+ } else { |
+ subBuilder = builder.newBuilderForField(field); |
+ } |
+ if (!field.isRepeated()) { |
+ Message originalMessage = (Message) getField(field); |
+ if (originalMessage != null) { |
+ subBuilder.mergeFrom(originalMessage); |
+ } |
+ } |
+ subBuilder.mergeFrom(bytes, extensionRegistry); |
+ return subBuilder.buildPartial(); |
+ } |
+ |
+ public MergeTarget newMergeTargetForField(Descriptors.FieldDescriptor field, |
+ Message defaultInstance) { |
+ if (defaultInstance != null) { |
+ return new BuilderAdapter( |
+ defaultInstance.newBuilderForType()); |
+ } else { |
+ return new BuilderAdapter(builder.newBuilderForField(field)); |
+ } |
+ } |
+ |
+ public 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; |
+ } |
+ |
+ public Object finish() { |
+ return builder.buildPartial(); |
+ } |
+ } |
+ |
+ |
+ static class ExtensionAdapter implements MergeTarget { |
+ |
+ private final FieldSet<Descriptors.FieldDescriptor> extensions; |
+ |
+ ExtensionAdapter(FieldSet<Descriptors.FieldDescriptor> extensions) { |
+ this.extensions = extensions; |
+ } |
+ |
+ public Descriptors.Descriptor getDescriptorForType() { |
+ throw new UnsupportedOperationException( |
+ "getDescriptorForType() called on FieldSet object"); |
+ } |
+ |
+ public Object getField(Descriptors.FieldDescriptor field) { |
+ return extensions.getField(field); |
+ } |
+ |
+ public boolean hasField(Descriptors.FieldDescriptor field) { |
+ return extensions.hasField(field); |
+ } |
+ |
+ public MergeTarget setField(Descriptors.FieldDescriptor field, |
+ Object value) { |
+ extensions.setField(field, value); |
+ return this; |
+ } |
+ |
+ public MergeTarget clearField(Descriptors.FieldDescriptor field) { |
+ extensions.clearField(field); |
+ return this; |
+ } |
+ |
+ public MergeTarget setRepeatedField( |
+ Descriptors.FieldDescriptor field, int index, Object value) { |
+ extensions.setRepeatedField(field, index, value); |
+ return this; |
+ } |
+ |
+ public MergeTarget addRepeatedField( |
+ Descriptors.FieldDescriptor field, Object value) { |
+ extensions.addRepeatedField(field, value); |
+ return this; |
+ } |
+ |
+ @Override |
+ public boolean hasOneof(Descriptors.OneofDescriptor oneof) { |
+ return false; |
+ } |
+ |
+ @Override |
+ public MergeTarget clearOneof(Descriptors.OneofDescriptor oneof) { |
+ // Nothing to clear. |
+ return this; |
+ } |
+ |
+ @Override |
+ public Descriptors.FieldDescriptor getOneofFieldDescriptor(Descriptors.OneofDescriptor oneof) { |
+ return null; |
+ } |
+ |
+ public ContainerType getContainerType() { |
+ return ContainerType.EXTENSION_SET; |
+ } |
+ |
+ public ExtensionRegistry.ExtensionInfo findExtensionByName( |
+ ExtensionRegistry registry, String name) { |
+ return registry.findImmutableExtensionByName(name); |
+ } |
+ |
+ public ExtensionRegistry.ExtensionInfo findExtensionByNumber( |
+ ExtensionRegistry registry, Descriptors.Descriptor containingType, |
+ int fieldNumber) { |
+ return registry.findImmutableExtensionByNumber(containingType, |
+ fieldNumber); |
+ } |
+ |
+ public Object parseGroup(CodedInputStream input, |
+ ExtensionRegistryLite registry, Descriptors.FieldDescriptor field, |
+ Message defaultInstance) throws IOException { |
+ Message.Builder subBuilder = |
+ defaultInstance.newBuilderForType(); |
+ if (!field.isRepeated()) { |
+ Message originalMessage = (Message) getField(field); |
+ if (originalMessage != null) { |
+ subBuilder.mergeFrom(originalMessage); |
+ } |
+ } |
+ input.readGroup(field.getNumber(), subBuilder, registry); |
+ return subBuilder.buildPartial(); |
+ } |
+ |
+ public Object parseMessage(CodedInputStream input, |
+ ExtensionRegistryLite registry, Descriptors.FieldDescriptor field, |
+ Message defaultInstance) throws IOException { |
+ Message.Builder subBuilder = |
+ defaultInstance.newBuilderForType(); |
+ if (!field.isRepeated()) { |
+ Message originalMessage = (Message) getField(field); |
+ if (originalMessage != null) { |
+ subBuilder.mergeFrom(originalMessage); |
+ } |
+ } |
+ input.readMessage(subBuilder, registry); |
+ return subBuilder.buildPartial(); |
+ } |
+ |
+ public Object parseMessageFromBytes(ByteString bytes, |
+ ExtensionRegistryLite registry, Descriptors.FieldDescriptor field, |
+ Message defaultInstance) throws IOException { |
+ Message.Builder subBuilder = defaultInstance.newBuilderForType(); |
+ if (!field.isRepeated()) { |
+ Message originalMessage = (Message) getField(field); |
+ if (originalMessage != null) { |
+ subBuilder.mergeFrom(originalMessage); |
+ } |
+ } |
+ subBuilder.mergeFrom(bytes, registry); |
+ return subBuilder.buildPartial(); |
+ } |
+ |
+ public MergeTarget newMergeTargetForField( |
+ Descriptors.FieldDescriptor descriptor, Message defaultInstance) { |
+ throw new UnsupportedOperationException( |
+ "newMergeTargetForField() called on FieldSet object"); |
+ } |
+ |
+ public WireFormat.Utf8Validation |
+ getUtf8Validation(Descriptors.FieldDescriptor descriptor) { |
+ if (descriptor.needsUtf8Check()) { |
+ return WireFormat.Utf8Validation.STRICT; |
+ } |
+ // TODO(liujisi): support lazy strings for ExtesnsionSet. |
+ return WireFormat.Utf8Validation.LOOSE; |
+ } |
+ |
+ 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); |
+ } |
+} |