From 46e8ff63cb67a6520711da5317aaaef04d0414d0 Mon Sep 17 00:00:00 2001 From: Jisi Liu Date: Mon, 5 Oct 2015 11:59:43 -0700 Subject: Down-integrate from google internal. --- .../com/google/protobuf/GeneratedMessageLite.java | 352 +++++++++++---------- .../main/java/com/google/protobuf/TextFormat.java | 15 + .../com/google/protobuf/UnknownFieldSetLite.java | 296 ++++++++++------- java/src/main/java/com/google/protobuf/Utf8.java | 10 +- .../java/com/google/protobuf/DescriptorsTest.java | 4 +- .../java/com/google/protobuf/TextFormatTest.java | 16 + .../google/protobuf/UnknownFieldSetLiteTest.java | 180 +++++++---- .../com/google/protobuf/test_bad_identifiers.proto | 10 +- java/util/pom.xml | 6 +- 9 files changed, 527 insertions(+), 362 deletions(-) (limited to 'java') diff --git a/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java b/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java index a535b718..4316efee 100644 --- a/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java +++ b/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java @@ -62,9 +62,8 @@ public abstract class GeneratedMessageLite< private static final long serialVersionUID = 1L; - /** For use by generated code only. */ - protected UnknownFieldSetLite unknownFields = - UnknownFieldSetLite.getDefaultInstance(); + /** For use by generated code only. Lazily initialized to reduce allocations. */ + protected UnknownFieldSetLite unknownFields = null; /** For use by generated code only. */ protected int memoizedSerializedSize = -1; @@ -84,19 +83,56 @@ public abstract class GeneratedMessageLite< return (BuilderType) dynamicMethod(MethodToInvoke.NEW_BUILDER); } + // The general strategy for unknown fields is to use an UnknownFieldSetLite that is treated as + // mutable during the parsing constructor and immutable after. This allows us to avoid + // any unnecessary intermediary allocations while reducing the generated code size. + + /** + * Lazily initializes unknown fields. + */ + private final void ensureUnknownFieldsInitialized() { + if (unknownFields == null) { + unknownFields = UnknownFieldSetLite.newInstance(); + } + } + /** - * Called by subclasses to parse an unknown field. For use by generated code - * only. + * Called by subclasses to parse an unknown field. For use by generated code only. + * * @return {@code true} unless the tag is an end-group tag. */ - protected static boolean parseUnknownField( - CodedInputStream input, - UnknownFieldSetLite.Builder unknownFields, - ExtensionRegistryLite extensionRegistry, - int tag) throws IOException { + protected boolean parseUnknownField(int tag, CodedInputStream input) throws IOException { + ensureUnknownFieldsInitialized(); return unknownFields.mergeFieldFrom(tag, input); } + /** + * Called by subclasses to parse an unknown field. For use by generated code only. + */ + protected void mergeVarintField(int tag, int value) { + ensureUnknownFieldsInitialized(); + unknownFields.mergeVarintField(tag, value); + } + + /** + * Called by subclasses to parse an unknown field. For use by generated code only. + */ + protected void mergeLengthDelimitedField(int fieldNumber, ByteString value) { + ensureUnknownFieldsInitialized(); + unknownFields.mergeLengthDelimitedField(fieldNumber, value); + } + + /** + * Called by subclasses to complete parsing. For use by generated code only. + */ + protected void doneParsing() { + if (unknownFields == null) { + unknownFields = UnknownFieldSetLite.getDefaultInstance(); + } else { + unknownFields.makeImmutable(); + } + } + public final boolean isInitialized() { return dynamicMethod(MethodToInvoke.IS_INITIALIZED, Boolean.TRUE) != null; } @@ -171,7 +207,7 @@ public abstract class GeneratedMessageLite< *

For use by generated code only. */ protected final void mergeUnknownFields(UnknownFieldSetLite unknownFields) { - this.unknownFields = UnknownFieldSetLite.concat(this.unknownFields, unknownFields); + this.unknownFields = UnknownFieldSetLite.mutableCopyOf(this.unknownFields, unknownFields); } @SuppressWarnings("unchecked") @@ -225,7 +261,13 @@ public abstract class GeneratedMessageLite< //@Override (Java 1.6 override semantics, but we must support 1.5) public MessageType buildPartial() { + if (isBuilt) { + return instance; + } + instance.dynamicMethod(MethodToInvoke.MAKE_IMMUTABLE); + instance.unknownFields.makeImmutable(); + isBuilt = true; return instance; } @@ -249,18 +291,6 @@ public abstract class GeneratedMessageLite< public MessageType getDefaultInstanceForType() { return defaultInstance; } - - /** - * Called by subclasses to parse an unknown field. - * @return {@code true} unless the tag is an end-group tag. - */ - protected boolean parseUnknownField( - CodedInputStream input, - UnknownFieldSetLite.Builder unknownFields, - ExtensionRegistryLite extensionRegistry, - int tag) throws IOException { - return unknownFields.mergeFieldFrom(tag, input); - } public BuilderType mergeFrom( com.google.protobuf.CodedInputStream input, @@ -334,6 +364,130 @@ public abstract class GeneratedMessageLite< extensions.mergeFrom(((ExtendableMessage) other).extensions); } + /** + * Parse an unknown field or an extension. For use by generated code only. + * + *

