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