Index: third_party/protobuf/java/src/main/java/com/google/protobuf/AbstractMessage.java |
diff --git a/third_party/protobuf/java/src/main/java/com/google/protobuf/AbstractMessage.java b/third_party/protobuf/java/src/main/java/com/google/protobuf/AbstractMessage.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..b9d8301681f8b996747bca217ab244872ad5922f |
--- /dev/null |
+++ b/third_party/protobuf/java/src/main/java/com/google/protobuf/AbstractMessage.java |
@@ -0,0 +1,764 @@ |
+// Protocol Buffers - Google's data interchange format |
+// Copyright 2008 Google Inc. All rights reserved. |
+// http://code.google.com/p/protobuf/ |
+// |
+// 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.Descriptor; |
+import com.google.protobuf.Descriptors.FieldDescriptor; |
+import com.google.protobuf.Internal.EnumLite; |
+ |
+import java.io.IOException; |
+import java.io.InputStream; |
+import java.util.ArrayList; |
+import java.util.List; |
+import java.util.Map; |
+ |
+/** |
+ * A partial implementation of the {@link Message} interface which implements |
+ * as many methods of that interface as possible in terms of other methods. |
+ * |
+ * @author kenton@google.com Kenton Varda |
+ */ |
+public abstract class AbstractMessage extends AbstractMessageLite |
+ implements Message { |
+ @SuppressWarnings("unchecked") |
+ public boolean isInitialized() { |
+ // Check that all required fields are present. |
+ for (final FieldDescriptor field : getDescriptorForType().getFields()) { |
+ if (field.isRequired()) { |
+ if (!hasField(field)) { |
+ return false; |
+ } |
+ } |
+ } |
+ |
+ // Check that embedded messages are initialized. |
+ for (final Map.Entry<FieldDescriptor, Object> entry : |
+ getAllFields().entrySet()) { |
+ final FieldDescriptor field = entry.getKey(); |
+ if (field.getJavaType() == 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; |
+ } |
+ |
+ @Override |
+ public final String toString() { |
+ return TextFormat.printToString(this); |
+ } |
+ |
+ public void writeTo(final CodedOutputStream output) throws IOException { |
+ final boolean isMessageSet = |
+ getDescriptorForType().getOptions().getMessageSetWireFormat(); |
+ |
+ for (final Map.Entry<FieldDescriptor, Object> entry : |
+ getAllFields().entrySet()) { |
+ final FieldDescriptor field = entry.getKey(); |
+ final Object value = entry.getValue(); |
+ if (isMessageSet && field.isExtension() && |
+ field.getType() == FieldDescriptor.Type.MESSAGE && |
+ !field.isRepeated()) { |
+ output.writeMessageSetExtension(field.getNumber(), (Message) value); |
+ } else { |
+ FieldSet.writeField(field, value, output); |
+ } |
+ } |
+ |
+ final UnknownFieldSet unknownFields = getUnknownFields(); |
+ if (isMessageSet) { |
+ unknownFields.writeAsMessageSetTo(output); |
+ } else { |
+ unknownFields.writeTo(output); |
+ } |
+ } |
+ |
+ private int memoizedSize = -1; |
+ |
+ public int getSerializedSize() { |
+ int size = memoizedSize; |
+ if (size != -1) { |
+ return size; |
+ } |
+ |
+ size = 0; |
+ final boolean isMessageSet = |
+ getDescriptorForType().getOptions().getMessageSetWireFormat(); |
+ |
+ for (final Map.Entry<FieldDescriptor, Object> entry : |
+ getAllFields().entrySet()) { |
+ final FieldDescriptor field = entry.getKey(); |
+ final Object value = entry.getValue(); |
+ if (isMessageSet && field.isExtension() && |
+ field.getType() == FieldDescriptor.Type.MESSAGE && |
+ !field.isRepeated()) { |
+ size += CodedOutputStream.computeMessageSetExtensionSize( |
+ field.getNumber(), (Message) value); |
+ } else { |
+ size += FieldSet.computeFieldSize(field, value); |
+ } |
+ } |
+ |
+ final UnknownFieldSet unknownFields = getUnknownFields(); |
+ if (isMessageSet) { |
+ size += unknownFields.getSerializedSizeAsMessageSet(); |
+ } else { |
+ size += unknownFields.getSerializedSize(); |
+ } |
+ |
+ memoizedSize = size; |
+ return size; |
+ } |
+ |
+ @Override |
+ public boolean equals(final Object other) { |
+ if (other == this) { |
+ return true; |
+ } |
+ if (!(other instanceof Message)) { |
+ return false; |
+ } |
+ final Message otherMessage = (Message) other; |
+ if (getDescriptorForType() != otherMessage.getDescriptorForType()) { |
+ return false; |
+ } |
+ return getAllFields().equals(otherMessage.getAllFields()) && |
+ getUnknownFields().equals(otherMessage.getUnknownFields()); |
+ } |
+ |
+ @Override |
+ public int hashCode() { |
+ int hash = 41; |
+ hash = (19 * hash) + getDescriptorForType().hashCode(); |
+ hash = hashFields(hash, getAllFields()); |
+ hash = (29 * hash) + getUnknownFields().hashCode(); |
+ return hash; |
+ } |
+ |
+ /** Get a hash code for given fields and values, using the given seed. */ |
+ @SuppressWarnings("unchecked") |
+ protected int hashFields(int hash, Map<FieldDescriptor, Object> map) { |
+ for (Map.Entry<FieldDescriptor, Object> entry : map.entrySet()) { |
+ FieldDescriptor field = entry.getKey(); |
+ Object value = entry.getValue(); |
+ hash = (37 * hash) + field.getNumber(); |
+ if (field.getType() != FieldDescriptor.Type.ENUM){ |
+ hash = (53 * hash) + value.hashCode(); |
+ } else if (field.isRepeated()) { |
+ List<? extends EnumLite> list = (List<? extends EnumLite>) value; |
+ hash = (53 * hash) + hashEnumList(list); |
+ } else { |
+ hash = (53 * hash) + hashEnum((EnumLite) value); |
+ } |
+ } |
+ return hash; |
+ } |
+ |
+ /** |
+ * Helper method for implementing {@link Message#hashCode()}. |
+ * @see Boolean#hashCode() |
+ */ |
+ protected static int hashLong(long n) { |
+ return (int) (n ^ (n >>> 32)); |
+ } |
+ |
+ /** |
+ * Helper method for implementing {@link Message#hashCode()}. |
+ * @see Boolean#hashCode() |
+ */ |
+ protected static int hashBoolean(boolean b) { |
+ return b ? 1231 : 1237; |
+ } |
+ |
+ /** |
+ * Helper method for implementing {@link Message#hashCode()}. |
+ * <p> |
+ * This is needed because {@link java.lang.Enum#hashCode()} is final, but we |
+ * need to use the field number as the hash code to ensure compatibility |
+ * between statically and dynamically generated enum objects. |
+ */ |
+ protected static int hashEnum(EnumLite e) { |
+ return e.getNumber(); |
+ } |
+ |
+ /** Helper method for implementing {@link Message#hashCode()}. */ |
+ protected static int hashEnumList(List<? extends EnumLite> list) { |
+ int hash = 1; |
+ for (EnumLite e : list) { |
+ hash = 31 * hash + hashEnum(e); |
+ } |
+ return hash; |
+ } |
+ |
+ // ================================================================= |
+ |
+ /** |
+ * A partial implementation of the {@link Message.Builder} interface which |
+ * implements as many methods of that interface as possible in terms of |
+ * other methods. |
+ */ |
+ @SuppressWarnings("unchecked") |
+ public static abstract class Builder<BuilderType extends Builder> |
+ extends AbstractMessageLite.Builder<BuilderType> |
+ implements Message.Builder { |
+ // The compiler produces an error if this is not declared explicitly. |
+ @Override |
+ public abstract BuilderType clone(); |
+ |
+ public BuilderType clear() { |
+ for (final Map.Entry<FieldDescriptor, Object> entry : |
+ getAllFields().entrySet()) { |
+ clearField(entry.getKey()); |
+ } |
+ return (BuilderType) this; |
+ } |
+ |
+ public BuilderType mergeFrom(final Message other) { |
+ if (other.getDescriptorForType() != getDescriptorForType()) { |
+ throw new IllegalArgumentException( |
+ "mergeFrom(Message) can only merge messages of the same type."); |
+ } |
+ |
+ // Note: We don't attempt to verify that other's fields have valid |
+ // types. Doing so would be a losing battle. We'd have to verify |
+ // all sub-messages as well, and we'd have to make copies of all of |
+ // them to insure that they don't change after verification (since |
+ // the Message interface itself cannot enforce immutability of |
+ // implementations). |
+ // TODO(kenton): Provide a function somewhere called makeDeepCopy() |
+ // which allows people to make secure deep copies of messages. |
+ |
+ for (final Map.Entry<FieldDescriptor, Object> entry : |
+ other.getAllFields().entrySet()) { |
+ final FieldDescriptor field = entry.getKey(); |
+ if (field.isRepeated()) { |
+ for (final Object element : (List)entry.getValue()) { |
+ addRepeatedField(field, element); |
+ } |
+ } else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { |
+ final Message existingValue = (Message)getField(field); |
+ if (existingValue == existingValue.getDefaultInstanceForType()) { |
+ setField(field, entry.getValue()); |
+ } else { |
+ setField(field, |
+ existingValue.newBuilderForType() |
+ .mergeFrom(existingValue) |
+ .mergeFrom((Message)entry.getValue()) |
+ .build()); |
+ } |
+ } else { |
+ setField(field, entry.getValue()); |
+ } |
+ } |
+ |
+ mergeUnknownFields(other.getUnknownFields()); |
+ |
+ return (BuilderType) this; |
+ } |
+ |
+ @Override |
+ public BuilderType mergeFrom(final CodedInputStream input) |
+ throws IOException { |
+ return mergeFrom(input, ExtensionRegistry.getEmptyRegistry()); |
+ } |
+ |
+ @Override |
+ public BuilderType mergeFrom( |
+ final CodedInputStream input, |
+ final ExtensionRegistryLite extensionRegistry) |
+ throws IOException { |
+ final UnknownFieldSet.Builder unknownFields = |
+ UnknownFieldSet.newBuilder(getUnknownFields()); |
+ while (true) { |
+ final int tag = input.readTag(); |
+ if (tag == 0) { |
+ break; |
+ } |
+ |
+ if (!mergeFieldFrom(input, unknownFields, extensionRegistry, |
+ this, tag)) { |
+ // end group tag |
+ break; |
+ } |
+ } |
+ setUnknownFields(unknownFields.build()); |
+ return (BuilderType) this; |
+ } |
+ |
+ /** |
+ * Like {@link #mergeFrom(CodedInputStream, UnknownFieldSet.Builder, |
+ * ExtensionRegistryLite, Message.Builder)}, but parses a single field. |
+ * 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( |
+ final CodedInputStream input, |
+ final UnknownFieldSet.Builder unknownFields, |
+ final ExtensionRegistryLite extensionRegistry, |
+ final Message.Builder builder, |
+ final int tag) throws IOException { |
+ final Descriptor type = builder.getDescriptorForType(); |
+ |
+ if (type.getOptions().getMessageSetWireFormat() && |
+ tag == WireFormat.MESSAGE_SET_ITEM_TAG) { |
+ mergeMessageSetExtensionFromCodedStream( |
+ input, unknownFields, extensionRegistry, builder); |
+ return true; |
+ } |
+ |
+ final int wireType = WireFormat.getTagWireType(tag); |
+ final int fieldNumber = WireFormat.getTagFieldNumber(tag); |
+ |
+ final 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 = |
+ ((ExtensionRegistry) extensionRegistry) |
+ .findExtensionByNumber(type, fieldNumber); |
+ if (extension == null) { |
+ field = null; |
+ } else { |
+ field = extension.descriptor; |
+ defaultInstance = extension.defaultInstance; |
+ if (defaultInstance == null && |
+ field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { |
+ throw new IllegalStateException( |
+ "Message-typed extension lacked default instance: " + |
+ field.getFullName()); |
+ } |
+ } |
+ } else { |
+ field = null; |
+ } |
+ } else { |
+ field = type.findFieldByNumber(fieldNumber); |
+ } |
+ |
+ 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(); |
+ 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; |
+ } |
+ builder.addRepeatedField(field, value); |
+ } |
+ } else { |
+ while (input.getBytesUntilLimit() > 0) { |
+ final Object value = |
+ FieldSet.readPrimitiveField(input, field.getLiteType()); |
+ builder.addRepeatedField(field, value); |
+ } |
+ } |
+ input.popLimit(limit); |
+ } else { |
+ final Object value; |
+ switch (field.getType()) { |
+ case GROUP: { |
+ final Message.Builder subBuilder; |
+ if (defaultInstance != null) { |
+ subBuilder = defaultInstance.newBuilderForType(); |
+ } else { |
+ subBuilder = builder.newBuilderForField(field); |
+ } |
+ if (!field.isRepeated()) { |
+ subBuilder.mergeFrom((Message) builder.getField(field)); |
+ } |
+ input.readGroup(field.getNumber(), subBuilder, extensionRegistry); |
+ value = subBuilder.build(); |
+ break; |
+ } |
+ case MESSAGE: { |
+ final Message.Builder subBuilder; |
+ if (defaultInstance != null) { |
+ subBuilder = defaultInstance.newBuilderForType(); |
+ } else { |
+ subBuilder = builder.newBuilderForField(field); |
+ } |
+ if (!field.isRepeated()) { |
+ subBuilder.mergeFrom((Message) builder.getField(field)); |
+ } |
+ input.readMessage(subBuilder, extensionRegistry); |
+ value = subBuilder.build(); |
+ break; |
+ } |
+ case ENUM: |
+ final int rawValue = input.readEnum(); |
+ 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 = FieldSet.readPrimitiveField(input, field.getLiteType()); |
+ break; |
+ } |
+ |
+ if (field.isRepeated()) { |
+ builder.addRepeatedField(field, value); |
+ } else { |
+ builder.setField(field, value); |
+ } |
+ } |
+ |
+ return true; |
+ } |
+ |
+ /** Called by {@code #mergeFieldFrom()} to parse a MessageSet extension. */ |
+ private static void mergeMessageSetExtensionFromCodedStream( |
+ final CodedInputStream input, |
+ final UnknownFieldSet.Builder unknownFields, |
+ final ExtensionRegistryLite extensionRegistry, |
+ final Message.Builder builder) throws IOException { |
+ final Descriptor type = builder.getDescriptorForType(); |
+ |
+ // 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" |
+ Message.Builder subBuilder = null; |
+ FieldDescriptor field = null; |
+ |
+ while (true) { |
+ final int tag = input.readTag(); |
+ if (tag == 0) { |
+ break; |
+ } |
+ |
+ if (tag == WireFormat.MESSAGE_SET_TYPE_ID_TAG) { |
+ typeId = input.readUInt32(); |
+ // Zero is not a valid type ID. |
+ if (typeId != 0) { |
+ final ExtensionRegistry.ExtensionInfo extension; |
+ |
+ // 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 = ((ExtensionRegistry) extensionRegistry) |
+ .findExtensionByNumber(type, typeId); |
+ } else { |
+ extension = null; |
+ } |
+ |
+ if (extension != null) { |
+ field = extension.descriptor; |
+ subBuilder = extension.defaultInstance.newBuilderForType(); |
+ final Message originalMessage = (Message)builder.getField(field); |
+ if (originalMessage != null) { |
+ subBuilder.mergeFrom(originalMessage); |
+ } |
+ if (rawBytes != null) { |
+ // We already encountered the message. Parse it now. |
+ subBuilder.mergeFrom( |
+ CodedInputStream.newInstance(rawBytes.newInput())); |
+ rawBytes = null; |
+ } |
+ } else { |
+ // Unknown extension number. If we already saw data, put it |
+ // in rawBytes. |
+ if (rawBytes != null) { |
+ unknownFields.mergeField(typeId, |
+ UnknownFieldSet.Field.newBuilder() |
+ .addLengthDelimited(rawBytes) |
+ .build()); |
+ rawBytes = null; |
+ } |
+ } |
+ } |
+ } else if (tag == WireFormat.MESSAGE_SET_MESSAGE_TAG) { |
+ if (typeId == 0) { |
+ // We haven't seen a type ID yet, so we have to store the raw bytes |
+ // for now. |
+ rawBytes = input.readBytes(); |
+ } else if (subBuilder == null) { |
+ // We don't know how to parse this. Ignore it. |
+ unknownFields.mergeField(typeId, |
+ UnknownFieldSet.Field.newBuilder() |
+ .addLengthDelimited(input.readBytes()) |
+ .build()); |
+ } else { |
+ // We already know the type, so we can parse directly from the input |
+ // with no copying. Hooray! |
+ input.readMessage(subBuilder, extensionRegistry); |
+ } |
+ } else { |
+ // Unknown tag. Skip it. |
+ if (!input.skipField(tag)) { |
+ break; // end of group |
+ } |
+ } |
+ } |
+ |
+ input.checkLastTagWas(WireFormat.MESSAGE_SET_ITEM_END_TAG); |
+ |
+ if (subBuilder != null) { |
+ builder.setField(field, subBuilder.build()); |
+ } |
+ } |
+ |
+ public BuilderType mergeUnknownFields(final UnknownFieldSet unknownFields) { |
+ setUnknownFields( |
+ UnknownFieldSet.newBuilder(getUnknownFields()) |
+ .mergeFrom(unknownFields) |
+ .build()); |
+ return (BuilderType) this; |
+ } |
+ |
+ /** |
+ * Construct an UninitializedMessageException reporting missing fields in |
+ * the given message. |
+ */ |
+ protected static UninitializedMessageException |
+ newUninitializedMessageException(Message message) { |
+ return new UninitializedMessageException(findMissingFields(message)); |
+ } |
+ |
+ /** |
+ * Populates {@code this.missingFields} with the full "path" of each |
+ * missing required field in the given message. |
+ */ |
+ private static List<String> findMissingFields(final Message message) { |
+ final List<String> results = new ArrayList<String>(); |
+ findMissingFields(message, "", results); |
+ return results; |
+ } |
+ |
+ /** Recursive helper implementing {@link #findMissingFields(Message)}. */ |
+ private static void findMissingFields(final Message message, |
+ final String prefix, |
+ final List<String> results) { |
+ for (final FieldDescriptor field : |
+ message.getDescriptorForType().getFields()) { |
+ if (field.isRequired() && !message.hasField(field)) { |
+ results.add(prefix + field.getName()); |
+ } |
+ } |
+ |
+ for (final Map.Entry<FieldDescriptor, Object> entry : |
+ message.getAllFields().entrySet()) { |
+ final FieldDescriptor field = entry.getKey(); |
+ final Object value = entry.getValue(); |
+ |
+ if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { |
+ if (field.isRepeated()) { |
+ int i = 0; |
+ for (final Object element : (List) value) { |
+ findMissingFields((Message) element, |
+ subMessagePrefix(prefix, field, i++), |
+ results); |
+ } |
+ } else { |
+ if (message.hasField(field)) { |
+ findMissingFields((Message) value, |
+ subMessagePrefix(prefix, field, -1), |
+ results); |
+ } |
+ } |
+ } |
+ } |
+ } |
+ |
+ private static String subMessagePrefix(final String prefix, |
+ final 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(); |
+ } |
+ |
+ // =============================================================== |
+ // The following definitions seem to be required in order to make javac |
+ // not produce weird errors like: |
+ // |
+ // java/com/google/protobuf/DynamicMessage.java:203: types |
+ // com.google.protobuf.AbstractMessage.Builder< |
+ // com.google.protobuf.DynamicMessage.Builder> and |
+ // com.google.protobuf.AbstractMessage.Builder< |
+ // com.google.protobuf.DynamicMessage.Builder> are incompatible; both |
+ // define mergeFrom(com.google.protobuf.ByteString), but with unrelated |
+ // return types. |
+ // |
+ // Strangely, these lines are only needed if javac is invoked separately |
+ // on AbstractMessage.java and AbstractMessageLite.java. If javac is |
+ // invoked on both simultaneously, it works. (Or maybe the important |
+ // point is whether or not DynamicMessage.java is compiled together with |
+ // AbstractMessageLite.java -- not sure.) I suspect this is a compiler |
+ // bug. |
+ |
+ @Override |
+ public BuilderType mergeFrom(final ByteString data) |
+ throws InvalidProtocolBufferException { |
+ return super.mergeFrom(data); |
+ } |
+ |
+ @Override |
+ public BuilderType mergeFrom( |
+ final ByteString data, |
+ final ExtensionRegistryLite extensionRegistry) |
+ throws InvalidProtocolBufferException { |
+ return super.mergeFrom(data, extensionRegistry); |
+ } |
+ |
+ @Override |
+ public BuilderType mergeFrom(final byte[] data) |
+ throws InvalidProtocolBufferException { |
+ return super.mergeFrom(data); |
+ } |
+ |
+ @Override |
+ public BuilderType mergeFrom( |
+ final byte[] data, final int off, final int len) |
+ throws InvalidProtocolBufferException { |
+ return super.mergeFrom(data, off, len); |
+ } |
+ |
+ @Override |
+ public BuilderType mergeFrom( |
+ final byte[] data, |
+ final ExtensionRegistryLite extensionRegistry) |
+ throws InvalidProtocolBufferException { |
+ return super.mergeFrom(data, extensionRegistry); |
+ } |
+ |
+ @Override |
+ public BuilderType mergeFrom( |
+ final byte[] data, final int off, final int len, |
+ final ExtensionRegistryLite extensionRegistry) |
+ throws InvalidProtocolBufferException { |
+ return super.mergeFrom(data, off, len, extensionRegistry); |
+ } |
+ |
+ @Override |
+ public BuilderType mergeFrom(final InputStream input) |
+ throws IOException { |
+ return super.mergeFrom(input); |
+ } |
+ |
+ @Override |
+ public BuilderType mergeFrom( |
+ final InputStream input, |
+ final ExtensionRegistryLite extensionRegistry) |
+ throws IOException { |
+ return super.mergeFrom(input, extensionRegistry); |
+ } |
+ |
+ @Override |
+ public boolean mergeDelimitedFrom(final InputStream input) |
+ throws IOException { |
+ return super.mergeDelimitedFrom(input); |
+ } |
+ |
+ @Override |
+ public boolean mergeDelimitedFrom( |
+ final InputStream input, |
+ final ExtensionRegistryLite extensionRegistry) |
+ throws IOException { |
+ return super.mergeDelimitedFrom(input, extensionRegistry); |
+ } |
+ |
+ } |
+} |