For use by generated code only. + * + * @return {@code true} unless the tag is an end-group tag. + */ + protected boolean parseUnknownField( + MessageType defaultInstance, + CodedInputStream input, + ExtensionRegistryLite extensionRegistry, + int tag) throws IOException { + int wireType = WireFormat.getTagWireType(tag); + int fieldNumber = WireFormat.getTagFieldNumber(tag); + + // TODO(dweis): How much bytecode would be saved by not requiring the generated code to + // provide the default instance? + GeneratedExtension extension = extensionRegistry.findLiteExtensionByNumber( + defaultInstance, fieldNumber); + + boolean unknown = false; + boolean packed = false; + if (extension == null) { + unknown = true; // Unknown field. + } else if (wireType == FieldSet.getWireFormatForFieldType( + extension.descriptor.getLiteType(), + false /* isPacked */)) { + packed = false; // Normal, unpacked value. + } else if (extension.descriptor.isRepeated && + extension.descriptor.type.isPackable() && + wireType == FieldSet.getWireFormatForFieldType( + extension.descriptor.getLiteType(), + true /* isPacked */)) { + packed = true; // Packed value. + } else { + unknown = true; // Wrong wire type. + } + + if (unknown) { // Unknown field or wrong wire type. Skip. + return parseUnknownField(tag, input); + } + + if (packed) { + int length = input.readRawVarint32(); + int limit = input.pushLimit(length); + if (extension.descriptor.getLiteType() == WireFormat.FieldType.ENUM) { + while (input.getBytesUntilLimit() > 0) { + int rawValue = input.readEnum(); + Object value = + extension.descriptor.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; + } + extensions.addRepeatedField(extension.descriptor, + extension.singularToFieldSetType(value)); + } + } else { + while (input.getBytesUntilLimit() > 0) { + Object value = + FieldSet.readPrimitiveField(input, + extension.descriptor.getLiteType(), + /*checkUtf8=*/ false); + extensions.addRepeatedField(extension.descriptor, value); + } + } + input.popLimit(limit); + } else { + Object value; + switch (extension.descriptor.getLiteJavaType()) { + case MESSAGE: { + MessageLite.Builder subBuilder = null; + if (!extension.descriptor.isRepeated()) { + MessageLite existingValue = + (MessageLite) extensions.getField(extension.descriptor); + if (existingValue != null) { + subBuilder = existingValue.toBuilder(); + } + } + if (subBuilder == null) { + subBuilder = extension.getMessageDefaultInstance() + .newBuilderForType(); + } + if (extension.descriptor.getLiteType() == + WireFormat.FieldType.GROUP) { + input.readGroup(extension.getNumber(), + subBuilder, extensionRegistry); + } else { + input.readMessage(subBuilder, extensionRegistry); + } + value = subBuilder.build(); + break; + } + case ENUM: + int rawValue = input.readEnum(); + value = extension.descriptor.getEnumType() + .findValueByNumber(rawValue); + // If the number isn't recognized as a valid value for this enum, + // write it to unknown fields object. + if (value == null) { + mergeVarintField(fieldNumber, rawValue); + return true; + } + break; + default: + value = FieldSet.readPrimitiveField(input, + extension.descriptor.getLiteType(), + /*checkUtf8=*/ false); + break; + } + + if (extension.descriptor.isRepeated()) { + extensions.addRepeatedField(extension.descriptor, + extension.singularToFieldSetType(value)); + } else { + extensions.setField(extension.descriptor, + extension.singularToFieldSetType(value)); + } + } + + return true; + } + private void verifyExtensionContainingType( final GeneratedExtension extension) { if (extension.getContainingTypeDefaultInstance() != @@ -404,11 +558,10 @@ public abstract class GeneratedMessageLite< } - /** - * Used by parsing constructors in generated classes. - */ - protected static void makeExtensionsImmutable( - FieldSet extensions) { + @Override + protected final void doneParsing() { + super.doneParsing(); + extensions.makeImmutable(); } @@ -619,131 +772,6 @@ public abstract class GeneratedMessageLite< } } - //----------------------------------------------------------------- - - /** - * Parse an unknown field or an extension. For use by generated code only. - * @return {@code true} unless the tag is an end-group tag. - */ - protected static - boolean parseUnknownField( - FieldSet extensions, - MessageType defaultInstance, - CodedInputStream input, - UnknownFieldSetLite.Builder unknownFields, - ExtensionRegistryLite extensionRegistry, - int tag) throws IOException { - int wireType = WireFormat.getTagWireType(tag); - int fieldNumber = WireFormat.getTagFieldNumber(tag); - - GeneratedExtension extension = - extensionRegistry.findLiteExtensionByNumber( - defaultInstance, fieldNumber); - - boolean unknown = false; - boolean packed = false; - if (extension == null) { - unknown = true; // Unknown field. - } else if (wireType == FieldSet.getWireFormatForFieldType( - extension.descriptor.getLiteType(), - false /* isPacked */)) { - packed = false; // Normal, unpacked value. - } else if (extension.descriptor.isRepeated && - extension.descriptor.type.isPackable() && - wireType == FieldSet.getWireFormatForFieldType( - extension.descriptor.getLiteType(), - true /* isPacked */)) { - packed = true; // Packed value. - } else { - unknown = true; // Wrong wire type. - } - - if (unknown) { // Unknown field or wrong wire type. Skip. - return unknownFields.mergeFieldFrom(tag, input); - } - - if (packed) { - int length = input.readRawVarint32(); - int limit = input.pushLimit(length); - if (extension.descriptor.getLiteType() == WireFormat.FieldType.ENUM) { - while (input.getBytesUntilLimit() > 0) { - int rawValue = input.readEnum(); - Object value = - extension.descriptor.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; - } - extensions.addRepeatedField(extension.descriptor, - extension.singularToFieldSetType(value)); - } - } else { - while (input.getBytesUntilLimit() > 0) { - Object value = - FieldSet.readPrimitiveField(input, - extension.descriptor.getLiteType(), - /*checkUtf8=*/ false); - extensions.addRepeatedField(extension.descriptor, value); - } - } - input.popLimit(limit); - } else { - Object value; - switch (extension.descriptor.getLiteJavaType()) { - case MESSAGE: { - MessageLite.Builder subBuilder = null; - if (!extension.descriptor.isRepeated()) { - MessageLite existingValue = - (MessageLite) extensions.getField(extension.descriptor); - if (existingValue != null) { - subBuilder = existingValue.toBuilder(); - } - } - if (subBuilder == null) { - subBuilder = extension.getMessageDefaultInstance() - .newBuilderForType(); - } - if (extension.descriptor.getLiteType() == - WireFormat.FieldType.GROUP) { - input.readGroup(extension.getNumber(), - subBuilder, extensionRegistry); - } else { - input.readMessage(subBuilder, extensionRegistry); - } - value = subBuilder.build(); - break; - } - case ENUM: - int rawValue = input.readEnum(); - value = extension.descriptor.getEnumType() - .findValueByNumber(rawValue); - // If the number isn't recognized as a valid value for this enum, - // write it to unknown fields object. - if (value == null) { - unknownFields.mergeVarintField(fieldNumber, rawValue); - return true; - } - break; - default: - value = FieldSet.readPrimitiveField(input, - extension.descriptor.getLiteType(), - /*checkUtf8=*/ false); - break; - } - - if (extension.descriptor.isRepeated()) { - extensions.addRepeatedField(extension.descriptor, - extension.singularToFieldSetType(value)); - } else { - extensions.setField(extension.descriptor, - extension.singularToFieldSetType(value)); - } - } - - return true; - } - // ----------------------------------------------------------------- /** For use by generated code only. */ @@ -893,7 +921,7 @@ public abstract class GeneratedMessageLite< extends ExtensionLite { /** - * Create a new isntance with the given parameters. + * Create a new instance with the given parameters. * * The last parameter {@code singularType} is only needed for enum types. * We store integer values for enum types in a {@link ExtendableMessage} @@ -905,7 +933,7 @@ public abstract class GeneratedMessageLite< final Type defaultValue, final MessageLite messageDefaultInstance, final ExtensionDescriptor descriptor, - Class singularType) { + final Class singularType) { // Defensive checks to verify the correct initialization order of // GeneratedExtensions and their related GeneratedMessages. if (containingTypeDefaultInstance == null) { @@ -921,24 +949,12 @@ public abstract class GeneratedMessageLite< this.defaultValue = defaultValue; this.messageDefaultInstance = messageDefaultInstance; this.descriptor = descriptor; - - // Use Java reflection to invoke the static method {@code valueOf} of - // enum types in order to convert integers to concrete enum objects. - this.singularType = singularType; - if (Internal.EnumLite.class.isAssignableFrom(singularType)) { - this.enumValueOf = getMethodOrDie( - singularType, "valueOf", int.class); - } else { - this.enumValueOf = null; - } } final ContainingType containingTypeDefaultInstance; final Type defaultValue; final MessageLite messageDefaultInstance; final ExtensionDescriptor descriptor; - final Class singularType; - final Method enumValueOf; /** * Default instance of the type being extended, used to identify that type. @@ -980,7 +996,7 @@ public abstract class GeneratedMessageLite< Object singularFromFieldSetType(final Object value) { if (descriptor.getLiteJavaType() == WireFormat.JavaType.ENUM) { - return invokeOrDie(enumValueOf, null, (Integer) value); + return descriptor.enumTypeMap.findValueByNumber((Integer) value); } else { return value; } diff --git a/java/src/main/java/com/google/protobuf/TextFormat.java b/java/src/main/java/com/google/protobuf/TextFormat.java index b4f4ce78..44d036c1 100644 --- a/java/src/main/java/com/google/protobuf/TextFormat.java +++ b/java/src/main/java/com/google/protobuf/TextFormat.java @@ -118,6 +118,21 @@ public final class TextFormat { } } + /** + * Generates a human readable form of the field, useful for debugging + * and other purposes, with no newline characters. + */ + public static String shortDebugString(final FieldDescriptor field, + final Object value) { + try { + final StringBuilder sb = new StringBuilder(); + SINGLE_LINE_PRINTER.printField(field, value, new TextGenerator(sb)); + return sb.toString().trim(); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + /** * Generates a human readable form of the unknown fields, useful for debugging * and other purposes, with no newline characters. diff --git a/java/src/main/java/com/google/protobuf/UnknownFieldSetLite.java b/java/src/main/java/com/google/protobuf/UnknownFieldSetLite.java index 45d5fc35..435ad4d4 100644 --- a/java/src/main/java/com/google/protobuf/UnknownFieldSetLite.java +++ b/java/src/main/java/com/google/protobuf/UnknownFieldSetLite.java @@ -45,12 +45,13 @@ import java.util.Arrays; * @author dweis@google.com (Daniel Weis) */ public final class UnknownFieldSetLite { - - private static final int[] EMPTY_INT_ARRAY = new int[0]; - private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0]; + + // Arbitrarily chosen. + // TODO(dweis): Tune this number? + private static final int MIN_CAPACITY = 8; private static final UnknownFieldSetLite DEFAULT_INSTANCE = - new UnknownFieldSetLite(0, EMPTY_INT_ARRAY, EMPTY_OBJECT_ARRAY); + new UnknownFieldSetLite(0, new int[0], new Object[0], false /* isMutable */); /** * Get an empty {@code UnknownFieldSetLite}. @@ -62,25 +63,32 @@ public final class UnknownFieldSetLite { } /** - * Create a new {@link Builder}. + * Returns an empty {@code UnknownFieldSetLite.Builder}. * *

For use by generated code only. */ public static Builder newBuilder() { return new Builder(); } + + /** + * Returns a new mutable instance. + */ + static UnknownFieldSetLite newInstance() { + return new UnknownFieldSetLite(); + } /** - * Returns an {@code UnknownFieldSetLite} that is the composite of {@code first} and + * Returns a mutable {@code UnknownFieldSetLite} that is the composite of {@code first} and * {@code second}. */ - static UnknownFieldSetLite concat(UnknownFieldSetLite first, UnknownFieldSetLite second) { + static UnknownFieldSetLite mutableCopyOf(UnknownFieldSetLite first, UnknownFieldSetLite second) { int count = first.count + second.count; int[] tags = Arrays.copyOf(first.tags, count); System.arraycopy(second.tags, 0, tags, first.count, second.count); Object[] objects = Arrays.copyOf(first.objects, count); System.arraycopy(second.objects, 0, objects, first.count, second.count); - return new UnknownFieldSetLite(count, tags, objects); + return new UnknownFieldSetLite(count, tags, objects, true /* isMutable */); } /** @@ -102,14 +110,45 @@ public final class UnknownFieldSetLite { * The lazily computed serialized size of the set. */ private int memoizedSerializedSize = -1; + + /** + * Indicates that this object is mutable. + */ + private boolean isMutable; + /** + * Constructs a mutable {@code UnknownFieldSetLite}. + */ + private UnknownFieldSetLite() { + this(0, new int[MIN_CAPACITY], new Object[MIN_CAPACITY], true /* isMutable */); + } + /** * Constructs the {@code UnknownFieldSetLite}. */ - private UnknownFieldSetLite(int count, int[] tags, Object[] objects) { + private UnknownFieldSetLite(int count, int[] tags, Object[] objects, boolean isMutable) { this.count = count; this.tags = tags; this.objects = objects; + this.isMutable = isMutable; + } + + /** + * Marks this object as immutable. + * + *

Future calls to methods that attempt to modify this object will throw. + */ + public void makeImmutable() { + this.isMutable = false; + } + + /** + * Throws an {@link UnsupportedOperationException} if immutable. + */ + void checkMutable() { + if (!isMutable) { + throw new UnsupportedOperationException(); + } } /** @@ -223,6 +262,114 @@ public final class UnknownFieldSetLite { return hashCode; } + private void storeField(int tag, Object value) { + ensureCapacity(); + + tags[count] = tag; + objects[count] = value; + count++; + } + + /** + * Ensures that our arrays are long enough to store more metadata. + */ + private void ensureCapacity() { + if (count == tags.length) { + int increment = count < (MIN_CAPACITY / 2) ? MIN_CAPACITY : count >> 1; + int newLength = count + increment; + + tags = Arrays.copyOf(tags, newLength); + objects = Arrays.copyOf(objects, newLength); + } + } + + /** + * Parse a single field from {@code input} and merge it into this set. + * + *

For use by generated code only. + * + * @param tag The field's tag number, which was already parsed. + * @return {@code false} if the tag is an end group tag. + */ + boolean mergeFieldFrom(final int tag, final CodedInputStream input) throws IOException { + checkMutable(); + final int fieldNumber = WireFormat.getTagFieldNumber(tag); + switch (WireFormat.getTagWireType(tag)) { + case WireFormat.WIRETYPE_VARINT: + storeField(tag, input.readInt64()); + return true; + case WireFormat.WIRETYPE_FIXED32: + storeField(tag, input.readFixed32()); + return true; + case WireFormat.WIRETYPE_FIXED64: + storeField(tag, input.readFixed64()); + return true; + case WireFormat.WIRETYPE_LENGTH_DELIMITED: + storeField(tag, input.readBytes()); + return true; + case WireFormat.WIRETYPE_START_GROUP: + final UnknownFieldSetLite subFieldSet = new UnknownFieldSetLite(); + subFieldSet.mergeFrom(input); + input.checkLastTagWas( + WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP)); + storeField(tag, subFieldSet); + return true; + case WireFormat.WIRETYPE_END_GROUP: + return false; + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } + + /** + * Convenience method for merging a new field containing a single varint + * value. This is used in particular when an unknown enum value is + * encountered. + * + *

For use by generated code only. + */ + UnknownFieldSetLite mergeVarintField(int fieldNumber, int value) { + checkMutable(); + if (fieldNumber == 0) { + throw new IllegalArgumentException("Zero is not a valid field number."); + } + + storeField(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_VARINT), (long) value); + + return this; + } + + /** + * Convenience method for merging a length-delimited field. + * + *

For use by generated code only. + */ + UnknownFieldSetLite mergeLengthDelimitedField(final int fieldNumber, final ByteString value) { + checkMutable(); + if (fieldNumber == 0) { + throw new IllegalArgumentException("Zero is not a valid field number."); + } + + storeField(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED), value); + + return this; + } + + /** + * Parse an entire message from {@code input} and merge its fields into + * this set. + */ + private UnknownFieldSetLite mergeFrom(final CodedInputStream input) throws IOException { + // Ensures initialization in mergeFieldFrom. + while (true) { + final int tag = input.readTag(); + if (tag == 0 || !mergeFieldFrom(tag, input)) { + break; + } + } + return this; + } + /** * Builder for {@link UnknownFieldSetLite}s. * @@ -230,53 +377,26 @@ public final class UnknownFieldSetLite { * *

For use by generated code only. */ + // TODO(dweis): Update the mutable API to no longer need this builder and delete. public static final class Builder { - - // Arbitrarily chosen. - // TODO(dweis): Tune this number? - private static final int MIN_CAPACITY = 8; - - private int count = 0; - private int[] tags = EMPTY_INT_ARRAY; - private Object[] objects = EMPTY_OBJECT_ARRAY; - private boolean built; - - /** - * Constructs a {@code Builder}. - */ - private Builder() {} + private UnknownFieldSetLite set; + + private Builder() { + this.set = null; + } /** * Ensures internal state is initialized for use. */ private void ensureNotBuilt() { - if (built) { - throw new IllegalStateException("Do not reuse UnknownFieldSetLite Builders."); + if (set == null) { + set = new UnknownFieldSetLite(); } - } - - private void storeField(int tag, Object value) { - ensureCapacity(); - tags[count] = tag; - objects[count] = value; - count++; + set.checkMutable(); } - /** - * Ensures that our arrays are long enough to store more metadata. - */ - private void ensureCapacity() { - if (count == tags.length) { - int increment = count < (MIN_CAPACITY / 2) ? MIN_CAPACITY : count >> 1; - int newLength = count + increment; - - tags = Arrays.copyOf(tags, newLength); - objects = Arrays.copyOf(objects, newLength); - } - } - /** * Parse a single field from {@code input} and merge it into this set. * @@ -285,36 +405,9 @@ public final class UnknownFieldSetLite { * @param tag The field's tag number, which was already parsed. * @return {@code false} if the tag is an end group tag. */ - public boolean mergeFieldFrom(final int tag, final CodedInputStream input) - throws IOException { + boolean mergeFieldFrom(final int tag, final CodedInputStream input) throws IOException { ensureNotBuilt(); - - final int fieldNumber = WireFormat.getTagFieldNumber(tag); - switch (WireFormat.getTagWireType(tag)) { - case WireFormat.WIRETYPE_VARINT: - storeField(tag, input.readInt64()); - return true; - case WireFormat.WIRETYPE_FIXED32: - storeField(tag, input.readFixed32()); - return true; - case WireFormat.WIRETYPE_FIXED64: - storeField(tag, input.readFixed64()); - return true; - case WireFormat.WIRETYPE_LENGTH_DELIMITED: - storeField(tag, input.readBytes()); - return true; - case WireFormat.WIRETYPE_START_GROUP: - final Builder subBuilder = newBuilder(); - subBuilder.mergeFrom(input); - input.checkLastTagWas( - WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP)); - storeField(tag, subBuilder.build()); - return true; - case WireFormat.WIRETYPE_END_GROUP: - return false; - default: - throw InvalidProtocolBufferException.invalidWireType(); - } + return set.mergeFieldFrom(tag, input); } /** @@ -324,71 +417,42 @@ public final class UnknownFieldSetLite { * *

For use by generated code only. */ - public Builder mergeVarintField(int fieldNumber, int value) { - if (fieldNumber == 0) { - throw new IllegalArgumentException("Zero is not a valid field number."); - } + Builder mergeVarintField(int fieldNumber, int value) { ensureNotBuilt(); - - storeField(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_VARINT), (long) value); - + set.mergeVarintField(fieldNumber, value); return this; } - + /** * Convenience method for merging a length-delimited field. * *

For use by generated code only. */ - public Builder mergeLengthDelimitedField( - final int fieldNumber, final ByteString value) { - if (fieldNumber == 0) { - throw new IllegalArgumentException("Zero is not a valid field number."); - } - ensureNotBuilt(); - - storeField(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED), value); - + public Builder mergeLengthDelimitedField(final int fieldNumber, final ByteString value) { + ensureNotBuilt(); + set.mergeLengthDelimitedField(fieldNumber, value); return this; } - /** - * Parse an entire message from {@code input} and merge its fields into - * this set. - */ - private Builder mergeFrom(final CodedInputStream input) throws IOException { - // Ensures initialization in mergeFieldFrom. - while (true) { - final int tag = input.readTag(); - if (tag == 0 || !mergeFieldFrom(tag, input)) { - break; - } - } - return this; - } - /** * Build the {@link UnknownFieldSetLite} and return it. * *

Once {@code build()} has been called, the {@code Builder} will no * longer be usable. Calling any method after {@code build()} will result - * in undefined behavior and can cause a {@code IllegalStateException} to be - * thrown. + * in undefined behavior and can cause an + * {@code UnsupportedOperationException} to be thrown. * *

For use by generated code only. */ public UnknownFieldSetLite build() { - if (built) { - throw new IllegalStateException("Do not reuse UnknownFieldSetLite Builders."); - } - - built = true; - - if (count == 0) { + if (set == null) { return DEFAULT_INSTANCE; } + + set.checkMutable(); + set.makeImmutable(); - return new UnknownFieldSetLite(count, tags, objects); + return set; } } } diff --git a/java/src/main/java/com/google/protobuf/Utf8.java b/java/src/main/java/com/google/protobuf/Utf8.java index 0699778f..48c7e9e6 100644 --- a/java/src/main/java/com/google/protobuf/Utf8.java +++ b/java/src/main/java/com/google/protobuf/Utf8.java @@ -360,8 +360,8 @@ final class Utf8 { static class UnpairedSurrogateException extends IllegalArgumentException { - private UnpairedSurrogateException(int index) { - super("Unpaired surrogate at index " + index); + private UnpairedSurrogateException(int index, int length) { + super("Unpaired surrogate at index " + index + " of " + length); } } @@ -417,7 +417,7 @@ final class Utf8 { // Check that we have a well-formed surrogate pair. int cp = Character.codePointAt(sequence, i); if (cp < Character.MIN_SUPPLEMENTARY_CODE_POINT) { - throw new UnpairedSurrogateException(i); + throw new UnpairedSurrogateException(i, utf16Length); } i++; } @@ -457,7 +457,7 @@ final class Utf8 { final char low; if (i + 1 == sequence.length() || !Character.isSurrogatePair(c, (low = sequence.charAt(++i)))) { - throw new UnpairedSurrogateException((i - 1)); + throw new UnpairedSurrogateException((i - 1), utf16Length); } int codePoint = Character.toCodePoint(c, low); bytes[j++] = (byte) ((0xF << 4) | (codePoint >>> 18)); @@ -470,7 +470,7 @@ final class Utf8 { if ((Character.MIN_SURROGATE <= c && c <= Character.MAX_SURROGATE) && (i + 1 == sequence.length() || !Character.isSurrogatePair(c, sequence.charAt(i + 1)))) { - throw new UnpairedSurrogateException(i); + throw new UnpairedSurrogateException(i, utf16Length); } throw new ArrayIndexOutOfBoundsException("Failed writing " + c + " at index " + j); } diff --git a/java/src/test/java/com/google/protobuf/DescriptorsTest.java b/java/src/test/java/com/google/protobuf/DescriptorsTest.java index edd7fc46..30da2487 100644 --- a/java/src/test/java/com/google/protobuf/DescriptorsTest.java +++ b/java/src/test/java/com/google/protobuf/DescriptorsTest.java @@ -46,6 +46,7 @@ import com.google.protobuf.Descriptors.OneofDescriptor; import com.google.protobuf.Descriptors.ServiceDescriptor; import com.google.protobuf.test.UnittestImport; import com.google.protobuf.test.UnittestImport.ImportEnum; +import com.google.protobuf.test.UnittestImport.ImportEnumForMap; import protobuf_unittest.TestCustomOptions; import protobuf_unittest.UnittestCustomOptions; import protobuf_unittest.UnittestProto; @@ -115,7 +116,8 @@ public class DescriptorsTest extends TestCase { assertEquals(enumType, file.findEnumTypeByName("ForeignEnum")); assertNull(file.findEnumTypeByName("NoSuchType")); assertNull(file.findEnumTypeByName("protobuf_unittest.ForeignEnum")); - assertEquals(Arrays.asList(ImportEnum.getDescriptor()), + assertEquals(Arrays.asList(ImportEnum.getDescriptor(), + ImportEnumForMap.getDescriptor()), UnittestImport.getDescriptor().getEnumTypes()); for (int i = 0; i < file.getEnumTypes().size(); i++) { assertEquals(i, file.getEnumTypes().get(i).getIndex()); diff --git a/java/src/test/java/com/google/protobuf/TextFormatTest.java b/java/src/test/java/com/google/protobuf/TextFormatTest.java index 8294b865..1df4fad7 100644 --- a/java/src/test/java/com/google/protobuf/TextFormatTest.java +++ b/java/src/test/java/com/google/protobuf/TextFormatTest.java @@ -830,6 +830,22 @@ public class TextFormatTest extends TestCase { .build())); } + public void testShortDebugString_field() { + final FieldDescriptor dataField = + OneString.getDescriptor().findFieldByName("data"); + assertEquals( + "data: \"test data\"", + TextFormat.shortDebugString(dataField, "test data")); + + final FieldDescriptor optionalField = + TestAllTypes.getDescriptor().findFieldByName("optional_nested_message"); + final Object value = NestedMessage.newBuilder().setBb(42).build(); + + assertEquals( + "optional_nested_message { bb: 42 }", + TextFormat.shortDebugString(optionalField, value)); + } + public void testShortDebugString_unknown() { assertEquals("5: 1 5: 0x00000002 5: 0x0000000000000003 5: \"4\" 5 { 10: 5 }" + " 8: 1 8: 2 8: 3 15: 12379813812177893520 15: 0xabcd1234 15:" diff --git a/java/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java b/java/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java index e76b4a67..dc987379 100644 --- a/java/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java +++ b/java/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java @@ -30,6 +30,8 @@ package com.google.protobuf; +import com.google.protobuf.UnittestLite.TestAllExtensionsLite; +import com.google.protobuf.UnittestLite.TestAllTypesLite; import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash; import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Bar; import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Foo; @@ -52,7 +54,40 @@ public class UnknownFieldSetLiteTest extends TestCase { UnknownFieldSetLite.newBuilder() .build()); } + + public void testBuilderReuse() throws IOException { + UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder(); + builder.mergeVarintField(10, 2); + builder.build(); + + try { + builder.build(); + fail(); + } catch (UnsupportedOperationException e) { + // Expected. + } + + try { + builder.mergeFieldFrom(0, CodedInputStream.newInstance(new byte[0])); + fail(); + } catch (UnsupportedOperationException e) { + // Expected. + } + + try { + builder.mergeVarintField(5, 1); + fail(); + } catch (UnsupportedOperationException e) { + // Expected. + } + } + public void testBuilderReuse_empty() { + UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder(); + builder.build(); + builder.build(); + } + public void testDefaultInstance() { UnknownFieldSetLite unknownFields = UnknownFieldSetLite.getDefaultInstance(); @@ -67,10 +102,10 @@ public class UnknownFieldSetLiteTest extends TestCase { CodedInputStream input = CodedInputStream.newInstance(foo.toByteArray()); - UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder(); - builder.mergeFieldFrom(input.readTag(), input); + UnknownFieldSetLite instance = UnknownFieldSetLite.newInstance(); + instance.mergeFieldFrom(input.readTag(), input); - assertEquals(foo.toByteString(), toByteString(builder.build())); + assertEquals(foo.toByteString(), toByteString(instance)); } public void testSerializedSize() throws IOException { @@ -80,18 +115,18 @@ public class UnknownFieldSetLiteTest extends TestCase { CodedInputStream input = CodedInputStream.newInstance(foo.toByteArray()); - UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder(); - builder.mergeFieldFrom(input.readTag(), input); + UnknownFieldSetLite instance = UnknownFieldSetLite.newInstance(); + instance.mergeFieldFrom(input.readTag(), input); - assertEquals(foo.toByteString().size(), builder.build().getSerializedSize()); + assertEquals(foo.toByteString().size(), instance.getSerializedSize()); } public void testMergeVarintField() throws IOException { - UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder(); - builder.mergeVarintField(10, 2); + UnknownFieldSetLite unknownFields = UnknownFieldSetLite.newInstance(); + unknownFields.mergeVarintField(10, 2); CodedInputStream input = - CodedInputStream.newInstance(toByteString(builder.build()).toByteArray()); + CodedInputStream.newInstance(toByteString(unknownFields).toByteArray()); int tag = input.readTag(); assertEquals(10, WireFormat.getTagFieldNumber(tag)); @@ -101,11 +136,11 @@ public class UnknownFieldSetLiteTest extends TestCase { } public void testMergeVarintField_negative() throws IOException { - UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder(); + UnknownFieldSetLite builder = UnknownFieldSetLite.newInstance(); builder.mergeVarintField(10, -6); CodedInputStream input = - CodedInputStream.newInstance(toByteString(builder.build()).toByteArray()); + CodedInputStream.newInstance(toByteString(builder).toByteArray()); int tag = input.readTag(); assertEquals(10, WireFormat.getTagFieldNumber(tag)); @@ -115,13 +150,11 @@ public class UnknownFieldSetLiteTest extends TestCase { } public void testEqualsAndHashCode() { - UnknownFieldSetLite.Builder builder1 = UnknownFieldSetLite.newBuilder(); - builder1.mergeVarintField(10, 2); - UnknownFieldSetLite unknownFields1 = builder1.build(); + UnknownFieldSetLite unknownFields1 = UnknownFieldSetLite.newInstance(); + unknownFields1.mergeVarintField(10, 2); - UnknownFieldSetLite.Builder builder2 = UnknownFieldSetLite.newBuilder(); - builder2.mergeVarintField(10, 2); - UnknownFieldSetLite unknownFields2 = builder2.build(); + UnknownFieldSetLite unknownFields2 = UnknownFieldSetLite.newInstance(); + unknownFields2.mergeVarintField(10, 2); assertEquals(unknownFields1, unknownFields2); assertEquals(unknownFields1.hashCode(), unknownFields2.hashCode()); @@ -129,12 +162,11 @@ public class UnknownFieldSetLiteTest extends TestCase { assertFalse(unknownFields1.hashCode() == UnknownFieldSetLite.getDefaultInstance().hashCode()); } - public void testConcat() throws IOException { - UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder(); - builder.mergeVarintField(10, 2); - UnknownFieldSetLite unknownFields = builder.build(); - - unknownFields = UnknownFieldSetLite.concat(unknownFields, unknownFields); + public void testMutableCopyOf() throws IOException { + UnknownFieldSetLite unknownFields = UnknownFieldSetLite.newInstance(); + unknownFields.mergeVarintField(10, 2); + unknownFields = UnknownFieldSetLite.mutableCopyOf(unknownFields, unknownFields); + unknownFields.checkMutable(); CodedInputStream input = CodedInputStream.newInstance(toByteString(unknownFields).toByteArray()); @@ -151,53 +183,15 @@ public class UnknownFieldSetLiteTest extends TestCase { assertTrue(input.isAtEnd()); } - public void testConcat_empty() { - UnknownFieldSetLite unknownFields = UnknownFieldSetLite.concat( + public void testMutableCopyOf_empty() { + UnknownFieldSetLite unknownFields = UnknownFieldSetLite.mutableCopyOf( UnknownFieldSetLite.getDefaultInstance(), UnknownFieldSetLite.getDefaultInstance()); + unknownFields.checkMutable(); assertEquals(0, unknownFields.getSerializedSize()); assertEquals(ByteString.EMPTY, toByteString(unknownFields)); } - public void testBuilderReuse() throws IOException { - UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder(); - builder.mergeVarintField(10, 2); - builder.build(); - - try { - builder.build(); - fail(); - } catch (IllegalStateException e) { - // Expected. - } - - try { - builder.mergeFieldFrom(0, CodedInputStream.newInstance(new byte[0])); - fail(); - } catch (IllegalStateException e) { - // Expected. - } - - try { - builder.mergeVarintField(5, 1); - fail(); - } catch (IllegalStateException e) { - // Expected. - } - } - - public void testBuilderReuse_empty() { - UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder(); - builder.build(); - - try { - builder.build(); - fail(); - } catch (IllegalStateException e) { - // Expected. - } - } - public void testRoundTrips() throws InvalidProtocolBufferException { Foo foo = Foo.newBuilder() .setValue(1) @@ -301,6 +295,64 @@ public class UnknownFieldSetLiteTest extends TestCase { // Expected. } } + + public void testMakeImmutable() throws Exception { + UnknownFieldSetLite unknownFields = UnknownFieldSetLite.newInstance(); + unknownFields.makeImmutable(); + + try { + unknownFields.mergeVarintField(1, 1); + fail(); + } catch (UnsupportedOperationException expected) {} + + try { + unknownFields.mergeLengthDelimitedField(2, ByteString.copyFromUtf8("hello")); + fail(); + } catch (UnsupportedOperationException expected) {} + + try { + unknownFields.mergeFieldFrom(1, CodedInputStream.newInstance(new byte[0])); + fail(); + } catch (UnsupportedOperationException expected) {} + } + + public void testEndToEnd() throws Exception { + TestAllTypesLite testAllTypes = TestAllTypesLite.getDefaultInstance(); + try { + testAllTypes.unknownFields.checkMutable(); + fail(); + } catch (UnsupportedOperationException expected) {} + + testAllTypes = TestAllTypesLite.parseFrom(new byte[0]); + try { + testAllTypes.unknownFields.checkMutable(); + fail(); + } catch (UnsupportedOperationException expected) {} + + testAllTypes = TestAllTypesLite.newBuilder().build(); + try { + testAllTypes.unknownFields.checkMutable(); + fail(); + } catch (UnsupportedOperationException expected) {} + + testAllTypes = TestAllTypesLite.newBuilder() + .setDefaultBool(true) + .build(); + try { + testAllTypes.unknownFields.checkMutable(); + fail(); + } catch (UnsupportedOperationException expected) {} + + TestAllExtensionsLite testAllExtensions = TestAllExtensionsLite.newBuilder() + .mergeFrom(TestAllExtensionsLite.newBuilder() + .setExtension(UnittestLite.optionalInt32ExtensionLite, 2) + .build().toByteArray()) + .build(); + try { + testAllExtensions.unknownFields.checkMutable(); + fail(); + } catch (UnsupportedOperationException expected) {} + } private ByteString toByteString(UnknownFieldSetLite unknownFields) { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); diff --git a/java/src/test/java/com/google/protobuf/test_bad_identifiers.proto b/java/src/test/java/com/google/protobuf/test_bad_identifiers.proto index dc082615..8c37c03c 100644 --- a/java/src/test/java/com/google/protobuf/test_bad_identifiers.proto +++ b/java/src/test/java/com/google/protobuf/test_bad_identifiers.proto @@ -140,11 +140,11 @@ message TestConflictingFieldNames { optional bytes bytes_field_count = 14; optional TestMessage message_field_count = 15; - repeated int32 Int32Field = 21; - repeated TestEnum EnumField = 22; - repeated string StringField = 23; - repeated bytes BytesField = 24; - repeated TestMessage MessageField = 25; + repeated int32 Int32Field = 21; // NO_PROTO3 + repeated TestEnum EnumField = 22; // NO_PROTO3 + repeated string StringField = 23; // NO_PROTO3 + repeated bytes BytesField = 24; // NO_PROTO3 + repeated TestMessage MessageField = 25; // NO_PROTO3 // This field conflicts with "int32_field" as they both generate // the method getInt32FieldList(). diff --git a/java/util/pom.xml b/java/util/pom.xml index 44a5662d..9416f380 100644 --- a/java/util/pom.xml +++ b/java/util/pom.xml @@ -10,7 +10,7 @@ com.google.protobuf protobuf-java-util - 3.0.0-beta-1 + 3.0.0-alpha-4-pre bundle Protocol Buffer Java API @@ -36,7 +36,7 @@ com.google.protobuf protobuf-java - 3.0.0-beta-1 + 3.0.0-alpha-4-pre compile @@ -123,7 +123,7 @@ https://developers.google.com/protocol-buffers/ com.google.protobuf.util - com.google.protobuf.util;version=3.0.0-beta-1 + com.google.protobuf.util;version=3.0.0-alpha-3 -- cgit v1.2.3