aboutsummaryrefslogtreecommitdiffhomepage
path: root/java
diff options
context:
space:
mode:
authorGravatar Jisi Liu <jisi.liu@gmail.com>2015-10-05 11:59:43 -0700
committerGravatar Jisi Liu <jisi.liu@gmail.com>2015-10-05 11:59:43 -0700
commit46e8ff63cb67a6520711da5317aaaef04d0414d0 (patch)
tree64370726fe469f8dfca7b14f8b8cb80b6cc856f6 /java
parent0087da9d4775f79c67362cc89c653f3a33a9bae2 (diff)
Down-integrate from google internal.
Diffstat (limited to 'java')
-rw-r--r--java/src/main/java/com/google/protobuf/GeneratedMessageLite.java352
-rw-r--r--java/src/main/java/com/google/protobuf/TextFormat.java15
-rw-r--r--java/src/main/java/com/google/protobuf/UnknownFieldSetLite.java296
-rw-r--r--java/src/main/java/com/google/protobuf/Utf8.java10
-rw-r--r--java/src/test/java/com/google/protobuf/DescriptorsTest.java4
-rw-r--r--java/src/test/java/com/google/protobuf/TextFormatTest.java16
-rw-r--r--java/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java180
-rw-r--r--java/src/test/java/com/google/protobuf/test_bad_identifiers.proto10
-rw-r--r--java/util/pom.xml6
9 files changed, 527 insertions, 362 deletions
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<
* <p>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.
+ *
+ * <p>For use by generated code only.
+ *
+ * @return {@code true} unless the tag is an end-group tag.
+ */
+ protected <MessageType extends MessageLite> 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<MessageType, ?> 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<MessageType, ?> extension) {
if (extension.getContainingTypeDefaultInstance() !=
@@ -404,11 +558,10 @@ public abstract class GeneratedMessageLite<
}
- /**
- * Used by parsing constructors in generated classes.
- */
- protected static void makeExtensionsImmutable(
- FieldSet<ExtensionDescriptor> 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 <MessageType extends MessageLite>
- boolean parseUnknownField(
- FieldSet<ExtensionDescriptor> 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<MessageType, ?> 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<ContainingType, Type> {
/**
- * 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
@@ -119,6 +119,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}.
*
* <p>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.
+ *
+ * <p>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.
+ *
+ * <p>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.
+ *
+ * <p>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.
+ *
+ * <p>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,54 +377,27 @@ public final class UnknownFieldSetLite {
*
* <p>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.
*
* <p>For use by generated code only.
@@ -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 {
*
* <p>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.
*
* <p>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.
*
* <p>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.
*
* <p>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 @@
</parent>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java-util</artifactId>
- <version>3.0.0-beta-1</version>
+ <version>3.0.0-alpha-4-pre</version>
<packaging>bundle</packaging>
<name>Protocol Buffer Java API</name>
<description>
@@ -36,7 +36,7 @@
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
- <version>3.0.0-beta-1</version>
+ <version>3.0.0-alpha-4-pre</version>
<scope>compile</scope>
</dependency>
<dependency>
@@ -123,7 +123,7 @@
<instructions>
<Bundle-DocURL>https://developers.google.com/protocol-buffers/</Bundle-DocURL>
<Bundle-SymbolicName>com.google.protobuf.util</Bundle-SymbolicName>
- <Export-Package>com.google.protobuf.util;version=3.0.0-beta-1</Export-Package>
+ <Export-Package>com.google.protobuf.util;version=3.0.0-alpha-3</Export-Package>
</instructions>
</configuration>
</plugin>