| // Protocol Buffers - Google's data interchange format |
| // Copyright 2008 Google Inc. All rights reserved. |
| // https://developers.google.com/protocol-buffers/ |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are |
| // met: |
| // |
| // * Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above |
| // copyright notice, this list of conditions and the following disclaimer |
| // in the documentation and/or other materials provided with the |
| // distribution. |
| // * Neither the name of Google Inc. nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| package com.google.protobuf; |
| |
| import com.google.protobuf.Descriptors.FieldDescriptor; |
| |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.TreeMap; |
| |
| /** |
| * Reflection utility methods shared by both mutable and immutable messages. |
| * |
| * @author liujisi@google.com (Pherl Liu) |
| */ |
| class MessageReflection { |
| |
| static void writeMessageTo( |
| Message message, |
| Map<FieldDescriptor, Object> fields, |
| CodedOutputStream output, |
| boolean alwaysWriteRequiredFields) |
| throws IOException { |
| final boolean isMessageSet = |
| message.getDescriptorForType().getOptions().getMessageSetWireFormat(); |
| if (alwaysWriteRequiredFields) { |
| fields = new TreeMap<FieldDescriptor, Object>(fields); |
| for (final FieldDescriptor field : |
| message.getDescriptorForType().getFields()) { |
| if (field.isRequired() && !fields.containsKey(field)) { |
| fields.put(field, message.getField(field)); |
| } |
| } |
| } |
| for (final Map.Entry<Descriptors.FieldDescriptor, Object> entry : |
| fields.entrySet()) { |
| final Descriptors.FieldDescriptor field = entry.getKey(); |
| final Object value = entry.getValue(); |
| if (isMessageSet && field.isExtension() && |
| field.getType() == Descriptors.FieldDescriptor.Type.MESSAGE && |
| !field.isRepeated()) { |
| output.writeMessageSetExtension(field.getNumber(), (Message) value); |
| } else { |
| FieldSet.writeField(field, value, output); |
| } |
| } |
| |
| final UnknownFieldSet unknownFields = message.getUnknownFields(); |
| if (isMessageSet) { |
| unknownFields.writeAsMessageSetTo(output); |
| } else { |
| unknownFields.writeTo(output); |
| } |
| } |
| |
| static int getSerializedSize( |
| Message message, |
| Map<FieldDescriptor, Object> fields) { |
| int size = 0; |
| final boolean isMessageSet = |
| message.getDescriptorForType().getOptions().getMessageSetWireFormat(); |
| |
| for (final Map.Entry<Descriptors.FieldDescriptor, Object> entry : |
| fields.entrySet()) { |
| final Descriptors.FieldDescriptor field = entry.getKey(); |
| final Object value = entry.getValue(); |
| if (isMessageSet && field.isExtension() && |
| field.getType() == Descriptors.FieldDescriptor.Type.MESSAGE && |
| !field.isRepeated()) { |
| size += CodedOutputStream.computeMessageSetExtensionSize( |
| field.getNumber(), (Message) value); |
| } else { |
| size += FieldSet.computeFieldSize(field, value); |
| } |
| } |
| |
| final UnknownFieldSet unknownFields = message.getUnknownFields(); |
| if (isMessageSet) { |
| size += unknownFields.getSerializedSizeAsMessageSet(); |
| } else { |
| size += unknownFields.getSerializedSize(); |
| } |
| return size; |
| } |
| |
| static String delimitWithCommas(List<String> parts) { |
| StringBuilder result = new StringBuilder(); |
| for (String part : parts) { |
| if (result.length() > 0) { |
| result.append(", "); |
| } |
| result.append(part); |
| } |
| return result.toString(); |
| } |
| |
| @SuppressWarnings("unchecked") |
| static boolean isInitialized(MessageOrBuilder message) { |
| // Check that all required fields are present. |
| for (final Descriptors.FieldDescriptor field : message |
| .getDescriptorForType() |
| .getFields()) { |
| if (field.isRequired()) { |
| if (!message.hasField(field)) { |
| return false; |
| } |
| } |
| } |
| |
| // Check that embedded messages are initialized. |
| for (final Map.Entry<Descriptors.FieldDescriptor, Object> entry : |
| message.getAllFields().entrySet()) { |
| final Descriptors.FieldDescriptor field = entry.getKey(); |
| if (field.getJavaType() == Descriptors.FieldDescriptor.JavaType.MESSAGE) { |
| if (field.isRepeated()) { |
| for (final Message element |
| : (List<Message>) entry.getValue()) { |
| if (!element.isInitialized()) { |
| return false; |
| } |
| } |
| } else { |
| if (!((Message) entry.getValue()).isInitialized()) { |
| return false; |
| } |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| private static String subMessagePrefix(final String prefix, |
| final Descriptors.FieldDescriptor field, |
| final int index) { |
| final StringBuilder result = new StringBuilder(prefix); |
| if (field.isExtension()) { |
| result.append('(') |
| .append(field.getFullName()) |
| .append(')'); |
| } else { |
| result.append(field.getName()); |
| } |
| if (index != -1) { |
| result.append('[') |
| .append(index) |
| .append(']'); |
| } |
| result.append('.'); |
| return result.toString(); |
| } |
| |
| private static void findMissingFields(final MessageOrBuilder message, |
| final String prefix, |
| final List<String> results) { |
| for (final Descriptors.FieldDescriptor field : |
| message.getDescriptorForType().getFields()) { |
| if (field.isRequired() && !message.hasField(field)) { |
| results.add(prefix + field.getName()); |
| } |
| } |
| |
| for (final Map.Entry<Descriptors.FieldDescriptor, Object> entry : |
| message.getAllFields().entrySet()) { |
| final Descriptors.FieldDescriptor field = entry.getKey(); |
| final Object value = entry.getValue(); |
| |
| if (field.getJavaType() == Descriptors.FieldDescriptor.JavaType.MESSAGE) { |
| if (field.isRepeated()) { |
| int i = 0; |
| for (final Object element : (List) value) { |
| findMissingFields((MessageOrBuilder) element, |
| subMessagePrefix(prefix, field, i++), |
| results); |
| } |
| } else { |
| if (message.hasField(field)) { |
| findMissingFields((MessageOrBuilder) value, |
| subMessagePrefix(prefix, field, -1), |
| results); |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Populates {@code this.missingFields} with the full "path" of each missing |
| * required field in the given message. |
| */ |
| static List<String> findMissingFields( |
| final MessageOrBuilder message) { |
| final List<String> results = new ArrayList<String>(); |
| findMissingFields(message, "", results); |
| return results; |
| } |
| |
| static interface MergeTarget { |
| enum ContainerType { |
| MESSAGE, EXTENSION_SET |
| } |
| |
| /** |
| * Returns the descriptor for the target. |
| */ |
| public Descriptors.Descriptor getDescriptorForType(); |
| |
| public ContainerType getContainerType(); |
| |
| public ExtensionRegistry.ExtensionInfo findExtensionByName( |
| ExtensionRegistry registry, String name); |
| |
| public ExtensionRegistry.ExtensionInfo findExtensionByNumber( |
| ExtensionRegistry registry, Descriptors.Descriptor containingType, |
| int fieldNumber); |
| |
| /** |
| * Obtains the value of the given field, or the default value if it is not |
| * set. For primitive fields, the boxed primitive value is returned. For |
| * enum fields, the EnumValueDescriptor for the value is returned. For |
| * embedded message fields, the sub-message is returned. For repeated |
| * fields, a java.util.List is returned. |
| */ |
| public Object getField(Descriptors.FieldDescriptor field); |
| |
| /** |
| * Returns true if the given field is set. This is exactly equivalent to |
| * calling the generated "has" accessor method corresponding to the field. |
| * |
| * @throws IllegalArgumentException The field is a repeated field, or {@code |
| * field.getContainingType() != getDescriptorForType()}. |
| */ |
| boolean hasField(Descriptors.FieldDescriptor field); |
| |
| /** |
| * Sets a field to the given value. The value must be of the correct type |
| * for this field, i.e. the same type that |
| * {@link Message#getField(Descriptors.FieldDescriptor)} |
| * would return. |
| */ |
| MergeTarget setField(Descriptors.FieldDescriptor field, Object value); |
| |
| /** |
| * Clears the field. This is exactly equivalent to calling the generated |
| * "clear" accessor method corresponding to the field. |
| */ |
| MergeTarget clearField(Descriptors.FieldDescriptor field); |
| |
| /** |
| * Sets an element of a repeated field to the given value. The value must |
| * be of the correct type for this field, i.e. the same type that {@link |
| * Message#getRepeatedField(Descriptors.FieldDescriptor, int)} would return. |
| * |
| * @throws IllegalArgumentException The field is not a repeated field, or |
| * {@code field.getContainingType() != |
| * getDescriptorForType()}. |
| */ |
| MergeTarget setRepeatedField(Descriptors.FieldDescriptor field, |
| int index, Object value); |
| |
| /** |
| * Like {@code setRepeatedField}, but appends the value as a new element. |
| * |
| * @throws IllegalArgumentException The field is not a repeated field, or |
| * {@code field.getContainingType() != |
| * getDescriptorForType()}. |
| */ |
| MergeTarget addRepeatedField(Descriptors.FieldDescriptor field, |
| Object value); |
| |
| /** |
| * Returns true if the given oneof is set. |
| * |
| * @throws IllegalArgumentException if |
| * {@code oneof.getContainingType() != getDescriptorForType()}. |
| */ |
| boolean hasOneof(Descriptors.OneofDescriptor oneof); |
| |
| /** |
| * Clears the oneof. This is exactly equivalent to calling the generated |
| * "clear" accessor method corresponding to the oneof. |
| */ |
| MergeTarget clearOneof(Descriptors.OneofDescriptor oneof); |
| |
| /** |
| * Obtains the FieldDescriptor if the given oneof is set. Returns null |
| * if no field is set. |
| */ |
| Descriptors.FieldDescriptor getOneofFieldDescriptor(Descriptors.OneofDescriptor oneof); |
| |
| /** |
| * Parse the input stream into a sub field group defined based on either |
| * FieldDescriptor or the default instance. |
| */ |
| Object parseGroup(CodedInputStream input, ExtensionRegistryLite registry, |
| Descriptors.FieldDescriptor descriptor, Message defaultInstance) |
| throws IOException; |
| |
| /** |
| * Parse the input stream into a sub field message defined based on either |
| * FieldDescriptor or the default instance. |
| */ |
| Object parseMessage(CodedInputStream input, ExtensionRegistryLite registry, |
| Descriptors.FieldDescriptor descriptor, Message defaultInstance) |
| throws IOException; |
| |
| /** |
| * Parse from a ByteString into a sub field message defined based on either |
| * FieldDescriptor or the default instance. There isn't a varint indicating |
| * the length of the message at the beginning of the input ByteString. |
| */ |
| Object parseMessageFromBytes( |
| ByteString bytes, ExtensionRegistryLite registry, |
| Descriptors.FieldDescriptor descriptor, Message defaultInstance) |
| throws IOException; |
| |
| /** |
| * Returns the UTF8 validation level for the field. |
| */ |
| WireFormat.Utf8Validation getUtf8Validation(Descriptors.FieldDescriptor |
| descriptor); |
| |
| /** |
| * Returns a new merge target for a sub-field. When defaultInstance is |
| * provided, it indicates the descriptor is for an extension type, and |
| * implementations should create a new instance from the defaultInstance |
| * prototype directly. |
| */ |
| MergeTarget newMergeTargetForField( |
| Descriptors.FieldDescriptor descriptor, |
| Message defaultInstance); |
| |
| /** |
| * Finishes the merge and returns the underlying object. |
| */ |
| Object finish(); |
| |
| } |
| |
| static class BuilderAdapter implements MergeTarget { |
| |
| private final Message.Builder builder; |
| |
| @Override |
| public Descriptors.Descriptor getDescriptorForType() { |
| return builder.getDescriptorForType(); |
| } |
| |
| public BuilderAdapter(Message.Builder builder) { |
| this.builder = builder; |
| } |
| |
| @Override |
| public Object getField(Descriptors.FieldDescriptor field) { |
| return builder.getField(field); |
| } |
| |
| @Override |
| public boolean hasField(Descriptors.FieldDescriptor field) { |
| return builder.hasField(field); |
| } |
| |
| @Override |
| public MergeTarget setField(Descriptors.FieldDescriptor field, Object value) { |
| builder.setField(field, value); |
| return this; |
| } |
| |
| @Override |
| public MergeTarget clearField(Descriptors.FieldDescriptor field) { |
| builder.clearField(field); |
| return this; |
| } |
| |
| @Override |
| public MergeTarget setRepeatedField( |
| Descriptors.FieldDescriptor field, int index, Object value) { |
| builder.setRepeatedField(field, index, value); |
| return this; |
| } |
| |
| @Override |
| public MergeTarget addRepeatedField(Descriptors.FieldDescriptor field, Object value) { |
| builder.addRepeatedField(field, value); |
| return this; |
| } |
| |
| @Override |
| public boolean hasOneof(Descriptors.OneofDescriptor oneof) { |
| return builder.hasOneof(oneof); |
| } |
| |
| @Override |
| public MergeTarget clearOneof(Descriptors.OneofDescriptor oneof) { |
| builder.clearOneof(oneof); |
| return this; |
| } |
| |
| @Override |
| public Descriptors.FieldDescriptor getOneofFieldDescriptor(Descriptors.OneofDescriptor oneof) { |
| return builder.getOneofFieldDescriptor(oneof); |
| } |
| |
| @Override |
| public ContainerType getContainerType() { |
| return ContainerType.MESSAGE; |
| } |
| |
| @Override |
| public ExtensionRegistry.ExtensionInfo findExtensionByName( |
| ExtensionRegistry registry, String name) { |
| return registry.findImmutableExtensionByName(name); |
| } |
| |
| @Override |
| public ExtensionRegistry.ExtensionInfo findExtensionByNumber( |
| ExtensionRegistry registry, Descriptors.Descriptor containingType, int fieldNumber) { |
| return registry.findImmutableExtensionByNumber(containingType, |
| fieldNumber); |
| } |
| |
| @Override |
| public Object parseGroup( |
| CodedInputStream input, |
| ExtensionRegistryLite extensionRegistry, |
| Descriptors.FieldDescriptor field, |
| Message defaultInstance) |
| throws IOException { |
| Message.Builder subBuilder; |
| // When default instance is not null. The field is an extension field. |
| if (defaultInstance != null) { |
| subBuilder = defaultInstance.newBuilderForType(); |
| } else { |
| subBuilder = builder.newBuilderForField(field); |
| } |
| if (!field.isRepeated()) { |
| Message originalMessage = (Message) getField(field); |
| if (originalMessage != null) { |
| subBuilder.mergeFrom(originalMessage); |
| } |
| } |
| input.readGroup(field.getNumber(), subBuilder, extensionRegistry); |
| return subBuilder.buildPartial(); |
| } |
| |
| @Override |
| public Object parseMessage( |
| CodedInputStream input, |
| ExtensionRegistryLite extensionRegistry, |
| Descriptors.FieldDescriptor field, |
| Message defaultInstance) |
| throws IOException { |
| Message.Builder subBuilder; |
| // When default instance is not null. The field is an extension field. |
| if (defaultInstance != null) { |
| subBuilder = defaultInstance.newBuilderForType(); |
| } else { |
| subBuilder = builder.newBuilderForField(field); |
| } |
| if (!field.isRepeated()) { |
| Message originalMessage = (Message) getField(field); |
| if (originalMessage != null) { |
| subBuilder.mergeFrom(originalMessage); |
| } |
| } |
| input.readMessage(subBuilder, extensionRegistry); |
| return subBuilder.buildPartial(); |
| } |
| |
| @Override |
| public Object parseMessageFromBytes( |
| ByteString bytes, |
| ExtensionRegistryLite extensionRegistry, |
| Descriptors.FieldDescriptor field, |
| Message defaultInstance) |
| throws IOException { |
| Message.Builder subBuilder; |
| // When default instance is not null. The field is an extension field. |
| if (defaultInstance != null) { |
| subBuilder = defaultInstance.newBuilderForType(); |
| } else { |
| subBuilder = builder.newBuilderForField(field); |
| } |
| if (!field.isRepeated()) { |
| Message originalMessage = (Message) getField(field); |
| if (originalMessage != null) { |
| subBuilder.mergeFrom(originalMessage); |
| } |
| } |
| subBuilder.mergeFrom(bytes, extensionRegistry); |
| return subBuilder.buildPartial(); |
| } |
| |
| @Override |
| public MergeTarget newMergeTargetForField( |
| Descriptors.FieldDescriptor field, Message defaultInstance) { |
| if (defaultInstance != null) { |
| return new BuilderAdapter( |
| defaultInstance.newBuilderForType()); |
| } else { |
| return new BuilderAdapter(builder.newBuilderForField(field)); |
| } |
| } |
| |
| @Override |
| public WireFormat.Utf8Validation getUtf8Validation(Descriptors.FieldDescriptor descriptor) { |
| if (descriptor.needsUtf8Check()) { |
| return WireFormat.Utf8Validation.STRICT; |
| } |
| // TODO(liujisi): support lazy strings for repeated fields. |
| if (!descriptor.isRepeated() |
| && builder instanceof GeneratedMessage.Builder) { |
| return WireFormat.Utf8Validation.LAZY; |
| } |
| return WireFormat.Utf8Validation.LOOSE; |
| } |
| |
| @Override |
| public Object finish() { |
| return builder.buildPartial(); |
| } |
| |
| } |
| |
| |
| static class ExtensionAdapter implements MergeTarget { |
| |
| private final FieldSet<Descriptors.FieldDescriptor> extensions; |
| |
| ExtensionAdapter(FieldSet<Descriptors.FieldDescriptor> extensions) { |
| this.extensions = extensions; |
| } |
| |
| @Override |
| public Descriptors.Descriptor getDescriptorForType() { |
| throw new UnsupportedOperationException( |
| "getDescriptorForType() called on FieldSet object"); |
| } |
| |
| @Override |
| public Object getField(Descriptors.FieldDescriptor field) { |
| return extensions.getField(field); |
| } |
| |
| @Override |
| public boolean hasField(Descriptors.FieldDescriptor field) { |
| return extensions.hasField(field); |
| } |
| |
| @Override |
| public MergeTarget setField(Descriptors.FieldDescriptor field, Object value) { |
| extensions.setField(field, value); |
| return this; |
| } |
| |
| @Override |
| public MergeTarget clearField(Descriptors.FieldDescriptor field) { |
| extensions.clearField(field); |
| return this; |
| } |
| |
| @Override |
| public MergeTarget setRepeatedField( |
| Descriptors.FieldDescriptor field, int index, Object value) { |
| extensions.setRepeatedField(field, index, value); |
| return this; |
| } |
| |
| @Override |
| public MergeTarget addRepeatedField(Descriptors.FieldDescriptor field, Object value) { |
| extensions.addRepeatedField(field, value); |
| return this; |
| } |
| |
| @Override |
| public boolean hasOneof(Descriptors.OneofDescriptor oneof) { |
| return false; |
| } |
| |
| @Override |
| public MergeTarget clearOneof(Descriptors.OneofDescriptor oneof) { |
| // Nothing to clear. |
| return this; |
| } |
| |
| @Override |
| public Descriptors.FieldDescriptor getOneofFieldDescriptor(Descriptors.OneofDescriptor oneof) { |
| return null; |
| } |
| |
| @Override |
| public ContainerType getContainerType() { |
| return ContainerType.EXTENSION_SET; |
| } |
| |
| @Override |
| public ExtensionRegistry.ExtensionInfo findExtensionByName( |
| ExtensionRegistry registry, String name) { |
| return registry.findImmutableExtensionByName(name); |
| } |
| |
| @Override |
| public ExtensionRegistry.ExtensionInfo findExtensionByNumber( |
| ExtensionRegistry registry, Descriptors.Descriptor containingType, int fieldNumber) { |
| return registry.findImmutableExtensionByNumber(containingType, |
| fieldNumber); |
| } |
| |
| @Override |
| public Object parseGroup( |
| CodedInputStream input, |
| ExtensionRegistryLite registry, |
| Descriptors.FieldDescriptor field, |
| Message defaultInstance) |
| throws IOException { |
| Message.Builder subBuilder = |
| defaultInstance.newBuilderForType(); |
| if (!field.isRepeated()) { |
| Message originalMessage = (Message) getField(field); |
| if (originalMessage != null) { |
| subBuilder.mergeFrom(originalMessage); |
| } |
| } |
| input.readGroup(field.getNumber(), subBuilder, registry); |
| return subBuilder.buildPartial(); |
| } |
| |
| @Override |
| public Object parseMessage( |
| CodedInputStream input, |
| ExtensionRegistryLite registry, |
| Descriptors.FieldDescriptor field, |
| Message defaultInstance) |
| throws IOException { |
| Message.Builder subBuilder = |
| defaultInstance.newBuilderForType(); |
| if (!field.isRepeated()) { |
| Message originalMessage = (Message) getField(field); |
| if (originalMessage != null) { |
| subBuilder.mergeFrom(originalMessage); |
| } |
| } |
| input.readMessage(subBuilder, registry); |
| return subBuilder.buildPartial(); |
| } |
| |
| @Override |
| public Object parseMessageFromBytes( |
| ByteString bytes, |
| ExtensionRegistryLite registry, |
| Descriptors.FieldDescriptor field, |
| Message defaultInstance) |
| throws IOException { |
| Message.Builder subBuilder = defaultInstance.newBuilderForType(); |
| if (!field.isRepeated()) { |
| Message originalMessage = (Message) getField(field); |
| if (originalMessage != null) { |
| subBuilder.mergeFrom(originalMessage); |
| } |
| } |
| subBuilder.mergeFrom(bytes, registry); |
| return subBuilder.buildPartial(); |
| } |
| |
| @Override |
| public MergeTarget newMergeTargetForField( |
| Descriptors.FieldDescriptor descriptor, Message defaultInstance) { |
| throw new UnsupportedOperationException( |
| "newMergeTargetForField() called on FieldSet object"); |
| } |
| |
| @Override |
| public WireFormat.Utf8Validation getUtf8Validation(Descriptors.FieldDescriptor descriptor) { |
| if (descriptor.needsUtf8Check()) { |
| return WireFormat.Utf8Validation.STRICT; |
| } |
| // TODO(liujisi): support lazy strings for ExtesnsionSet. |
| return WireFormat.Utf8Validation.LOOSE; |
| } |
| |
| @Override |
| public Object finish() { |
| throw new UnsupportedOperationException( |
| "finish() called on FieldSet object"); |
| } |
| |
| } |
| |
| /** |
| * Parses a single field into MergeTarget. The target can be Message.Builder, |
| * FieldSet or MutableMessage. |
| * |
| * 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); |
| } |
| } |