Index: third_party/protobuf/java/src/main/java/com/google/protobuf/AbstractMessage.java |
=================================================================== |
--- third_party/protobuf/java/src/main/java/com/google/protobuf/AbstractMessage.java (revision 216642) |
+++ third_party/protobuf/java/src/main/java/com/google/protobuf/AbstractMessage.java (working copy) |
@@ -32,6 +32,7 @@ |
import com.google.protobuf.Descriptors.Descriptor; |
import com.google.protobuf.Descriptors.FieldDescriptor; |
+import com.google.protobuf.GeneratedMessage.ExtendableBuilder; |
import com.google.protobuf.Internal.EnumLite; |
import java.io.IOException; |
@@ -81,6 +82,25 @@ |
return true; |
} |
+ public List<String> findInitializationErrors() { |
+ return Builder.findMissingFields(this); |
+ } |
+ |
+ public String getInitializationErrorString() { |
+ return delimitWithCommas(findInitializationErrors()); |
+ } |
+ |
+ private 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(); |
+ } |
+ |
@Override |
public final String toString() { |
return TextFormat.printToString(this); |
@@ -209,6 +229,15 @@ |
} |
/** |
+ * Package private helper method for AbstractParser to create |
+ * UninitializedMessageException with missing field information. |
+ */ |
+ @Override |
+ UninitializedMessageException newUninitializedMessageException() { |
+ return Builder.newUninitializedMessageException(this); |
+ } |
+ |
+ /** |
* Helper method for implementing {@link Message#hashCode()}. |
* <p> |
* This is needed because {@link java.lang.Enum#hashCode()} is final, but we |
@@ -251,6 +280,14 @@ |
return (BuilderType) this; |
} |
+ public List<String> findInitializationErrors() { |
+ return findMissingFields(this); |
+ } |
+ |
+ public String getInitializationErrorString() { |
+ return delimitWithCommas(findInitializationErrors()); |
+ } |
+ |
public BuilderType mergeFrom(final Message other) { |
if (other.getDescriptorForType() != getDescriptorForType()) { |
throw new IllegalArgumentException( |
@@ -314,7 +351,7 @@ |
} |
if (!mergeFieldFrom(input, unknownFields, extensionRegistry, |
- this, tag)) { |
+ getDescriptorForType(), this, null, tag)) { |
// end group tag |
break; |
} |
@@ -323,25 +360,93 @@ |
return (BuilderType) this; |
} |
+ /** helper method to handle {@code builder} and {@code extensions}. */ |
+ private static void addRepeatedField( |
+ Message.Builder builder, |
+ FieldSet<FieldDescriptor> extensions, |
+ FieldDescriptor field, |
+ Object value) { |
+ if (builder != null) { |
+ builder.addRepeatedField(field, value); |
+ } else { |
+ extensions.addRepeatedField(field, value); |
+ } |
+ } |
+ |
+ /** helper method to handle {@code builder} and {@code extensions}. */ |
+ private static void setField( |
+ Message.Builder builder, |
+ FieldSet<FieldDescriptor> extensions, |
+ FieldDescriptor field, |
+ Object value) { |
+ if (builder != null) { |
+ builder.setField(field, value); |
+ } else { |
+ extensions.setField(field, value); |
+ } |
+ } |
+ |
+ /** helper method to handle {@code builder} and {@code extensions}. */ |
+ private static boolean hasOriginalMessage( |
+ Message.Builder builder, |
+ FieldSet<FieldDescriptor> extensions, |
+ FieldDescriptor field) { |
+ if (builder != null) { |
+ return builder.hasField(field); |
+ } else { |
+ return extensions.hasField(field); |
+ } |
+ } |
+ |
+ /** helper method to handle {@code builder} and {@code extensions}. */ |
+ private static Message getOriginalMessage( |
+ Message.Builder builder, |
+ FieldSet<FieldDescriptor> extensions, |
+ FieldDescriptor field) { |
+ if (builder != null) { |
+ return (Message) builder.getField(field); |
+ } else { |
+ return (Message) extensions.getField(field); |
+ } |
+ } |
+ |
+ /** helper method to handle {@code builder} and {@code extensions}. */ |
+ private static void mergeOriginalMessage( |
+ Message.Builder builder, |
+ FieldSet<FieldDescriptor> extensions, |
+ FieldDescriptor field, |
+ Message.Builder subBuilder) { |
+ Message originalMessage = getOriginalMessage(builder, extensions, field); |
+ if (originalMessage != null) { |
+ subBuilder.mergeFrom(originalMessage); |
+ } |
+ } |
+ |
/** |
- * Like {@link #mergeFrom(CodedInputStream, UnknownFieldSet.Builder, |
- * ExtensionRegistryLite, Message.Builder)}, but parses a single field. |
+ * Like {@link #mergeFrom(CodedInputStream, ExtensionRegistryLite)}, but |
+ * parses a single field. |
+ * |
+ * When {@code builder} is not null, the method will parse and merge the |
+ * field into {@code builder}. Otherwise, it will try to parse the field |
+ * into {@code extensions}, when it's called by the parsing constructor in |
+ * generated classes. |
+ * |
* 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(); |
- |
+ CodedInputStream input, |
+ UnknownFieldSet.Builder unknownFields, |
+ ExtensionRegistryLite extensionRegistry, |
+ Descriptor type, |
+ Message.Builder builder, |
+ FieldSet<FieldDescriptor> extensions, |
+ int tag) throws IOException { |
if (type.getOptions().getMessageSetWireFormat() && |
tag == WireFormat.MESSAGE_SET_ITEM_TAG) { |
mergeMessageSetExtensionFromCodedStream( |
- input, unknownFields, extensionRegistry, builder); |
+ input, unknownFields, extensionRegistry, type, builder, extensions); |
return true; |
} |
@@ -376,8 +481,10 @@ |
} else { |
field = null; |
} |
+ } else if (builder != null) { |
+ field = type.findFieldByNumber(fieldNumber); |
} else { |
- field = type.findFieldByNumber(fieldNumber); |
+ field = null; |
} |
boolean unknown = false; |
@@ -413,13 +520,13 @@ |
// enum, drop it (don't even add it to unknownFields). |
return true; |
} |
- builder.addRepeatedField(field, value); |
+ addRepeatedField(builder, extensions, field, value); |
} |
} else { |
while (input.getBytesUntilLimit() > 0) { |
final Object value = |
FieldSet.readPrimitiveField(input, field.getLiteType()); |
- builder.addRepeatedField(field, value); |
+ addRepeatedField(builder, extensions, field, value); |
} |
} |
input.popLimit(limit); |
@@ -434,10 +541,10 @@ |
subBuilder = builder.newBuilderForField(field); |
} |
if (!field.isRepeated()) { |
- subBuilder.mergeFrom((Message) builder.getField(field)); |
+ mergeOriginalMessage(builder, extensions, field, subBuilder); |
} |
input.readGroup(field.getNumber(), subBuilder, extensionRegistry); |
- value = subBuilder.build(); |
+ value = subBuilder.buildPartial(); |
break; |
} |
case MESSAGE: { |
@@ -448,10 +555,10 @@ |
subBuilder = builder.newBuilderForField(field); |
} |
if (!field.isRepeated()) { |
- subBuilder.mergeFrom((Message) builder.getField(field)); |
+ mergeOriginalMessage(builder, extensions, field, subBuilder); |
} |
input.readMessage(subBuilder, extensionRegistry); |
- value = subBuilder.build(); |
+ value = subBuilder.buildPartial(); |
break; |
} |
case ENUM: |
@@ -470,22 +577,28 @@ |
} |
if (field.isRepeated()) { |
- builder.addRepeatedField(field, value); |
+ addRepeatedField(builder, extensions, field, value); |
} else { |
- builder.setField(field, value); |
+ setField(builder, extensions, field, value); |
} |
} |
return true; |
} |
- /** Called by {@code #mergeFieldFrom()} to parse a MessageSet extension. */ |
+ /** |
+ * Called by {@code #mergeFieldFrom()} to parse a MessageSet extension. |
+ * If {@code builder} is not null, this method will merge MessageSet into |
+ * the builder. Otherwise, it will merge the MessageSet into {@code |
+ * extensions}. |
+ */ |
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(); |
+ CodedInputStream input, |
+ UnknownFieldSet.Builder unknownFields, |
+ ExtensionRegistryLite extensionRegistry, |
+ Descriptor type, |
+ Message.Builder builder, |
+ FieldSet<FieldDescriptor> extensions) throws IOException { |
// The wire format for MessageSet is: |
// message MessageSet { |
@@ -504,10 +617,11 @@ |
// 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; |
+ 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) { |
@@ -516,78 +630,124 @@ |
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 |
+ // 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 |
+ // 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) { |
+ 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, builder, extensions); |
+ rawBytes = null; |
+ continue; |
} |
} |
- } 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. |
+ // 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 |
+ break; // End of group |
} |
} |
} |
- |
input.checkLastTagWas(WireFormat.MESSAGE_SET_ITEM_END_TAG); |
- if (subBuilder != null) { |
- builder.setField(field, subBuilder.build()); |
+ // 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, builder, extensions); |
+ } 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 eagerlyMergeMessageSetExtension( |
+ CodedInputStream input, |
+ ExtensionRegistry.ExtensionInfo extension, |
+ ExtensionRegistryLite extensionRegistry, |
+ Message.Builder builder, |
+ FieldSet<FieldDescriptor> extensions) throws IOException { |
+ |
+ FieldDescriptor field = extension.descriptor; |
+ Message value = null; |
+ if (hasOriginalMessage(builder, extensions, field)) { |
+ Message originalMessage = |
+ getOriginalMessage(builder, extensions, field); |
+ Message.Builder subBuilder = originalMessage.toBuilder(); |
+ input.readMessage(subBuilder, extensionRegistry); |
+ value = subBuilder.buildPartial(); |
+ } else { |
+ value = input.readMessage(extension.defaultInstance.getParserForType(), |
+ extensionRegistry); |
+ } |
+ |
+ if (builder != null) { |
+ builder.setField(field, value); |
+ } else { |
+ extensions.setField(field, value); |
+ } |
+ } |
+ |
+ private static void mergeMessageSetExtensionFromBytes( |
+ ByteString rawBytes, |
+ ExtensionRegistry.ExtensionInfo extension, |
+ ExtensionRegistryLite extensionRegistry, |
+ Message.Builder builder, |
+ FieldSet<FieldDescriptor> extensions) throws IOException { |
+ |
+ FieldDescriptor field = extension.descriptor; |
+ boolean hasOriginalValue = hasOriginalMessage(builder, extensions, field); |
+ |
+ if (hasOriginalValue || ExtensionRegistryLite.isEagerlyParseMessageSets()) { |
+ // If the field already exists, we just parse the field. |
+ Message value = null; |
+ if (hasOriginalValue) { |
+ Message originalMessage = |
+ getOriginalMessage(builder, extensions, field); |
+ Message.Builder subBuilder= originalMessage.toBuilder(); |
+ subBuilder.mergeFrom(rawBytes, extensionRegistry); |
+ value = subBuilder.buildPartial(); |
+ } else { |
+ value = extension.defaultInstance.getParserForType() |
+ .parsePartialFrom(rawBytes, extensionRegistry); |
+ } |
+ setField(builder, extensions, field, value); |
+ } else { |
+ // Use LazyField to load MessageSet lazily. |
+ LazyField lazyField = new LazyField( |
+ extension.defaultInstance, extensionRegistry, rawBytes); |
+ if (builder != null) { |
+ // TODO(xiangl): it looks like this method can only be invoked by |
+ // ExtendableBuilder, but I'm not sure. So I double check the type of |
+ // builder here. It may be useless and need more investigation. |
+ if (builder instanceof ExtendableBuilder) { |
+ builder.setField(field, lazyField); |
+ } else { |
+ builder.setField(field, lazyField.getValue()); |
+ } |
+ } else { |
+ extensions.setField(field, lazyField); |
+ } |
+ } |
+ } |
+ |
public BuilderType mergeUnknownFields(final UnknownFieldSet unknownFields) { |
setUnknownFields( |
UnknownFieldSet.newBuilder(getUnknownFields()) |
@@ -596,6 +756,11 @@ |
return (BuilderType) this; |
} |
+ public Message.Builder getFieldBuilder(final FieldDescriptor field) { |
+ throw new UnsupportedOperationException( |
+ "getFieldBuilder() called on an unsupported message type."); |
+ } |
+ |
/** |
* Construct an UninitializedMessageException reporting missing fields in |
* the given message. |
@@ -609,14 +774,15 @@ |
* 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) { |
+ private static List<String> findMissingFields( |
+ final MessageOrBuilder 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, |
+ private static void findMissingFields(final MessageOrBuilder message, |
final String prefix, |
final List<String> results) { |
for (final FieldDescriptor field : |
@@ -635,13 +801,13 @@ |
if (field.isRepeated()) { |
int i = 0; |
for (final Object element : (List) value) { |
- findMissingFields((Message) element, |
+ findMissingFields((MessageOrBuilder) element, |
subMessagePrefix(prefix, field, i++), |
results); |
} |
} else { |
if (message.hasField(field)) { |
- findMissingFields((Message) value, |
+ findMissingFields((MessageOrBuilder) value, |
subMessagePrefix(prefix, field, -1), |
results); |
} |