| 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);
|
| + }
|
| +}
|
|
|