aboutsummaryrefslogtreecommitdiffhomepage
path: root/java
diff options
context:
space:
mode:
authorGravatar Jos Hickson <jos.hickson@gmail.com>2016-05-11 09:23:46 +0100
committerGravatar Jos Hickson <jos.hickson@gmail.com>2016-05-11 09:23:46 +0100
commit2b22b611a8af9e9d06491de2ebcc5d9b962e544c (patch)
tree1d8b5a7399380da5fb3260e2f8eaa2b8cf31bec2 /java
parent48ebb29a8ec118bf6b9ee39f6be42b57321c099a (diff)
parenta1938b2aa9ca86ce7ce50c27ff9737c1008d2a03 (diff)
Merge remote-tracking branch 'refs/remotes/google/master'
Diffstat (limited to 'java')
-rw-r--r--java/core/src/main/java/com/google/protobuf/AbstractMessage.java48
-rw-r--r--java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java79
-rw-r--r--java/core/src/main/java/com/google/protobuf/AbstractParser.java85
-rw-r--r--java/core/src/main/java/com/google/protobuf/AbstractProtobufList.java48
-rw-r--r--java/core/src/main/java/com/google/protobuf/BooleanArrayList.java69
-rw-r--r--java/core/src/main/java/com/google/protobuf/ByteBufferWriter.java145
-rw-r--r--java/core/src/main/java/com/google/protobuf/ByteOutput.java116
-rw-r--r--java/core/src/main/java/com/google/protobuf/ByteString.java120
-rw-r--r--java/core/src/main/java/com/google/protobuf/CodedInputStream.java42
-rw-r--r--java/core/src/main/java/com/google/protobuf/CodedOutputStream.java2890
-rw-r--r--java/core/src/main/java/com/google/protobuf/Descriptors.java185
-rw-r--r--java/core/src/main/java/com/google/protobuf/DoubleArrayList.java65
-rw-r--r--java/core/src/main/java/com/google/protobuf/DynamicMessage.java40
-rw-r--r--java/core/src/main/java/com/google/protobuf/ExperimentalApi.java30
-rw-r--r--java/core/src/main/java/com/google/protobuf/Extension.java1
-rw-r--r--java/core/src/main/java/com/google/protobuf/FieldSet.java19
-rw-r--r--java/core/src/main/java/com/google/protobuf/FloatArrayList.java64
-rw-r--r--java/core/src/main/java/com/google/protobuf/GeneratedMessage.java261
-rw-r--r--java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java1308
-rw-r--r--java/core/src/main/java/com/google/protobuf/IntArrayList.java64
-rw-r--r--java/core/src/main/java/com/google/protobuf/Internal.java72
-rw-r--r--java/core/src/main/java/com/google/protobuf/LazyField.java16
-rw-r--r--java/core/src/main/java/com/google/protobuf/LazyFieldLite.java153
-rw-r--r--java/core/src/main/java/com/google/protobuf/LazyStringArrayList.java52
-rw-r--r--java/core/src/main/java/com/google/protobuf/LongArrayList.java64
-rw-r--r--java/core/src/main/java/com/google/protobuf/MapEntryLite.java10
-rw-r--r--java/core/src/main/java/com/google/protobuf/MapField.java3
-rw-r--r--java/core/src/main/java/com/google/protobuf/Message.java70
-rw-r--r--java/core/src/main/java/com/google/protobuf/MessageLite.java21
-rw-r--r--java/core/src/main/java/com/google/protobuf/MessageLiteToString.java239
-rw-r--r--java/core/src/main/java/com/google/protobuf/MessageOrBuilder.java2
-rw-r--r--java/core/src/main/java/com/google/protobuf/MessageReflection.java107
-rw-r--r--java/core/src/main/java/com/google/protobuf/NioByteString.java55
-rw-r--r--java/core/src/main/java/com/google/protobuf/Parser.java1
-rw-r--r--java/core/src/main/java/com/google/protobuf/ProtobufArrayList.java22
-rw-r--r--java/core/src/main/java/com/google/protobuf/ProtocolMessageEnum.java1
-rw-r--r--java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java8
-rw-r--r--java/core/src/main/java/com/google/protobuf/RopeByteString.java26
-rw-r--r--java/core/src/main/java/com/google/protobuf/RpcUtil.java4
-rw-r--r--java/core/src/main/java/com/google/protobuf/SingleFieldBuilder.java2
-rw-r--r--java/core/src/main/java/com/google/protobuf/SmallSortedMap.java108
-rw-r--r--java/core/src/main/java/com/google/protobuf/TextFormat.java178
-rw-r--r--java/core/src/main/java/com/google/protobuf/TextFormatEscaper.java137
-rw-r--r--java/core/src/main/java/com/google/protobuf/TextFormatParseInfoTree.java225
-rw-r--r--java/core/src/main/java/com/google/protobuf/TextFormatParseLocation.java104
-rw-r--r--java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java77
-rw-r--r--java/core/src/main/java/com/google/protobuf/UnknownFieldSetLite.java110
-rw-r--r--java/core/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java50
-rw-r--r--java/core/src/main/java/com/google/protobuf/UnsafeByteOperations.java25
-rw-r--r--java/core/src/main/java/com/google/protobuf/Utf8.java1664
-rw-r--r--java/core/src/main/java/com/google/protobuf/WireFormat.java19
-rw-r--r--java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java42
-rw-r--r--java/core/src/test/java/com/google/protobuf/AnyTest.java45
-rw-r--r--java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java14
-rw-r--r--java/core/src/test/java/com/google/protobuf/BoundedByteStringTest.java1
-rw-r--r--java/core/src/test/java/com/google/protobuf/ByteBufferWriterTest.java81
-rw-r--r--java/core/src/test/java/com/google/protobuf/ByteStringTest.java14
-rw-r--r--java/core/src/test/java/com/google/protobuf/CheckUtf8Test.java1
-rw-r--r--java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java52
-rw-r--r--java/core/src/test/java/com/google/protobuf/CodedOutputStreamTest.java776
-rw-r--r--java/core/src/test/java/com/google/protobuf/DeprecatedFieldTest.java1
-rw-r--r--java/core/src/test/java/com/google/protobuf/DescriptorsTest.java37
-rw-r--r--java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java14
-rw-r--r--java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java2
-rw-r--r--java/core/src/test/java/com/google/protobuf/EnumTest.java76
-rw-r--r--java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java98
-rw-r--r--java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java14
-rw-r--r--java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java2
-rw-r--r--java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java23
-rw-r--r--java/core/src/test/java/com/google/protobuf/IntArrayListTest.java14
-rw-r--r--java/core/src/test/java/com/google/protobuf/IsValidUtf8Test.java73
-rw-r--r--java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java202
-rw-r--r--java/core/src/test/java/com/google/protobuf/LazyFieldLiteTest.java3
-rw-r--r--java/core/src/test/java/com/google/protobuf/LazyFieldTest.java3
-rw-r--r--java/core/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java17
-rw-r--r--java/core/src/test/java/com/google/protobuf/LiteTest.java881
-rw-r--r--java/core/src/test/java/com/google/protobuf/LiteralByteStringTest.java70
-rw-r--r--java/core/src/test/java/com/google/protobuf/LongArrayListTest.java14
-rw-r--r--java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java2
-rw-r--r--java/core/src/test/java/com/google/protobuf/MapForProto2Test.java1
-rw-r--r--java/core/src/test/java/com/google/protobuf/MapTest.java1
-rw-r--r--java/core/src/test/java/com/google/protobuf/MessageTest.java4
-rw-r--r--java/core/src/test/java/com/google/protobuf/NestedBuildersTest.java2
-rw-r--r--java/core/src/test/java/com/google/protobuf/NioByteStringTest.java215
-rw-r--r--java/core/src/test/java/com/google/protobuf/ParseExceptionsTest.java206
-rw-r--r--java/core/src/test/java/com/google/protobuf/ParserTest.java20
-rw-r--r--java/core/src/test/java/com/google/protobuf/ProtobufArrayListTest.java14
-rw-r--r--java/core/src/test/java/com/google/protobuf/ServiceTest.java34
-rw-r--r--java/core/src/test/java/com/google/protobuf/SmallSortedMapTest.java3
-rw-r--r--java/core/src/test/java/com/google/protobuf/TestUtil.java750
-rw-r--r--java/core/src/test/java/com/google/protobuf/TestUtilLite.java559
-rw-r--r--java/core/src/test/java/com/google/protobuf/TextFormatParseInfoTreeTest.java182
-rw-r--r--java/core/src/test/java/com/google/protobuf/TextFormatParseLocationTest.java86
-rw-r--r--java/core/src/test/java/com/google/protobuf/TextFormatTest.java112
-rw-r--r--java/core/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java40
-rw-r--r--java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java1
-rw-r--r--java/core/src/test/java/com/google/protobuf/WireFormatTest.java32
-rw-r--r--java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto15
-rw-r--r--java/lite/generate-sources-build.xml20
-rw-r--r--java/lite/generate-test-sources-build.xml43
-rw-r--r--java/lite/pom.xml8
-rw-r--r--java/pom.xml4
-rw-r--r--java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java81
-rw-r--r--java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java45
-rw-r--r--java/util/src/main/java/com/google/protobuf/util/JsonFormat.java33
-rw-r--r--java/util/src/test/java/com/google/protobuf/util/FieldMaskTreeTest.java144
-rw-r--r--java/util/src/test/java/com/google/protobuf/util/FieldMaskUtilTest.java9
-rw-r--r--java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java240
-rw-r--r--java/util/src/test/proto/com/google/protobuf/util/json_test.proto31
109 files changed, 11169 insertions, 3642 deletions
diff --git a/java/core/src/main/java/com/google/protobuf/AbstractMessage.java b/java/core/src/main/java/com/google/protobuf/AbstractMessage.java
index 9f418f2b..03c0d579 100644
--- a/java/core/src/main/java/com/google/protobuf/AbstractMessage.java
+++ b/java/core/src/main/java/com/google/protobuf/AbstractMessage.java
@@ -50,17 +50,23 @@ import java.util.Map;
*
* @author kenton@google.com Kenton Varda
*/
-public abstract class AbstractMessage extends AbstractMessageLite
- implements Message {
+public abstract class AbstractMessage
+ // TODO(dweis): Update GeneratedMessage to parameterize with MessageType and BuilderType.
+ extends AbstractMessageLite
+ implements Message {
+
+ @Override
public boolean isInitialized() {
return MessageReflection.isInitialized(this);
}
+ @Override
public List<String> findInitializationErrors() {
return MessageReflection.findMissingFields(this);
}
+ @Override
public String getInitializationErrorString() {
return MessageReflection.delimitWithCommas(findInitializationErrors());
}
@@ -83,12 +89,14 @@ public abstract class AbstractMessage extends AbstractMessageLite
return TextFormat.printToString(this);
}
+ @Override
public void writeTo(final CodedOutputStream output) throws IOException {
MessageReflection.writeMessageTo(this, getAllFields(), output, false);
}
protected int memoizedSize = -1;
+ @Override
public int getSerializedSize() {
int size = memoizedSize;
if (size != -1) {
@@ -288,8 +296,8 @@ public abstract class AbstractMessage extends AbstractMessageLite
* other methods.
*/
@SuppressWarnings("unchecked")
- public static abstract class Builder<BuilderType extends Builder>
- extends AbstractMessageLite.Builder<BuilderType>
+ public static abstract class Builder<BuilderType extends Builder<BuilderType>>
+ extends AbstractMessageLite.Builder
implements Message.Builder {
// The compiler produces an error if this is not declared explicitly.
@Override
@@ -314,6 +322,7 @@ public abstract class AbstractMessage extends AbstractMessageLite
throw new UnsupportedOperationException("clearOneof() is not implemented.");
}
+ @Override
public BuilderType clear() {
for (final Map.Entry<FieldDescriptor, Object> entry :
getAllFields().entrySet()) {
@@ -322,14 +331,22 @@ public abstract class AbstractMessage extends AbstractMessageLite
return (BuilderType) this;
}
+ @Override
public List<String> findInitializationErrors() {
return MessageReflection.findMissingFields(this);
}
+ @Override
public String getInitializationErrorString() {
return MessageReflection.delimitWithCommas(findInitializationErrors());
}
+
+ @Override
+ protected BuilderType internalMergeFrom(AbstractMessageLite other) {
+ return mergeFrom((Message) other);
+ }
+ @Override
public BuilderType mergeFrom(final Message other) {
if (other.getDescriptorForType() != getDescriptorForType()) {
throw new IllegalArgumentException(
@@ -407,6 +424,7 @@ public abstract class AbstractMessage extends AbstractMessageLite
return (BuilderType) this;
}
+ @Override
public BuilderType mergeUnknownFields(final UnknownFieldSet unknownFields) {
setUnknownFields(
UnknownFieldSet.newBuilder(getUnknownFields())
@@ -415,17 +433,19 @@ public abstract class AbstractMessage extends AbstractMessageLite
return (BuilderType) this;
}
+ @Override
public Message.Builder getFieldBuilder(final FieldDescriptor field) {
throw new UnsupportedOperationException(
"getFieldBuilder() called on an unsupported message type.");
}
- public Message.Builder getRepeatedFieldBuilder(final FieldDescriptor field,
- int index) {
+ @Override
+ public Message.Builder getRepeatedFieldBuilder(final FieldDescriptor field, int index) {
throw new UnsupportedOperationException(
"getRepeatedFieldBuilder() called on an unsupported message type.");
}
+ @Override
public String toString() {
return TextFormat.printToString(this);
}
@@ -462,7 +482,7 @@ public abstract class AbstractMessage extends AbstractMessageLite
@Override
public BuilderType mergeFrom(final ByteString data)
throws InvalidProtocolBufferException {
- return super.mergeFrom(data);
+ return (BuilderType) super.mergeFrom(data);
}
@Override
@@ -470,20 +490,20 @@ public abstract class AbstractMessage extends AbstractMessageLite
final ByteString data,
final ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
- return super.mergeFrom(data, extensionRegistry);
+ return (BuilderType) super.mergeFrom(data, extensionRegistry);
}
@Override
public BuilderType mergeFrom(final byte[] data)
throws InvalidProtocolBufferException {
- return super.mergeFrom(data);
+ return (BuilderType) super.mergeFrom(data);
}
@Override
public BuilderType mergeFrom(
final byte[] data, final int off, final int len)
throws InvalidProtocolBufferException {
- return super.mergeFrom(data, off, len);
+ return (BuilderType) super.mergeFrom(data, off, len);
}
@Override
@@ -491,7 +511,7 @@ public abstract class AbstractMessage extends AbstractMessageLite
final byte[] data,
final ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
- return super.mergeFrom(data, extensionRegistry);
+ return (BuilderType) super.mergeFrom(data, extensionRegistry);
}
@Override
@@ -499,13 +519,13 @@ public abstract class AbstractMessage extends AbstractMessageLite
final byte[] data, final int off, final int len,
final ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
- return super.mergeFrom(data, off, len, extensionRegistry);
+ return (BuilderType) super.mergeFrom(data, off, len, extensionRegistry);
}
@Override
public BuilderType mergeFrom(final InputStream input)
throws IOException {
- return super.mergeFrom(input);
+ return (BuilderType) super.mergeFrom(input);
}
@Override
@@ -513,7 +533,7 @@ public abstract class AbstractMessage extends AbstractMessageLite
final InputStream input,
final ExtensionRegistryLite extensionRegistry)
throws IOException {
- return super.mergeFrom(input, extensionRegistry);
+ return (BuilderType) super.mergeFrom(input, extensionRegistry);
}
@Override
diff --git a/java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java b/java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java
index 12384983..43736dd1 100644
--- a/java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java
+++ b/java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java
@@ -43,9 +43,13 @@ import java.util.Collection;
*
* @author kenton@google.com Kenton Varda
*/
-public abstract class AbstractMessageLite implements MessageLite {
+public abstract class AbstractMessageLite<
+ MessageType extends AbstractMessageLite<MessageType, BuilderType>,
+ BuilderType extends AbstractMessageLite.Builder<MessageType, BuilderType>>
+ implements MessageLite {
protected int memoizedHashCode = 0;
-
+
+ @Override
public ByteString toByteString() {
try {
final ByteString.CodedBuilder out =
@@ -59,6 +63,7 @@ public abstract class AbstractMessageLite implements MessageLite {
}
}
+ @Override
public byte[] toByteArray() {
try {
final byte[] result = new byte[getSerializedSize()];
@@ -73,6 +78,7 @@ public abstract class AbstractMessageLite implements MessageLite {
}
}
+ @Override
public void writeTo(final OutputStream output) throws IOException {
final int bufferSize =
CodedOutputStream.computePreferredBufferSize(getSerializedSize());
@@ -82,6 +88,7 @@ public abstract class AbstractMessageLite implements MessageLite {
codedOutput.flush();
}
+ @Override
public void writeDelimitedTo(final OutputStream output) throws IOException {
final int serialized = getSerializedSize();
final int bufferSize = CodedOutputStream.computePreferredBufferSize(
@@ -120,25 +127,27 @@ public abstract class AbstractMessageLite implements MessageLite {
* other methods.
*/
@SuppressWarnings("unchecked")
- public static abstract class Builder<BuilderType extends Builder>
+ public abstract static class Builder<
+ MessageType extends AbstractMessageLite<MessageType, BuilderType>,
+ BuilderType extends Builder<MessageType, BuilderType>>
implements MessageLite.Builder {
// The compiler produces an error if this is not declared explicitly.
@Override
public abstract BuilderType clone();
- public BuilderType mergeFrom(final CodedInputStream input)
- throws IOException {
+ @Override
+ public BuilderType mergeFrom(final CodedInputStream input) throws IOException {
return mergeFrom(input, ExtensionRegistryLite.getEmptyRegistry());
}
// Re-defined here for return type covariance.
+ @Override
public abstract BuilderType mergeFrom(
- final CodedInputStream input,
- final ExtensionRegistryLite extensionRegistry)
+ final CodedInputStream input, final ExtensionRegistryLite extensionRegistry)
throws IOException;
- public BuilderType mergeFrom(final ByteString data)
- throws InvalidProtocolBufferException {
+ @Override
+ public BuilderType mergeFrom(final ByteString data) throws InvalidProtocolBufferException {
try {
final CodedInputStream input = data.newCodedInput();
mergeFrom(input);
@@ -153,9 +162,9 @@ public abstract class AbstractMessageLite implements MessageLite {
}
}
+ @Override
public BuilderType mergeFrom(
- final ByteString data,
- final ExtensionRegistryLite extensionRegistry)
+ final ByteString data, final ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
try {
final CodedInputStream input = data.newCodedInput();
@@ -171,14 +180,14 @@ public abstract class AbstractMessageLite implements MessageLite {
}
}
- public BuilderType mergeFrom(final byte[] data)
- throws InvalidProtocolBufferException {
+ @Override
+ public BuilderType mergeFrom(final byte[] data) throws InvalidProtocolBufferException {
return mergeFrom(data, 0, data.length);
}
- public BuilderType mergeFrom(final byte[] data, final int off,
- final int len)
- throws InvalidProtocolBufferException {
+ @Override
+ public BuilderType mergeFrom(final byte[] data, final int off, final int len)
+ throws InvalidProtocolBufferException {
try {
final CodedInputStream input =
CodedInputStream.newInstance(data, off, len);
@@ -194,15 +203,17 @@ public abstract class AbstractMessageLite implements MessageLite {
}
}
- public BuilderType mergeFrom(
- final byte[] data,
- final ExtensionRegistryLite extensionRegistry)
+ @Override
+ public BuilderType mergeFrom(final byte[] data, final ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return mergeFrom(data, 0, data.length, extensionRegistry);
}
+ @Override
public BuilderType mergeFrom(
- final byte[] data, final int off, final int len,
+ final byte[] data,
+ final int off,
+ final int len,
final ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
try {
@@ -220,6 +231,7 @@ public abstract class AbstractMessageLite implements MessageLite {
}
}
+ @Override
public BuilderType mergeFrom(final InputStream input) throws IOException {
final CodedInputStream codedInput = CodedInputStream.newInstance(input);
mergeFrom(codedInput);
@@ -227,10 +239,9 @@ public abstract class AbstractMessageLite implements MessageLite {
return (BuilderType) this;
}
+ @Override
public BuilderType mergeFrom(
- final InputStream input,
- final ExtensionRegistryLite extensionRegistry)
- throws IOException {
+ final InputStream input, final ExtensionRegistryLite extensionRegistry) throws IOException {
final CodedInputStream codedInput = CodedInputStream.newInstance(input);
mergeFrom(codedInput, extensionRegistry);
codedInput.checkLastTagWas(0);
@@ -292,10 +303,9 @@ public abstract class AbstractMessageLite implements MessageLite {
}
}
+ @Override
public boolean mergeDelimitedFrom(
- final InputStream input,
- final ExtensionRegistryLite extensionRegistry)
- throws IOException {
+ final InputStream input, final ExtensionRegistryLite extensionRegistry) throws IOException {
final int firstByte = input.read();
if (firstByte == -1) {
return false;
@@ -306,11 +316,24 @@ public abstract class AbstractMessageLite implements MessageLite {
return true;
}
- public boolean mergeDelimitedFrom(final InputStream input)
- throws IOException {
+ @Override
+ public boolean mergeDelimitedFrom(final InputStream input) throws IOException {
return mergeDelimitedFrom(input,
ExtensionRegistryLite.getEmptyRegistry());
}
+
+ @Override
+ @SuppressWarnings("unchecked") // isInstance takes care of this
+ public BuilderType mergeFrom(final MessageLite other) {
+ if (!getDefaultInstanceForType().getClass().isInstance(other)) {
+ throw new IllegalArgumentException(
+ "mergeFrom(MessageLite) can only merge messages of the same type.");
+ }
+
+ return internalMergeFrom((MessageType) other);
+ }
+
+ protected abstract BuilderType internalMergeFrom(MessageType message);
/**
* Construct an UninitializedMessageException reporting missing fields in
diff --git a/java/core/src/main/java/com/google/protobuf/AbstractParser.java b/java/core/src/main/java/com/google/protobuf/AbstractParser.java
index 1a4c6311..66b0ee3b 100644
--- a/java/core/src/main/java/com/google/protobuf/AbstractParser.java
+++ b/java/core/src/main/java/com/google/protobuf/AbstractParser.java
@@ -78,26 +78,27 @@ public abstract class AbstractParser<MessageType extends MessageLite>
private static final ExtensionRegistryLite EMPTY_REGISTRY
= ExtensionRegistryLite.getEmptyRegistry();
+ @Override
public MessageType parsePartialFrom(CodedInputStream input)
throws InvalidProtocolBufferException {
return parsePartialFrom(input, EMPTY_REGISTRY);
}
- public MessageType parseFrom(CodedInputStream input,
- ExtensionRegistryLite extensionRegistry)
+ @Override
+ public MessageType parseFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return checkMessageInitialized(
parsePartialFrom(input, extensionRegistry));
}
- public MessageType parseFrom(CodedInputStream input)
- throws InvalidProtocolBufferException {
+ @Override
+ public MessageType parseFrom(CodedInputStream input) throws InvalidProtocolBufferException {
return parseFrom(input, EMPTY_REGISTRY);
}
- public MessageType parsePartialFrom(ByteString data,
- ExtensionRegistryLite extensionRegistry)
- throws InvalidProtocolBufferException {
+ @Override
+ public MessageType parsePartialFrom(ByteString data, ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
MessageType message;
try {
CodedInputStream input = data.newCodedInput();
@@ -113,24 +114,25 @@ public abstract class AbstractParser<MessageType extends MessageLite>
}
}
- public MessageType parsePartialFrom(ByteString data)
- throws InvalidProtocolBufferException {
+ @Override
+ public MessageType parsePartialFrom(ByteString data) throws InvalidProtocolBufferException {
return parsePartialFrom(data, EMPTY_REGISTRY);
}
- public MessageType parseFrom(ByteString data,
- ExtensionRegistryLite extensionRegistry)
+ @Override
+ public MessageType parseFrom(ByteString data, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return checkMessageInitialized(parsePartialFrom(data, extensionRegistry));
}
- public MessageType parseFrom(ByteString data)
- throws InvalidProtocolBufferException {
+ @Override
+ public MessageType parseFrom(ByteString data) throws InvalidProtocolBufferException {
return parseFrom(data, EMPTY_REGISTRY);
}
- public MessageType parsePartialFrom(byte[] data, int off, int len,
- ExtensionRegistryLite extensionRegistry)
+ @Override
+ public MessageType parsePartialFrom(
+ byte[] data, int off, int len, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
try {
CodedInputStream input = CodedInputStream.newInstance(data, off, len);
@@ -146,47 +148,50 @@ public abstract class AbstractParser<MessageType extends MessageLite>
}
}
+ @Override
public MessageType parsePartialFrom(byte[] data, int off, int len)
throws InvalidProtocolBufferException {
return parsePartialFrom(data, off, len, EMPTY_REGISTRY);
}
- public MessageType parsePartialFrom(byte[] data,
- ExtensionRegistryLite extensionRegistry)
+ @Override
+ public MessageType parsePartialFrom(byte[] data, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return parsePartialFrom(data, 0, data.length, extensionRegistry);
}
- public MessageType parsePartialFrom(byte[] data)
- throws InvalidProtocolBufferException {
+ @Override
+ public MessageType parsePartialFrom(byte[] data) throws InvalidProtocolBufferException {
return parsePartialFrom(data, 0, data.length, EMPTY_REGISTRY);
}
- public MessageType parseFrom(byte[] data, int off, int len,
- ExtensionRegistryLite extensionRegistry)
+ @Override
+ public MessageType parseFrom(
+ byte[] data, int off, int len, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return checkMessageInitialized(
parsePartialFrom(data, off, len, extensionRegistry));
}
+ @Override
public MessageType parseFrom(byte[] data, int off, int len)
throws InvalidProtocolBufferException {
return parseFrom(data, off, len, EMPTY_REGISTRY);
}
- public MessageType parseFrom(byte[] data,
- ExtensionRegistryLite extensionRegistry)
+ @Override
+ public MessageType parseFrom(byte[] data, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return parseFrom(data, 0, data.length, extensionRegistry);
}
- public MessageType parseFrom(byte[] data)
- throws InvalidProtocolBufferException {
+ @Override
+ public MessageType parseFrom(byte[] data) throws InvalidProtocolBufferException {
return parseFrom(data, EMPTY_REGISTRY);
}
- public MessageType parsePartialFrom(InputStream input,
- ExtensionRegistryLite extensionRegistry)
+ @Override
+ public MessageType parsePartialFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
CodedInputStream codedInput = CodedInputStream.newInstance(input);
MessageType message = parsePartialFrom(codedInput, extensionRegistry);
@@ -198,26 +203,26 @@ public abstract class AbstractParser<MessageType extends MessageLite>
return message;
}
- public MessageType parsePartialFrom(InputStream input)
- throws InvalidProtocolBufferException {
+ @Override
+ public MessageType parsePartialFrom(InputStream input) throws InvalidProtocolBufferException {
return parsePartialFrom(input, EMPTY_REGISTRY);
}
- public MessageType parseFrom(InputStream input,
- ExtensionRegistryLite extensionRegistry)
+ @Override
+ public MessageType parseFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return checkMessageInitialized(
parsePartialFrom(input, extensionRegistry));
}
- public MessageType parseFrom(InputStream input)
- throws InvalidProtocolBufferException {
+ @Override
+ public MessageType parseFrom(InputStream input) throws InvalidProtocolBufferException {
return parseFrom(input, EMPTY_REGISTRY);
}
+ @Override
public MessageType parsePartialDelimitedFrom(
- InputStream input,
- ExtensionRegistryLite extensionRegistry)
+ InputStream input, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
int size;
try {
@@ -233,21 +238,21 @@ public abstract class AbstractParser<MessageType extends MessageLite>
return parsePartialFrom(limitedInput, extensionRegistry);
}
+ @Override
public MessageType parsePartialDelimitedFrom(InputStream input)
throws InvalidProtocolBufferException {
return parsePartialDelimitedFrom(input, EMPTY_REGISTRY);
}
- public MessageType parseDelimitedFrom(
- InputStream input,
- ExtensionRegistryLite extensionRegistry)
+ @Override
+ public MessageType parseDelimitedFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return checkMessageInitialized(
parsePartialDelimitedFrom(input, extensionRegistry));
}
- public MessageType parseDelimitedFrom(InputStream input)
- throws InvalidProtocolBufferException {
+ @Override
+ public MessageType parseDelimitedFrom(InputStream input) throws InvalidProtocolBufferException {
return parseDelimitedFrom(input, EMPTY_REGISTRY);
}
}
diff --git a/java/core/src/main/java/com/google/protobuf/AbstractProtobufList.java b/java/core/src/main/java/com/google/protobuf/AbstractProtobufList.java
index bb6446b2..b17db6e0 100644
--- a/java/core/src/main/java/com/google/protobuf/AbstractProtobufList.java
+++ b/java/core/src/main/java/com/google/protobuf/AbstractProtobufList.java
@@ -34,19 +34,25 @@ import com.google.protobuf.Internal.ProtobufList;
import java.util.AbstractList;
import java.util.Collection;
+import java.util.List;
+import java.util.RandomAccess;
/**
* An abstract implementation of {@link ProtobufList} which manages mutability semantics. All mutate
- * methods are check if the list is mutable before proceeding. Subclasses must invoke
+ * methods must check if the list is mutable before proceeding. Subclasses must invoke
* {@link #ensureIsMutable()} manually when overriding those methods.
+ * <p>
+ * This implementation assumes all subclasses are array based, supporting random access.
*/
abstract class AbstractProtobufList<E> extends AbstractList<E> implements ProtobufList<E> {
+ protected static final int DEFAULT_CAPACITY = 10;
+
/**
* Whether or not this list is modifiable.
*/
private boolean isMutable;
-
+
/**
* Constructs a mutable list by default.
*/
@@ -55,6 +61,44 @@ abstract class AbstractProtobufList<E> extends AbstractList<E> implements Protob
}
@Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (!(o instanceof List)) {
+ return false;
+ }
+ // Handle lists that do not support RandomAccess as efficiently as possible by using an iterator
+ // based approach in our super class. Otherwise our index based approach will avoid those
+ // allocations.
+ if (!(o instanceof RandomAccess)) {
+ return super.equals(o);
+ }
+
+ List<?> other = (List<?>) o;
+ final int size = size();
+ if (size != other.size()) {
+ return false;
+ }
+ for (int i = 0; i < size; i++) {
+ if (!get(i).equals(other.get(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ final int size = size();
+ int hashCode = 1;
+ for (int i = 0; i < size; i++) {
+ hashCode = (31 * hashCode) + get(i).hashCode();
+ }
+ return hashCode;
+ }
+
+ @Override
public boolean add(E e) {
ensureIsMutable();
return super.add(e);
diff --git a/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java b/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java
index 70e042f5..8b2820b6 100644
--- a/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java
@@ -34,7 +34,6 @@ import com.google.protobuf.Internal.BooleanList;
import java.util.Arrays;
import java.util.Collection;
-import java.util.List;
import java.util.RandomAccess;
/**
@@ -45,8 +44,6 @@ import java.util.RandomAccess;
final class BooleanArrayList
extends AbstractProtobufList<Boolean> implements BooleanList, RandomAccess {
- private static final int DEFAULT_CAPACITY = 10;
-
private static final BooleanArrayList EMPTY_LIST = new BooleanArrayList();
static {
EMPTY_LIST.makeImmutable();
@@ -60,7 +57,7 @@ final class BooleanArrayList
* The backing store for the list.
*/
private boolean[] array;
-
+
/**
* The size of the list distinct from the length of the array. That is, it is the number of
* elements set in the list.
@@ -71,35 +68,57 @@ final class BooleanArrayList
* Constructs a new mutable {@code BooleanArrayList} with default capacity.
*/
BooleanArrayList() {
- this(DEFAULT_CAPACITY);
+ this(new boolean[DEFAULT_CAPACITY], 0);
}
/**
- * Constructs a new mutable {@code BooleanArrayList} with the provided capacity.
+ * Constructs a new mutable {@code BooleanArrayList}.
*/
- BooleanArrayList(int capacity) {
- array = new boolean[capacity];
- size = 0;
+ private BooleanArrayList(boolean[] array, int size) {
+ this.array = array;
+ this.size = size;
}
-
- /**
- * Constructs a new mutable {@code BooleanArrayList} containing the same elements as
- * {@code other}.
- */
- BooleanArrayList(List<Boolean> other) {
- if (other instanceof BooleanArrayList) {
- BooleanArrayList list = (BooleanArrayList) other;
- array = list.array.clone();
- size = list.size;
- } else {
- size = other.size();
- array = new boolean[size];
- for (int i = 0; i < size; i++) {
- array[i] = other.get(i);
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof BooleanArrayList)) {
+ return super.equals(o);
+ }
+ BooleanArrayList other = (BooleanArrayList) o;
+ if (size != other.size) {
+ return false;
+ }
+
+ final boolean[] arr = other.array;
+ for (int i = 0; i < size; i++) {
+ if (array[i] != arr[i]) {
+ return false;
}
}
+
+ return true;
}
-
+
+ @Override
+ public int hashCode() {
+ int result = 1;
+ for (int i = 0; i < size; i++) {
+ result = (31 * result) + Internal.hashBoolean(array[i]);
+ }
+ return result;
+ }
+
+ @Override
+ public BooleanList mutableCopyWithCapacity(int capacity) {
+ if (capacity < size) {
+ throw new IllegalArgumentException();
+ }
+ return new BooleanArrayList(Arrays.copyOf(array, capacity), size);
+ }
+
@Override
public Boolean get(int index) {
return getBoolean(index);
diff --git a/java/core/src/main/java/com/google/protobuf/ByteBufferWriter.java b/java/core/src/main/java/com/google/protobuf/ByteBufferWriter.java
new file mode 100644
index 00000000..0cc38175
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/ByteBufferWriter.java
@@ -0,0 +1,145 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import static java.lang.Math.max;
+import static java.lang.Math.min;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.ref.SoftReference;
+import java.nio.ByteBuffer;
+
+/**
+ * Utility class to provide efficient writing of {@link ByteBuffer}s to {@link OutputStream}s.
+ */
+final class ByteBufferWriter {
+ private ByteBufferWriter() {}
+
+ /**
+ * Minimum size for a cached buffer. This prevents us from allocating buffers that are too
+ * small to be easily reused.
+ */
+ // TODO(nathanmittler): tune this property or allow configuration?
+ private static final int MIN_CACHED_BUFFER_SIZE = 1024;
+
+ /**
+ * Maximum size for a cached buffer. If a larger buffer is required, it will be allocated
+ * but not cached.
+ */
+ // TODO(nathanmittler): tune this property or allow configuration?
+ private static final int MAX_CACHED_BUFFER_SIZE = 16 * 1024;
+
+ /**
+ * The fraction of the requested buffer size under which the buffer will be reallocated.
+ */
+ // TODO(nathanmittler): tune this property or allow configuration?
+ private static final float BUFFER_REALLOCATION_THRESHOLD = 0.5f;
+
+ /**
+ * Keeping a soft reference to a thread-local buffer. This buffer is used for writing a
+ * {@link ByteBuffer} to an {@link OutputStream} when no zero-copy alternative was available.
+ * Using a "soft" reference since VMs may keep this reference around longer than "weak"
+ * (e.g. HotSpot will maintain soft references until memory pressure warrants collection).
+ */
+ private static final ThreadLocal<SoftReference<byte[]>> BUFFER =
+ new ThreadLocal<SoftReference<byte[]>>();
+
+ /**
+ * For testing purposes only. Clears the cached buffer to force a new allocation on the next
+ * invocation.
+ */
+ static void clearCachedBuffer() {
+ BUFFER.set(null);
+ }
+
+ /**
+ * Writes the remaining content of the buffer to the given stream. The buffer {@code position}
+ * will remain unchanged by this method.
+ */
+ static void write(ByteBuffer buffer, OutputStream output) throws IOException {
+ final int initialPos = buffer.position();
+ try {
+ if (buffer.hasArray()) {
+ // Optimized write for array-backed buffers.
+ // Note that we're taking the risk that a malicious OutputStream could modify the array.
+ output.write(buffer.array(), buffer.arrayOffset() + buffer.position(), buffer.remaining());
+ } else if (output instanceof FileOutputStream) {
+ // Use a channel to write out the ByteBuffer. This will automatically empty the buffer.
+ ((FileOutputStream) output).getChannel().write(buffer);
+ } else {
+ // Read all of the data from the buffer to an array.
+ // TODO(nathanmittler): Consider performance improvements for other "known" stream types.
+ final byte[] array = getOrCreateBuffer(buffer.remaining());
+ while (buffer.hasRemaining()) {
+ int length = min(buffer.remaining(), array.length);
+ buffer.get(array, 0, length);
+ output.write(array, 0, length);
+ }
+ }
+ } finally {
+ // Restore the initial position.
+ buffer.position(initialPos);
+ }
+ }
+
+ private static byte[] getOrCreateBuffer(int requestedSize) {
+ requestedSize = max(requestedSize, MIN_CACHED_BUFFER_SIZE);
+
+ byte[] buffer = getBuffer();
+ // Only allocate if we need to.
+ if (buffer == null || needToReallocate(requestedSize, buffer.length)) {
+ buffer = new byte[requestedSize];
+
+ // Only cache the buffer if it's not too big.
+ if (requestedSize <= MAX_CACHED_BUFFER_SIZE) {
+ setBuffer(buffer);
+ }
+ }
+ return buffer;
+ }
+
+ private static boolean needToReallocate(int requestedSize, int bufferLength) {
+ // First check against just the requested length to avoid the multiply.
+ return bufferLength < requestedSize
+ && bufferLength < requestedSize * BUFFER_REALLOCATION_THRESHOLD;
+ }
+
+ private static byte[] getBuffer() {
+ SoftReference<byte[]> sr = BUFFER.get();
+ return sr == null ? null : sr.get();
+ }
+
+ private static void setBuffer(byte[] value) {
+ BUFFER.set(new SoftReference<byte[]>(value));
+ }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/ByteOutput.java b/java/core/src/main/java/com/google/protobuf/ByteOutput.java
new file mode 100644
index 00000000..8b7b04c8
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/ByteOutput.java
@@ -0,0 +1,116 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * An output target for raw bytes. This interface provides semantics that support two types of
+ * writing:
+ *
+ * <p/><b>Traditional write operations:</b>
+ * (as defined by {@link java.io.OutputStream}) where the target method is responsible for either
+ * copying the data or completing the write before returning from the method call.
+ *
+ * <p/><b>Lazy write operations:</b> where the caller guarantees that it will never modify the
+ * provided buffer and it can therefore be considered immutable. The target method is free to
+ * maintain a reference to the buffer beyond the scope of the method call (e.g. until the write
+ * operation completes).
+ */
+@ExperimentalApi
+public abstract class ByteOutput {
+ /**
+ * Writes a single byte.
+ *
+ * @param value the byte to be written
+ * @throws IOException thrown if an error occurred while writing
+ */
+ public abstract void write(byte value) throws IOException;
+
+ /**
+ * Writes a sequence of bytes. The {@link ByteOutput} must copy {@code value} if it will
+ * not be processed prior to the return of this method call, since {@code value} may be
+ * reused/altered by the caller.
+ *
+ * <p>NOTE: This method <strong>MUST NOT</strong> modify the {@code value}. Doing so is a
+ * programming error and will lead to data corruption which will be difficult to debug.
+ *
+ * @param value the bytes to be written
+ * @param offset the offset of the start of the writable range
+ * @param length the number of bytes to write starting from {@code offset}
+ * @throws IOException thrown if an error occurred while writing
+ */
+ public abstract void write(byte[] value, int offset, int length) throws IOException;
+
+ /**
+ * Writes a sequence of bytes. The {@link ByteOutput} is free to retain a reference to the value
+ * beyond the scope of this method call (e.g. write later) since it is considered immutable and is
+ * guaranteed not to change by the caller.
+ *
+ * <p>NOTE: This method <strong>MUST NOT</strong> modify the {@code value}. Doing so is a
+ * programming error and will lead to data corruption which will be difficult to debug.
+ *
+ * @param value the bytes to be written
+ * @param offset the offset of the start of the writable range
+ * @param length the number of bytes to write starting from {@code offset}
+ * @throws IOException thrown if an error occurred while writing
+ */
+ public abstract void writeLazy(byte[] value, int offset, int length) throws IOException;
+
+ /**
+ * Writes a sequence of bytes. The {@link ByteOutput} must copy {@code value} if it will
+ * not be processed prior to the return of this method call, since {@code value} may be
+ * reused/altered by the caller.
+ *
+ * <p>NOTE: This method <strong>MUST NOT</strong> modify the {@code value}. Doing so is a
+ * programming error and will lead to data corruption which will be difficult to debug.
+ *
+ * @param value the bytes to be written. Upon returning from this call, the {@code position} of
+ * this buffer will be set to the {@code limit}
+ * @throws IOException thrown if an error occurred while writing
+ */
+ public abstract void write(ByteBuffer value) throws IOException;
+
+ /**
+ * Writes a sequence of bytes. The {@link ByteOutput} is free to retain a reference to the value
+ * beyond the scope of this method call (e.g. write later) since it is considered immutable and is
+ * guaranteed not to change by the caller.
+ *
+ * <p>NOTE: This method <strong>MUST NOT</strong> modify the {@code value}. Doing so is a
+ * programming error and will lead to data corruption which will be difficult to debug.
+ *
+ * @param value the bytes to be written. Upon returning from this call, the {@code position} of
+ * this buffer will be set to the {@code limit}
+ * @throws IOException thrown if an error occurred while writing
+ */
+ public abstract void writeLazy(ByteBuffer value) throws IOException;
+}
diff --git a/java/core/src/main/java/com/google/protobuf/ByteString.java b/java/core/src/main/java/com/google/protobuf/ByteString.java
index 305236f3..62c94508 100644
--- a/java/core/src/main/java/com/google/protobuf/ByteString.java
+++ b/java/core/src/main/java/com/google/protobuf/ByteString.java
@@ -1,4 +1,32 @@
-// Copyright 2007 Google Inc. All rights reserved.
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
@@ -15,6 +43,7 @@ import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
@@ -58,6 +87,54 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
* Empty {@code ByteString}.
*/
public static final ByteString EMPTY = new LiteralByteString(Internal.EMPTY_BYTE_ARRAY);
+
+ /**
+ * An interface to efficiently copy {@code byte[]}.
+ *
+ * <p>One of the noticable costs of copying a byte[] into a new array using
+ * {@code System.arraycopy} is nullification of a new buffer before the copy. It has been shown
+ * the Hotspot VM is capable to intrisicfy {@code Arrays.copyOfRange} operation to avoid this
+ * expensive nullification and provide substantial performance gain. Unfortunately this does not
+ * hold on Android runtimes and could make the copy slightly slower due to additional code in
+ * the {@code Arrays.copyOfRange}. Thus we provide two different implementation for array copier
+ * for Hotspot and Android runtimes.
+ */
+ private interface ByteArrayCopier {
+ /**
+ * Copies the specified range of the specified array into a new array
+ */
+ byte[] copyFrom(byte[] bytes, int offset, int size);
+ }
+
+ /** Implementation of {@code ByteArrayCopier} which uses {@link System#arraycopy}. */
+ private static final class SystemByteArrayCopier implements ByteArrayCopier {
+ @Override
+ public byte[] copyFrom(byte[] bytes, int offset, int size) {
+ byte[] copy = new byte[size];
+ System.arraycopy(bytes, offset, copy, 0, size);
+ return copy;
+ }
+ }
+
+ /** Implementation of {@code ByteArrayCopier} which uses {@link Arrays#copyOfRange}. */
+ private static final class ArraysByteArrayCopier implements ByteArrayCopier {
+ @Override
+ public byte[] copyFrom(byte[] bytes, int offset, int size) {
+ return Arrays.copyOfRange(bytes, offset, offset + size);
+ }
+ }
+
+ private static final ByteArrayCopier byteArrayCopier;
+ static {
+ boolean isAndroid = true;
+ try {
+ Class.forName("android.content.Context");
+ } catch (ClassNotFoundException e) {
+ isAndroid = false;
+ }
+
+ byteArrayCopier = isAndroid ? new SystemByteArrayCopier() : new ArraysByteArrayCopier();
+ }
/**
* Cached hash value. Intentionally accessed via a data race, which
@@ -77,7 +154,7 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
*
* @param index index of byte
* @return the value
- * @throws ArrayIndexOutOfBoundsException {@code index < 0 or index >= size}
+ * @throws IndexOutOfBoundsException {@code index < 0 or index >= size}
*/
public abstract byte byteAt(int index);
@@ -109,7 +186,7 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
public byte nextByte() {
try {
return byteAt(position++);
- } catch (ArrayIndexOutOfBoundsException e) {
+ } catch (IndexOutOfBoundsException e) {
throw new NoSuchElementException(e.getMessage());
}
}
@@ -220,9 +297,7 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
* @return new {@code ByteString}
*/
public static ByteString copyFrom(byte[] bytes, int offset, int size) {
- byte[] copy = new byte[size];
- System.arraycopy(bytes, offset, copy, 0, size);
- return new LiteralByteString(copy);
+ return new LiteralByteString(byteArrayCopier.copyFrom(bytes, offset, size));
}
/**
@@ -559,12 +634,7 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
}
/**
- * Writes the complete contents of this byte string to
- * the specified output stream argument.
- *
- * <p>It is assumed that the {@link OutputStream} will not modify the contents passed it
- * it. It may be possible for a malicious {@link OutputStream} to corrupt
- * the data underlying the {@link ByteString}.
+ * Writes a copy of the contents of this byte string to the specified output stream argument.
*
* @param out the output stream to which to write the data.
* @throws IOException if an I/O error occurs.
@@ -578,8 +648,7 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
* @param sourceOffset offset within these bytes
* @param numberToWrite number of bytes to write
* @throws IOException if an I/O error occurs.
- * @throws IndexOutOfBoundsException if an offset or size is negative or too
- * large
+ * @throws IndexOutOfBoundsException if an offset or size is negative or too large
*/
final void writeTo(OutputStream out, int sourceOffset, int numberToWrite)
throws IOException {
@@ -597,6 +666,20 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
throws IOException;
/**
+ * Writes this {@link ByteString} to the provided {@link ByteOutput}. Calling
+ * this method may result in multiple operations on the target {@link ByteOutput}.
+ *
+ * <p>This method may expose internal backing buffers of the {@link ByteString} to the {@link
+ * ByteOutput} in order to avoid additional copying overhead. It would be possible for a malicious
+ * {@link ByteOutput} to corrupt the {@link ByteString}. Use with caution!
+ *
+ * @param byteOutput the output target to receive the bytes
+ * @throws IOException if an I/O error occurs
+ * @see UnsafeByteOperations#unsafeWriteTo(ByteString, ByteOutput)
+ */
+ abstract void writeTo(ByteOutput byteOutput) throws IOException;
+
+ /**
* Constructs a read-only {@code java.nio.ByteBuffer} whose content
* is equal to the contents of this byte string.
* The result uses the same backing array as the byte string, if possible.
@@ -1102,7 +1185,7 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
*
* @param index the index position to be tested
* @param size the length of the array
- * @throws ArrayIndexOutOfBoundsException if the index does not fall within the array.
+ * @throws IndexOutOfBoundsException if the index does not fall within the array.
*/
static void checkIndex(int index, int size) {
if ((index | (size - (index + 1))) < 0) {
@@ -1120,7 +1203,7 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
* @param endIndex the end index of the range (exclusive)
* @param size the size of the array.
* @return the length of the range.
- * @throws ArrayIndexOutOfBoundsException some or all of the range falls outside of the array.
+ * @throws IndexOutOfBoundsException some or all of the range falls outside of the array.
*/
static int checkRange(int startIndex, int endIndex, int size) {
final int length = endIndex - startIndex;
@@ -1236,6 +1319,11 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
}
@Override
+ final void writeTo(ByteOutput output) throws IOException {
+ output.writeLazy(bytes, getOffsetIntoBytes(), size());
+ }
+
+ @Override
protected final String toStringInternal(Charset charset) {
return new String(bytes, getOffsetIntoBytes(), size(), charset);
}
diff --git a/java/core/src/main/java/com/google/protobuf/CodedInputStream.java b/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
index b3118ee0..e8860651 100644
--- a/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
+++ b/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
@@ -55,7 +55,14 @@ public final class CodedInputStream {
* Create a new CodedInputStream wrapping the given InputStream.
*/
public static CodedInputStream newInstance(final InputStream input) {
- return new CodedInputStream(input);
+ return new CodedInputStream(input, BUFFER_SIZE);
+ }
+
+ /**
+ * Create a new CodedInputStream wrapping the given InputStream.
+ */
+ static CodedInputStream newInstance(final InputStream input, int bufferSize) {
+ return new CodedInputStream(input, bufferSize);
}
/**
@@ -70,14 +77,14 @@ public final class CodedInputStream {
*/
public static CodedInputStream newInstance(final byte[] buf, final int off,
final int len) {
- return newInstance(buf, off, len, false);
+ return newInstance(buf, off, len, false /* bufferIsImmutable */);
}
-
+
/**
* Create a new CodedInputStream wrapping the given byte array slice.
*/
- public static CodedInputStream newInstance(final byte[] buf, final int off,
- final int len, boolean bufferIsImmutable) {
+ static CodedInputStream newInstance(
+ final byte[] buf, final int off, final int len, final boolean bufferIsImmutable) {
CodedInputStream result = new CodedInputStream(buf, off, len, bufferIsImmutable);
try {
// Some uses of CodedInputStream can be more efficient if they know
@@ -361,6 +368,11 @@ public final class CodedInputStream {
return result;
} else if (size == 0) {
return "";
+ } else if (size <= bufferSize) {
+ refillBuffer(size);
+ String result = new String(buffer, bufferPos, size, Internal.UTF_8);
+ bufferPos += size;
+ return result;
} else {
// Slow path: Build a byte array first then copy it.
return new String(readRawBytesSlowPath(size), Internal.UTF_8);
@@ -375,14 +387,21 @@ public final class CodedInputStream {
public String readStringRequireUtf8() throws IOException {
final int size = readRawVarint32();
final byte[] bytes;
- int pos = bufferPos;
- if (size <= (bufferSize - pos) && size > 0) {
+ final int oldPos = bufferPos;
+ final int pos;
+ if (size <= (bufferSize - oldPos) && size > 0) {
// Fast path: We already have the bytes in a contiguous buffer, so
// just copy directly from it.
bytes = buffer;
- bufferPos = pos + size;
+ bufferPos = oldPos + size;
+ pos = oldPos;
} else if (size == 0) {
return "";
+ } else if (size <= bufferSize) {
+ refillBuffer(size);
+ bytes = buffer;
+ pos = 0;
+ bufferPos = pos + size;
} else {
// Slow path: Build a byte array first then copy it.
bytes = readRawBytesSlowPath(size);
@@ -869,7 +888,8 @@ public final class CodedInputStream {
private static final int DEFAULT_SIZE_LIMIT = 64 << 20; // 64MB
private static final int BUFFER_SIZE = 4096;
- private CodedInputStream(final byte[] buffer, final int off, final int len, boolean bufferIsImmutable) {
+ private CodedInputStream(
+ final byte[] buffer, final int off, final int len, boolean bufferIsImmutable) {
this.buffer = buffer;
bufferSize = off + len;
bufferPos = off;
@@ -878,8 +898,8 @@ public final class CodedInputStream {
this.bufferIsImmutable = bufferIsImmutable;
}
- private CodedInputStream(final InputStream input) {
- buffer = new byte[BUFFER_SIZE];
+ private CodedInputStream(final InputStream input, int bufferSize) {
+ buffer = new byte[bufferSize];
bufferSize = 0;
bufferPos = 0;
totalBytesRetired = 0;
diff --git a/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java b/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
index d8ebad21..ad174d0f 100644
--- a/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
+++ b/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
@@ -30,11 +30,18 @@
package com.google.protobuf;
+import static java.lang.Math.max;
+
import com.google.protobuf.Utf8.UnpairedSurrogateException;
import java.io.IOException;
import java.io.OutputStream;
+import java.lang.reflect.Field;
+import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.security.AccessController;
+import java.security.PrivilegedExceptionAction;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -49,20 +56,22 @@ import java.util.logging.Logger;
* you are writing some other format of your own design, use the latter.
*
* <p>This class is totally unsynchronized.
- *
- * @author kneton@google.com Kenton Varda
*/
-public final class CodedOutputStream {
-
+public abstract class CodedOutputStream extends ByteOutput {
private static final Logger logger = Logger.getLogger(CodedOutputStream.class.getName());
+ private static final sun.misc.Unsafe UNSAFE = getUnsafe();
+ private static final boolean HAS_UNSAFE_ARRAY_OPERATIONS = supportsUnsafeArrayOperations();
+ private static final long ARRAY_BASE_OFFSET = byteArrayBaseOffset();
- // TODO(dweis): Consider migrating to a ByteBuffer.
- private final byte[] buffer;
- private final int limit;
- private int position;
- private int totalBytesWritten = 0;
+ private static final int FIXED_32_SIZE = 4;
+ private static final int FIXED_64_SIZE = 8;
+ private static final int MAX_VARINT_SIZE = 10;
- private final OutputStream output;
+ /**
+ * @deprecated Use {@link #computeFixed32SizeNoTag(int)} instead.
+ */
+ @Deprecated
+ public static final int LITTLE_ENDIAN_32_SIZE = FIXED_32_SIZE;
/**
* The buffer size used in {@link #newInstance(OutputStream)}.
@@ -77,40 +86,33 @@ public final class CodedOutputStream {
* CodedOutputStream.
*/
static int computePreferredBufferSize(int dataLength) {
- if (dataLength > DEFAULT_BUFFER_SIZE) return DEFAULT_BUFFER_SIZE;
+ if (dataLength > DEFAULT_BUFFER_SIZE) {
+ return DEFAULT_BUFFER_SIZE;
+ }
return dataLength;
}
- private CodedOutputStream(final byte[] buffer, final int offset,
- final int length) {
- output = null;
- this.buffer = buffer;
- position = offset;
- limit = offset + length;
- }
-
- private CodedOutputStream(final OutputStream output, final byte[] buffer) {
- this.output = output;
- this.buffer = buffer;
- position = 0;
- limit = buffer.length;
- }
-
/**
- * Create a new {@code CodedOutputStream} wrapping the given
- * {@code OutputStream}.
+ * Create a new {@code CodedOutputStream} wrapping the given {@code OutputStream}.
+ *
+ * <p> NOTE: The provided {@link OutputStream} <strong>MUST NOT</strong> retain access or
+ * modify the provided byte arrays. Doing so may result in corrupted data, which would be
+ * difficult to debug.
*/
public static CodedOutputStream newInstance(final OutputStream output) {
return newInstance(output, DEFAULT_BUFFER_SIZE);
}
/**
- * Create a new {@code CodedOutputStream} wrapping the given
- * {@code OutputStream} with a given buffer size.
+ * Create a new {@code CodedOutputStream} wrapping the given {@code OutputStream} with a given
+ * buffer size.
+ *
+ * <p> NOTE: The provided {@link OutputStream} <strong>MUST NOT</strong> retain access or
+ * modify the provided byte arrays. Doing so may result in corrupted data, which would be
+ * difficult to debug.
*/
- public static CodedOutputStream newInstance(final OutputStream output,
- final int bufferSize) {
- return new CodedOutputStream(output, new byte[bufferSize]);
+ public static CodedOutputStream newInstance(final OutputStream output, final int bufferSize) {
+ return new OutputStreamEncoder(output, bufferSize);
}
/**
@@ -131,149 +133,146 @@ public final class CodedOutputStream {
* array is faster than writing to an {@code OutputStream}. See also
* {@link ByteString#newCodedBuilder}.
*/
- public static CodedOutputStream newInstance(final byte[] flatArray,
- final int offset,
- final int length) {
- return new CodedOutputStream(flatArray, offset, length);
+ public static CodedOutputStream newInstance(
+ final byte[] flatArray, final int offset, final int length) {
+ return new ArrayEncoder(flatArray, offset, length);
}
/**
- * Create a new {@code CodedOutputStream} that writes to the given ByteBuffer.
+ * Create a new {@code CodedOutputStream} that writes to the given {@link ByteBuffer}.
*/
public static CodedOutputStream newInstance(ByteBuffer byteBuffer) {
- return newInstance(byteBuffer, DEFAULT_BUFFER_SIZE);
+ if (byteBuffer.hasArray()) {
+ return new NioHeapEncoder(byteBuffer);
+ }
+ return new NioEncoder(byteBuffer);
}
/**
- * Create a new {@code CodedOutputStream} that writes to the given ByteBuffer.
+ * Create a new {@code CodedOutputStream} that writes to the given {@link ByteBuffer}.
+ *
+ * @deprecated the size parameter is no longer used since use of an internal buffer is useless
+ * (and wasteful) when writing to a {@link ByteBuffer}. Use {@link #newInstance(ByteBuffer)}
+ * instead.
*/
+ @Deprecated
public static CodedOutputStream newInstance(ByteBuffer byteBuffer,
- int bufferSize) {
- return newInstance(new ByteBufferOutputStream(byteBuffer), bufferSize);
+ @SuppressWarnings("unused") int unused) {
+ return newInstance(byteBuffer);
}
- private static class ByteBufferOutputStream extends OutputStream {
- private final ByteBuffer byteBuffer;
- public ByteBufferOutputStream(ByteBuffer byteBuffer) {
- this.byteBuffer = byteBuffer;
+ /**
+ * Create a new {@code CodedOutputStream} that writes to the provided {@link ByteOutput}.
+ *
+ * <p> NOTE: The {@link ByteOutput} <strong>MUST NOT</strong> modify the provided buffers. Doing
+ * so may result in corrupted data, which would be difficult to debug.
+ *
+ * @param byteOutput the output target for encoded bytes.
+ * @param bufferSize the size of the internal scratch buffer to be used for string encoding.
+ * Setting this to {@code 0} will disable buffering, requiring an allocation for each encoded
+ * string.
+ */
+ static CodedOutputStream newInstance(ByteOutput byteOutput, int bufferSize) {
+ if (bufferSize < 0) {
+ throw new IllegalArgumentException("bufferSize must be positive");
}
- @Override
- public void write(int b) throws IOException {
- byteBuffer.put((byte) b);
- }
+ return new ByteOutputEncoder(byteOutput, bufferSize);
+ }
- @Override
- public void write(byte[] data, int offset, int length) throws IOException {
- byteBuffer.put(data, offset, length);
- }
+ // Disallow construction outside of this class.
+ private CodedOutputStream() {
}
// -----------------------------------------------------------------
- /** Write a {@code double} field, including tag, to the stream. */
- public void writeDouble(final int fieldNumber, final double value)
- throws IOException {
- writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
- writeDoubleNoTag(value);
- }
+ /** Encode and write a tag. */
+ // Abstract to avoid overhead of additional virtual method calls.
+ public abstract void writeTag(int fieldNumber, int wireType) throws IOException;
- /** Write a {@code float} field, including tag, to the stream. */
- public void writeFloat(final int fieldNumber, final float value)
- throws IOException {
- writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
- writeFloatNoTag(value);
+ /** Write an {@code int32} field, including tag, to the stream. */
+ // Abstract to avoid overhead of additional virtual method calls.
+ public abstract void writeInt32(int fieldNumber, int value) throws IOException;
+
+ /** Write a {@code uint32} field, including tag, to the stream. */
+ // Abstract to avoid overhead of additional virtual method calls.
+ public abstract void writeUInt32(int fieldNumber, int value) throws IOException;
+
+ /** Write a {@code sint32} field, including tag, to the stream. */
+ public final void writeSInt32(final int fieldNumber, final int value) throws IOException {
+ writeUInt32(fieldNumber, encodeZigZag32(value));
}
- /** Write a {@code uint64} field, including tag, to the stream. */
- public void writeUInt64(final int fieldNumber, final long value)
- throws IOException {
- writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
- writeUInt64NoTag(value);
+ /** Write a {@code fixed32} field, including tag, to the stream. */
+ // Abstract to avoid overhead of additional virtual method calls.
+ public abstract void writeFixed32(int fieldNumber, int value) throws IOException;
+
+ /** Write an {@code sfixed32} field, including tag, to the stream. */
+ public final void writeSFixed32(final int fieldNumber, final int value) throws IOException {
+ writeFixed32(fieldNumber, value);
}
/** Write an {@code int64} field, including tag, to the stream. */
- public void writeInt64(final int fieldNumber, final long value)
- throws IOException {
- writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
- writeInt64NoTag(value);
+ public final void writeInt64(final int fieldNumber, final long value) throws IOException {
+ writeUInt64(fieldNumber, value);
}
- /** Write an {@code int32} field, including tag, to the stream. */
- public void writeInt32(final int fieldNumber, final int value)
- throws IOException {
- writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
- writeInt32NoTag(value);
- }
+ /** Write a {@code uint64} field, including tag, to the stream. */
+ // Abstract to avoid overhead of additional virtual method calls.
+ public abstract void writeUInt64(int fieldNumber, long value) throws IOException;
- /** Write a {@code fixed64} field, including tag, to the stream. */
- public void writeFixed64(final int fieldNumber, final long value)
- throws IOException {
- writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
- writeFixed64NoTag(value);
+ /** Write an {@code sint64} field, including tag, to the stream. */
+ public final void writeSInt64(final int fieldNumber, final long value) throws IOException {
+ writeUInt64(fieldNumber, encodeZigZag64(value));
}
- /** Write a {@code fixed32} field, including tag, to the stream. */
- public void writeFixed32(final int fieldNumber, final int value)
- throws IOException {
- writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
- writeFixed32NoTag(value);
- }
+ /** Write a {@code fixed64} field, including tag, to the stream. */
+ // Abstract to avoid overhead of additional virtual method calls.
+ public abstract void writeFixed64(int fieldNumber, long value) throws IOException;
- /** Write a {@code bool} field, including tag, to the stream. */
- public void writeBool(final int fieldNumber, final boolean value)
- throws IOException {
- writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
- writeBoolNoTag(value);
+ /** Write an {@code sfixed64} field, including tag, to the stream. */
+ public final void writeSFixed64(final int fieldNumber, final long value) throws IOException {
+ writeFixed64(fieldNumber, value);
}
- /** Write a {@code string} field, including tag, to the stream. */
- public void writeString(final int fieldNumber, final String value)
- throws IOException {
- writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
- writeStringNoTag(value);
+ /** Write a {@code float} field, including tag, to the stream. */
+ public final void writeFloat(final int fieldNumber, final float value) throws IOException {
+ writeFixed32(fieldNumber, Float.floatToRawIntBits(value));
}
- /** Write a {@code group} field, including tag, to the stream. */
- public void writeGroup(final int fieldNumber, final MessageLite value)
- throws IOException {
- writeTag(fieldNumber, WireFormat.WIRETYPE_START_GROUP);
- writeGroupNoTag(value);
- writeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP);
+ /** Write a {@code double} field, including tag, to the stream. */
+ public final void writeDouble(final int fieldNumber, final double value) throws IOException {
+ writeFixed64(fieldNumber, Double.doubleToRawLongBits(value));
}
+ /** Write a {@code bool} field, including tag, to the stream. */
+ // Abstract to avoid overhead of additional virtual method calls.
+ public abstract void writeBool(int fieldNumber, boolean value) throws IOException;
- /** Write an embedded message field, including tag, to the stream. */
- public void writeMessage(final int fieldNumber, final MessageLite value)
- throws IOException {
- writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
- writeMessageNoTag(value);
+ /**
+ * Write an enum field, including tag, to the stream. The provided value is the numeric
+ * value used to represent the enum value on the wire (not the enum ordinal value).
+ */
+ public final void writeEnum(final int fieldNumber, final int value) throws IOException {
+ writeInt32(fieldNumber, value);
}
+ /** Write a {@code string} field, including tag, to the stream. */
+ // Abstract to avoid overhead of additional virtual method calls.
+ public abstract void writeString(int fieldNumber, String value) throws IOException;
/** Write a {@code bytes} field, including tag, to the stream. */
- public void writeBytes(final int fieldNumber, final ByteString value)
- throws IOException {
- writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
- writeBytesNoTag(value);
- }
+ // Abstract to avoid overhead of additional virtual method calls.
+ public abstract void writeBytes(int fieldNumber, ByteString value) throws IOException;
/** Write a {@code bytes} field, including tag, to the stream. */
- public void writeByteArray(final int fieldNumber, final byte[] value)
- throws IOException {
- writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
- writeByteArrayNoTag(value);
- }
+ // Abstract to avoid overhead of additional virtual method calls.
+ public abstract void writeByteArray(int fieldNumber, byte[] value) throws IOException;
/** Write a {@code bytes} field, including tag, to the stream. */
- public void writeByteArray(final int fieldNumber,
- final byte[] value,
- final int offset,
- final int length)
- throws IOException {
- writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
- writeByteArrayNoTag(value, offset, length);
- }
+ // Abstract to avoid overhead of additional virtual method calls.
+ public abstract void writeByteArray(int fieldNumber, byte[] value, int offset, int length)
+ throws IOException;
/**
* Write a {@code bytes} field, including tag, to the stream.
@@ -285,317 +284,221 @@ public final class CodedOutputStream {
* of a ByteBuffer, you can call
* {@code writeByteBuffer(fieldNumber, byteBuffer.slice())}.
*/
- public void writeByteBuffer(final int fieldNumber, final ByteBuffer value)
- throws IOException {
- writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
- writeByteBufferNoTag(value);
- }
-
- /** Write a {@code uint32} field, including tag, to the stream. */
- public void writeUInt32(final int fieldNumber, final int value)
- throws IOException {
- writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
- writeUInt32NoTag(value);
- }
+ // Abstract to avoid overhead of additional virtual method calls.
+ public abstract void writeByteBuffer(int fieldNumber, ByteBuffer value) throws IOException;
/**
- * Write an enum field, including tag, to the stream. Caller is responsible
- * for converting the enum value to its numeric value.
+ * Write a single byte.
*/
- public void writeEnum(final int fieldNumber, final int value)
- throws IOException {
- writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
- writeEnumNoTag(value);
+ public final void writeRawByte(final byte value) throws IOException {
+ write(value);
}
- /** Write an {@code sfixed32} field, including tag, to the stream. */
- public void writeSFixed32(final int fieldNumber, final int value)
- throws IOException {
- writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
- writeSFixed32NoTag(value);
+ /** Write a single byte, represented by an integer value. */
+ public final void writeRawByte(final int value) throws IOException {
+ write((byte) value);
}
- /** Write an {@code sfixed64} field, including tag, to the stream. */
- public void writeSFixed64(final int fieldNumber, final long value)
- throws IOException {
- writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
- writeSFixed64NoTag(value);
+ /** Write an array of bytes. */
+ public final void writeRawBytes(final byte[] value) throws IOException {
+ write(value, 0, value.length);
}
- /** Write an {@code sint32} field, including tag, to the stream. */
- public void writeSInt32(final int fieldNumber, final int value)
- throws IOException {
- writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
- writeSInt32NoTag(value);
+ /**
+ * Write part of an array of bytes.
+ */
+ public final void writeRawBytes(final byte[] value, int offset, int length) throws IOException {
+ write(value, offset, length);
}
- /** Write an {@code sint64} field, including tag, to the stream. */
- public void writeSInt64(final int fieldNumber, final long value)
- throws IOException {
- writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
- writeSInt64NoTag(value);
+ /** Write a byte string. */
+ public final void writeRawBytes(final ByteString value) throws IOException {
+ value.writeTo(this);
}
/**
+ * Write a ByteBuffer. This method will write all content of the ByteBuffer
+ * regardless of the current position and limit (i.e., the number of bytes
+ * to be written is value.capacity(), not value.remaining()). Furthermore,
+ * this method doesn't alter the state of the passed-in ByteBuffer. Its
+ * position, limit, mark, etc. will remain unchanged. If you only want to
+ * write the remaining bytes of a ByteBuffer, you can call
+ * {@code writeRawBytes(byteBuffer.slice())}.
+ */
+ // Abstract to avoid overhead of additional virtual method calls.
+ public abstract void writeRawBytes(final ByteBuffer value) throws IOException;
+
+ /** Write an embedded message field, including tag, to the stream. */
+ // Abstract to avoid overhead of additional virtual method calls.
+ public abstract void writeMessage(final int fieldNumber, final MessageLite value)
+ throws IOException;
+
+ /**
* Write a MessageSet extension field to the stream. For historical reasons,
* the wire format differs from normal fields.
*/
- public void writeMessageSetExtension(final int fieldNumber,
- final MessageLite value)
- throws IOException {
- writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
- writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
- writeMessage(WireFormat.MESSAGE_SET_MESSAGE, value);
- writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
- }
+ // Abstract to avoid overhead of additional virtual method calls.
+ public abstract void writeMessageSetExtension(final int fieldNumber, final MessageLite value)
+ throws IOException;
/**
* Write an unparsed MessageSet extension field to the stream. For
* historical reasons, the wire format differs from normal fields.
*/
- public void writeRawMessageSetExtension(final int fieldNumber,
- final ByteString value)
- throws IOException {
- writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
- writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
- writeBytes(WireFormat.MESSAGE_SET_MESSAGE, value);
- writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
- }
+ // Abstract to avoid overhead of additional virtual method calls.
+ public abstract void writeRawMessageSetExtension(final int fieldNumber, final ByteString value)
+ throws IOException;
// -----------------------------------------------------------------
- /** Write a {@code double} field to the stream. */
- public void writeDoubleNoTag(final double value) throws IOException {
- writeRawLittleEndian64(Double.doubleToRawLongBits(value));
- }
+ /** Write an {@code int32} field to the stream. */
+ // Abstract to avoid overhead of additional virtual method calls.
+ public abstract void writeInt32NoTag(final int value) throws IOException;
- /** Write a {@code float} field to the stream. */
- public void writeFloatNoTag(final float value) throws IOException {
- writeRawLittleEndian32(Float.floatToRawIntBits(value));
+ /** Write a {@code uint32} field to the stream. */
+ // Abstract to avoid overhead of additional virtual method calls.
+ public abstract void writeUInt32NoTag(int value) throws IOException;
+
+ /** Write a {@code sint32} field to the stream. */
+ public final void writeSInt32NoTag(final int value) throws IOException {
+ writeUInt32NoTag(encodeZigZag32(value));
}
- /** Write a {@code uint64} field to the stream. */
- public void writeUInt64NoTag(final long value) throws IOException {
- writeRawVarint64(value);
+ /** Write a {@code fixed32} field to the stream. */
+ // Abstract to avoid overhead of additional virtual method calls.
+ public abstract void writeFixed32NoTag(int value) throws IOException;
+
+ /** Write a {@code sfixed32} field to the stream. */
+ public final void writeSFixed32NoTag(final int value) throws IOException {
+ writeFixed32NoTag(value);
}
/** Write an {@code int64} field to the stream. */
- public void writeInt64NoTag(final long value) throws IOException {
- writeRawVarint64(value);
+ public final void writeInt64NoTag(final long value) throws IOException {
+ writeUInt64NoTag(value);
}
- /** Write an {@code int32} field to the stream. */
- public void writeInt32NoTag(final int value) throws IOException {
- if (value >= 0) {
- writeRawVarint32(value);
- } else {
- // Must sign-extend.
- writeRawVarint64(value);
- }
+ /** Write a {@code uint64} field to the stream. */
+ // Abstract to avoid overhead of additional virtual method calls.
+ public abstract void writeUInt64NoTag(long value) throws IOException;
+
+ /** Write a {@code sint64} field to the stream. */
+ public final void writeSInt64NoTag(final long value) throws IOException {
+ writeUInt64NoTag(encodeZigZag64(value));
}
/** Write a {@code fixed64} field to the stream. */
- public void writeFixed64NoTag(final long value) throws IOException {
- writeRawLittleEndian64(value);
- }
+ // Abstract to avoid overhead of additional virtual method calls.
+ public abstract void writeFixed64NoTag(long value) throws IOException;
- /** Write a {@code fixed32} field to the stream. */
- public void writeFixed32NoTag(final int value) throws IOException {
- writeRawLittleEndian32(value);
+ /** Write a {@code sfixed64} field to the stream. */
+ public final void writeSFixed64NoTag(final long value) throws IOException {
+ writeFixed64NoTag(value);
}
- /** Write a {@code bool} field to the stream. */
- public void writeBoolNoTag(final boolean value) throws IOException {
- writeRawByte(value ? 1 : 0);
+ /** Write a {@code float} field to the stream. */
+ public final void writeFloatNoTag(final float value) throws IOException {
+ writeFixed32NoTag(Float.floatToRawIntBits(value));
}
- /** Write a {@code string} field to the stream. */
- // TODO(dweis): Document behavior on ill-formed UTF-16 input.
- public void writeStringNoTag(final String value) throws IOException {
- try {
- efficientWriteStringNoTag(value);
- } catch (UnpairedSurrogateException e) {
- logger.log(Level.WARNING,
- "Converting ill-formed UTF-16. Your Protocol Buffer will not round trip correctly!", e);
- inefficientWriteStringNoTag(value);
- }
+ /** Write a {@code double} field to the stream. */
+ public final void writeDoubleNoTag(final double value) throws IOException {
+ writeFixed64NoTag(Double.doubleToRawLongBits(value));
}
- /** Write a {@code string} field to the stream. */
- private void inefficientWriteStringNoTag(final String value) throws IOException {
- // Unfortunately there does not appear to be any way to tell Java to encode
- // UTF-8 directly into our buffer, so we have to let it create its own byte
- // array and then copy.
- // TODO(dweis): Consider using nio Charset methods instead.
- final byte[] bytes = value.getBytes(Internal.UTF_8);
- writeRawVarint32(bytes.length);
- writeRawBytes(bytes);
+ /** Write a {@code bool} field to the stream. */
+ public final void writeBoolNoTag(final boolean value) throws IOException {
+ write((byte) (value ? 1 : 0));
}
/**
- * Write a {@code string} field to the stream efficiently. If the {@code string} is malformed,
- * this method rolls back its changes and throws an {@link UnpairedSurrogateException} with the
- * intent that the caller will catch and retry with {@link #inefficientWriteStringNoTag(String)}.
- *
- * @param value the string to write to the stream
- *
- * @throws UnpairedSurrogateException when {@code value} is ill-formed UTF-16.
- */
- private void efficientWriteStringNoTag(final String value) throws IOException {
- // UTF-8 byte length of the string is at least its UTF-16 code unit length (value.length()),
- // and at most 3 times of it. We take advantage of this in both branches below.
- final int maxLength = value.length() * Utf8.MAX_BYTES_PER_CHAR;
- final int maxLengthVarIntSize = computeRawVarint32Size(maxLength);
-
- // If we are streaming and the potential length is too big to fit in our buffer, we take the
- // slower path. Otherwise, we're good to try the fast path.
- if (output != null && maxLengthVarIntSize + maxLength > limit - position) {
- // Allocate a byte[] that we know can fit the string and encode into it. String.getBytes()
- // does the same internally and then does *another copy* to return a byte[] of exactly the
- // right size. We can skip that copy and just writeRawBytes up to the actualLength of the
- // UTF-8 encoded bytes.
- final byte[] encodedBytes = new byte[maxLength];
- int actualLength = Utf8.encode(value, encodedBytes, 0, maxLength);
- writeRawVarint32(actualLength);
- writeRawBytes(encodedBytes, 0, actualLength);
- } else {
- // Optimize for the case where we know this length results in a constant varint length as this
- // saves a pass for measuring the length of the string.
- final int minLengthVarIntSize = computeRawVarint32Size(value.length());
- int oldPosition = position;
- final int length;
- try {
- if (minLengthVarIntSize == maxLengthVarIntSize) {
- position = oldPosition + minLengthVarIntSize;
- int newPosition = Utf8.encode(value, buffer, position, limit - position);
- // Since this class is stateful and tracks the position, we rewind and store the state,
- // prepend the length, then reset it back to the end of the string.
- position = oldPosition;
- length = newPosition - oldPosition - minLengthVarIntSize;
- writeRawVarint32(length);
- position = newPosition;
- } else {
- length = Utf8.encodedLength(value);
- writeRawVarint32(length);
- position = Utf8.encode(value, buffer, position, limit - position);
- }
- } catch (UnpairedSurrogateException e) {
- // Be extra careful and restore the original position for retrying the write with the less
- // efficient path.
- position = oldPosition;
- throw e;
- } catch (ArrayIndexOutOfBoundsException e) {
- throw new OutOfSpaceException(e);
- }
- totalBytesWritten += length;
- }
- }
-
- /** Write a {@code group} field to the stream. */
- public void writeGroupNoTag(final MessageLite value) throws IOException {
- value.writeTo(this);
- }
-
-
- /** Write an embedded message field to the stream. */
- public void writeMessageNoTag(final MessageLite value) throws IOException {
- writeRawVarint32(value.getSerializedSize());
- value.writeTo(this);
+ * Write an enum field to the stream. The provided value is the numeric
+ * value used to represent the enum value on the wire (not the enum ordinal value).
+ */
+ public final void writeEnumNoTag(final int value) throws IOException {
+ writeInt32NoTag(value);
}
+ /** Write a {@code string} field to the stream. */
+ // TODO(dweis): Document behavior on ill-formed UTF-16 input.
+ // Abstract to avoid overhead of additional virtual method calls.
+ public abstract void writeStringNoTag(String value) throws IOException;
/** Write a {@code bytes} field to the stream. */
- public void writeBytesNoTag(final ByteString value) throws IOException {
- writeRawVarint32(value.size());
- writeRawBytes(value);
- }
-
- /** Write a {@code bytes} field to the stream. */
- public void writeByteArrayNoTag(final byte[] value) throws IOException {
- writeRawVarint32(value.length);
- writeRawBytes(value);
- }
+ // Abstract to avoid overhead of additional virtual method calls.
+ public abstract void writeBytesNoTag(final ByteString value) throws IOException;
/** Write a {@code bytes} field to the stream. */
- public void writeByteArrayNoTag(final byte[] value,
- final int offset,
- final int length) throws IOException {
- writeRawVarint32(length);
- writeRawBytes(value, offset, length);
+ public final void writeByteArrayNoTag(final byte[] value) throws IOException {
+ writeByteArrayNoTag(value, 0, value.length);
}
- /**
- * Write a {@code bytes} field to the stream. This method will write all
- * content of the ByteBuffer regardless of the current position and limit
- * (i.e., the number of bytes to be written is value.capacity(), not
- * value.remaining()). Furthermore, this method doesn't alter the state of
- * the passed-in ByteBuffer. Its position, limit, mark, etc. will remain
- * unchanged. If you only want to write the remaining bytes of a ByteBuffer,
- * you can call {@code writeByteBufferNoTag(byteBuffer.slice())}.
- */
- public void writeByteBufferNoTag(final ByteBuffer value) throws IOException {
- writeRawVarint32(value.capacity());
- writeRawBytes(value);
- }
+ /** Write an embedded message field to the stream. */
+ // Abstract to avoid overhead of additional virtual method calls.
+ public abstract void writeMessageNoTag(final MessageLite value) throws IOException;
- /** Write a {@code uint32} field to the stream. */
- public void writeUInt32NoTag(final int value) throws IOException {
- writeRawVarint32(value);
- }
+ //=================================================================
- /**
- * Write an enum field to the stream. Caller is responsible
- * for converting the enum value to its numeric value.
- */
- public void writeEnumNoTag(final int value) throws IOException {
- writeInt32NoTag(value);
- }
+ @ExperimentalApi
+ @Override
+ public abstract void write(byte value) throws IOException;
- /** Write an {@code sfixed32} field to the stream. */
- public void writeSFixed32NoTag(final int value) throws IOException {
- writeRawLittleEndian32(value);
- }
+ @ExperimentalApi
+ @Override
+ public abstract void write(byte[] value, int offset, int length) throws IOException;
- /** Write an {@code sfixed64} field to the stream. */
- public void writeSFixed64NoTag(final long value) throws IOException {
- writeRawLittleEndian64(value);
- }
+ @ExperimentalApi
+ @Override
+ public abstract void writeLazy(byte[] value, int offset, int length) throws IOException;
- /** Write an {@code sint32} field to the stream. */
- public void writeSInt32NoTag(final int value) throws IOException {
- writeRawVarint32(encodeZigZag32(value));
- }
+ @Override
+ public abstract void write(ByteBuffer value) throws IOException;
- /** Write an {@code sint64} field to the stream. */
- public void writeSInt64NoTag(final long value) throws IOException {
- writeRawVarint64(encodeZigZag64(value));
- }
+ @ExperimentalApi
+ @Override
+ public abstract void writeLazy(ByteBuffer value) throws IOException;
// =================================================================
+ // =================================================================
/**
- * Compute the number of bytes that would be needed to encode a
- * {@code double} field, including tag.
+ * Compute the number of bytes that would be needed to encode an
+ * {@code int32} field, including tag.
*/
- public static int computeDoubleSize(final int fieldNumber,
- final double value) {
- return computeTagSize(fieldNumber) + computeDoubleSizeNoTag(value);
+ public static int computeInt32Size(final int fieldNumber, final int value) {
+ return computeTagSize(fieldNumber) + computeInt32SizeNoTag(value);
}
/**
* Compute the number of bytes that would be needed to encode a
- * {@code float} field, including tag.
+ * {@code uint32} field, including tag.
*/
- public static int computeFloatSize(final int fieldNumber, final float value) {
- return computeTagSize(fieldNumber) + computeFloatSizeNoTag(value);
+ public static int computeUInt32Size(final int fieldNumber, final int value) {
+ return computeTagSize(fieldNumber) + computeUInt32SizeNoTag(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an
+ * {@code sint32} field, including tag.
+ */
+ public static int computeSInt32Size(final int fieldNumber, final int value) {
+ return computeTagSize(fieldNumber) + computeSInt32SizeNoTag(value);
}
/**
* Compute the number of bytes that would be needed to encode a
- * {@code uint64} field, including tag.
+ * {@code fixed32} field, including tag.
*/
- public static int computeUInt64Size(final int fieldNumber, final long value) {
- return computeTagSize(fieldNumber) + computeUInt64SizeNoTag(value);
+ public static int computeFixed32Size(final int fieldNumber, final int value) {
+ return computeTagSize(fieldNumber) + computeFixed32SizeNoTag(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an
+ * {@code sfixed32} field, including tag.
+ */
+ public static int computeSFixed32Size(final int fieldNumber, final int value) {
+ return computeTagSize(fieldNumber) + computeSFixed32SizeNoTag(value);
}
/**
@@ -607,73 +510,83 @@ public final class CodedOutputStream {
}
/**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code uint64} field, including tag.
+ */
+ public static int computeUInt64Size(final int fieldNumber, final long value) {
+ return computeTagSize(fieldNumber) + computeUInt64SizeNoTag(value);
+ }
+
+ /**
* Compute the number of bytes that would be needed to encode an
- * {@code int32} field, including tag.
+ * {@code sint64} field, including tag.
*/
- public static int computeInt32Size(final int fieldNumber, final int value) {
- return computeTagSize(fieldNumber) + computeInt32SizeNoTag(value);
+ public static int computeSInt64Size(final int fieldNumber, final long value) {
+ return computeTagSize(fieldNumber) + computeSInt64SizeNoTag(value);
}
/**
* Compute the number of bytes that would be needed to encode a
* {@code fixed64} field, including tag.
*/
- public static int computeFixed64Size(final int fieldNumber,
- final long value) {
+ public static int computeFixed64Size(final int fieldNumber, final long value) {
return computeTagSize(fieldNumber) + computeFixed64SizeNoTag(value);
}
/**
- * Compute the number of bytes that would be needed to encode a
- * {@code fixed32} field, including tag.
+ * Compute the number of bytes that would be needed to encode an
+ * {@code sfixed64} field, including tag.
*/
- public static int computeFixed32Size(final int fieldNumber,
- final int value) {
- return computeTagSize(fieldNumber) + computeFixed32SizeNoTag(value);
+ public static int computeSFixed64Size(final int fieldNumber, final long value) {
+ return computeTagSize(fieldNumber) + computeSFixed64SizeNoTag(value);
}
/**
* Compute the number of bytes that would be needed to encode a
- * {@code bool} field, including tag.
+ * {@code float} field, including tag.
*/
- public static int computeBoolSize(final int fieldNumber,
- final boolean value) {
- return computeTagSize(fieldNumber) + computeBoolSizeNoTag(value);
+ public static int computeFloatSize(final int fieldNumber, final float value) {
+ return computeTagSize(fieldNumber) + computeFloatSizeNoTag(value);
}
/**
* Compute the number of bytes that would be needed to encode a
- * {@code string} field, including tag.
+ * {@code double} field, including tag.
*/
- public static int computeStringSize(final int fieldNumber,
- final String value) {
- return computeTagSize(fieldNumber) + computeStringSizeNoTag(value);
+ public static int computeDoubleSize(final int fieldNumber, final double value) {
+ return computeTagSize(fieldNumber) + computeDoubleSizeNoTag(value);
}
/**
* Compute the number of bytes that would be needed to encode a
- * {@code group} field, including tag.
+ * {@code bool} field, including tag.
*/
- public static int computeGroupSize(final int fieldNumber,
- final MessageLite value) {
- return computeTagSize(fieldNumber) * 2 + computeGroupSizeNoTag(value);
+ public static int computeBoolSize(final int fieldNumber, final boolean value) {
+ return computeTagSize(fieldNumber) + computeBoolSizeNoTag(value);
}
/**
* Compute the number of bytes that would be needed to encode an
- * embedded message field, including tag.
+ * enum field, including tag. The provided value is the numeric
+ * value used to represent the enum value on the wire (not the enum ordinal value).
*/
- public static int computeMessageSize(final int fieldNumber,
- final MessageLite value) {
- return computeTagSize(fieldNumber) + computeMessageSizeNoTag(value);
+ public static int computeEnumSize(final int fieldNumber, final int value) {
+ return computeTagSize(fieldNumber) + computeEnumSizeNoTag(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code string} field, including tag.
+ */
+ public static int computeStringSize(final int fieldNumber, final String value) {
+ return computeTagSize(fieldNumber) + computeStringSizeNoTag(value);
}
/**
* Compute the number of bytes that would be needed to encode a
* {@code bytes} field, including tag.
*/
- public static int computeBytesSize(final int fieldNumber,
- final ByteString value) {
+ public static int computeBytesSize(final int fieldNumber, final ByteString value) {
return computeTagSize(fieldNumber) + computeBytesSizeNoTag(value);
}
@@ -681,8 +594,7 @@ public final class CodedOutputStream {
* Compute the number of bytes that would be needed to encode a
* {@code bytes} field, including tag.
*/
- public static int computeByteArraySize(final int fieldNumber,
- final byte[] value) {
+ public static int computeByteArraySize(final int fieldNumber, final byte[] value) {
return computeTagSize(fieldNumber) + computeByteArraySizeNoTag(value);
}
@@ -690,8 +602,7 @@ public final class CodedOutputStream {
* Compute the number of bytes that would be needed to encode a
* {@code bytes} field, including tag.
*/
- public static int computeByteBufferSize(final int fieldNumber,
- final ByteBuffer value) {
+ public static int computeByteBufferSize(final int fieldNumber, final ByteBuffer value) {
return computeTagSize(fieldNumber) + computeByteBufferSizeNoTag(value);
}
@@ -699,167 +610,206 @@ public final class CodedOutputStream {
* Compute the number of bytes that would be needed to encode an
* embedded message in lazy field, including tag.
*/
- public static int computeLazyFieldSize(final int fieldNumber,
- final LazyFieldLite value) {
+ public static int computeLazyFieldSize(final int fieldNumber, final LazyFieldLite value) {
return computeTagSize(fieldNumber) + computeLazyFieldSizeNoTag(value);
}
/**
+ * Compute the number of bytes that would be needed to encode an
+ * embedded message field, including tag.
+ */
+ public static int computeMessageSize(final int fieldNumber, final MessageLite value) {
+ return computeTagSize(fieldNumber) + computeMessageSizeNoTag(value);
+ }
+
+ /**
* Compute the number of bytes that would be needed to encode a
- * {@code uint32} field, including tag.
+ * MessageSet extension to the stream. For historical reasons,
+ * the wire format differs from normal fields.
*/
- public static int computeUInt32Size(final int fieldNumber, final int value) {
- return computeTagSize(fieldNumber) + computeUInt32SizeNoTag(value);
+ public static int computeMessageSetExtensionSize(final int fieldNumber, final MessageLite value) {
+ return computeTagSize(WireFormat.MESSAGE_SET_ITEM) * 2
+ + computeUInt32Size(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber)
+ + computeMessageSize(WireFormat.MESSAGE_SET_MESSAGE, value);
}
/**
* Compute the number of bytes that would be needed to encode an
- * enum field, including tag. Caller is responsible for converting the
- * enum value to its numeric value.
+ * unparsed MessageSet extension field to the stream. For
+ * historical reasons, the wire format differs from normal fields.
*/
- public static int computeEnumSize(final int fieldNumber, final int value) {
- return computeTagSize(fieldNumber) + computeEnumSizeNoTag(value);
+ public static int computeRawMessageSetExtensionSize(
+ final int fieldNumber, final ByteString value) {
+ return computeTagSize(WireFormat.MESSAGE_SET_ITEM) * 2
+ + computeUInt32Size(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber)
+ + computeBytesSize(WireFormat.MESSAGE_SET_MESSAGE, value);
}
/**
* Compute the number of bytes that would be needed to encode an
- * {@code sfixed32} field, including tag.
+ * lazily parsed MessageSet extension field to the stream. For
+ * historical reasons, the wire format differs from normal fields.
*/
- public static int computeSFixed32Size(final int fieldNumber,
- final int value) {
- return computeTagSize(fieldNumber) + computeSFixed32SizeNoTag(value);
+ public static int computeLazyFieldMessageSetExtensionSize(
+ final int fieldNumber, final LazyFieldLite value) {
+ return computeTagSize(WireFormat.MESSAGE_SET_ITEM) * 2
+ + computeUInt32Size(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber)
+ + computeLazyFieldSize(WireFormat.MESSAGE_SET_MESSAGE, value);
+ }
+
+ // -----------------------------------------------------------------
+
+ /** Compute the number of bytes that would be needed to encode a tag. */
+ public static int computeTagSize(final int fieldNumber) {
+ return computeUInt32SizeNoTag(WireFormat.makeTag(fieldNumber, 0));
}
/**
* Compute the number of bytes that would be needed to encode an
- * {@code sfixed64} field, including tag.
+ * {@code int32} field, including tag.
*/
- public static int computeSFixed64Size(final int fieldNumber,
- final long value) {
- return computeTagSize(fieldNumber) + computeSFixed64SizeNoTag(value);
+ public static int computeInt32SizeNoTag(final int value) {
+ if (value >= 0) {
+ return computeUInt32SizeNoTag(value);
+ } else {
+ // Must sign-extend.
+ return MAX_VARINT_SIZE;
+ }
}
/**
- * Compute the number of bytes that would be needed to encode an
- * {@code sint32} field, including tag.
+ * Compute the number of bytes that would be needed to encode a
+ * {@code uint32} field.
*/
- public static int computeSInt32Size(final int fieldNumber, final int value) {
- return computeTagSize(fieldNumber) + computeSInt32SizeNoTag(value);
+ public static int computeUInt32SizeNoTag(final int value) {
+ if ((value & (~0 << 7)) == 0) {
+ return 1;
+ }
+ if ((value & (~0 << 14)) == 0) {
+ return 2;
+ }
+ if ((value & (~0 << 21)) == 0) {
+ return 3;
+ }
+ if ((value & (~0 << 28)) == 0) {
+ return 4;
+ }
+ return 5;
}
/**
* Compute the number of bytes that would be needed to encode an
- * {@code sint64} field, including tag.
+ * {@code sint32} field.
*/
- public static int computeSInt64Size(final int fieldNumber, final long value) {
- return computeTagSize(fieldNumber) + computeSInt64SizeNoTag(value);
+ public static int computeSInt32SizeNoTag(final int value) {
+ return computeUInt32SizeNoTag(encodeZigZag32(value));
}
/**
* Compute the number of bytes that would be needed to encode a
- * MessageSet extension to the stream. For historical reasons,
- * the wire format differs from normal fields.
+ * {@code fixed32} field.
*/
- public static int computeMessageSetExtensionSize(
- final int fieldNumber, final MessageLite value) {
- return computeTagSize(WireFormat.MESSAGE_SET_ITEM) * 2 +
- computeUInt32Size(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber) +
- computeMessageSize(WireFormat.MESSAGE_SET_MESSAGE, value);
+ public static int computeFixed32SizeNoTag(@SuppressWarnings("unused") final int unused) {
+ return FIXED_32_SIZE;
}
/**
* Compute the number of bytes that would be needed to encode an
- * unparsed MessageSet extension field to the stream. For
- * historical reasons, the wire format differs from normal fields.
+ * {@code sfixed32} field.
*/
- public static int computeRawMessageSetExtensionSize(
- final int fieldNumber, final ByteString value) {
- return computeTagSize(WireFormat.MESSAGE_SET_ITEM) * 2 +
- computeUInt32Size(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber) +
- computeBytesSize(WireFormat.MESSAGE_SET_MESSAGE, value);
+ public static int computeSFixed32SizeNoTag(@SuppressWarnings("unused") final int unused) {
+ return FIXED_32_SIZE;
}
/**
* Compute the number of bytes that would be needed to encode an
- * lazily parsed MessageSet extension field to the stream. For
- * historical reasons, the wire format differs from normal fields.
+ * {@code int64} field, including tag.
*/
- public static int computeLazyFieldMessageSetExtensionSize(
- final int fieldNumber, final LazyFieldLite value) {
- return computeTagSize(WireFormat.MESSAGE_SET_ITEM) * 2 +
- computeUInt32Size(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber) +
- computeLazyFieldSize(WireFormat.MESSAGE_SET_MESSAGE, value);
+ public static int computeInt64SizeNoTag(final long value) {
+ return computeUInt64SizeNoTag(value);
}
- // -----------------------------------------------------------------
-
/**
* Compute the number of bytes that would be needed to encode a
- * {@code double} field, including tag.
+ * {@code uint64} field, including tag.
*/
- public static int computeDoubleSizeNoTag(final double value) {
- return LITTLE_ENDIAN_64_SIZE;
+ public static int computeUInt64SizeNoTag(long value) {
+ // handle two popular special cases up front ...
+ if ((value & (~0L << 7)) == 0L) {
+ return 1;
+ }
+ if (value < 0L) {
+ return 10;
+ }
+ // ... leaving us with 8 remaining, which we can divide and conquer
+ int n = 2;
+ if ((value & (~0L << 35)) != 0L) {
+ n += 4; value >>>= 28;
+ }
+ if ((value & (~0L << 21)) != 0L) {
+ n += 2; value >>>= 14;
+ }
+ if ((value & (~0L << 14)) != 0L) {
+ n += 1;
+ }
+ return n;
}
/**
- * Compute the number of bytes that would be needed to encode a
- * {@code float} field, including tag.
+ * Compute the number of bytes that would be needed to encode an
+ * {@code sint64} field.
*/
- public static int computeFloatSizeNoTag(final float value) {
- return LITTLE_ENDIAN_32_SIZE;
+ public static int computeSInt64SizeNoTag(final long value) {
+ return computeUInt64SizeNoTag(encodeZigZag64(value));
}
/**
* Compute the number of bytes that would be needed to encode a
- * {@code uint64} field, including tag.
+ * {@code fixed64} field.
*/
- public static int computeUInt64SizeNoTag(final long value) {
- return computeRawVarint64Size(value);
+ public static int computeFixed64SizeNoTag(@SuppressWarnings("unused") final long unused) {
+ return FIXED_64_SIZE;
}
/**
* Compute the number of bytes that would be needed to encode an
- * {@code int64} field, including tag.
+ * {@code sfixed64} field.
*/
- public static int computeInt64SizeNoTag(final long value) {
- return computeRawVarint64Size(value);
+ public static int computeSFixed64SizeNoTag(@SuppressWarnings("unused") final long unused) {
+ return FIXED_64_SIZE;
}
/**
- * Compute the number of bytes that would be needed to encode an
- * {@code int32} field, including tag.
+ * Compute the number of bytes that would be needed to encode a
+ * {@code float} field, including tag.
*/
- public static int computeInt32SizeNoTag(final int value) {
- if (value >= 0) {
- return computeRawVarint32Size(value);
- } else {
- // Must sign-extend.
- return 10;
- }
+ public static int computeFloatSizeNoTag(@SuppressWarnings("unused") final float unused) {
+ return FIXED_32_SIZE;
}
/**
* Compute the number of bytes that would be needed to encode a
- * {@code fixed64} field.
+ * {@code double} field, including tag.
*/
- public static int computeFixed64SizeNoTag(final long value) {
- return LITTLE_ENDIAN_64_SIZE;
+ public static int computeDoubleSizeNoTag(@SuppressWarnings("unused") final double unused) {
+ return FIXED_64_SIZE;
}
/**
* Compute the number of bytes that would be needed to encode a
- * {@code fixed32} field.
+ * {@code bool} field.
*/
- public static int computeFixed32SizeNoTag(final int value) {
- return LITTLE_ENDIAN_32_SIZE;
+ public static int computeBoolSizeNoTag(@SuppressWarnings("unused") final boolean unused) {
+ return 1;
}
/**
- * Compute the number of bytes that would be needed to encode a
- * {@code bool} field.
+ * Compute the number of bytes that would be needed to encode an enum field.
+ * The provided value is the numeric value used to represent the enum value on the wire
+ * (not the enum ordinal value).
*/
- public static int computeBoolSizeNoTag(final boolean value) {
- return 1;
+ public static int computeEnumSizeNoTag(final int value) {
+ return computeInt32SizeNoTag(value);
}
/**
@@ -876,24 +826,7 @@ public final class CodedOutputStream {
length = bytes.length;
}
- return computeRawVarint32Size(length) + length;
- }
-
- /**
- * Compute the number of bytes that would be needed to encode a
- * {@code group} field.
- */
- public static int computeGroupSizeNoTag(final MessageLite value) {
- return value.getSerializedSize();
- }
-
- /**
- * Compute the number of bytes that would be needed to encode an embedded
- * message field.
- */
- public static int computeMessageSizeNoTag(final MessageLite value) {
- final int size = value.getSerializedSize();
- return computeRawVarint32Size(size) + size;
+ return computeLengthDelimitedFieldSize(length);
}
/**
@@ -901,8 +834,7 @@ public final class CodedOutputStream {
* message stored in lazy field.
*/
public static int computeLazyFieldSizeNoTag(final LazyFieldLite value) {
- final int size = value.getSerializedSize();
- return computeRawVarint32Size(size) + size;
+ return computeLengthDelimitedFieldSize(value.getSerializedSize());
}
/**
@@ -910,8 +842,7 @@ public final class CodedOutputStream {
* {@code bytes} field.
*/
public static int computeBytesSizeNoTag(final ByteString value) {
- return computeRawVarint32Size(value.size()) +
- value.size();
+ return computeLengthDelimitedFieldSize(value.size());
}
/**
@@ -919,7 +850,7 @@ public final class CodedOutputStream {
* {@code bytes} field.
*/
public static int computeByteArraySizeNoTag(final byte[] value) {
- return computeRawVarint32Size(value.length) + value.length;
+ return computeLengthDelimitedFieldSize(value.length);
}
/**
@@ -927,98 +858,64 @@ public final class CodedOutputStream {
* {@code bytes} field.
*/
public static int computeByteBufferSizeNoTag(final ByteBuffer value) {
- return computeRawVarint32Size(value.capacity()) + value.capacity();
+ return computeLengthDelimitedFieldSize(value.capacity());
}
/**
- * Compute the number of bytes that would be needed to encode a
- * {@code uint32} field.
- */
- public static int computeUInt32SizeNoTag(final int value) {
- return computeRawVarint32Size(value);
- }
-
- /**
- * Compute the number of bytes that would be needed to encode an enum field.
- * Caller is responsible for converting the enum value to its numeric value.
+ * Compute the number of bytes that would be needed to encode an embedded
+ * message field.
*/
- public static int computeEnumSizeNoTag(final int value) {
- return computeInt32SizeNoTag(value);
+ public static int computeMessageSizeNoTag(final MessageLite value) {
+ return computeLengthDelimitedFieldSize(value.getSerializedSize());
}
- /**
- * Compute the number of bytes that would be needed to encode an
- * {@code sfixed32} field.
- */
- public static int computeSFixed32SizeNoTag(final int value) {
- return LITTLE_ENDIAN_32_SIZE;
+ private static int computeLengthDelimitedFieldSize(int fieldLength) {
+ return computeUInt32SizeNoTag(fieldLength) + fieldLength;
}
/**
- * Compute the number of bytes that would be needed to encode an
- * {@code sfixed64} field.
- */
- public static int computeSFixed64SizeNoTag(final long value) {
- return LITTLE_ENDIAN_64_SIZE;
- }
-
- /**
- * Compute the number of bytes that would be needed to encode an
- * {@code sint32} field.
+ * Encode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers
+ * into values that can be efficiently encoded with varint. (Otherwise,
+ * negative values must be sign-extended to 64 bits to be varint encoded,
+ * thus always taking 10 bytes on the wire.)
+ *
+ * @param n A signed 32-bit integer.
+ * @return An unsigned 32-bit integer, stored in a signed int because
+ * Java has no explicit unsigned support.
*/
- public static int computeSInt32SizeNoTag(final int value) {
- return computeRawVarint32Size(encodeZigZag32(value));
+ public static int encodeZigZag32(final int n) {
+ // Note: the right-shift must be arithmetic
+ return (n << 1) ^ (n >> 31);
}
/**
- * Compute the number of bytes that would be needed to encode an
- * {@code sint64} field.
+ * Encode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers
+ * into values that can be efficiently encoded with varint. (Otherwise,
+ * negative values must be sign-extended to 64 bits to be varint encoded,
+ * thus always taking 10 bytes on the wire.)
+ *
+ * @param n A signed 64-bit integer.
+ * @return An unsigned 64-bit integer, stored in a signed int because
+ * Java has no explicit unsigned support.
*/
- public static int computeSInt64SizeNoTag(final long value) {
- return computeRawVarint64Size(encodeZigZag64(value));
+ public static long encodeZigZag64(final long n) {
+ // Note: the right-shift must be arithmetic
+ return (n << 1) ^ (n >> 63);
}
// =================================================================
/**
- * Internal helper that writes the current buffer to the output. The
- * buffer position is reset to its initial value when this returns.
- */
- private void refreshBuffer() throws IOException {
- if (output == null) {
- // We're writing to a single buffer.
- throw new OutOfSpaceException();
- }
-
- // Since we have an output stream, this is our buffer
- // and buffer offset == 0
- output.write(buffer, 0, position);
- position = 0;
- }
-
- /**
* Flushes the stream and forces any buffered bytes to be written. This
* does not flush the underlying OutputStream.
*/
- public void flush() throws IOException {
- if (output != null) {
- refreshBuffer();
- }
- }
+ public abstract void flush() throws IOException;
/**
* If writing to a flat array, return the space left in the array.
* Otherwise, throws {@code UnsupportedOperationException}.
*/
- public int spaceLeft() {
- if (output == null) {
- return limit - position;
- } else {
- throw new UnsupportedOperationException(
- "spaceLeft() can only be called on CodedOutputStreams that are " +
- "writing to a flat array.");
- }
- }
+ public abstract int spaceLeft();
/**
* Verifies that {@link #spaceLeft()} returns zero. It's common to create
@@ -1027,10 +924,9 @@ public final class CodedOutputStream {
* after writing verifies that the message was actually as big as expected,
* which can help catch bugs.
*/
- public void checkNoSpaceLeft() {
+ public final void checkNoSpaceLeft() {
if (spaceLeft() != 0) {
- throw new IllegalStateException(
- "Did not write as much data as expected.");
+ throw new IllegalStateException("Did not write as much data as expected.");
}
}
@@ -1059,274 +955,1710 @@ public final class CodedOutputStream {
* returned value is not guaranteed to be accurate if exceptions have been
* found in the middle of writing.
*/
- public int getTotalBytesWritten() {
- return totalBytesWritten;
- }
+ public abstract int getTotalBytesWritten();
- /** Write a single byte. */
- public void writeRawByte(final byte value) throws IOException {
- if (position == limit) {
- refreshBuffer();
+ // =================================================================
+
+ /** Write a {@code bytes} field to the stream. Visible for testing. */
+ abstract void writeByteArrayNoTag(final byte[] value, final int offset, final int length)
+ throws IOException;
+
+ final void inefficientWriteStringNoTag(String value, UnpairedSurrogateException cause)
+ throws IOException {
+ logger.log(Level.WARNING,
+ "Converting ill-formed UTF-16. Your Protocol Buffer will not round trip correctly!", cause);
+
+ // Unfortunately there does not appear to be any way to tell Java to encode
+ // UTF-8 directly into our buffer, so we have to let it create its own byte
+ // array and then copy.
+ // TODO(dweis): Consider using nio Charset methods instead.
+ final byte[] bytes = value.getBytes(Internal.UTF_8);
+ try {
+ writeUInt32NoTag(bytes.length);
+ writeLazy(bytes, 0, bytes.length);
+ } catch (IndexOutOfBoundsException e) {
+ throw new OutOfSpaceException(e);
+ } catch (OutOfSpaceException e) {
+ throw e;
}
+ }
- buffer[position++] = value;
- ++totalBytesWritten;
+ // =================================================================
+
+ /**
+ * Write a {@code group} field, including tag, to the stream.
+ *
+ * @deprecated groups are deprecated.
+ */
+ @Deprecated
+ public final void writeGroup(final int fieldNumber, final MessageLite value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_START_GROUP);
+ writeGroupNoTag(value);
+ writeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP);
}
- /** Write a single byte, represented by an integer value. */
- public void writeRawByte(final int value) throws IOException {
- writeRawByte((byte) value);
+ /**
+ * Write a {@code group} field to the stream.
+ *
+ * @deprecated groups are deprecated.
+ */
+ @Deprecated
+ public final void writeGroupNoTag(final MessageLite value) throws IOException {
+ value.writeTo(this);
}
- /** Write a byte string. */
- public void writeRawBytes(final ByteString value) throws IOException {
- writeRawBytes(value, 0, value.size());
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code group} field, including tag.
+ *
+ * @deprecated groups are deprecated.
+ */
+ @Deprecated
+ public static int computeGroupSize(final int fieldNumber, final MessageLite value) {
+ return computeTagSize(fieldNumber) * 2 + computeGroupSizeNoTag(value);
}
- /** Write an array of bytes. */
- public void writeRawBytes(final byte[] value) throws IOException {
- writeRawBytes(value, 0, value.length);
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code group} field.
+ */
+ @Deprecated
+ public static int computeGroupSizeNoTag(final MessageLite value) {
+ return value.getSerializedSize();
}
/**
- * Write a ByteBuffer. This method will write all content of the ByteBuffer
- * regardless of the current position and limit (i.e., the number of bytes
- * to be written is value.capacity(), not value.remaining()). Furthermore,
- * this method doesn't alter the state of the passed-in ByteBuffer. Its
- * position, limit, mark, etc. will remain unchanged. If you only want to
- * write the remaining bytes of a ByteBuffer, you can call
- * {@code writeRawBytes(byteBuffer.slice())}.
+ * Encode and write a varint. {@code value} is treated as
+ * unsigned, so it won't be sign-extended if negative.
+ *
+ * @deprecated use {@link #writeUInt32NoTag} instead.
*/
- public void writeRawBytes(final ByteBuffer value) throws IOException {
- if (value.hasArray()) {
- writeRawBytes(value.array(), value.arrayOffset(), value.capacity());
- } else {
- ByteBuffer duplicated = value.duplicate();
- duplicated.clear();
- writeRawBytesInternal(duplicated);
- }
+ @Deprecated
+ public final void writeRawVarint32(int value) throws IOException {
+ writeUInt32NoTag(value);
}
- /** Write a ByteBuffer that isn't backed by an array. */
- private void writeRawBytesInternal(final ByteBuffer value)
- throws IOException {
- int length = value.remaining();
- if (limit - position >= length) {
- // We have room in the current buffer.
- value.get(buffer, position, length);
- position += length;
- totalBytesWritten += length;
- } else {
- // Write extends past current buffer. Fill the rest of this buffer and
- // flush.
- final int bytesWritten = limit - position;
- value.get(buffer, position, bytesWritten);
- length -= bytesWritten;
- position = limit;
- totalBytesWritten += bytesWritten;
- refreshBuffer();
-
- // Now deal with the rest.
- // Since we have an output stream, this is our buffer
- // and buffer offset == 0
- while (length > limit) {
- // Copy data into the buffer before writing it to OutputStream.
- // TODO(xiaofeng): Introduce ZeroCopyOutputStream to avoid this copy.
- value.get(buffer, 0, limit);
- output.write(buffer, 0, limit);
- length -= limit;
- totalBytesWritten += limit;
+ /**
+ * Encode and write a varint.
+ *
+ * @deprecated use {@link #writeUInt64NoTag} instead.
+ */
+ @Deprecated
+ public final void writeRawVarint64(long value) throws IOException {
+ writeUInt64NoTag(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a varint.
+ * {@code value} is treated as unsigned, so it won't be sign-extended if
+ * negative.
+ *
+ * @deprecated use {@link #computeUInt32SizeNoTag(int)} instead.
+ */
+ @Deprecated
+ public static int computeRawVarint32Size(final int value) {
+ return computeUInt32SizeNoTag(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a varint.
+ *
+ * @deprecated use {@link #computeUInt64SizeNoTag(long)} instead.
+ */
+ @Deprecated
+ public static int computeRawVarint64Size(long value) {
+ return computeUInt64SizeNoTag(value);
+ }
+
+ /**
+ * Write a little-endian 32-bit integer.
+ *
+ * @deprecated Use {@link #writeFixed32NoTag} instead.
+ */
+ @Deprecated
+ public final void writeRawLittleEndian32(final int value) throws IOException {
+ writeFixed32NoTag(value);
+ }
+
+ /**
+ * Write a little-endian 64-bit integer.
+ *
+ * @deprecated Use {@link #writeFixed64NoTag} instead.
+ */
+ @Deprecated
+ public final void writeRawLittleEndian64(final long value) throws IOException {
+ writeFixed64NoTag(value);
+ }
+
+ // =================================================================
+
+ /**
+ * A {@link CodedOutputStream} that writes directly to a byte array.
+ */
+ private static class ArrayEncoder extends CodedOutputStream {
+ private final byte[] buffer;
+ private final int offset;
+ private final int limit;
+ private int position;
+
+ ArrayEncoder(byte[] buffer, int offset, int length) {
+ if (buffer == null) {
+ throw new NullPointerException("buffer");
}
- value.get(buffer, 0, length);
- position = length;
- totalBytesWritten += length;
+ if ((offset | length | (buffer.length - (offset + length))) < 0) {
+ throw new IllegalArgumentException(String.format(
+ "Array range is invalid. Buffer.length=%d, offset=%d, length=%d",
+ buffer.length, offset, length));
+ }
+ this.buffer = buffer;
+ this.offset = offset;
+ position = offset;
+ limit = offset + length;
}
- }
- /** Write part of an array of bytes. */
- public void writeRawBytes(final byte[] value, int offset, int length)
- throws IOException {
- if (limit - position >= length) {
- // We have room in the current buffer.
- System.arraycopy(value, offset, buffer, position, length);
- position += length;
- totalBytesWritten += length;
- } else {
- // Write extends past current buffer. Fill the rest of this buffer and
- // flush.
- final int bytesWritten = limit - position;
- System.arraycopy(value, offset, buffer, position, bytesWritten);
- offset += bytesWritten;
- length -= bytesWritten;
- position = limit;
- totalBytesWritten += bytesWritten;
- refreshBuffer();
-
- // Now deal with the rest.
- // Since we have an output stream, this is our buffer
- // and buffer offset == 0
- if (length <= limit) {
- // Fits in new buffer.
- System.arraycopy(value, offset, buffer, 0, length);
- position = length;
+ @Override
+ public final void writeTag(final int fieldNumber, final int wireType) throws IOException {
+ writeUInt32NoTag(WireFormat.makeTag(fieldNumber, wireType));
+ }
+
+ @Override
+ public final void writeInt32(final int fieldNumber, final int value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+ writeInt32NoTag(value);
+ }
+
+ @Override
+ public final void writeUInt32(final int fieldNumber, final int value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+ writeUInt32NoTag(value);
+ }
+
+ @Override
+ public final void writeFixed32(final int fieldNumber, final int value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
+ writeFixed32NoTag(value);
+ }
+
+ @Override
+ public final void writeUInt64(final int fieldNumber, final long value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+ writeUInt64NoTag(value);
+ }
+
+ @Override
+ public final void writeFixed64(final int fieldNumber, final long value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
+ writeFixed64NoTag(value);
+ }
+
+ @Override
+ public final void writeBool(final int fieldNumber, final boolean value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+ write((byte) (value ? 1 : 0));
+ }
+
+ @Override
+ public final void writeString(final int fieldNumber, final String value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ writeStringNoTag(value);
+ }
+
+ @Override
+ public final void writeBytes(final int fieldNumber, final ByteString value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ writeBytesNoTag(value);
+ }
+
+ @Override
+ public final void writeByteArray(final int fieldNumber, final byte[] value) throws IOException {
+ writeByteArray(fieldNumber, value, 0, value.length);
+ }
+
+ @Override
+ public final void writeByteArray(
+ final int fieldNumber, final byte[] value, final int offset, final int length)
+ throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ writeByteArrayNoTag(value, offset, length);
+ }
+
+ @Override
+ public final void writeByteBuffer(final int fieldNumber, final ByteBuffer value)
+ throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ writeUInt32NoTag(value.capacity());
+ writeRawBytes(value);
+ }
+
+ @Override
+ public final void writeBytesNoTag(final ByteString value) throws IOException {
+ writeUInt32NoTag(value.size());
+ value.writeTo(this);
+ }
+
+ @Override
+ public final void writeByteArrayNoTag(final byte[] value, int offset, int length)
+ throws IOException {
+ writeUInt32NoTag(length);
+ write(value, offset, length);
+ }
+
+ @Override
+ public final void writeRawBytes(final ByteBuffer value) throws IOException {
+ if (value.hasArray()) {
+ write(value.array(), value.arrayOffset(), value.capacity());
} else {
- // Write is very big. Let's do it all at once.
- output.write(value, offset, length);
+ ByteBuffer duplicated = value.duplicate();
+ duplicated.clear();
+ write(duplicated);
}
- totalBytesWritten += length;
}
- }
- /** Write part of a byte string. */
- public void writeRawBytes(final ByteString value, int offset, int length)
- throws IOException {
- if (limit - position >= length) {
- // We have room in the current buffer.
- value.copyTo(buffer, offset, position, length);
- position += length;
- totalBytesWritten += length;
- } else {
- // Write extends past current buffer. Fill the rest of this buffer and
- // flush.
- final int bytesWritten = limit - position;
- value.copyTo(buffer, offset, position, bytesWritten);
- offset += bytesWritten;
- length -= bytesWritten;
- position = limit;
- totalBytesWritten += bytesWritten;
- refreshBuffer();
-
- // Now deal with the rest.
- // Since we have an output stream, this is our buffer
- // and buffer offset == 0
- if (length <= limit) {
- // Fits in new buffer.
- value.copyTo(buffer, offset, 0, length);
- position = length;
+ @Override
+ public final void writeMessage(final int fieldNumber, final MessageLite value)
+ throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ writeMessageNoTag(value);
+ }
+
+ @Override
+ public final void writeMessageSetExtension(final int fieldNumber, final MessageLite value)
+ throws IOException {
+ writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
+ writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
+ writeMessage(WireFormat.MESSAGE_SET_MESSAGE, value);
+ writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
+ }
+
+ @Override
+ public final void writeRawMessageSetExtension(final int fieldNumber, final ByteString value)
+ throws IOException {
+ writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
+ writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
+ writeBytes(WireFormat.MESSAGE_SET_MESSAGE, value);
+ writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
+ }
+
+ @Override
+ public final void writeMessageNoTag(final MessageLite value) throws IOException {
+ writeUInt32NoTag(value.getSerializedSize());
+ value.writeTo(this);
+ }
+
+ @Override
+ public final void write(byte value) throws IOException {
+ try {
+ buffer[position++] = value;
+ } catch (IndexOutOfBoundsException e) {
+ throw new OutOfSpaceException(new IndexOutOfBoundsException(
+ String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)));
+ }
+ }
+
+ @Override
+ public final void writeInt32NoTag(int value) throws IOException {
+ if (value >= 0) {
+ writeUInt32NoTag(value);
} else {
- value.writeTo(output, offset, length);
+ // Must sign-extend.
+ writeUInt64NoTag(value);
}
- totalBytesWritten += length;
}
- }
- /** Encode and write a tag. */
- public void writeTag(final int fieldNumber, final int wireType)
- throws IOException {
- writeRawVarint32(WireFormat.makeTag(fieldNumber, wireType));
+ @Override
+ public final void writeUInt32NoTag(int value) throws IOException {
+ if (HAS_UNSAFE_ARRAY_OPERATIONS && spaceLeft() >= MAX_VARINT_SIZE) {
+ long pos = ARRAY_BASE_OFFSET + position;
+ while (true) {
+ if ((value & ~0x7F) == 0) {
+ UNSAFE.putByte(buffer, pos++, (byte) value);
+ position++;
+ return;
+ } else {
+ UNSAFE.putByte(buffer, pos++, (byte) ((value & 0x7F) | 0x80));
+ position++;
+ value >>>= 7;
+ }
+ }
+ } else {
+ try {
+ while (true) {
+ if ((value & ~0x7F) == 0) {
+ buffer[position++] = (byte) value;
+ return;
+ } else {
+ buffer[position++] = (byte) ((value & 0x7F) | 0x80);
+ value >>>= 7;
+ }
+ }
+ } catch (IndexOutOfBoundsException e) {
+ throw new OutOfSpaceException(
+ new IndexOutOfBoundsException(
+ String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)));
+ }
+ }
+ }
+
+ @Override
+ public final void writeFixed32NoTag(int value) throws IOException {
+ try {
+ buffer[position++] = (byte) (value & 0xFF);
+ buffer[position++] = (byte) ((value >> 8) & 0xFF);
+ buffer[position++] = (byte) ((value >> 16) & 0xFF);
+ buffer[position++] = (byte) ((value >> 24) & 0xFF);
+ } catch (IndexOutOfBoundsException e) {
+ throw new OutOfSpaceException(
+ new IndexOutOfBoundsException(
+ String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)));
+ }
+ }
+
+ @Override
+ public final void writeUInt64NoTag(long value) throws IOException {
+ if (HAS_UNSAFE_ARRAY_OPERATIONS && spaceLeft() >= MAX_VARINT_SIZE) {
+ long pos = ARRAY_BASE_OFFSET + position;
+ while (true) {
+ if ((value & ~0x7FL) == 0) {
+ UNSAFE.putByte(buffer, pos++, (byte) value);
+ position++;
+ return;
+ } else {
+ UNSAFE.putByte(buffer, pos++, (byte) (((int) value & 0x7F) | 0x80));
+ position++;
+ value >>>= 7;
+ }
+ }
+ } else {
+ try {
+ while (true) {
+ if ((value & ~0x7FL) == 0) {
+ buffer[position++] = (byte) value;
+ return;
+ } else {
+ buffer[position++] = (byte) (((int) value & 0x7F) | 0x80);
+ value >>>= 7;
+ }
+ }
+ } catch (IndexOutOfBoundsException e) {
+ throw new OutOfSpaceException(
+ new IndexOutOfBoundsException(
+ String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)));
+ }
+ }
+ }
+
+ @Override
+ public final void writeFixed64NoTag(long value) throws IOException {
+ try {
+ buffer[position++] = (byte) ((int) (value) & 0xFF);
+ buffer[position++] = (byte) ((int) (value >> 8) & 0xFF);
+ buffer[position++] = (byte) ((int) (value >> 16) & 0xFF);
+ buffer[position++] = (byte) ((int) (value >> 24) & 0xFF);
+ buffer[position++] = (byte) ((int) (value >> 32) & 0xFF);
+ buffer[position++] = (byte) ((int) (value >> 40) & 0xFF);
+ buffer[position++] = (byte) ((int) (value >> 48) & 0xFF);
+ buffer[position++] = (byte) ((int) (value >> 56) & 0xFF);
+ } catch (IndexOutOfBoundsException e) {
+ throw new OutOfSpaceException(
+ new IndexOutOfBoundsException(
+ String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)));
+ }
+ }
+
+ @Override
+ public final void write(byte[] value, int offset, int length) throws IOException {
+ try {
+ System.arraycopy(value, offset, buffer, position, length);
+ position += length;
+ } catch (IndexOutOfBoundsException e) {
+ throw new OutOfSpaceException(
+ new IndexOutOfBoundsException(
+ String.format("Pos: %d, limit: %d, len: %d", position, limit, length)));
+ }
+ }
+
+ @Override
+ public final void writeLazy(byte[] value, int offset, int length) throws IOException {
+ write(value, offset, length);
+ }
+
+ @Override
+ public final void write(ByteBuffer value) throws IOException {
+ final int length = value.remaining();
+ try {
+ value.get(buffer, position, length);
+ position += length;
+ } catch (IndexOutOfBoundsException e) {
+ throw new OutOfSpaceException(
+ new IndexOutOfBoundsException(
+ String.format("Pos: %d, limit: %d, len: %d", position, limit, length)));
+ }
+ }
+
+ @Override
+ public final void writeLazy(ByteBuffer value) throws IOException {
+ write(value);
+ }
+
+ @Override
+ public final void writeStringNoTag(String value) throws IOException {
+ final int oldPosition = position;
+ try {
+ // UTF-8 byte length of the string is at least its UTF-16 code unit length (value.length()),
+ // and at most 3 times of it. We take advantage of this in both branches below.
+ final int maxLength = value.length() * Utf8.MAX_BYTES_PER_CHAR;
+ final int maxLengthVarIntSize = computeUInt32SizeNoTag(maxLength);
+ final int minLengthVarIntSize = computeUInt32SizeNoTag(value.length());
+ if (minLengthVarIntSize == maxLengthVarIntSize) {
+ position = oldPosition + minLengthVarIntSize;
+ int newPosition = Utf8.encode(value, buffer, position, spaceLeft());
+ // Since this class is stateful and tracks the position, we rewind and store the state,
+ // prepend the length, then reset it back to the end of the string.
+ position = oldPosition;
+ int length = newPosition - oldPosition - minLengthVarIntSize;
+ writeUInt32NoTag(length);
+ position = newPosition;
+ } else {
+ int length = Utf8.encodedLength(value);
+ writeUInt32NoTag(length);
+ position = Utf8.encode(value, buffer, position, spaceLeft());
+ }
+ } catch (UnpairedSurrogateException e) {
+ // Roll back the change - we fall back to inefficient path.
+ position = oldPosition;
+
+ // TODO(nathanmittler): We should throw an IOException here instead.
+ inefficientWriteStringNoTag(value, e);
+ } catch (IndexOutOfBoundsException e) {
+ throw new OutOfSpaceException(e);
+ }
+ }
+
+ @Override
+ public void flush() {
+ // Do nothing.
+ }
+
+ @Override
+ public final int spaceLeft() {
+ return limit - position;
+ }
+
+ @Override
+ public final int getTotalBytesWritten() {
+ return position - offset;
+ }
}
- /** Compute the number of bytes that would be needed to encode a tag. */
- public static int computeTagSize(final int fieldNumber) {
- return computeRawVarint32Size(WireFormat.makeTag(fieldNumber, 0));
+ /**
+ * A {@link CodedOutputStream} that writes directly to a heap {@link ByteBuffer}. Writes are
+ * done directly to the underlying array. The buffer position is only updated after a flush.
+ */
+ private static final class NioHeapEncoder extends ArrayEncoder {
+ private final ByteBuffer byteBuffer;
+ private int initialPosition;
+
+ NioHeapEncoder(ByteBuffer byteBuffer) {
+ super(byteBuffer.array(), byteBuffer.arrayOffset() + byteBuffer.position(),
+ byteBuffer.remaining());
+ this.byteBuffer = byteBuffer;
+ this.initialPosition = byteBuffer.position();
+ }
+
+ @Override
+ public void flush() {
+ // Update the position on the buffer.
+ byteBuffer.position(initialPosition + getTotalBytesWritten());
+ }
}
/**
- * Encode and write a varint. {@code value} is treated as
- * unsigned, so it won't be sign-extended if negative.
+ * A {@link CodedOutputStream} that writes directly to a {@link ByteBuffer}.
*/
- public void writeRawVarint32(int value) throws IOException {
- while (true) {
- if ((value & ~0x7F) == 0) {
- writeRawByte(value);
- return;
+ private static final class NioEncoder extends CodedOutputStream {
+ private final ByteBuffer originalBuffer;
+ private final ByteBuffer buffer;
+ private final int initialPosition;
+
+ NioEncoder(ByteBuffer buffer) {
+ this.originalBuffer = buffer;
+ this.buffer = buffer.duplicate().order(ByteOrder.LITTLE_ENDIAN);
+ initialPosition = buffer.position();
+ }
+
+ @Override
+ public void writeTag(final int fieldNumber, final int wireType) throws IOException {
+ writeUInt32NoTag(WireFormat.makeTag(fieldNumber, wireType));
+ }
+
+ @Override
+ public void writeInt32(final int fieldNumber, final int value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+ writeInt32NoTag(value);
+ }
+
+ @Override
+ public void writeUInt32(final int fieldNumber, final int value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+ writeUInt32NoTag(value);
+ }
+
+ @Override
+ public void writeFixed32(final int fieldNumber, final int value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
+ writeFixed32NoTag(value);
+ }
+
+ @Override
+ public void writeUInt64(final int fieldNumber, final long value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+ writeUInt64NoTag(value);
+ }
+
+ @Override
+ public void writeFixed64(final int fieldNumber, final long value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
+ writeFixed64NoTag(value);
+ }
+
+ @Override
+ public void writeBool(final int fieldNumber, final boolean value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+ write((byte) (value ? 1 : 0));
+ }
+
+ @Override
+ public void writeString(final int fieldNumber, final String value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ writeStringNoTag(value);
+ }
+
+ @Override
+ public void writeBytes(final int fieldNumber, final ByteString value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ writeBytesNoTag(value);
+ }
+
+ @Override
+ public void writeByteArray(final int fieldNumber, final byte[] value) throws IOException {
+ writeByteArray(fieldNumber, value, 0, value.length);
+ }
+
+ @Override
+ public void writeByteArray(
+ final int fieldNumber, final byte[] value, final int offset, final int length)
+ throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ writeByteArrayNoTag(value, offset, length);
+ }
+
+ @Override
+ public void writeByteBuffer(final int fieldNumber, final ByteBuffer value)
+ throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ writeUInt32NoTag(value.capacity());
+ writeRawBytes(value);
+ }
+
+ @Override
+ public void writeMessage(final int fieldNumber, final MessageLite value)
+ throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ writeMessageNoTag(value);
+ }
+
+ @Override
+ public void writeMessageSetExtension(final int fieldNumber, final MessageLite value)
+ throws IOException {
+ writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
+ writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
+ writeMessage(WireFormat.MESSAGE_SET_MESSAGE, value);
+ writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
+ }
+
+ @Override
+ public void writeRawMessageSetExtension(final int fieldNumber, final ByteString value)
+ throws IOException {
+ writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
+ writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
+ writeBytes(WireFormat.MESSAGE_SET_MESSAGE, value);
+ writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
+ }
+
+ @Override
+ public void writeMessageNoTag(final MessageLite value) throws IOException {
+ writeUInt32NoTag(value.getSerializedSize());
+ value.writeTo(this);
+ }
+
+ @Override
+ public void write(byte value) throws IOException {
+ try {
+ buffer.put(value);
+ } catch (BufferOverflowException e) {
+ throw new OutOfSpaceException(e);
+ }
+ }
+
+ @Override
+ public void writeBytesNoTag(final ByteString value) throws IOException {
+ writeUInt32NoTag(value.size());
+ value.writeTo(this);
+ }
+
+ @Override
+ public void writeByteArrayNoTag(final byte[] value, int offset, int length) throws IOException {
+ writeUInt32NoTag(length);
+ write(value, offset, length);
+ }
+
+ @Override
+ public void writeRawBytes(final ByteBuffer value) throws IOException {
+ if (value.hasArray()) {
+ write(value.array(), value.arrayOffset(), value.capacity());
} else {
- writeRawByte((value & 0x7F) | 0x80);
- value >>>= 7;
+ ByteBuffer duplicated = value.duplicate();
+ duplicated.clear();
+ write(duplicated);
+ }
+ }
+
+ @Override
+ public void writeInt32NoTag(int value) throws IOException {
+ if (value >= 0) {
+ writeUInt32NoTag(value);
+ } else {
+ // Must sign-extend.
+ writeUInt64NoTag(value);
+ }
+ }
+
+ @Override
+ public void writeUInt32NoTag(int value) throws IOException {
+ try {
+ while (true) {
+ if ((value & ~0x7F) == 0) {
+ buffer.put((byte) value);
+ return;
+ } else {
+ buffer.put((byte) ((value & 0x7F) | 0x80));
+ value >>>= 7;
+ }
+ }
+ } catch (BufferOverflowException e) {
+ throw new OutOfSpaceException(e);
+ }
+ }
+
+ @Override
+ public void writeFixed32NoTag(int value) throws IOException {
+ try {
+ buffer.putInt(value);
+ } catch (BufferOverflowException e) {
+ throw new OutOfSpaceException(e);
+ }
+ }
+
+ @Override
+ public void writeUInt64NoTag(long value) throws IOException {
+ try {
+ while (true) {
+ if ((value & ~0x7FL) == 0) {
+ buffer.put((byte) value);
+ return;
+ } else {
+ buffer.put((byte) (((int) value & 0x7F) | 0x80));
+ value >>>= 7;
+ }
+ }
+ } catch (BufferOverflowException e) {
+ throw new OutOfSpaceException(e);
+ }
+ }
+
+ @Override
+ public void writeFixed64NoTag(long value) throws IOException {
+ try {
+ buffer.putLong(value);
+ } catch (BufferOverflowException e) {
+ throw new OutOfSpaceException(e);
+ }
+ }
+
+ @Override
+ public void write(byte[] value, int offset, int length) throws IOException {
+ try {
+ buffer.put(value, offset, length);
+ } catch (IndexOutOfBoundsException e) {
+ throw new OutOfSpaceException(e);
+ } catch (BufferOverflowException e) {
+ throw new OutOfSpaceException(e);
+ }
+ }
+
+ @Override
+ public void writeLazy(byte[] value, int offset, int length) throws IOException {
+ write(value, offset, length);
+ }
+
+ @Override
+ public void write(ByteBuffer value) throws IOException {
+ try {
+ buffer.put(value);
+ } catch (BufferOverflowException e) {
+ throw new OutOfSpaceException(e);
+ }
+ }
+
+ @Override
+ public void writeLazy(ByteBuffer value) throws IOException {
+ write(value);
+ }
+
+ @Override
+ public void writeStringNoTag(String value) throws IOException {
+ final int startPos = buffer.position();
+ try {
+ // UTF-8 byte length of the string is at least its UTF-16 code unit length (value.length()),
+ // and at most 3 times of it. We take advantage of this in both branches below.
+ final int maxEncodedSize = value.length() * Utf8.MAX_BYTES_PER_CHAR;
+ final int maxLengthVarIntSize = computeUInt32SizeNoTag(maxEncodedSize);
+ final int minLengthVarIntSize = computeUInt32SizeNoTag(value.length());
+ if (minLengthVarIntSize == maxLengthVarIntSize) {
+ // Save the current position and increment past the length field. We'll come back
+ // and write the length field after the encoding is complete.
+ final int startOfBytes = buffer.position() + minLengthVarIntSize;
+ buffer.position(startOfBytes);
+
+ // Encode the string.
+ encode(value);
+
+ // Now go back to the beginning and write the length.
+ int endOfBytes = buffer.position();
+ buffer.position(startPos);
+ writeUInt32NoTag(endOfBytes - startOfBytes);
+
+ // Reposition the buffer past the written data.
+ buffer.position(endOfBytes);
+ } else {
+ final int length = Utf8.encodedLength(value);
+ writeUInt32NoTag(length);
+ encode(value);
+ }
+ } catch (UnpairedSurrogateException e) {
+ // Roll back the change and convert to an IOException.
+ buffer.position(startPos);
+
+ // TODO(nathanmittler): We should throw an IOException here instead.
+ inefficientWriteStringNoTag(value, e);
+ } catch (IllegalArgumentException e) {
+ // Thrown by buffer.position() if out of range.
+ throw new OutOfSpaceException(e);
+ }
+ }
+
+ @Override
+ public void flush() {
+ // Update the position of the original buffer.
+ originalBuffer.position(buffer.position());
+ }
+
+ @Override
+ public int spaceLeft() {
+ return buffer.remaining();
+ }
+
+ @Override
+ public int getTotalBytesWritten() {
+ return buffer.position() - initialPosition;
+ }
+
+ private void encode(String value) throws IOException {
+ try {
+ Utf8.encodeUtf8(value, buffer);
+ } catch (IndexOutOfBoundsException e) {
+ throw new OutOfSpaceException(e);
}
}
}
/**
- * Compute the number of bytes that would be needed to encode a varint.
- * {@code value} is treated as unsigned, so it won't be sign-extended if
- * negative.
+ * Abstract base class for buffered encoders.
*/
- public static int computeRawVarint32Size(final int value) {
- if ((value & (~0 << 7)) == 0) return 1;
- if ((value & (~0 << 14)) == 0) return 2;
- if ((value & (~0 << 21)) == 0) return 3;
- if ((value & (~0 << 28)) == 0) return 4;
- return 5;
- }
+ private abstract static class AbstractBufferedEncoder extends CodedOutputStream {
+ final byte[] buffer;
+ final int limit;
+ int position;
+ int totalBytesWritten;
- /** Encode and write a varint. */
- public void writeRawVarint64(long value) throws IOException {
- while (true) {
- if ((value & ~0x7FL) == 0) {
- writeRawByte((int)value);
- return;
+ AbstractBufferedEncoder(int bufferSize) {
+ if (bufferSize < 0) {
+ throw new IllegalArgumentException("bufferSize must be >= 0");
+ }
+ // As an optimization, we require that the buffer be able to store at least 2
+ // varints so that we can buffer any integer write (tag + value). This reduces the
+ // number of range checks for a single write to 1 (i.e. if there is not enough space
+ // to buffer the tag+value, flush and then buffer it).
+ this.buffer = new byte[max(bufferSize, MAX_VARINT_SIZE * 2)];
+ this.limit = buffer.length;
+ }
+
+ @Override
+ public final int spaceLeft() {
+ throw new UnsupportedOperationException(
+ "spaceLeft() can only be called on CodedOutputStreams that are "
+ + "writing to a flat array or ByteBuffer.");
+ }
+
+ @Override
+ public final int getTotalBytesWritten() {
+ return totalBytesWritten;
+ }
+
+ /**
+ * This method does not perform bounds checking on the array. Checking array bounds is the
+ * responsibility of the caller.
+ */
+ final void buffer(byte value) {
+ buffer[position++] = value;
+ totalBytesWritten++;
+ }
+
+ /**
+ * This method does not perform bounds checking on the array. Checking array bounds is the
+ * responsibility of the caller.
+ */
+ final void bufferTag(final int fieldNumber, final int wireType) {
+ bufferUInt32NoTag(WireFormat.makeTag(fieldNumber, wireType));
+ }
+
+ /**
+ * This method does not perform bounds checking on the array. Checking array bounds is the
+ * responsibility of the caller.
+ */
+ final void bufferInt32NoTag(final int value) {
+ if (value >= 0) {
+ bufferUInt32NoTag(value);
} else {
- writeRawByte(((int)value & 0x7F) | 0x80);
- value >>>= 7;
+ // Must sign-extend.
+ bufferUInt64NoTag(value);
}
}
- }
- /** Compute the number of bytes that would be needed to encode a varint. */
- public static int computeRawVarint64Size(long value) {
- // handle two popular special cases up front ...
- if ((value & (~0L << 7)) == 0L) return 1;
- if (value < 0L) return 10;
- // ... leaving us with 8 remaining, which we can divide and conquer
- int n = 2;
- if ((value & (~0L << 35)) != 0L) { n += 4; value >>>= 28; }
- if ((value & (~0L << 21)) != 0L) { n += 2; value >>>= 14; }
- if ((value & (~0L << 14)) != 0L) { n += 1; }
- return n;
+ /**
+ * This method does not perform bounds checking on the array. Checking array bounds is the
+ * responsibility of the caller.
+ */
+ final void bufferUInt32NoTag(int value) {
+ if (HAS_UNSAFE_ARRAY_OPERATIONS) {
+ final long originalPos = ARRAY_BASE_OFFSET + position;
+ long pos = originalPos;
+ while (true) {
+ if ((value & ~0x7F) == 0) {
+ UNSAFE.putByte(buffer, pos++, (byte) value);
+ break;
+ } else {
+ UNSAFE.putByte(buffer, pos++, (byte) ((value & 0x7F) | 0x80));
+ value >>>= 7;
+ }
+ }
+ int delta = (int) (pos - originalPos);
+ position += delta;
+ totalBytesWritten += delta;
+ } else {
+ while (true) {
+ if ((value & ~0x7F) == 0) {
+ buffer[position++] = (byte) value;
+ totalBytesWritten++;
+ return;
+ } else {
+ buffer[position++] = (byte) ((value & 0x7F) | 0x80);
+ totalBytesWritten++;
+ value >>>= 7;
+ }
+ }
+ }
+ }
+
+ /**
+ * This method does not perform bounds checking on the array. Checking array bounds is the
+ * responsibility of the caller.
+ */
+ final void bufferUInt64NoTag(long value) {
+ if (HAS_UNSAFE_ARRAY_OPERATIONS) {
+ final long originalPos = ARRAY_BASE_OFFSET + position;
+ long pos = originalPos;
+ while (true) {
+ if ((value & ~0x7FL) == 0) {
+ UNSAFE.putByte(buffer, pos++, (byte) value);
+ break;
+ } else {
+ UNSAFE.putByte(buffer, pos++, (byte) (((int) value & 0x7F) | 0x80));
+ value >>>= 7;
+ }
+ }
+ int delta = (int) (pos - originalPos);
+ position += delta;
+ totalBytesWritten += delta;
+ } else {
+ while (true) {
+ if ((value & ~0x7FL) == 0) {
+ buffer[position++] = (byte) value;
+ totalBytesWritten++;
+ return;
+ } else {
+ buffer[position++] = (byte) (((int) value & 0x7F) | 0x80);
+ totalBytesWritten++;
+ value >>>= 7;
+ }
+ }
+ }
+ }
+
+ /**
+ * This method does not perform bounds checking on the array. Checking array bounds is the
+ * responsibility of the caller.
+ */
+ final void bufferFixed32NoTag(int value) {
+ buffer[position++] = (byte) (value & 0xFF);
+ buffer[position++] = (byte) ((value >> 8) & 0xFF);
+ buffer[position++] = (byte) ((value >> 16) & 0xFF);
+ buffer[position++] = (byte) ((value >> 24) & 0xFF);
+ totalBytesWritten += FIXED_32_SIZE;
+ }
+
+ /**
+ * This method does not perform bounds checking on the array. Checking array bounds is the
+ * responsibility of the caller.
+ */
+ final void bufferFixed64NoTag(long value) {
+ buffer[position++] = (byte) (value & 0xFF);
+ buffer[position++] = (byte) ((value >> 8) & 0xFF);
+ buffer[position++] = (byte) ((value >> 16) & 0xFF);
+ buffer[position++] = (byte) ((value >> 24) & 0xFF);
+ buffer[position++] = (byte) ((int) (value >> 32) & 0xFF);
+ buffer[position++] = (byte) ((int) (value >> 40) & 0xFF);
+ buffer[position++] = (byte) ((int) (value >> 48) & 0xFF);
+ buffer[position++] = (byte) ((int) (value >> 56) & 0xFF);
+ totalBytesWritten += FIXED_64_SIZE;
+ }
}
- /** Write a little-endian 32-bit integer. */
- public void writeRawLittleEndian32(final int value) throws IOException {
- writeRawByte((value ) & 0xFF);
- writeRawByte((value >> 8) & 0xFF);
- writeRawByte((value >> 16) & 0xFF);
- writeRawByte((value >> 24) & 0xFF);
+ /**
+ * A {@link CodedOutputStream} that decorates a {@link ByteOutput}. It internal buffer only to
+ * support string encoding operations. All other writes are just passed through to the
+ * {@link ByteOutput}.
+ */
+ private static final class ByteOutputEncoder extends AbstractBufferedEncoder {
+ private final ByteOutput out;
+
+ ByteOutputEncoder(ByteOutput out, int bufferSize) {
+ super(bufferSize);
+ if (out == null) {
+ throw new NullPointerException("out");
+ }
+ this.out = out;
+ }
+
+ @Override
+ public void writeTag(final int fieldNumber, final int wireType) throws IOException {
+ writeUInt32NoTag(WireFormat.makeTag(fieldNumber, wireType));
+ }
+
+ @Override
+ public void writeInt32(final int fieldNumber, final int value) throws IOException {
+ flushIfNotAvailable(MAX_VARINT_SIZE * 2);
+ bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+ bufferInt32NoTag(value);
+ }
+
+ @Override
+ public void writeUInt32(final int fieldNumber, final int value) throws IOException {
+ flushIfNotAvailable(MAX_VARINT_SIZE * 2);
+ bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+ bufferUInt32NoTag(value);
+ }
+
+ @Override
+ public void writeFixed32(final int fieldNumber, final int value) throws IOException {
+ flushIfNotAvailable(MAX_VARINT_SIZE + FIXED_32_SIZE);
+ bufferTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
+ bufferFixed32NoTag(value);
+ }
+
+ @Override
+ public void writeUInt64(final int fieldNumber, final long value) throws IOException {
+ flushIfNotAvailable(MAX_VARINT_SIZE * 2);
+ bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+ bufferUInt64NoTag(value);
+ }
+
+ @Override
+ public void writeFixed64(final int fieldNumber, final long value) throws IOException {
+ flushIfNotAvailable(MAX_VARINT_SIZE + FIXED_64_SIZE);
+ bufferTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
+ bufferFixed64NoTag(value);
+ }
+
+ @Override
+ public void writeBool(final int fieldNumber, final boolean value) throws IOException {
+ flushIfNotAvailable(MAX_VARINT_SIZE + 1);
+ bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+ buffer((byte) (value ? 1 : 0));
+ }
+
+ @Override
+ public void writeString(final int fieldNumber, final String value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ writeStringNoTag(value);
+ }
+
+ @Override
+ public void writeBytes(final int fieldNumber, final ByteString value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ writeBytesNoTag(value);
+ }
+
+ @Override
+ public void writeByteArray(final int fieldNumber, final byte[] value) throws IOException {
+ writeByteArray(fieldNumber, value, 0, value.length);
+ }
+
+ @Override
+ public void writeByteArray(
+ final int fieldNumber, final byte[] value, final int offset, final int length)
+ throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ writeByteArrayNoTag(value, offset, length);
+ }
+
+ @Override
+ public void writeByteBuffer(final int fieldNumber, final ByteBuffer value)
+ throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ writeUInt32NoTag(value.capacity());
+ writeRawBytes(value);
+ }
+
+ @Override
+ public void writeBytesNoTag(final ByteString value) throws IOException {
+ writeUInt32NoTag(value.size());
+ value.writeTo(this);
+ }
+
+ @Override
+ public void writeByteArrayNoTag(final byte[] value, int offset, int length) throws IOException {
+ writeUInt32NoTag(length);
+ write(value, offset, length);
+ }
+
+ @Override
+ public void writeRawBytes(final ByteBuffer value) throws IOException {
+ if (value.hasArray()) {
+ write(value.array(), value.arrayOffset(), value.capacity());
+ } else {
+ ByteBuffer duplicated = value.duplicate();
+ duplicated.clear();
+ write(duplicated);
+ }
+ }
+
+ @Override
+ public void writeMessage(final int fieldNumber, final MessageLite value)
+ throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ writeMessageNoTag(value);
+ }
+
+ @Override
+ public void writeMessageSetExtension(final int fieldNumber, final MessageLite value)
+ throws IOException {
+ writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
+ writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
+ writeMessage(WireFormat.MESSAGE_SET_MESSAGE, value);
+ writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
+ }
+
+ @Override
+ public void writeRawMessageSetExtension(final int fieldNumber, final ByteString value)
+ throws IOException {
+ writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
+ writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
+ writeBytes(WireFormat.MESSAGE_SET_MESSAGE, value);
+ writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
+ }
+
+ @Override
+ public void writeMessageNoTag(final MessageLite value) throws IOException {
+ writeUInt32NoTag(value.getSerializedSize());
+ value.writeTo(this);
+ }
+
+ @Override
+ public void write(byte value) throws IOException {
+ if (position == limit) {
+ doFlush();
+ }
+
+ buffer(value);
+ }
+
+ @Override
+ public void writeInt32NoTag(int value) throws IOException {
+ if (value >= 0) {
+ writeUInt32NoTag(value);
+ } else {
+ // Must sign-extend.
+ writeUInt64NoTag(value);
+ }
+ }
+
+ @Override
+ public void writeUInt32NoTag(int value) throws IOException {
+ flushIfNotAvailable(MAX_VARINT_SIZE);
+ bufferUInt32NoTag(value);
+ }
+
+ @Override
+ public void writeFixed32NoTag(final int value) throws IOException {
+ flushIfNotAvailable(FIXED_32_SIZE);
+ bufferFixed32NoTag(value);
+ }
+
+ @Override
+ public void writeUInt64NoTag(long value) throws IOException {
+ flushIfNotAvailable(MAX_VARINT_SIZE);
+ bufferUInt64NoTag(value);
+ }
+
+ @Override
+ public void writeFixed64NoTag(final long value) throws IOException {
+ flushIfNotAvailable(FIXED_64_SIZE);
+ bufferFixed64NoTag(value);
+ }
+
+ @Override
+ public void writeStringNoTag(String value) throws IOException {
+ // UTF-8 byte length of the string is at least its UTF-16 code unit length (value.length()),
+ // and at most 3 times of it. We take advantage of this in both branches below.
+ final int maxLength = value.length() * Utf8.MAX_BYTES_PER_CHAR;
+ final int maxLengthVarIntSize = computeUInt32SizeNoTag(maxLength);
+
+ // If we are streaming and the potential length is too big to fit in our buffer, we take the
+ // slower path.
+ if (maxLengthVarIntSize + maxLength > limit) {
+ // Allocate a byte[] that we know can fit the string and encode into it. String.getBytes()
+ // does the same internally and then does *another copy* to return a byte[] of exactly the
+ // right size. We can skip that copy and just writeRawBytes up to the actualLength of the
+ // UTF-8 encoded bytes.
+ final byte[] encodedBytes = new byte[maxLength];
+ int actualLength = Utf8.encode(value, encodedBytes, 0, maxLength);
+ writeUInt32NoTag(actualLength);
+ writeLazy(encodedBytes, 0, actualLength);
+ return;
+ }
+
+ // Fast path: we have enough space available in our buffer for the string...
+ if (maxLengthVarIntSize + maxLength > limit - position) {
+ // Flush to free up space.
+ doFlush();
+ }
+
+ final int oldPosition = position;
+ try {
+ // Optimize for the case where we know this length results in a constant varint length as
+ // this saves a pass for measuring the length of the string.
+ final int minLengthVarIntSize = computeUInt32SizeNoTag(value.length());
+
+ if (minLengthVarIntSize == maxLengthVarIntSize) {
+ position = oldPosition + minLengthVarIntSize;
+ int newPosition = Utf8.encode(value, buffer, position, limit - position);
+ // Since this class is stateful and tracks the position, we rewind and store the state,
+ // prepend the length, then reset it back to the end of the string.
+ position = oldPosition;
+ int length = newPosition - oldPosition - minLengthVarIntSize;
+ bufferUInt32NoTag(length);
+ position = newPosition;
+ totalBytesWritten += length;
+ } else {
+ int length = Utf8.encodedLength(value);
+ bufferUInt32NoTag(length);
+ position = Utf8.encode(value, buffer, position, length);
+ totalBytesWritten += length;
+ }
+ } catch (UnpairedSurrogateException e) {
+ // Roll back the change and convert to an IOException.
+ totalBytesWritten -= position - oldPosition;
+ position = oldPosition;
+
+ // TODO(nathanmittler): We should throw an IOException here instead.
+ inefficientWriteStringNoTag(value, e);
+ } catch (IndexOutOfBoundsException e) {
+ throw new OutOfSpaceException(e);
+ }
+ }
+
+ @Override
+ public void flush() throws IOException {
+ if (position > 0) {
+ // Flush the buffer.
+ doFlush();
+ }
+ }
+
+ @Override
+ public void write(byte[] value, int offset, int length) throws IOException {
+ flush();
+ out.write(value, offset, length);
+ totalBytesWritten += length;
+ }
+
+ @Override
+ public void writeLazy(byte[] value, int offset, int length) throws IOException {
+ flush();
+ out.writeLazy(value, offset, length);
+ totalBytesWritten += length;
+ }
+
+ @Override
+ public void write(ByteBuffer value) throws IOException {
+ flush();
+ int length = value.remaining();
+ out.write(value);
+ totalBytesWritten += length;
+ }
+
+ @Override
+ public void writeLazy(ByteBuffer value) throws IOException {
+ flush();
+ int length = value.remaining();
+ out.writeLazy(value);
+ totalBytesWritten += length;
+ }
+
+ private void flushIfNotAvailable(int requiredSize) throws IOException {
+ if (limit - position < requiredSize) {
+ doFlush();
+ }
+ }
+
+ private void doFlush() throws IOException {
+ out.write(buffer, 0, position);
+ position = 0;
+ }
}
- public static final int LITTLE_ENDIAN_32_SIZE = 4;
+ /**
+ * An {@link CodedOutputStream} that decorates an {@link OutputStream}. It performs internal
+ * buffering to optimize writes to the {@link OutputStream}.
+ */
+ private static final class OutputStreamEncoder extends AbstractBufferedEncoder {
+ private final OutputStream out;
+
+ OutputStreamEncoder(OutputStream out, int bufferSize) {
+ super(bufferSize);
+ if (out == null) {
+ throw new NullPointerException("out");
+ }
+ this.out = out;
+ }
+
+ @Override
+ public void writeTag(final int fieldNumber, final int wireType) throws IOException {
+ writeUInt32NoTag(WireFormat.makeTag(fieldNumber, wireType));
+ }
+
+ @Override
+ public void writeInt32(final int fieldNumber, final int value) throws IOException {
+ flushIfNotAvailable(MAX_VARINT_SIZE * 2);
+ bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+ bufferInt32NoTag(value);
+ }
+
+ @Override
+ public void writeUInt32(final int fieldNumber, final int value) throws IOException {
+ flushIfNotAvailable(MAX_VARINT_SIZE * 2);
+ bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+ bufferUInt32NoTag(value);
+ }
+
+ @Override
+ public void writeFixed32(final int fieldNumber, final int value) throws IOException {
+ flushIfNotAvailable(MAX_VARINT_SIZE + FIXED_32_SIZE);
+ bufferTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
+ bufferFixed32NoTag(value);
+ }
+
+ @Override
+ public void writeUInt64(final int fieldNumber, final long value) throws IOException {
+ flushIfNotAvailable(MAX_VARINT_SIZE * 2);
+ bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+ bufferUInt64NoTag(value);
+ }
+
+ @Override
+ public void writeFixed64(final int fieldNumber, final long value) throws IOException {
+ flushIfNotAvailable(MAX_VARINT_SIZE + FIXED_64_SIZE);
+ bufferTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
+ bufferFixed64NoTag(value);
+ }
+
+ @Override
+ public void writeBool(final int fieldNumber, final boolean value) throws IOException {
+ flushIfNotAvailable(MAX_VARINT_SIZE + 1);
+ bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+ buffer((byte) (value ? 1 : 0));
+ }
+
+ @Override
+ public void writeString(final int fieldNumber, final String value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ writeStringNoTag(value);
+ }
+
+ @Override
+ public void writeBytes(final int fieldNumber, final ByteString value) throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ writeBytesNoTag(value);
+ }
+
+ @Override
+ public void writeByteArray(final int fieldNumber, final byte[] value) throws IOException {
+ writeByteArray(fieldNumber, value, 0, value.length);
+ }
+
+ @Override
+ public void writeByteArray(
+ final int fieldNumber, final byte[] value, final int offset, final int length)
+ throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ writeByteArrayNoTag(value, offset, length);
+ }
+
+ @Override
+ public void writeByteBuffer(final int fieldNumber, final ByteBuffer value)
+ throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ writeUInt32NoTag(value.capacity());
+ writeRawBytes(value);
+ }
+
+ @Override
+ public void writeBytesNoTag(final ByteString value) throws IOException {
+ writeUInt32NoTag(value.size());
+ value.writeTo(this);
+ }
+
+ @Override
+ public void writeByteArrayNoTag(final byte[] value, int offset, int length) throws IOException {
+ writeUInt32NoTag(length);
+ write(value, offset, length);
+ }
+
+ @Override
+ public void writeRawBytes(final ByteBuffer value) throws IOException {
+ if (value.hasArray()) {
+ write(value.array(), value.arrayOffset(), value.capacity());
+ } else {
+ ByteBuffer duplicated = value.duplicate();
+ duplicated.clear();
+ write(duplicated);
+ }
+ }
+
+ @Override
+ public void writeMessage(final int fieldNumber, final MessageLite value)
+ throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ writeMessageNoTag(value);
+ }
+
+ @Override
+ public void writeMessageSetExtension(final int fieldNumber, final MessageLite value)
+ throws IOException {
+ writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
+ writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
+ writeMessage(WireFormat.MESSAGE_SET_MESSAGE, value);
+ writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
+ }
+
+ @Override
+ public void writeRawMessageSetExtension(final int fieldNumber, final ByteString value)
+ throws IOException {
+ writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
+ writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
+ writeBytes(WireFormat.MESSAGE_SET_MESSAGE, value);
+ writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
+ }
+
+ @Override
+ public void writeMessageNoTag(final MessageLite value) throws IOException {
+ writeUInt32NoTag(value.getSerializedSize());
+ value.writeTo(this);
+ }
+
+ @Override
+ public void write(byte value) throws IOException {
+ if (position == limit) {
+ doFlush();
+ }
- /** Write a little-endian 64-bit integer. */
- public void writeRawLittleEndian64(final long value) throws IOException {
- writeRawByte((int)(value ) & 0xFF);
- writeRawByte((int)(value >> 8) & 0xFF);
- writeRawByte((int)(value >> 16) & 0xFF);
- writeRawByte((int)(value >> 24) & 0xFF);
- writeRawByte((int)(value >> 32) & 0xFF);
- writeRawByte((int)(value >> 40) & 0xFF);
- writeRawByte((int)(value >> 48) & 0xFF);
- writeRawByte((int)(value >> 56) & 0xFF);
+ buffer(value);
+ }
+
+ @Override
+ public void writeInt32NoTag(int value) throws IOException {
+ if (value >= 0) {
+ writeUInt32NoTag(value);
+ } else {
+ // Must sign-extend.
+ writeUInt64NoTag(value);
+ }
+ }
+
+ @Override
+ public void writeUInt32NoTag(int value) throws IOException {
+ flushIfNotAvailable(MAX_VARINT_SIZE);
+ bufferUInt32NoTag(value);
+ }
+
+ @Override
+ public void writeFixed32NoTag(final int value) throws IOException {
+ flushIfNotAvailable(FIXED_32_SIZE);
+ bufferFixed32NoTag(value);
+ }
+
+ @Override
+ public void writeUInt64NoTag(long value) throws IOException {
+ flushIfNotAvailable(MAX_VARINT_SIZE);
+ bufferUInt64NoTag(value);
+ }
+
+ @Override
+ public void writeFixed64NoTag(final long value) throws IOException {
+ flushIfNotAvailable(FIXED_64_SIZE);
+ bufferFixed64NoTag(value);
+ }
+
+ @Override
+ public void writeStringNoTag(String value) throws IOException {
+ try {
+ // UTF-8 byte length of the string is at least its UTF-16 code unit length (value.length()),
+ // and at most 3 times of it. We take advantage of this in both branches below.
+ final int maxLength = value.length() * Utf8.MAX_BYTES_PER_CHAR;
+ final int maxLengthVarIntSize = computeUInt32SizeNoTag(maxLength);
+
+ // If we are streaming and the potential length is too big to fit in our buffer, we take the
+ // slower path.
+ if (maxLengthVarIntSize + maxLength > limit) {
+ // Allocate a byte[] that we know can fit the string and encode into it. String.getBytes()
+ // does the same internally and then does *another copy* to return a byte[] of exactly the
+ // right size. We can skip that copy and just writeRawBytes up to the actualLength of the
+ // UTF-8 encoded bytes.
+ final byte[] encodedBytes = new byte[maxLength];
+ int actualLength = Utf8.encode(value, encodedBytes, 0, maxLength);
+ writeUInt32NoTag(actualLength);
+ writeLazy(encodedBytes, 0, actualLength);
+ return;
+ }
+
+ // Fast path: we have enough space available in our buffer for the string...
+ if (maxLengthVarIntSize + maxLength > limit - position) {
+ // Flush to free up space.
+ doFlush();
+ }
+
+ // Optimize for the case where we know this length results in a constant varint length as
+ // this saves a pass for measuring the length of the string.
+ final int minLengthVarIntSize = computeUInt32SizeNoTag(value.length());
+ int oldPosition = position;
+ final int length;
+ try {
+ if (minLengthVarIntSize == maxLengthVarIntSize) {
+ position = oldPosition + minLengthVarIntSize;
+ int newPosition = Utf8.encode(value, buffer, position, limit - position);
+ // Since this class is stateful and tracks the position, we rewind and store the
+ // state, prepend the length, then reset it back to the end of the string.
+ position = oldPosition;
+ length = newPosition - oldPosition - minLengthVarIntSize;
+ bufferUInt32NoTag(length);
+ position = newPosition;
+ } else {
+ length = Utf8.encodedLength(value);
+ bufferUInt32NoTag(length);
+ position = Utf8.encode(value, buffer, position, length);
+ }
+ totalBytesWritten += length;
+ } catch (UnpairedSurrogateException e) {
+ // Be extra careful and restore the original position for retrying the write with the
+ // less efficient path.
+ totalBytesWritten -= position - oldPosition;
+ position = oldPosition;
+ throw e;
+ } catch (ArrayIndexOutOfBoundsException e) {
+ throw new OutOfSpaceException(e);
+ }
+ } catch (UnpairedSurrogateException e) {
+ inefficientWriteStringNoTag(value, e);
+ }
+ }
+
+ @Override
+ public void flush() throws IOException {
+ if (position > 0) {
+ // Flush the buffer.
+ doFlush();
+ }
+ }
+
+ @Override
+ public void write(byte[] value, int offset, int length)
+ throws IOException {
+ if (limit - position >= length) {
+ // We have room in the current buffer.
+ System.arraycopy(value, offset, buffer, position, length);
+ position += length;
+ totalBytesWritten += length;
+ } else {
+ // Write extends past current buffer. Fill the rest of this buffer and
+ // flush.
+ final int bytesWritten = limit - position;
+ System.arraycopy(value, offset, buffer, position, bytesWritten);
+ offset += bytesWritten;
+ length -= bytesWritten;
+ position = limit;
+ totalBytesWritten += bytesWritten;
+ doFlush();
+
+ // Now deal with the rest.
+ // Since we have an output stream, this is our buffer
+ // and buffer offset == 0
+ if (length <= limit) {
+ // Fits in new buffer.
+ System.arraycopy(value, offset, buffer, 0, length);
+ position = length;
+ } else {
+ // Write is very big. Let's do it all at once.
+ out.write(value, offset, length);
+ }
+ totalBytesWritten += length;
+ }
+ }
+
+ @Override
+ public void writeLazy(byte[] value, int offset, int length) throws IOException {
+ write(value, offset, length);
+ }
+
+ @Override
+ public void write(ByteBuffer value) throws IOException {
+ int length = value.remaining();
+ if (limit - position >= length) {
+ // We have room in the current buffer.
+ value.get(buffer, position, length);
+ position += length;
+ totalBytesWritten += length;
+ } else {
+ // Write extends past current buffer. Fill the rest of this buffer and
+ // flush.
+ final int bytesWritten = limit - position;
+ value.get(buffer, position, bytesWritten);
+ length -= bytesWritten;
+ position = limit;
+ totalBytesWritten += bytesWritten;
+ doFlush();
+
+ // Now deal with the rest.
+ // Since we have an output stream, this is our buffer
+ // and buffer offset == 0
+ while (length > limit) {
+ // Copy data into the buffer before writing it to OutputStream.
+ value.get(buffer, 0, limit);
+ out.write(buffer, 0, limit);
+ length -= limit;
+ totalBytesWritten += limit;
+ }
+ value.get(buffer, 0, length);
+ position = length;
+ totalBytesWritten += length;
+ }
+ }
+
+ @Override
+ public void writeLazy(ByteBuffer value) throws IOException {
+ write(value);
+ }
+
+ private void flushIfNotAvailable(int requiredSize) throws IOException {
+ if (limit - position < requiredSize) {
+ doFlush();
+ }
+ }
+
+ private void doFlush() throws IOException {
+ out.write(buffer, 0, position);
+ position = 0;
+ }
}
- public static final int LITTLE_ENDIAN_64_SIZE = 8;
+ /**
+ * Gets the {@code sun.misc.Unsafe} instance, or {@code null} if not available on this
+ * platform.
+ */
+ private static sun.misc.Unsafe getUnsafe() {
+ sun.misc.Unsafe unsafe = null;
+ try {
+ unsafe = AccessController.doPrivileged(new PrivilegedExceptionAction<sun.misc.Unsafe>() {
+ @Override
+ public sun.misc.Unsafe run() throws Exception {
+ Class<sun.misc.Unsafe> k = sun.misc.Unsafe.class;
+
+ for (Field f : k.getDeclaredFields()) {
+ f.setAccessible(true);
+ Object x = f.get(null);
+ if (k.isInstance(x)) {
+ return k.cast(x);
+ }
+ }
+ // The sun.misc.Unsafe field does not exist.
+ return null;
+ }
+ });
+ } catch (Throwable e) {
+ // Catching Throwable here due to the fact that Google AppEngine raises NoClassDefFoundError
+ // for Unsafe.
+ }
+
+ logger.log(Level.FINEST, "sun.misc.Unsafe: {}",
+ unsafe != null ? "available" : "unavailable");
+ return unsafe;
+ }
/**
- * Encode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers
- * into values that can be efficiently encoded with varint. (Otherwise,
- * negative values must be sign-extended to 64 bits to be varint encoded,
- * thus always taking 10 bytes on the wire.)
- *
- * @param n A signed 32-bit integer.
- * @return An unsigned 32-bit integer, stored in a signed int because
- * Java has no explicit unsigned support.
+ * Indicates whether or not unsafe array operations are supported on this platform.
*/
- public static int encodeZigZag32(final int n) {
- // Note: the right-shift must be arithmetic
- return (n << 1) ^ (n >> 31);
+ // TODO(nathanmittler): Add support for Android's MemoryBlock.
+ private static boolean supportsUnsafeArrayOperations() {
+ boolean supported = false;
+ if (UNSAFE != null) {
+ try {
+ UNSAFE.getClass().getMethod("arrayBaseOffset", Class.class);
+ UNSAFE.getClass().getMethod("putByte", Object.class, long.class, byte.class);
+ supported = true;
+ } catch (Throwable e) {
+ // Do nothing.
+ }
+ }
+ logger.log(Level.FINEST, "Unsafe array operations: {}",
+ supported ? "available" : "unavailable");
+ return supported;
}
/**
- * Encode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers
- * into values that can be efficiently encoded with varint. (Otherwise,
- * negative values must be sign-extended to 64 bits to be varint encoded,
- * thus always taking 10 bytes on the wire.)
- *
- * @param n A signed 64-bit integer.
- * @return An unsigned 64-bit integer, stored in a signed int because
- * Java has no explicit unsigned support.
+ * Get the base offset for byte arrays, or {@code -1} if {@code sun.misc.Unsafe} is not
+ * available.
*/
- public static long encodeZigZag64(final long n) {
- // Note: the right-shift must be arithmetic
- return (n << 1) ^ (n >> 63);
+ private static <T> int byteArrayBaseOffset() {
+ return HAS_UNSAFE_ARRAY_OPERATIONS ? UNSAFE.arrayBaseOffset(byte[].class) : -1;
}
}
diff --git a/java/core/src/main/java/com/google/protobuf/Descriptors.java b/java/core/src/main/java/com/google/protobuf/Descriptors.java
index 5e15cfbe..e00ea342 100644
--- a/java/core/src/main/java/com/google/protobuf/Descriptors.java
+++ b/java/core/src/main/java/com/google/protobuf/Descriptors.java
@@ -74,16 +74,28 @@ public final class Descriptors {
*/
public static final class FileDescriptor extends GenericDescriptor {
/** Convert the descriptor to its protocol message representation. */
- public FileDescriptorProto toProto() { return proto; }
+ @Override
+ public FileDescriptorProto toProto() {
+ return proto;
+ }
/** Get the file name. */
- public String getName() { return proto.getName(); }
+ @Override
+ public String getName() {
+ return proto.getName();
+ }
/** Returns this object. */
- public FileDescriptor getFile() { return this; }
+ @Override
+ public FileDescriptor getFile() {
+ return this;
+ }
/** Returns the same as getName(). */
- public String getFullName() { return proto.getName(); }
+ @Override
+ public String getFullName() {
+ return proto.getName();
+ }
/**
* Get the proto package name. This is the package name given by the
@@ -272,7 +284,7 @@ public final class Descriptors {
* because a field has an undefined type or because two messages
* were defined with the same name.
*/
- private static FileDescriptor buildFrom(
+ public static FileDescriptor buildFrom(
final FileDescriptorProto proto, final FileDescriptor[] dependencies,
final boolean allowUnknownDependencies)
throws DescriptorValidationException {
@@ -582,10 +594,16 @@ public final class Descriptors {
public int getIndex() { return index; }
/** Convert the descriptor to its protocol message representation. */
- public DescriptorProto toProto() { return proto; }
+ @Override
+ public DescriptorProto toProto() {
+ return proto;
+ }
/** Get the type's unqualified name. */
- public String getName() { return proto.getName(); }
+ @Override
+ public String getName() {
+ return proto.getName();
+ }
/**
* Get the type's fully-qualified name, within the proto language's
@@ -598,10 +616,16 @@ public final class Descriptors {
* </pre>
* {@code Baz}'s full name is "foo.bar.Baz".
*/
- public String getFullName() { return fullName; }
+ @Override
+ public String getFullName() {
+ return fullName;
+ }
/** Get the {@link FileDescriptor} containing this descriptor. */
- public FileDescriptor getFile() { return file; }
+ @Override
+ public FileDescriptor getFile() {
+ return file;
+ }
/** If this is a nested type, get the outer descriptor, otherwise null. */
public Descriptor getContainingType() { return containingType; }
@@ -875,19 +899,31 @@ public final class Descriptors {
public int getIndex() { return index; }
/** Convert the descriptor to its protocol message representation. */
- public FieldDescriptorProto toProto() { return proto; }
+ @Override
+ public FieldDescriptorProto toProto() {
+ return proto;
+ }
/** Get the field's unqualified name. */
- public String getName() { return proto.getName(); }
+ @Override
+ public String getName() {
+ return proto.getName();
+ }
/** Get the field's number. */
- public int getNumber() { return proto.getNumber(); }
+ @Override
+ public int getNumber() {
+ return proto.getNumber();
+ }
/**
* Get the field's fully-qualified name.
* @see Descriptors.Descriptor#getFullName()
*/
- public String getFullName() { return fullName; }
+ @Override
+ public String getFullName() {
+ return fullName;
+ }
/** Get the JSON name of this field. */
public String getJsonName() {
@@ -901,17 +937,22 @@ public final class Descriptors {
public JavaType getJavaType() { return type.getJavaType(); }
/** For internal use only. */
+ @Override
public WireFormat.JavaType getLiteJavaType() {
return getLiteType().getJavaType();
}
/** Get the {@code FileDescriptor} containing this descriptor. */
- public FileDescriptor getFile() { return file; }
+ @Override
+ public FileDescriptor getFile() {
+ return file;
+ }
/** Get the field's declared type. */
public Type getType() { return type; }
/** For internal use only. */
+ @Override
public WireFormat.FieldType getLiteType() {
return table[type.ordinal()];
}
@@ -953,6 +994,7 @@ public final class Descriptors {
}
/** Is this field declared repeated? */
+ @Override
public boolean isRepeated() {
return proto.getLabel() == FieldDescriptorProto.Label.LABEL_REPEATED;
}
@@ -960,6 +1002,7 @@ public final class Descriptors {
/** Does this field have the {@code [packed = true]} option or is this field
* packable in proto3 and not explicitly setted to unpacked?
*/
+ @Override
public boolean isPacked() {
if (!isPackable()) {
return false;
@@ -1048,6 +1091,7 @@ public final class Descriptors {
}
/** For enum fields, gets the field's type. */
+ @Override
public EnumDescriptor getEnumType() {
if (getJavaType() != JavaType.ENUM) {
throw new UnsupportedOperationException(
@@ -1066,6 +1110,7 @@ public final class Descriptors {
* @return negative, zero, or positive if {@code this} is less than,
* equal to, or greater than {@code other}, respectively.
*/
+ @Override
public int compareTo(final FieldDescriptor other) {
if (other.containingType != containingType) {
throw new IllegalArgumentException(
@@ -1123,7 +1168,7 @@ public final class Descriptors {
private JavaType javaType;
public FieldDescriptorProto.Type toProto() {
- return FieldDescriptorProto.Type.valueOf(ordinal() + 1);
+ return FieldDescriptorProto.Type.forNumber(ordinal() + 1);
}
public JavaType getJavaType() { return javaType; }
@@ -1466,8 +1511,8 @@ public final class Descriptors {
* For internal use only. This is to satisfy the FieldDescriptorLite
* interface.
*/
- public MessageLite.Builder internalMergeFrom(
- MessageLite.Builder to, MessageLite from) {
+ @Override
+ public MessageLite.Builder internalMergeFrom(MessageLite.Builder to, MessageLite from) {
// FieldDescriptors are only used with non-lite messages so we can just
// down-cast and call mergeFrom directly.
return ((Message.Builder) to).mergeFrom((Message) from);
@@ -1487,19 +1532,31 @@ public final class Descriptors {
public int getIndex() { return index; }
/** Convert the descriptor to its protocol message representation. */
- public EnumDescriptorProto toProto() { return proto; }
+ @Override
+ public EnumDescriptorProto toProto() {
+ return proto;
+ }
/** Get the type's unqualified name. */
- public String getName() { return proto.getName(); }
+ @Override
+ public String getName() {
+ return proto.getName();
+ }
/**
* Get the type's fully-qualified name.
* @see Descriptors.Descriptor#getFullName()
*/
- public String getFullName() { return fullName; }
+ @Override
+ public String getFullName() {
+ return fullName;
+ }
/** Get the {@link FileDescriptor} containing this descriptor. */
- public FileDescriptor getFile() { return file; }
+ @Override
+ public FileDescriptor getFile() {
+ return file;
+ }
/** If this is a nested type, get the outer descriptor, otherwise null. */
public Descriptor getContainingType() { return containingType; }
@@ -1533,6 +1590,7 @@ public final class Descriptors {
* @param number The value's number.
* @return the value's descriptor, or {@code null} if not found.
*/
+ @Override
public EnumValueDescriptor findValueByNumber(final int number) {
return file.pool.enumValuesByNumber.get(
new DescriptorPool.DescriptorIntPair(this, number));
@@ -1659,13 +1717,22 @@ public final class Descriptors {
public int getIndex() { return index; }
/** Convert the descriptor to its protocol message representation. */
- public EnumValueDescriptorProto toProto() { return proto; }
+ @Override
+ public EnumValueDescriptorProto toProto() {
+ return proto;
+ }
/** Get the value's unqualified name. */
- public String getName() { return proto.getName(); }
+ @Override
+ public String getName() {
+ return proto.getName();
+ }
/** Get the value's number. */
- public int getNumber() { return proto.getNumber(); }
+ @Override
+ public int getNumber() {
+ return proto.getNumber();
+ }
@Override
public String toString() { return proto.getName(); }
@@ -1674,10 +1741,16 @@ public final class Descriptors {
* Get the value's fully-qualified name.
* @see Descriptors.Descriptor#getFullName()
*/
- public String getFullName() { return fullName; }
+ @Override
+ public String getFullName() {
+ return fullName;
+ }
/** Get the {@link FileDescriptor} containing this descriptor. */
- public FileDescriptor getFile() { return file; }
+ @Override
+ public FileDescriptor getFile() {
+ return file;
+ }
/** Get the value's enum type. */
public EnumDescriptor getType() { return type; }
@@ -1745,19 +1818,31 @@ public final class Descriptors {
public int getIndex() { return index; }
/** Convert the descriptor to its protocol message representation. */
- public ServiceDescriptorProto toProto() { return proto; }
+ @Override
+ public ServiceDescriptorProto toProto() {
+ return proto;
+ }
/** Get the type's unqualified name. */
- public String getName() { return proto.getName(); }
+ @Override
+ public String getName() {
+ return proto.getName();
+ }
/**
* Get the type's fully-qualified name.
* @see Descriptors.Descriptor#getFullName()
*/
- public String getFullName() { return fullName; }
+ @Override
+ public String getFullName() {
+ return fullName;
+ }
/** Get the {@link FileDescriptor} containing this descriptor. */
- public FileDescriptor getFile() { return file; }
+ @Override
+ public FileDescriptor getFile() {
+ return file;
+ }
/** Get the {@code ServiceOptions}, defined in {@code descriptor.proto}. */
public ServiceOptions getOptions() { return proto.getOptions(); }
@@ -1835,19 +1920,31 @@ public final class Descriptors {
public int getIndex() { return index; }
/** Convert the descriptor to its protocol message representation. */
- public MethodDescriptorProto toProto() { return proto; }
+ @Override
+ public MethodDescriptorProto toProto() {
+ return proto;
+ }
/** Get the method's unqualified name. */
- public String getName() { return proto.getName(); }
+ @Override
+ public String getName() {
+ return proto.getName();
+ }
/**
* Get the method's fully-qualified name.
* @see Descriptors.Descriptor#getFullName()
*/
- public String getFullName() { return fullName; }
+ @Override
+ public String getFullName() {
+ return fullName;
+ }
/** Get the {@link FileDescriptor} containing this descriptor. */
- public FileDescriptor getFile() { return file; }
+ @Override
+ public FileDescriptor getFile() {
+ return file;
+ }
/** Get the method's service type. */
public ServiceDescriptor getService() { return service; }
@@ -2248,10 +2345,22 @@ public final class Descriptors {
* that has the same name as an existing package.
*/
private static final class PackageDescriptor extends GenericDescriptor {
- public Message toProto() { return file.toProto(); }
- public String getName() { return name; }
- public String getFullName() { return fullName; }
- public FileDescriptor getFile() { return file; }
+ @Override
+ public Message toProto() {
+ return file.toProto();
+ }
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getFullName() {
+ return fullName;
+ }
+ @Override
+ public FileDescriptor getFile() {
+ return file;
+ }
PackageDescriptor(final String name, final String fullName,
final FileDescriptor file) {
diff --git a/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java b/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java
index bcc9d6ee..a9543b83 100644
--- a/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java
@@ -34,7 +34,6 @@ import com.google.protobuf.Internal.DoubleList;
import java.util.Arrays;
import java.util.Collection;
-import java.util.List;
import java.util.RandomAccess;
/**
@@ -45,8 +44,6 @@ import java.util.RandomAccess;
final class DoubleArrayList
extends AbstractProtobufList<Double> implements DoubleList, RandomAccess {
- private static final int DEFAULT_CAPACITY = 10;
-
private static final DoubleArrayList EMPTY_LIST = new DoubleArrayList();
static {
EMPTY_LIST.makeImmutable();
@@ -71,32 +68,56 @@ final class DoubleArrayList
* Constructs a new mutable {@code DoubleArrayList} with default capacity.
*/
DoubleArrayList() {
- this(DEFAULT_CAPACITY);
- }
-
- /**
- * Constructs a new mutable {@code DoubleArrayList} with the provided capacity.
- */
- DoubleArrayList(int capacity) {
- array = new double[capacity];
- size = 0;
+ this(new double[DEFAULT_CAPACITY], 0);
}
/**
* Constructs a new mutable {@code DoubleArrayList} containing the same elements as {@code other}.
*/
- DoubleArrayList(List<Double> other) {
- if (other instanceof DoubleArrayList) {
- DoubleArrayList list = (DoubleArrayList) other;
- array = list.array.clone();
- size = list.size;
- } else {
- size = other.size();
- array = new double[size];
- for (int i = 0; i < size; i++) {
- array[i] = other.get(i);
+ private DoubleArrayList(double[] array, int size) {
+ this.array = array;
+ this.size = size;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof DoubleArrayList)) {
+ return super.equals(o);
+ }
+ DoubleArrayList other = (DoubleArrayList) o;
+ if (size != other.size) {
+ return false;
+ }
+
+ final double[] arr = other.array;
+ for (int i = 0; i < size; i++) {
+ if (array[i] != arr[i]) {
+ return false;
}
}
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 1;
+ for (int i = 0; i < size; i++) {
+ long bits = Double.doubleToLongBits(array[i]);
+ result = (31 * result) + Internal.hashLong(bits);
+ }
+ return result;
+ }
+
+ @Override
+ public DoubleList mutableCopyWithCapacity(int capacity) {
+ if (capacity < size) {
+ throw new IllegalArgumentException();
+ }
+ return new DoubleArrayList(Arrays.copyOf(array, capacity), size);
}
@Override
diff --git a/java/core/src/main/java/com/google/protobuf/DynamicMessage.java b/java/core/src/main/java/com/google/protobuf/DynamicMessage.java
index 3ea1b688..859a9e8f 100644
--- a/java/core/src/main/java/com/google/protobuf/DynamicMessage.java
+++ b/java/core/src/main/java/com/google/protobuf/DynamicMessage.java
@@ -156,18 +156,22 @@ public final class DynamicMessage extends AbstractMessage {
// -----------------------------------------------------------------
// Implementation of Message interface.
+ @Override
public Descriptor getDescriptorForType() {
return type;
}
+ @Override
public DynamicMessage getDefaultInstanceForType() {
return getDefaultInstance(type);
}
+ @Override
public Map<FieldDescriptor, Object> getAllFields() {
return fields.getAllFields();
}
+ @Override
public boolean hasOneof(OneofDescriptor oneof) {
verifyOneofContainingType(oneof);
FieldDescriptor field = oneofCases[oneof.getIndex()];
@@ -177,16 +181,19 @@ public final class DynamicMessage extends AbstractMessage {
return true;
}
+ @Override
public FieldDescriptor getOneofFieldDescriptor(OneofDescriptor oneof) {
verifyOneofContainingType(oneof);
return oneofCases[oneof.getIndex()];
}
+ @Override
public boolean hasField(FieldDescriptor field) {
verifyContainingType(field);
return fields.hasField(field);
}
+ @Override
public Object getField(FieldDescriptor field) {
verifyContainingType(field);
Object result = fields.getField(field);
@@ -202,16 +209,19 @@ public final class DynamicMessage extends AbstractMessage {
return result;
}
+ @Override
public int getRepeatedFieldCount(FieldDescriptor field) {
verifyContainingType(field);
return fields.getRepeatedFieldCount(field);
}
+ @Override
public Object getRepeatedField(FieldDescriptor field, int index) {
verifyContainingType(field);
return fields.getRepeatedField(field, index);
}
+ @Override
public UnknownFieldSet getUnknownFields() {
return unknownFields;
}
@@ -264,19 +274,22 @@ public final class DynamicMessage extends AbstractMessage {
return size;
}
+ @Override
public Builder newBuilderForType() {
return new Builder(type);
}
+ @Override
public Builder toBuilder() {
return newBuilderForType().mergeFrom(this);
}
+ @Override
public Parser<DynamicMessage> getParserForType() {
return new AbstractParser<DynamicMessage>() {
+ @Override
public DynamicMessage parsePartialFrom(
- CodedInputStream input,
- ExtensionRegistryLite extensionRegistry)
+ CodedInputStream input, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
Builder builder = newBuilder(type);
try {
@@ -370,6 +383,7 @@ public final class DynamicMessage extends AbstractMessage {
}
}
+ @Override
public DynamicMessage build() {
if (!isInitialized()) {
throw newUninitializedMessageException(
@@ -394,6 +408,7 @@ public final class DynamicMessage extends AbstractMessage {
return buildPartial();
}
+ @Override
public DynamicMessage buildPartial() {
fields.makeImmutable();
DynamicMessage result =
@@ -411,22 +426,27 @@ public final class DynamicMessage extends AbstractMessage {
return result;
}
+ @Override
public boolean isInitialized() {
return DynamicMessage.isInitialized(type, fields);
}
+ @Override
public Descriptor getDescriptorForType() {
return type;
}
+ @Override
public DynamicMessage getDefaultInstanceForType() {
return getDefaultInstance(type);
}
+ @Override
public Map<FieldDescriptor, Object> getAllFields() {
return fields.getAllFields();
}
+ @Override
public Builder newBuilderForField(FieldDescriptor field) {
verifyContainingType(field);
@@ -438,6 +458,7 @@ public final class DynamicMessage extends AbstractMessage {
return new Builder(field.getMessageType());
}
+ @Override
public boolean hasOneof(OneofDescriptor oneof) {
verifyOneofContainingType(oneof);
FieldDescriptor field = oneofCases[oneof.getIndex()];
@@ -447,11 +468,13 @@ public final class DynamicMessage extends AbstractMessage {
return true;
}
+ @Override
public FieldDescriptor getOneofFieldDescriptor(OneofDescriptor oneof) {
verifyOneofContainingType(oneof);
return oneofCases[oneof.getIndex()];
}
+ @Override
public Builder clearOneof(OneofDescriptor oneof) {
verifyOneofContainingType(oneof);
FieldDescriptor field = oneofCases[oneof.getIndex()];
@@ -461,11 +484,13 @@ public final class DynamicMessage extends AbstractMessage {
return this;
}
+ @Override
public boolean hasField(FieldDescriptor field) {
verifyContainingType(field);
return fields.hasField(field);
}
+ @Override
public Object getField(FieldDescriptor field) {
verifyContainingType(field);
Object result = fields.getField(field);
@@ -481,6 +506,7 @@ public final class DynamicMessage extends AbstractMessage {
return result;
}
+ @Override
public Builder setField(FieldDescriptor field, Object value) {
verifyContainingType(field);
ensureIsMutable();
@@ -505,6 +531,7 @@ public final class DynamicMessage extends AbstractMessage {
return this;
}
+ @Override
public Builder clearField(FieldDescriptor field) {
verifyContainingType(field);
ensureIsMutable();
@@ -519,24 +546,27 @@ public final class DynamicMessage extends AbstractMessage {
return this;
}
+ @Override
public int getRepeatedFieldCount(FieldDescriptor field) {
verifyContainingType(field);
return fields.getRepeatedFieldCount(field);
}
+ @Override
public Object getRepeatedField(FieldDescriptor field, int index) {
verifyContainingType(field);
return fields.getRepeatedField(field, index);
}
- public Builder setRepeatedField(FieldDescriptor field,
- int index, Object value) {
+ @Override
+ public Builder setRepeatedField(FieldDescriptor field, int index, Object value) {
verifyContainingType(field);
ensureIsMutable();
fields.setRepeatedField(field, index, value);
return this;
}
+ @Override
public Builder addRepeatedField(FieldDescriptor field, Object value) {
verifyContainingType(field);
ensureIsMutable();
@@ -544,10 +574,12 @@ public final class DynamicMessage extends AbstractMessage {
return this;
}
+ @Override
public UnknownFieldSet getUnknownFields() {
return unknownFields;
}
+ @Override
public Builder setUnknownFields(UnknownFieldSet unknownFields) {
if (getDescriptorForType().getFile().getSyntax()
== Descriptors.FileDescriptor.Syntax.PROTO3) {
diff --git a/java/core/src/main/java/com/google/protobuf/ExperimentalApi.java b/java/core/src/main/java/com/google/protobuf/ExperimentalApi.java
index 6f41fb81..3cd4c884 100644
--- a/java/core/src/main/java/com/google/protobuf/ExperimentalApi.java
+++ b/java/core/src/main/java/com/google/protobuf/ExperimentalApi.java
@@ -1,3 +1,33 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
package com.google.protobuf;
import java.lang.annotation.Documented;
diff --git a/java/core/src/main/java/com/google/protobuf/Extension.java b/java/core/src/main/java/com/google/protobuf/Extension.java
index 68d29f33..08ec5b45 100644
--- a/java/core/src/main/java/com/google/protobuf/Extension.java
+++ b/java/core/src/main/java/com/google/protobuf/Extension.java
@@ -42,6 +42,7 @@ public abstract class Extension<ContainingType extends MessageLite, Type>
public abstract Descriptors.FieldDescriptor getDescriptor();
/** Returns whether or not this extension is a Lite Extension. */
+ @Override
final boolean isLite() {
return false;
}
diff --git a/java/core/src/main/java/com/google/protobuf/FieldSet.java b/java/core/src/main/java/com/google/protobuf/FieldSet.java
index 47924b65..4e89709f 100644
--- a/java/core/src/main/java/com/google/protobuf/FieldSet.java
+++ b/java/core/src/main/java/com/google/protobuf/FieldSet.java
@@ -120,6 +120,25 @@ final class FieldSet<FieldDescriptorType extends
public boolean isImmutable() {
return isImmutable;
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+
+ if (!(o instanceof FieldSet)) {
+ return false;
+ }
+
+ FieldSet<?> other = (FieldSet<?>) o;
+ return other.fields.equals(other.fields);
+ }
+
+ @Override
+ public int hashCode() {
+ return fields.hashCode();
+ }
/**
* Clones the FieldSet. The returned FieldSet will be mutable even if the
diff --git a/java/core/src/main/java/com/google/protobuf/FloatArrayList.java b/java/core/src/main/java/com/google/protobuf/FloatArrayList.java
index 033b5eed..63cb6d77 100644
--- a/java/core/src/main/java/com/google/protobuf/FloatArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/FloatArrayList.java
@@ -34,7 +34,6 @@ import com.google.protobuf.Internal.FloatList;
import java.util.Arrays;
import java.util.Collection;
-import java.util.List;
import java.util.RandomAccess;
/**
@@ -44,8 +43,6 @@ import java.util.RandomAccess;
*/
final class FloatArrayList extends AbstractProtobufList<Float> implements FloatList, RandomAccess {
- private static final int DEFAULT_CAPACITY = 10;
-
private static final FloatArrayList EMPTY_LIST = new FloatArrayList();
static {
EMPTY_LIST.makeImmutable();
@@ -70,32 +67,55 @@ final class FloatArrayList extends AbstractProtobufList<Float> implements FloatL
* Constructs a new mutable {@code FloatArrayList} with default capacity.
*/
FloatArrayList() {
- this(DEFAULT_CAPACITY);
- }
-
- /**
- * Constructs a new mutable {@code FloatArrayList} with the provided capacity.
- */
- FloatArrayList(int capacity) {
- array = new float[capacity];
- size = 0;
+ this(new float[DEFAULT_CAPACITY], 0);
}
/**
* Constructs a new mutable {@code FloatArrayList} containing the same elements as {@code other}.
*/
- FloatArrayList(List<Float> other) {
- if (other instanceof FloatArrayList) {
- FloatArrayList list = (FloatArrayList) other;
- array = list.array.clone();
- size = list.size;
- } else {
- size = other.size();
- array = new float[size];
- for (int i = 0; i < size; i++) {
- array[i] = other.get(i);
+ private FloatArrayList(float[] array, int size) {
+ this.array = array;
+ this.size = size;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof FloatArrayList)) {
+ return super.equals(o);
+ }
+ FloatArrayList other = (FloatArrayList) o;
+ if (size != other.size) {
+ return false;
+ }
+
+ final float[] arr = other.array;
+ for (int i = 0; i < size; i++) {
+ if (array[i] != arr[i]) {
+ return false;
}
}
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 1;
+ for (int i = 0; i < size; i++) {
+ result = (31 * result) + Float.floatToIntBits(array[i]);
+ }
+ return result;
+ }
+
+ @Override
+ public FloatList mutableCopyWithCapacity(int capacity) {
+ if (capacity < size) {
+ throw new IllegalArgumentException();
+ }
+ return new FloatArrayList(Arrays.copyOf(array, capacity), size);
}
@Override
diff --git a/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java b/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java
index ceb97a4e..790cb622 100644
--- a/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java
+++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java
@@ -80,6 +80,7 @@ public abstract class GeneratedMessage extends AbstractMessage
unknownFields = builder.getUnknownFields();
}
+ @Override
public Parser<? extends GeneratedMessage> getParserForType() {
throw new UnsupportedOperationException(
"This is supposed to be overridden by subclasses.");
@@ -102,7 +103,7 @@ public abstract class GeneratedMessage extends AbstractMessage
*/
protected abstract FieldAccessorTable internalGetFieldAccessorTable();
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public Descriptor getDescriptorForType() {
return internalGetFieldAccessorTable().descriptor;
}
@@ -191,7 +192,7 @@ public abstract class GeneratedMessage extends AbstractMessage
return true;
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public Map<FieldDescriptor, Object> getAllFields() {
return Collections.unmodifiableMap(
getAllFieldsMutable(/* getBytesForString = */ false));
@@ -212,22 +213,22 @@ public abstract class GeneratedMessage extends AbstractMessage
getAllFieldsMutable(/* getBytesForString = */ true));
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public boolean hasOneof(final OneofDescriptor oneof) {
return internalGetFieldAccessorTable().getOneof(oneof).has(this);
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public FieldDescriptor getOneofFieldDescriptor(final OneofDescriptor oneof) {
return internalGetFieldAccessorTable().getOneof(oneof).get(this);
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public boolean hasField(final FieldDescriptor field) {
return internalGetFieldAccessorTable().getField(field).has(this);
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public Object getField(final FieldDescriptor field) {
return internalGetFieldAccessorTable().getField(field).get(this);
}
@@ -244,19 +245,19 @@ public abstract class GeneratedMessage extends AbstractMessage
return internalGetFieldAccessorTable().getField(field).getRaw(this);
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public int getRepeatedFieldCount(final FieldDescriptor field) {
return internalGetFieldAccessorTable().getField(field)
.getRepeatedCount(this);
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public Object getRepeatedField(final FieldDescriptor field, final int index) {
return internalGetFieldAccessorTable().getField(field)
.getRepeated(this, index);
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public UnknownFieldSet getUnknownFields() {
throw new UnsupportedOperationException(
"This is supposed to be overridden by subclasses.");
@@ -380,7 +381,7 @@ public abstract class GeneratedMessage extends AbstractMessage
}
@SuppressWarnings("unchecked")
- public abstract static class Builder <BuilderType extends Builder>
+ public abstract static class Builder <BuilderType extends Builder<BuilderType>>
extends AbstractMessage.Builder<BuilderType> {
private BuilderParent builderParent;
@@ -444,6 +445,7 @@ public abstract class GeneratedMessage extends AbstractMessage
* Called by the initialization and clear code paths to allow subclasses to
* reset any of their builtin fields back to the initial values.
*/
+ @Override
public BuilderType clear() {
unknownFields = UnknownFieldSet.getDefaultInstance();
onChanged();
@@ -457,12 +459,12 @@ public abstract class GeneratedMessage extends AbstractMessage
*/
protected abstract FieldAccessorTable internalGetFieldAccessorTable();
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public Descriptor getDescriptorForType() {
return internalGetFieldAccessorTable().descriptor;
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public Map<FieldDescriptor, Object> getAllFields() {
return Collections.unmodifiableMap(getAllFieldsMutable());
}
@@ -510,39 +512,38 @@ public abstract class GeneratedMessage extends AbstractMessage
return result;
}
- public Message.Builder newBuilderForField(
- final FieldDescriptor field) {
+ @Override
+ public Message.Builder newBuilderForField(final FieldDescriptor field) {
return internalGetFieldAccessorTable().getField(field).newBuilder();
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public Message.Builder getFieldBuilder(final FieldDescriptor field) {
return internalGetFieldAccessorTable().getField(field).getBuilder(this);
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
- public Message.Builder getRepeatedFieldBuilder(final FieldDescriptor field,
- int index) {
+ @Override
+ public Message.Builder getRepeatedFieldBuilder(final FieldDescriptor field, int index) {
return internalGetFieldAccessorTable().getField(field).getRepeatedBuilder(
this, index);
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public boolean hasOneof(final OneofDescriptor oneof) {
return internalGetFieldAccessorTable().getOneof(oneof).has(this);
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public FieldDescriptor getOneofFieldDescriptor(final OneofDescriptor oneof) {
return internalGetFieldAccessorTable().getOneof(oneof).get(this);
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public boolean hasField(final FieldDescriptor field) {
return internalGetFieldAccessorTable().getField(field).has(this);
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public Object getField(final FieldDescriptor field) {
Object object = internalGetFieldAccessorTable().getField(field).get(this);
if (field.isRepeated()) {
@@ -554,52 +555,52 @@ public abstract class GeneratedMessage extends AbstractMessage
}
}
- public BuilderType setField(final FieldDescriptor field,
- final Object value) {
+ @Override
+ public BuilderType setField(final FieldDescriptor field, final Object value) {
internalGetFieldAccessorTable().getField(field).set(this, value);
return (BuilderType) this;
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public BuilderType clearField(final FieldDescriptor field) {
internalGetFieldAccessorTable().getField(field).clear(this);
return (BuilderType) this;
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public BuilderType clearOneof(final OneofDescriptor oneof) {
internalGetFieldAccessorTable().getOneof(oneof).clear(this);
return (BuilderType) this;
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public int getRepeatedFieldCount(final FieldDescriptor field) {
return internalGetFieldAccessorTable().getField(field)
.getRepeatedCount(this);
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
- public Object getRepeatedField(final FieldDescriptor field,
- final int index) {
+ @Override
+ public Object getRepeatedField(final FieldDescriptor field, final int index) {
return internalGetFieldAccessorTable().getField(field)
.getRepeated(this, index);
}
- public BuilderType setRepeatedField(final FieldDescriptor field,
- final int index, final Object value) {
+ @Override
+ public BuilderType setRepeatedField(
+ final FieldDescriptor field, final int index, final Object value) {
internalGetFieldAccessorTable().getField(field)
.setRepeated(this, index, value);
return (BuilderType) this;
}
- public BuilderType addRepeatedField(final FieldDescriptor field,
- final Object value) {
+ @Override
+ public BuilderType addRepeatedField(final FieldDescriptor field, final Object value) {
internalGetFieldAccessorTable().getField(field).addRepeated(this, value);
return (BuilderType) this;
}
- public BuilderType setUnknownFields(
- final UnknownFieldSet unknownFields) {
+ @Override
+ public BuilderType setUnknownFields(final UnknownFieldSet unknownFields) {
this.unknownFields = unknownFields;
onChanged();
return (BuilderType) this;
@@ -616,7 +617,7 @@ public abstract class GeneratedMessage extends AbstractMessage
return (BuilderType) this;
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public boolean isInitialized() {
for (final FieldDescriptor field : getDescriptorForType().getFields()) {
// Check that all required fields are present.
@@ -646,7 +647,7 @@ public abstract class GeneratedMessage extends AbstractMessage
return true;
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public final UnknownFieldSet getUnknownFields() {
return unknownFields;
}
@@ -670,7 +671,7 @@ public abstract class GeneratedMessage extends AbstractMessage
*/
private class BuilderParentImpl implements BuilderParent {
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public void markDirty() {
onChanged();
}
@@ -735,6 +736,7 @@ public abstract class GeneratedMessage extends AbstractMessage
public interface ExtendableMessageOrBuilder<
MessageType extends ExtendableMessage> extends MessageOrBuilder {
// Re-define for return type covariance.
+ @Override
Message getDefaultInstanceForType();
/** Check if a singular extension is present. */
@@ -795,6 +797,8 @@ public abstract class GeneratedMessage extends AbstractMessage
extends GeneratedMessage
implements ExtendableMessageOrBuilder<MessageType> {
+ private static final long serialVersionUID = 1L;
+
private final FieldSet<FieldDescriptor> extensions;
protected ExtendableMessage() {
@@ -821,9 +825,8 @@ public abstract class GeneratedMessage extends AbstractMessage
}
/** Check if a singular extension is present. */
- //@Override (Java 1.6 override semantics, but we must support 1.5)
- public final <Type> boolean hasExtension(
- final ExtensionLite<MessageType, Type> extensionLite) {
+ @Override
+ public final <Type> boolean hasExtension(final ExtensionLite<MessageType, Type> extensionLite) {
Extension<MessageType, Type> extension = checkNotLite(extensionLite);
verifyExtensionContainingType(extension);
@@ -831,7 +834,7 @@ public abstract class GeneratedMessage extends AbstractMessage
}
/** Get the number of elements in a repeated extension. */
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public final <Type> int getExtensionCount(
final ExtensionLite<MessageType, List<Type>> extensionLite) {
Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
@@ -842,10 +845,9 @@ public abstract class GeneratedMessage extends AbstractMessage
}
/** Get the value of an extension. */
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
@SuppressWarnings("unchecked")
- public final <Type> Type getExtension(
- final ExtensionLite<MessageType, Type> extensionLite) {
+ public final <Type> Type getExtension(final ExtensionLite<MessageType, Type> extensionLite) {
Extension<MessageType, Type> extension = checkNotLite(extensionLite);
verifyExtensionContainingType(extension);
@@ -867,11 +869,10 @@ public abstract class GeneratedMessage extends AbstractMessage
}
/** Get one element of a repeated extension. */
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
@SuppressWarnings("unchecked")
public final <Type> Type getExtension(
- final ExtensionLite<MessageType, List<Type>> extensionLite,
- final int index) {
+ final ExtensionLite<MessageType, List<Type>> extensionLite, final int index) {
Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
verifyExtensionContainingType(extension);
@@ -1019,7 +1020,9 @@ public abstract class GeneratedMessage extends AbstractMessage
verifyContainingType(field);
final Object value = extensions.getField(field);
if (value == null) {
- if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+ if (field.isRepeated()) {
+ return Collections.emptyList();
+ } else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
// Lacking an ExtensionRegistry, we have no way to determine the
// extension's real type, so we return a DynamicMessage.
return DynamicMessage.getDefaultInstance(field.getMessageType());
@@ -1103,7 +1106,7 @@ public abstract class GeneratedMessage extends AbstractMessage
@SuppressWarnings("unchecked")
public abstract static class ExtendableBuilder<
MessageType extends ExtendableMessage,
- BuilderType extends ExtendableBuilder>
+ BuilderType extends ExtendableBuilder<MessageType, BuilderType>>
extends Builder<BuilderType>
implements ExtendableMessageOrBuilder<MessageType> {
@@ -1155,9 +1158,8 @@ public abstract class GeneratedMessage extends AbstractMessage
}
/** Check if a singular extension is present. */
- //@Override (Java 1.6 override semantics, but we must support 1.5)
- public final <Type> boolean hasExtension(
- final ExtensionLite<MessageType, Type> extensionLite) {
+ @Override
+ public final <Type> boolean hasExtension(final ExtensionLite<MessageType, Type> extensionLite) {
Extension<MessageType, Type> extension = checkNotLite(extensionLite);
verifyExtensionContainingType(extension);
@@ -1165,7 +1167,7 @@ public abstract class GeneratedMessage extends AbstractMessage
}
/** Get the number of elements in a repeated extension. */
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public final <Type> int getExtensionCount(
final ExtensionLite<MessageType, List<Type>> extensionLite) {
Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
@@ -1176,9 +1178,8 @@ public abstract class GeneratedMessage extends AbstractMessage
}
/** Get the value of an extension. */
- //@Override (Java 1.6 override semantics, but we must support 1.5)
- public final <Type> Type getExtension(
- final ExtensionLite<MessageType, Type> extensionLite) {
+ @Override
+ public final <Type> Type getExtension(final ExtensionLite<MessageType, Type> extensionLite) {
Extension<MessageType, Type> extension = checkNotLite(extensionLite);
verifyExtensionContainingType(extension);
@@ -1200,10 +1201,9 @@ public abstract class GeneratedMessage extends AbstractMessage
}
/** Get one element of a repeated extension. */
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public final <Type> Type getExtension(
- final ExtensionLite<MessageType, List<Type>> extensionLite,
- final int index) {
+ final ExtensionLite<MessageType, List<Type>> extensionLite, final int index) {
Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
verifyExtensionContainingType(extension);
@@ -1456,10 +1456,9 @@ public abstract class GeneratedMessage extends AbstractMessage
// obtained.
return new GeneratedExtension<ContainingType, Type>(
new CachedDescriptorRetriever() {
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public FieldDescriptor loadDescriptor() {
- return scope.getDescriptorForType().getExtensions()
- .get(descriptorIndex);
+ return scope.getDescriptorForType().getExtensions().get(descriptorIndex);
}
},
singularType,
@@ -1487,6 +1486,7 @@ public abstract class GeneratedMessage extends AbstractMessage
private volatile FieldDescriptor descriptor;
protected abstract FieldDescriptor loadDescriptor();
+ @Override
public FieldDescriptor getDescriptor() {
if (descriptor == null) {
synchronized (this) {
@@ -1516,6 +1516,7 @@ public abstract class GeneratedMessage extends AbstractMessage
// obtained.
return new GeneratedExtension<ContainingType, Type>(
new CachedDescriptorRetriever() {
+ @Override
protected FieldDescriptor loadDescriptor() {
return scope.getDescriptorForType().findFieldByName(name);
}
@@ -1542,17 +1543,18 @@ public abstract class GeneratedMessage extends AbstractMessage
// used to obtain the extension's FieldDescriptor.
return new GeneratedExtension<ContainingType, Type>(
new CachedDescriptorRetriever() {
+ @Override
protected FieldDescriptor loadDescriptor() {
try {
- Class clazz =
- singularType.getClassLoader().loadClass(descriptorOuterClass);
- FileDescriptor file =
- (FileDescriptor) clazz.getField("descriptor").get(null);
+ Class clazz = singularType.getClassLoader().loadClass(descriptorOuterClass);
+ FileDescriptor file = (FileDescriptor) clazz.getField("descriptor").get(null);
return file.findExtensionByName(extensionName);
} catch (Exception e) {
throw new RuntimeException(
- "Cannot load descriptors: " + descriptorOuterClass +
- " is not a valid descriptor class name", e);
+ "Cannot load descriptors: "
+ + descriptorOuterClass
+ + " is not a valid descriptor class name",
+ e);
}
}
},
@@ -1634,12 +1636,13 @@ public abstract class GeneratedMessage extends AbstractMessage
if (descriptorRetriever != null) {
throw new IllegalStateException("Already initialized.");
}
- descriptorRetriever = new ExtensionDescriptorRetriever() {
- //@Override (Java 1.6 override semantics, but we must support 1.5)
- public FieldDescriptor getDescriptor() {
- return descriptor;
- }
- };
+ descriptorRetriever =
+ new ExtensionDescriptorRetriever() {
+ @Override
+ public FieldDescriptor getDescriptor() {
+ return descriptor;
+ }
+ };
}
private ExtensionDescriptorRetriever descriptorRetriever;
@@ -1649,6 +1652,7 @@ public abstract class GeneratedMessage extends AbstractMessage
private final Method enumGetValueDescriptor;
private final ExtensionType extensionType;
+ @Override
public FieldDescriptor getDescriptor() {
if (descriptorRetriever == null) {
throw new IllegalStateException(
@@ -1661,10 +1665,12 @@ public abstract class GeneratedMessage extends AbstractMessage
* If the extension is an embedded message or group, returns the default
* instance of the message.
*/
+ @Override
public Message getMessageDefaultInstance() {
return messageDefaultInstance;
}
+ @Override
protected ExtensionType getExtensionType() {
return extensionType;
}
@@ -1675,7 +1681,7 @@ public abstract class GeneratedMessage extends AbstractMessage
* EnumValueDescriptors but the native accessors use the generated enum
* type.
*/
- // @Override
+ @Override
@SuppressWarnings("unchecked")
protected Object fromReflectionType(final Object value) {
FieldDescriptor descriptor = getDescriptor();
@@ -1700,7 +1706,7 @@ public abstract class GeneratedMessage extends AbstractMessage
* Like {@link #fromReflectionType(Object)}, but if the type is a repeated
* type, this converts a single element.
*/
- // @Override
+ @Override
protected Object singularFromReflectionType(final Object value) {
FieldDescriptor descriptor = getDescriptor();
switch (descriptor.getJavaType()) {
@@ -1724,7 +1730,7 @@ public abstract class GeneratedMessage extends AbstractMessage
* EnumValueDescriptors but the native accessors use the generated enum
* type.
*/
- // @Override
+ @Override
@SuppressWarnings("unchecked")
protected Object toReflectionType(final Object value) {
FieldDescriptor descriptor = getDescriptor();
@@ -1748,7 +1754,7 @@ public abstract class GeneratedMessage extends AbstractMessage
* Like {@link #toReflectionType(Object)}, but if the type is a repeated
* type, this converts a single element.
*/
- // @Override
+ @Override
protected Object singularToReflectionType(final Object value) {
FieldDescriptor descriptor = getDescriptor();
switch (descriptor.getJavaType()) {
@@ -1759,22 +1765,22 @@ public abstract class GeneratedMessage extends AbstractMessage
}
}
- // @Override
+ @Override
public int getNumber() {
return getDescriptor().getNumber();
}
- // @Override
+ @Override
public WireFormat.FieldType getLiteType() {
return getDescriptor().getLiteType();
}
- // @Override
+ @Override
public boolean isRepeated() {
return getDescriptor().isRepeated();
}
- // @Override
+ @Override
@SuppressWarnings("unchecked")
public Type getDefaultValue() {
if (isRepeated()) {
@@ -2124,49 +2130,57 @@ public abstract class GeneratedMessage extends AbstractMessage
return ((Internal.EnumLite) invokeOrDie(caseMethodBuilder, builder)).getNumber();
}
+ @Override
public Object get(final GeneratedMessage message) {
return invokeOrDie(getMethod, message);
}
+ @Override
public Object get(GeneratedMessage.Builder builder) {
return invokeOrDie(getMethodBuilder, builder);
}
+ @Override
public Object getRaw(final GeneratedMessage message) {
return get(message);
}
+ @Override
public Object getRaw(GeneratedMessage.Builder builder) {
return get(builder);
}
+ @Override
public void set(final Builder builder, final Object value) {
invokeOrDie(setMethod, builder, value);
}
- public Object getRepeated(final GeneratedMessage message,
- final int index) {
+ @Override
+ public Object getRepeated(final GeneratedMessage message, final int index) {
throw new UnsupportedOperationException(
"getRepeatedField() called on a singular field.");
}
- public Object getRepeatedRaw(final GeneratedMessage message,
- final int index) {
+ @Override
+ public Object getRepeatedRaw(final GeneratedMessage message, final int index) {
throw new UnsupportedOperationException(
"getRepeatedFieldRaw() called on a singular field.");
}
+ @Override
public Object getRepeated(GeneratedMessage.Builder builder, int index) {
throw new UnsupportedOperationException(
"getRepeatedField() called on a singular field.");
}
- public Object getRepeatedRaw(GeneratedMessage.Builder builder,
- int index) {
+ @Override
+ public Object getRepeatedRaw(GeneratedMessage.Builder builder, int index) {
throw new UnsupportedOperationException(
"getRepeatedFieldRaw() called on a singular field.");
}
- public void setRepeated(final Builder builder, final int index,
- final Object value) {
+ @Override
+ public void setRepeated(final Builder builder, final int index, final Object value) {
throw new UnsupportedOperationException(
"setRepeatedField() called on a singular field.");
}
+ @Override
public void addRepeated(final Builder builder, final Object value) {
throw new UnsupportedOperationException(
"addRepeatedField() called on a singular field.");
}
+ @Override
public boolean has(final GeneratedMessage message) {
if (!hasHasMethod) {
if (isOneofField) {
@@ -2176,6 +2190,7 @@ public abstract class GeneratedMessage extends AbstractMessage
}
return (Boolean) invokeOrDie(hasMethod, message);
}
+ @Override
public boolean has(GeneratedMessage.Builder builder) {
if (!hasHasMethod) {
if (isOneofField) {
@@ -2185,27 +2200,32 @@ public abstract class GeneratedMessage extends AbstractMessage
}
return (Boolean) invokeOrDie(hasMethodBuilder, builder);
}
+ @Override
public int getRepeatedCount(final GeneratedMessage message) {
throw new UnsupportedOperationException(
"getRepeatedFieldSize() called on a singular field.");
}
+ @Override
public int getRepeatedCount(GeneratedMessage.Builder builder) {
throw new UnsupportedOperationException(
"getRepeatedFieldSize() called on a singular field.");
}
+ @Override
public void clear(final Builder builder) {
invokeOrDie(clearMethod, builder);
}
+ @Override
public Message.Builder newBuilder() {
throw new UnsupportedOperationException(
"newBuilderForField() called on a non-Message type.");
}
+ @Override
public Message.Builder getBuilder(GeneratedMessage.Builder builder) {
throw new UnsupportedOperationException(
"getFieldBuilder() called on a non-Message type.");
}
- public Message.Builder getRepeatedBuilder(GeneratedMessage.Builder builder,
- int index) {
+ @Override
+ public Message.Builder getRepeatedBuilder(GeneratedMessage.Builder builder, int index) {
throw new UnsupportedOperationException(
"getRepeatedFieldBuilder() called on a non-Message type.");
}
@@ -2249,18 +2269,23 @@ public abstract class GeneratedMessage extends AbstractMessage
clearMethod = getMethodOrDie(builderClass, "clear" + camelCaseName);
}
+ @Override
public Object get(final GeneratedMessage message) {
return invokeOrDie(getMethod, message);
}
+ @Override
public Object get(GeneratedMessage.Builder builder) {
return invokeOrDie(getMethodBuilder, builder);
}
+ @Override
public Object getRaw(final GeneratedMessage message) {
return get(message);
}
+ @Override
public Object getRaw(GeneratedMessage.Builder builder) {
return get(builder);
}
+ @Override
public void set(final Builder builder, final Object value) {
// Add all the elements individually. This serves two purposes:
// 1) Verifies that each element has the correct type.
@@ -2271,54 +2296,64 @@ public abstract class GeneratedMessage extends AbstractMessage
addRepeated(builder, element);
}
}
- public Object getRepeated(final GeneratedMessage message,
- final int index) {
+ @Override
+ public Object getRepeated(final GeneratedMessage message, final int index) {
return invokeOrDie(getRepeatedMethod, message, index);
}
+ @Override
public Object getRepeated(GeneratedMessage.Builder builder, int index) {
return invokeOrDie(getRepeatedMethodBuilder, builder, index);
}
+ @Override
public Object getRepeatedRaw(GeneratedMessage message, int index) {
return getRepeated(message, index);
}
- public Object getRepeatedRaw(GeneratedMessage.Builder builder,
- int index) {
+ @Override
+ public Object getRepeatedRaw(GeneratedMessage.Builder builder, int index) {
return getRepeated(builder, index);
}
- public void setRepeated(final Builder builder,
- final int index, final Object value) {
+ @Override
+ public void setRepeated(final Builder builder, final int index, final Object value) {
invokeOrDie(setRepeatedMethod, builder, index, value);
}
+ @Override
public void addRepeated(final Builder builder, final Object value) {
invokeOrDie(addRepeatedMethod, builder, value);
}
+ @Override
public boolean has(final GeneratedMessage message) {
throw new UnsupportedOperationException(
"hasField() called on a repeated field.");
}
+ @Override
public boolean has(GeneratedMessage.Builder builder) {
throw new UnsupportedOperationException(
"hasField() called on a repeated field.");
}
+ @Override
public int getRepeatedCount(final GeneratedMessage message) {
return (Integer) invokeOrDie(getCountMethod, message);
}
+ @Override
public int getRepeatedCount(GeneratedMessage.Builder builder) {
return (Integer) invokeOrDie(getCountMethodBuilder, builder);
}
+ @Override
public void clear(final Builder builder) {
invokeOrDie(clearMethod, builder);
}
+ @Override
public Message.Builder newBuilder() {
throw new UnsupportedOperationException(
"newBuilderForField() called on a non-Message type.");
}
+ @Override
public Message.Builder getBuilder(GeneratedMessage.Builder builder) {
throw new UnsupportedOperationException(
"getFieldBuilder() called on a non-Message type.");
}
- public Message.Builder getRepeatedBuilder(GeneratedMessage.Builder builder,
- int index) {
+ @Override
+ public Message.Builder getRepeatedBuilder(GeneratedMessage.Builder builder, int index) {
throw new UnsupportedOperationException(
"getRepeatedFieldBuilder() called on a non-Message type.");
}
@@ -2355,6 +2390,7 @@ public abstract class GeneratedMessage extends AbstractMessage
field.getNumber());
}
+ @Override
public Object get(GeneratedMessage message) {
List result = new ArrayList();
for (int i = 0; i < getRepeatedCount(message); i++) {
@@ -2363,6 +2399,7 @@ public abstract class GeneratedMessage extends AbstractMessage
return Collections.unmodifiableList(result);
}
+ @Override
public Object get(Builder builder) {
List result = new ArrayList();
for (int i = 0; i < getRepeatedCount(builder); i++) {
@@ -2371,14 +2408,17 @@ public abstract class GeneratedMessage extends AbstractMessage
return Collections.unmodifiableList(result);
}
+ @Override
public Object getRaw(GeneratedMessage message) {
return get(message);
}
+ @Override
public Object getRaw(GeneratedMessage.Builder builder) {
return get(builder);
}
+ @Override
public void set(Builder builder, Object value) {
clear(builder);
for (Object entry : (List) value) {
@@ -2386,63 +2426,76 @@ public abstract class GeneratedMessage extends AbstractMessage
}
}
+ @Override
public Object getRepeated(GeneratedMessage message, int index) {
return getMapField(message).getList().get(index);
}
+ @Override
public Object getRepeated(Builder builder, int index) {
return getMapField(builder).getList().get(index);
}
+ @Override
public Object getRepeatedRaw(GeneratedMessage message, int index) {
return getRepeated(message, index);
}
+ @Override
public Object getRepeatedRaw(Builder builder, int index) {
return getRepeated(builder, index);
}
+ @Override
public void setRepeated(Builder builder, int index, Object value) {
getMutableMapField(builder).getMutableList().set(index, (Message) value);
}
+ @Override
public void addRepeated(Builder builder, Object value) {
getMutableMapField(builder).getMutableList().add((Message) value);
}
+ @Override
public boolean has(GeneratedMessage message) {
throw new UnsupportedOperationException(
"hasField() is not supported for repeated fields.");
}
+ @Override
public boolean has(Builder builder) {
throw new UnsupportedOperationException(
"hasField() is not supported for repeated fields.");
}
+ @Override
public int getRepeatedCount(GeneratedMessage message) {
return getMapField(message).getList().size();
}
+ @Override
public int getRepeatedCount(Builder builder) {
return getMapField(builder).getList().size();
}
+ @Override
public void clear(Builder builder) {
getMutableMapField(builder).getMutableList().clear();
}
+ @Override
public com.google.protobuf.Message.Builder newBuilder() {
return mapEntryMessageDefaultInstance.newBuilderForType();
}
+ @Override
public com.google.protobuf.Message.Builder getBuilder(Builder builder) {
throw new UnsupportedOperationException(
"Nested builder not supported for map fields.");
}
- public com.google.protobuf.Message.Builder getRepeatedBuilder(
- Builder builder, int index) {
+ @Override
+ public com.google.protobuf.Message.Builder getRepeatedBuilder(Builder builder, int index) {
throw new UnsupportedOperationException(
"Nested builder not supported for map fields.");
}
diff --git a/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java b/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
index 81e1862c..c5adc5ad 100644
--- a/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
+++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
@@ -30,6 +30,8 @@
package com.google.protobuf;
+import com.google.protobuf.AbstractMessageLite.Builder.LimitedInputStream;
+import com.google.protobuf.GeneratedMessageLite.EqualsVisitor.NotEqualsException;
import com.google.protobuf.Internal.BooleanList;
import com.google.protobuf.Internal.DoubleList;
import com.google.protobuf.Internal.FloatList;
@@ -39,6 +41,7 @@ import com.google.protobuf.Internal.ProtobufList;
import com.google.protobuf.WireFormat.FieldType;
import java.io.IOException;
+import java.io.InputStream;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
@@ -57,32 +60,108 @@ import java.util.Map;
public abstract class GeneratedMessageLite<
MessageType extends GeneratedMessageLite<MessageType, BuilderType>,
BuilderType extends GeneratedMessageLite.Builder<MessageType, BuilderType>>
- extends AbstractMessageLite
- implements Serializable {
-
- private static final long serialVersionUID = 1L;
+ extends AbstractMessageLite<MessageType, BuilderType> {
/** For use by generated code only. Lazily initialized to reduce allocations. */
- protected UnknownFieldSetLite unknownFields = null;
+ protected UnknownFieldSetLite unknownFields = UnknownFieldSetLite.getDefaultInstance();
/** For use by generated code only. */
protected int memoizedSerializedSize = -1;
+ @Override
@SuppressWarnings("unchecked") // Guaranteed by runtime.
public final Parser<MessageType> getParserForType() {
return (Parser<MessageType>) dynamicMethod(MethodToInvoke.GET_PARSER);
}
+ @Override
@SuppressWarnings("unchecked") // Guaranteed by runtime.
public final MessageType getDefaultInstanceForType() {
return (MessageType) dynamicMethod(MethodToInvoke.GET_DEFAULT_INSTANCE);
}
+ @Override
@SuppressWarnings("unchecked") // Guaranteed by runtime.
public final BuilderType newBuilderForType() {
return (BuilderType) dynamicMethod(MethodToInvoke.NEW_BUILDER);
}
+ /**
+ * A reflective toString function. This is primarily intended as a developer aid, while keeping
+ * binary size down. The first line of the {@code toString()} representation includes a commented
+ * version of {@code super.toString()} to act as an indicator that this should not be relied on
+ * for comparisons.
+ * <p>
+ * NOTE: This method relies on the field getter methods not being stripped or renamed by proguard.
+ * If they are, the fields will not be included in the returned string representation.
+ * <p>
+ * NOTE: This implementation is liable to change in the future, and should not be relied on in
+ * code.
+ */
+ @Override
+ public String toString() {
+ return MessageLiteToString.toString(this, super.toString());
+ }
+
+ @SuppressWarnings("unchecked") // Guaranteed by runtime
+ @Override
+ public int hashCode() {
+ if (memoizedHashCode == 0) {
+ HashCodeVisitor visitor = new HashCodeVisitor();
+ visit(visitor, (MessageType) this);
+ memoizedHashCode = visitor.hashCode;
+ }
+ return memoizedHashCode;
+ }
+
+ @SuppressWarnings("unchecked") // Guaranteed by runtime
+ int hashCode(HashCodeVisitor visitor) {
+ if (memoizedHashCode == 0) {
+ int inProgressHashCode = visitor.hashCode;
+ visitor.hashCode = 0;
+ visit(visitor, (MessageType) this);
+ memoizedHashCode = visitor.hashCode;
+ visitor.hashCode = inProgressHashCode;
+ }
+ return memoizedHashCode;
+ }
+
+ @SuppressWarnings("unchecked") // Guaranteed by isInstance + runtime
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+
+ if (!getDefaultInstanceForType().getClass().isInstance(other)) {
+ return false;
+ }
+
+ try {
+ visit(EqualsVisitor.INSTANCE, (MessageType) other);
+ } catch (NotEqualsException e) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Same as {@link #equals(Object)} but throws {@code NotEqualsException}.
+ */
+ @SuppressWarnings("unchecked") // Guaranteed by isInstance + runtime
+ boolean equals(EqualsVisitor visitor, MessageLite other) {
+ if (this == other) {
+ return true;
+ }
+
+ if (!getDefaultInstanceForType().getClass().isInstance(other)) {
+ return false;
+ }
+
+ visit(visitor, (MessageType) other);
+ return true;
+ }
+
// 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.
@@ -91,7 +170,7 @@ public abstract class GeneratedMessageLite<
* Lazily initializes unknown fields.
*/
private final void ensureUnknownFieldsInitialized() {
- if (unknownFields == null) {
+ if (unknownFields == UnknownFieldSetLite.getDefaultInstance()) {
unknownFields = UnknownFieldSetLite.newInstance();
}
}
@@ -130,18 +209,18 @@ public abstract class GeneratedMessageLite<
/**
* Called by subclasses to complete parsing. For use by generated code only.
*/
- protected void doneParsing() {
- if (unknownFields == null) {
- unknownFields = UnknownFieldSetLite.getDefaultInstance();
- } else {
- unknownFields.makeImmutable();
- }
+ protected void makeImmutable() {
+ dynamicMethod(MethodToInvoke.MAKE_IMMUTABLE);
+
+ unknownFields.makeImmutable();
}
+ @Override
public final boolean isInitialized() {
return dynamicMethod(MethodToInvoke.IS_INITIALIZED, Boolean.TRUE) != null;
}
+ @Override
public final BuilderType toBuilder() {
BuilderType builder = (BuilderType) dynamicMethod(MethodToInvoke.NEW_BUILDER);
builder.mergeFrom((MessageType) this);
@@ -155,11 +234,14 @@ public abstract class GeneratedMessageLite<
* For use by generated code only.
*/
public static enum MethodToInvoke {
+ // Rely on/modify instance state
IS_INITIALIZED,
- PARSE_PARTIAL_FROM,
- MERGE_FROM,
+ VISIT,
+ MERGE_FROM_STREAM,
MAKE_IMMUTABLE,
- NEW_INSTANCE,
+
+ // Rely on static state
+ NEW_MUTABLE_INSTANCE,
NEW_BUILDER,
GET_DEFAULT_INSTANCE,
GET_PARSER;
@@ -171,17 +253,18 @@ public abstract class GeneratedMessageLite<
* builders in the runtime. This method bundles those operations to reduce the generated methods
* count.
* <ul>
- * <li>{@code PARSE_PARTIAL_FROM} is parameterized with an {@link CodedInputStream} and
+ * <li>{@code MERGE_FROM_STREAM} is parameterized with an {@link CodedInputStream} and
* {@link ExtensionRegistryLite}. It consumes the input stream, parsing the contents into the
* returned protocol buffer. If parsing throws an {@link InvalidProtocolBufferException}, the
- * implementation wraps it in a RuntimeException
- * <li>{@code NEW_INSTANCE} returns a new instance of the protocol buffer
+ * implementation wraps it in a RuntimeException.
+ * <li>{@code NEW_INSTANCE} returns a new instance of the protocol buffer that has not yet been
+ * made immutable. See {@code MAKE_IMMUTABLE}.
* <li>{@code IS_INITIALIZED} is parameterized with a {@code Boolean} detailing whether to
* memoize. It returns {@code null} for false and the default instance for true. We optionally
* memoize to support the Builder case, where memoization is not desired.
* <li>{@code NEW_BUILDER} returns a {@code BuilderType} instance.
- * <li>{@code MERGE_FROM} is parameterized with a {@code MessageType} and merges the fields from
- * that instance into this instance.
+ * <li>{@code VISIT} is parameterized with a {@code Visitor} and a {@code MessageType} and
+ * recursively iterates through the fields side by side between this and the instance.
* <li>{@code MAKE_IMMUTABLE} sets all internal fields to an immutable state.
* </ul>
* This method, plus the implementation of the Builder, enables the Builder class to be proguarded
@@ -205,6 +288,11 @@ public abstract class GeneratedMessageLite<
return dynamicMethod(method, null, null);
}
+ void visit(Visitor visitor, MessageType other) {
+ dynamicMethod(MethodToInvoke.VISIT, visitor, other);
+ unknownFields = visitor.visitUnknownFields(unknownFields, other.unknownFields);
+ }
+
/**
* Merge some unknown fields into the {@link UnknownFieldSetLite} for this
* message.
@@ -219,7 +307,7 @@ public abstract class GeneratedMessageLite<
public abstract static class Builder<
MessageType extends GeneratedMessageLite<MessageType, BuilderType>,
BuilderType extends Builder<MessageType, BuilderType>>
- extends AbstractMessageLite.Builder<BuilderType> {
+ extends AbstractMessageLite.Builder<MessageType, BuilderType> {
private final MessageType defaultInstance;
protected MessageType instance;
@@ -227,7 +315,8 @@ public abstract class GeneratedMessageLite<
protected Builder(MessageType defaultInstance) {
this.defaultInstance = defaultInstance;
- this.instance = (MessageType) defaultInstance.dynamicMethod(MethodToInvoke.NEW_INSTANCE);
+ this.instance =
+ (MessageType) defaultInstance.dynamicMethod(MethodToInvoke.NEW_MUTABLE_INSTANCE);
isBuilt = false;
}
@@ -237,26 +326,27 @@ public abstract class GeneratedMessageLite<
*/
protected void copyOnWrite() {
if (isBuilt) {
- MessageType newInstance = (MessageType) instance.dynamicMethod(MethodToInvoke.NEW_INSTANCE);
- newInstance.dynamicMethod(MethodToInvoke.MERGE_FROM, instance);
+ MessageType newInstance =
+ (MessageType) instance.dynamicMethod(MethodToInvoke.NEW_MUTABLE_INSTANCE);
+ newInstance.visit(MergeFromVisitor.INSTANCE, instance);
instance = newInstance;
isBuilt = false;
}
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public final boolean isInitialized() {
return GeneratedMessageLite.isInitialized(instance, false /* shouldMemoize */);
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public final BuilderType clear() {
// No need to copy on write since we're dropping the instance anyways.
- instance = (MessageType) instance.dynamicMethod(MethodToInvoke.NEW_INSTANCE);
+ instance = (MessageType) instance.dynamicMethod(MethodToInvoke.NEW_MUTABLE_INSTANCE);
return (BuilderType) this;
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public BuilderType clone() {
BuilderType builder =
(BuilderType) getDefaultInstanceForType().newBuilderForType();
@@ -264,20 +354,19 @@ public abstract class GeneratedMessageLite<
return builder;
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public MessageType buildPartial() {
if (isBuilt) {
return instance;
}
- instance.dynamicMethod(MethodToInvoke.MAKE_IMMUTABLE);
- instance.unknownFields.makeImmutable();
+ instance.makeImmutable();
isBuilt = true;
return instance;
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public final MessageType build() {
MessageType result = buildPartial();
if (!result.isInitialized()) {
@@ -286,33 +375,36 @@ public abstract class GeneratedMessageLite<
return result;
}
+ @Override
+ protected BuilderType internalMergeFrom(MessageType message) {
+ return mergeFrom(message);
+ }
+
/** All subclasses implement this. */
public BuilderType mergeFrom(MessageType message) {
copyOnWrite();
- instance.dynamicMethod(MethodToInvoke.MERGE_FROM, message);
+ instance.visit(MergeFromVisitor.INSTANCE, message);
return (BuilderType) this;
}
+ @Override
public MessageType getDefaultInstanceForType() {
return defaultInstance;
}
+ @Override
public BuilderType mergeFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- MessageType parsedMessage = null;
+ throws IOException {
+ copyOnWrite();
try {
- parsedMessage =
- (MessageType) getDefaultInstanceForType().getParserForType().parsePartialFrom(
- input, extensionRegistry);
- } catch (com.google.protobuf.InvalidProtocolBufferException e) {
- parsedMessage = (MessageType) e.getUnfinishedMessage();
- throw e;
- } finally {
- if (parsedMessage != null) {
- mergeFrom(parsedMessage);
+ instance.dynamicMethod(MethodToInvoke.MERGE_FROM_STREAM, input, extensionRegistry);
+ } catch (RuntimeException e) {
+ if (e.getCause() instanceof IOException) {
+ throw (IOException) e.getCause();
}
+ throw e;
}
return (BuilderType) this;
}
@@ -368,6 +460,12 @@ public abstract class GeneratedMessageLite<
}
extensions.mergeFrom(((ExtendableMessage) other).extensions);
}
+
+ @Override
+ final void visit(Visitor visitor, MessageType other) {
+ super.visit(visitor, other);
+ extensions = visitor.visitExtensions(extensions, other.extensions);
+ }
/**
* Parse an unknown field or an extension. For use by generated code only.
@@ -505,9 +603,8 @@ public abstract class GeneratedMessageLite<
}
/** Check if a singular extension is present. */
- //@Override (Java 1.6 override semantics, but we must support 1.5)
- public final <Type> boolean hasExtension(
- final ExtensionLite<MessageType, Type> extension) {
+ @Override
+ public final <Type> boolean hasExtension(final ExtensionLite<MessageType, Type> extension) {
GeneratedExtension<MessageType, Type> extensionLite =
checkIsLite(extension);
@@ -516,7 +613,7 @@ public abstract class GeneratedMessageLite<
}
/** Get the number of elements in a repeated extension. */
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public final <Type> int getExtensionCount(
final ExtensionLite<MessageType, List<Type>> extension) {
GeneratedExtension<MessageType, List<Type>> extensionLite =
@@ -527,10 +624,9 @@ public abstract class GeneratedMessageLite<
}
/** Get the value of an extension. */
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
@SuppressWarnings("unchecked")
- public final <Type> Type getExtension(
- final ExtensionLite<MessageType, Type> extension) {
+ public final <Type> Type getExtension(final ExtensionLite<MessageType, Type> extension) {
GeneratedExtension<MessageType, Type> extensionLite =
checkIsLite(extension);
@@ -544,11 +640,10 @@ public abstract class GeneratedMessageLite<
}
/** Get one element of a repeated extension. */
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
@SuppressWarnings("unchecked")
public final <Type> Type getExtension(
- final ExtensionLite<MessageType, List<Type>> extension,
- final int index) {
+ final ExtensionLite<MessageType, List<Type>> extension, final int index) {
GeneratedExtension<MessageType, List<Type>> extensionLite =
checkIsLite(extension);
@@ -562,10 +657,9 @@ public abstract class GeneratedMessageLite<
return extensions.isInitialized();
}
-
@Override
- protected final void doneParsing() {
- super.doneParsing();
+ protected final void makeImmutable() {
+ super.makeImmutable();
extensions.makeImmutable();
}
@@ -654,7 +748,7 @@ public abstract class GeneratedMessageLite<
instance.extensions = extensions;
}
- // @Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
protected void copyOnWrite() {
if (!isBuilt) {
return;
@@ -664,7 +758,7 @@ public abstract class GeneratedMessageLite<
instance.extensions = instance.extensions.clone();
}
- // @Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public final MessageType buildPartial() {
if (isBuilt) {
return instance;
@@ -686,33 +780,30 @@ public abstract class GeneratedMessageLite<
}
/** Check if a singular extension is present. */
- //@Override (Java 1.6 override semantics, but we must support 1.5)
- public final <Type> boolean hasExtension(
- final ExtensionLite<MessageType, Type> extension) {
+ @Override
+ public final <Type> boolean hasExtension(final ExtensionLite<MessageType, Type> extension) {
return instance.hasExtension(extension);
}
/** Get the number of elements in a repeated extension. */
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public final <Type> int getExtensionCount(
final ExtensionLite<MessageType, List<Type>> extension) {
return instance.getExtensionCount(extension);
}
/** Get the value of an extension. */
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
@SuppressWarnings("unchecked")
- public final <Type> Type getExtension(
- final ExtensionLite<MessageType, Type> extension) {
+ public final <Type> Type getExtension(final ExtensionLite<MessageType, Type> extension) {
return instance.getExtension(extension);
}
/** Get one element of a repeated extension. */
+ @Override
@SuppressWarnings("unchecked")
- //@Override (Java 1.6 override semantics, but we must support 1.5)
public final <Type> Type getExtension(
- final ExtensionLite<MessageType, List<Type>> extension,
- final int index) {
+ final ExtensionLite<MessageType, List<Type>> extension, final int index) {
return instance.getExtension(extension, index);
}
@@ -844,37 +935,44 @@ public abstract class GeneratedMessageLite<
final boolean isRepeated;
final boolean isPacked;
+ @Override
public int getNumber() {
return number;
}
+ @Override
public WireFormat.FieldType getLiteType() {
return type;
}
+ @Override
public WireFormat.JavaType getLiteJavaType() {
return type.getJavaType();
}
+ @Override
public boolean isRepeated() {
return isRepeated;
}
+ @Override
public boolean isPacked() {
return isPacked;
}
+ @Override
public Internal.EnumLiteMap<?> getEnumType() {
return enumTypeMap;
}
+ @Override
@SuppressWarnings("unchecked")
- public MessageLite.Builder internalMergeFrom(
- MessageLite.Builder to, MessageLite from) {
+ public MessageLite.Builder internalMergeFrom(MessageLite.Builder to, MessageLite from) {
return ((Builder) to).mergeFrom((GeneratedMessageLite) from);
}
+ @Override
public int compareTo(ExtensionDescriptor other) {
return number - other.number;
}
@@ -969,6 +1067,7 @@ public abstract class GeneratedMessageLite<
}
/** Get the field number. */
+ @Override
public int getNumber() {
return descriptor.getNumber();
}
@@ -978,6 +1077,7 @@ public abstract class GeneratedMessageLite<
* If the extension is an embedded message or group, returns the default
* instance of the message.
*/
+ @Override
public MessageLite getMessageDefaultInstance() {
return messageDefaultInstance;
}
@@ -1032,14 +1132,17 @@ public abstract class GeneratedMessageLite<
}
}
+ @Override
public FieldType getLiteType() {
return descriptor.getLiteType();
}
+ @Override
public boolean isRepeated() {
return descriptor.isRepeated;
}
+ @Override
public Type getDefaultValue() {
return defaultValue;
}
@@ -1049,7 +1152,12 @@ public abstract class GeneratedMessageLite<
* A serialized (serializable) form of the generated message. Stores the
* message as a class name and a byte array.
*/
- static final class SerializedForm implements Serializable {
+ protected static final class SerializedForm implements Serializable {
+
+ public static SerializedForm of(MessageLite message) {
+ return new SerializedForm(message);
+ }
+
private static final long serialVersionUID = 0L;
private final String messageClassName;
@@ -1093,16 +1201,6 @@ public abstract class GeneratedMessageLite<
}
}
}
-
- /**
- * Replaces this object in the output stream with a serialized form.
- * Part of Java's serialization magic. Generated sub-classes must override
- * this method by calling {@code return super.writeReplace();}
- * @return a SerializedForm of this message
- */
- protected Object writeReplace() throws ObjectStreamException {
- return new SerializedForm(this);
- }
/**
* Checks that the {@link Extension} is Lite and returns it as a
@@ -1129,30 +1227,72 @@ public abstract class GeneratedMessageLite<
protected static final <T extends GeneratedMessageLite<T, ?>> boolean isInitialized(
T message, boolean shouldMemoize) {
return message.dynamicMethod(MethodToInvoke.IS_INITIALIZED, shouldMemoize) != null;
- }
+ }
protected static final <T extends GeneratedMessageLite<T, ?>> void makeImmutable(T message) {
message.dynamicMethod(MethodToInvoke.MAKE_IMMUTABLE);
}
+
+ protected static IntList emptyIntList() {
+ return IntArrayList.emptyList();
+ }
+
+ protected static IntList mutableCopy(IntList list) {
+ int size = list.size();
+ return list.mutableCopyWithCapacity(
+ size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2);
+ }
+
+ protected static LongList emptyLongList() {
+ return LongArrayList.emptyList();
+ }
- /**
- * A static helper method for parsing a partial from input using the extension registry and the
- * instance.
- */
- static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom(
- T instance, CodedInputStream input, ExtensionRegistryLite extensionRegistry)
- throws InvalidProtocolBufferException {
- try {
- return (T) instance.dynamicMethod(
- MethodToInvoke.PARSE_PARTIAL_FROM, input, extensionRegistry);
- } catch (RuntimeException e) {
- if (e.getCause() instanceof InvalidProtocolBufferException) {
- throw (InvalidProtocolBufferException) e.getCause();
- }
- throw e;
- }
+ protected static LongList mutableCopy(LongList list) {
+ int size = list.size();
+ return list.mutableCopyWithCapacity(
+ size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2);
+ }
+
+ protected static FloatList emptyFloatList() {
+ return FloatArrayList.emptyList();
+ }
+
+ protected static FloatList mutableCopy(FloatList list) {
+ int size = list.size();
+ return list.mutableCopyWithCapacity(
+ size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2);
+ }
+
+ protected static DoubleList emptyDoubleList() {
+ return DoubleArrayList.emptyList();
+ }
+
+ protected static DoubleList mutableCopy(DoubleList list) {
+ int size = list.size();
+ return list.mutableCopyWithCapacity(
+ size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2);
+ }
+
+ protected static BooleanList emptyBooleanList() {
+ return BooleanArrayList.emptyList();
}
+ protected static BooleanList mutableCopy(BooleanList list) {
+ int size = list.size();
+ return list.mutableCopyWithCapacity(
+ size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2);
+ }
+
+ protected static <E> ProtobufList<E> emptyProtobufList() {
+ return ProtobufArrayList.emptyList();
+ }
+
+ protected static <E> ProtobufList<E> mutableCopy(ProtobufList<E> list) {
+ int size = list.size();
+ return list.mutableCopyWithCapacity(
+ size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2);
+ }
+
/**
* A {@link Parser} implementation that delegates to the default instance.
* <p>
@@ -1174,103 +1314,929 @@ public abstract class GeneratedMessageLite<
}
}
- protected static IntList newIntList() {
- return new IntArrayList();
- }
-
- protected static IntList newIntListWithCapacity(int capacity) {
- return new IntArrayList(capacity);
+ /**
+ * A static helper method for parsing a partial from input using the extension registry and the
+ * instance.
+ */
+ // TODO(dweis): Should this verify that the last tag was 0?
+ static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom(
+ T instance, CodedInputStream input, ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
+ @SuppressWarnings("unchecked") // Guaranteed by protoc
+ T result = (T) instance.dynamicMethod(MethodToInvoke.NEW_MUTABLE_INSTANCE);
+ try {
+ result.dynamicMethod(MethodToInvoke.MERGE_FROM_STREAM, input, extensionRegistry);
+ result.makeImmutable();
+ } catch (RuntimeException e) {
+ if (e.getCause() instanceof InvalidProtocolBufferException) {
+ throw (InvalidProtocolBufferException) e.getCause();
+ }
+ throw e;
+ }
+ return result;
}
- protected static IntList newIntList(List<Integer> toCopy) {
- return new IntArrayList(toCopy);
+ protected static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom(
+ T defaultInstance,
+ CodedInputStream input)
+ throws InvalidProtocolBufferException {
+ return parsePartialFrom(defaultInstance, input, ExtensionRegistryLite.getEmptyRegistry());
}
- protected static IntList emptyIntList() {
- return IntArrayList.emptyList();
+ /**
+ * Helper method to check if message is initialized.
+ *
+ * @throws InvalidProtocolBufferException if it is not initialized.
+ * @return The message to check.
+ */
+ private static <T extends GeneratedMessageLite<T, ?>> T checkMessageInitialized(T message)
+ throws InvalidProtocolBufferException {
+ if (message != null && !message.isInitialized()) {
+ throw message.newUninitializedMessageException()
+ .asInvalidProtocolBufferException()
+ .setUnfinishedMessage(message);
+ }
+ return message;
}
- protected static LongList newLongList() {
- return new LongArrayList();
+ // Validates last tag.
+ protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
+ T defaultInstance, ByteString data)
+ throws InvalidProtocolBufferException {
+ return checkMessageInitialized(
+ parseFrom(defaultInstance, data, ExtensionRegistryLite.getEmptyRegistry()));
}
- protected static LongList newLongListWithCapacity(int capacity) {
- return new LongArrayList(capacity);
- }
-
- protected static LongList newLongList(List<Long> toCopy) {
- return new LongArrayList(toCopy);
- }
-
- protected static LongList emptyLongList() {
- return LongArrayList.emptyList();
+ // Validates last tag.
+ protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
+ T defaultInstance, ByteString data, ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
+ return checkMessageInitialized(parsePartialFrom(defaultInstance, data, extensionRegistry));
}
- protected static FloatList newFloatList() {
- return new FloatArrayList();
- }
-
- protected static FloatList newFloatListWithCapacity(int capacity) {
- return new FloatArrayList(capacity);
- }
-
- protected static FloatList newFloatList(List<Float> toCopy) {
- return new FloatArrayList(toCopy);
+ // This is a special case since we want to verify that the last tag is 0. We assume we exhaust the
+ // ByteString.
+ private static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom(
+ T defaultInstance, ByteString data, ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
+ T message;
+ try {
+ CodedInputStream input = data.newCodedInput();
+ message = parsePartialFrom(defaultInstance, input, extensionRegistry);
+ try {
+ input.checkLastTagWas(0);
+ } catch (InvalidProtocolBufferException e) {
+ throw e.setUnfinishedMessage(message);
+ }
+ return message;
+ } catch (InvalidProtocolBufferException e) {
+ throw e;
+ }
}
- protected static FloatList emptyFloatList() {
- return FloatArrayList.emptyList();
+ // This is a special case since we want to verify that the last tag is 0. We assume we exhaust the
+ // ByteString.
+ private static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom(
+ T defaultInstance, byte[] data, ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
+ T message;
+ try {
+ CodedInputStream input = CodedInputStream.newInstance(data);
+ message = parsePartialFrom(defaultInstance, input, extensionRegistry);
+ try {
+ input.checkLastTagWas(0);
+ } catch (InvalidProtocolBufferException e) {
+ throw e.setUnfinishedMessage(message);
+ }
+ return message;
+ } catch (InvalidProtocolBufferException e) {
+ throw e;
+ }
}
-
- protected static DoubleList newDoubleList() {
- return new DoubleArrayList();
+
+ // Validates last tag.
+ protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
+ T defaultInstance, byte[] data)
+ throws InvalidProtocolBufferException {
+ return checkMessageInitialized(
+ parsePartialFrom(defaultInstance, data, ExtensionRegistryLite.getEmptyRegistry()));
}
-
- protected static DoubleList newDoubleListWithCapacity(int capacity) {
- return new DoubleArrayList(capacity);
+
+ // Validates last tag.
+ protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
+ T defaultInstance, byte[] data, ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
+ return checkMessageInitialized(parsePartialFrom(defaultInstance, data, extensionRegistry));
}
-
- protected static DoubleList newDoubleList(List<Double> toCopy) {
- return new DoubleArrayList(toCopy);
+
+ // Does not validate last tag.
+ protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
+ T defaultInstance, InputStream input)
+ throws InvalidProtocolBufferException {
+ return checkMessageInitialized(
+ parsePartialFrom(defaultInstance, CodedInputStream.newInstance(input),
+ ExtensionRegistryLite.getEmptyRegistry()));
}
-
- protected static DoubleList emptyDoubleList() {
- return DoubleArrayList.emptyList();
+
+ // Does not validate last tag.
+ protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
+ T defaultInstance, InputStream input, ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
+ return checkMessageInitialized(
+ parsePartialFrom(defaultInstance, CodedInputStream.newInstance(input), extensionRegistry));
}
-
- protected static BooleanList newBooleanList() {
- return new BooleanArrayList();
+
+ // Does not validate last tag.
+ protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
+ T defaultInstance, CodedInputStream input)
+ throws InvalidProtocolBufferException {
+ return parseFrom(defaultInstance, input, ExtensionRegistryLite.getEmptyRegistry());
}
-
- protected static BooleanList newBooleanListWithCapacity(int capacity) {
- return new BooleanArrayList(capacity);
+
+ // Does not validate last tag.
+ protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
+ T defaultInstance, CodedInputStream input, ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
+ return checkMessageInitialized(
+ parsePartialFrom(defaultInstance, input, extensionRegistry));
}
-
- protected static BooleanList newBooleanList(List<Boolean> toCopy) {
- return new BooleanArrayList(toCopy);
+
+ // Validates last tag.
+ protected static <T extends GeneratedMessageLite<T, ?>> T parseDelimitedFrom(
+ T defaultInstance, InputStream input)
+ throws InvalidProtocolBufferException {
+ return checkMessageInitialized(
+ parsePartialDelimitedFrom(defaultInstance, input,
+ ExtensionRegistryLite.getEmptyRegistry()));
}
-
- protected static BooleanList emptyBooleanList() {
- return BooleanArrayList.emptyList();
+
+ // Validates last tag.
+ protected static <T extends GeneratedMessageLite<T, ?>> T parseDelimitedFrom(
+ T defaultInstance, InputStream input, ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
+ return checkMessageInitialized(
+ parsePartialDelimitedFrom(defaultInstance, input, extensionRegistry));
}
- protected static <E> ProtobufList<E> newProtobufList() {
- return new ProtobufArrayList<E>();
+ private static <T extends GeneratedMessageLite<T, ?>> T parsePartialDelimitedFrom(
+ T defaultInstance,
+ InputStream input,
+ ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
+ int size;
+ try {
+ int firstByte = input.read();
+ if (firstByte == -1) {
+ return null;
+ }
+ size = CodedInputStream.readRawVarint32(firstByte, input);
+ } catch (IOException e) {
+ throw new InvalidProtocolBufferException(e.getMessage());
+ }
+ InputStream limitedInput = new LimitedInputStream(input, size);
+ CodedInputStream codedInput = CodedInputStream.newInstance(limitedInput);
+ T message = parsePartialFrom(defaultInstance, codedInput, extensionRegistry);
+ try {
+ codedInput.checkLastTagWas(0);
+ } catch (InvalidProtocolBufferException e) {
+ throw e.setUnfinishedMessage(message);
+ }
+ return message;
}
-
- protected static <E> ProtobufList<E> newProtobufList(List<E> toCopy) {
- return new ProtobufArrayList<E>(toCopy);
+
+ /**
+ * An abstract visitor that the generated code calls into that we use to implement various
+ * features. Fields that are not members of oneofs are always visited. Members of a oneof are only
+ * visited when they are the set oneof case value on the "other" proto. The visitOneofNotSet
+ * method is invoked if other's oneof case is not set.
+ */
+ protected interface Visitor {
+ boolean visitBoolean(boolean minePresent, boolean mine, boolean otherPresent, boolean other);
+ int visitInt(boolean minePresent, int mine, boolean otherPresent, int other);
+ double visitDouble(boolean minePresent, double mine, boolean otherPresent, double other);
+ float visitFloat(boolean minePresent, float mine, boolean otherPresent, float other);
+ long visitLong(boolean minePresent, long mine, boolean otherPresent, long other);
+ String visitString(boolean minePresent, String mine, boolean otherPresent, String other);
+ ByteString visitByteString(
+ boolean minePresent, ByteString mine, boolean otherPresent, ByteString other);
+
+ Object visitOneofBoolean(boolean minePresent, Object mine, Object other);
+ Object visitOneofInt(boolean minePresent, Object mine, Object other);
+ Object visitOneofDouble(boolean minePresent, Object mine, Object other);
+ Object visitOneofFloat(boolean minePresent, Object mine, Object other);
+ Object visitOneofLong(boolean minePresent, Object mine, Object other);
+ Object visitOneofString(boolean minePresent, Object mine, Object other);
+ Object visitOneofByteString(boolean minePresent, Object mine, Object other);
+ Object visitOneofLazyMessage(boolean minePresent, Object mine, Object other);
+ Object visitOneofMessage(boolean minePresent, Object mine, Object other);
+ void visitOneofNotSet(boolean minePresent);
+
+ /**
+ * Message fields use null sentinals.
+ */
+ <T extends MessageLite> T visitMessage(T mine, T other);
+ LazyFieldLite visitLazyMessage(
+ boolean minePresent, LazyFieldLite mine, boolean otherPresent, LazyFieldLite other);
+
+ <T> ProtobufList<T> visitList(ProtobufList<T> mine, ProtobufList<T> other);
+ BooleanList visitBooleanList(BooleanList mine, BooleanList other);
+ IntList visitIntList(IntList mine, IntList other);
+ DoubleList visitDoubleList(DoubleList mine, DoubleList other);
+ FloatList visitFloatList(FloatList mine, FloatList other);
+ LongList visitLongList(LongList mine, LongList other);
+ FieldSet<ExtensionDescriptor> visitExtensions(
+ FieldSet<ExtensionDescriptor> mine, FieldSet<ExtensionDescriptor> other);
+ UnknownFieldSetLite visitUnknownFields(UnknownFieldSetLite mine, UnknownFieldSetLite other);
+ <K, V> MapFieldLite<K, V> visitMap(MapFieldLite<K, V> mine, MapFieldLite<K, V> other);
}
-
- protected static <E> ProtobufList<E> newProtobufListWithCapacity(int capacity) {
- return new ProtobufArrayList<E>(capacity);
+
+ /**
+ * Implements equals. Throws a {@link NotEqualsException} when not equal.
+ */
+ static class EqualsVisitor implements Visitor {
+
+ static final class NotEqualsException extends RuntimeException {}
+
+ static final EqualsVisitor INSTANCE = new EqualsVisitor();
+
+ static final NotEqualsException NOT_EQUALS = new NotEqualsException();
+
+ private EqualsVisitor() {}
+
+ @Override
+ public boolean visitBoolean(
+ boolean minePresent, boolean mine, boolean otherPresent, boolean other) {
+ if (minePresent != otherPresent || mine != other) {
+ throw NOT_EQUALS;
+ }
+ return mine;
+ }
+
+ @Override
+ public int visitInt(boolean minePresent, int mine, boolean otherPresent, int other) {
+ if (minePresent != otherPresent || mine != other) {
+ throw NOT_EQUALS;
+ }
+ return mine;
+ }
+
+ @Override
+ public double visitDouble(
+ boolean minePresent, double mine, boolean otherPresent, double other) {
+ if (minePresent != otherPresent || mine != other) {
+ throw NOT_EQUALS;
+ }
+ return mine;
+ }
+
+ @Override
+ public float visitFloat(boolean minePresent, float mine, boolean otherPresent, float other) {
+ if (minePresent != otherPresent || mine != other) {
+ throw NOT_EQUALS;
+ }
+ return mine;
+ }
+
+ @Override
+ public long visitLong(boolean minePresent, long mine, boolean otherPresent, long other) {
+ if (minePresent != otherPresent || mine != other) {
+ throw NOT_EQUALS;
+ }
+ return mine;
+ }
+
+ @Override
+ public String visitString(
+ boolean minePresent, String mine, boolean otherPresent, String other) {
+ if (minePresent != otherPresent || !mine.equals(other)) {
+ throw NOT_EQUALS;
+ }
+ return mine;
+ }
+
+ @Override
+ public ByteString visitByteString(
+ boolean minePresent, ByteString mine, boolean otherPresent, ByteString other) {
+ if (minePresent != otherPresent || !mine.equals(other)) {
+ throw NOT_EQUALS;
+ }
+ return mine;
+ }
+
+ @Override
+ public Object visitOneofBoolean(boolean minePresent, Object mine, Object other) {
+ if (minePresent && mine.equals(other)) {
+ return mine;
+ }
+ throw NOT_EQUALS;
+ }
+
+ @Override
+ public Object visitOneofInt(boolean minePresent, Object mine, Object other) {
+ if (minePresent && mine.equals(other)) {
+ return mine;
+ }
+ throw NOT_EQUALS;
+ }
+
+ @Override
+ public Object visitOneofDouble(boolean minePresent, Object mine, Object other) {
+ if (minePresent && mine.equals(other)) {
+ return mine;
+ }
+ throw NOT_EQUALS;
+ }
+
+ @Override
+ public Object visitOneofFloat(boolean minePresent, Object mine, Object other) {
+ if (minePresent && mine.equals(other)) {
+ return mine;
+ }
+ throw NOT_EQUALS;
+ }
+
+ @Override
+ public Object visitOneofLong(boolean minePresent, Object mine, Object other) {
+ if (minePresent && mine.equals(other)) {
+ return mine;
+ }
+ throw NOT_EQUALS;
+ }
+
+ @Override
+ public Object visitOneofString(boolean minePresent, Object mine, Object other) {
+ if (minePresent && mine.equals(other)) {
+ return mine;
+ }
+ throw NOT_EQUALS;
+ }
+
+ @Override
+ public Object visitOneofByteString(boolean minePresent, Object mine, Object other) {
+ if (minePresent && mine.equals(other)) {
+ return mine;
+ }
+ throw NOT_EQUALS;
+ }
+
+ @Override
+ public Object visitOneofLazyMessage(boolean minePresent, Object mine, Object other) {
+ if (minePresent && mine.equals(other)) {
+ return mine;
+ }
+ throw NOT_EQUALS;
+ }
+
+ @Override
+ public Object visitOneofMessage(boolean minePresent, Object mine, Object other) {
+ if (minePresent && ((GeneratedMessageLite<?, ?>) mine).equals(this, (MessageLite) other)) {
+ return mine;
+ }
+ throw NOT_EQUALS;
+ }
+
+ @Override
+ public void visitOneofNotSet(boolean minePresent) {
+ if (minePresent) {
+ throw NOT_EQUALS;
+ }
+ }
+
+ @Override
+ public <T extends MessageLite> T visitMessage(T mine, T other) {
+ if (mine == null && other == null) {
+ return null;
+ }
+
+ if (mine == null || other == null) {
+ throw NOT_EQUALS;
+ }
+
+ ((GeneratedMessageLite<?, ?>) mine).equals(this, other);
+
+ return mine;
+ }
+
+ @Override
+ public LazyFieldLite visitLazyMessage(
+ boolean minePresent, LazyFieldLite mine, boolean otherPresent, LazyFieldLite other) {
+ if (!minePresent && !otherPresent) {
+ return mine;
+ } else if (minePresent && otherPresent && mine.equals(other)) {
+ return mine;
+ }
+ throw NOT_EQUALS;
+ }
+
+ @Override
+ public <T> ProtobufList<T> visitList(ProtobufList<T> mine, ProtobufList<T> other) {
+ if (!mine.equals(other)) {
+ throw NOT_EQUALS;
+ }
+ return mine;
+ }
+
+ @Override
+ public BooleanList visitBooleanList(BooleanList mine, BooleanList other) {
+ if (!mine.equals(other)) {
+ throw NOT_EQUALS;
+ }
+ return mine;
+ }
+
+ @Override
+ public IntList visitIntList(IntList mine, IntList other) {
+ if (!mine.equals(other)) {
+ throw NOT_EQUALS;
+ }
+ return mine;
+ }
+
+ @Override
+ public DoubleList visitDoubleList(DoubleList mine, DoubleList other) {
+ if (!mine.equals(other)) {
+ throw NOT_EQUALS;
+ }
+ return mine;
+ }
+
+ @Override
+ public FloatList visitFloatList(FloatList mine, FloatList other) {
+ if (!mine.equals(other)) {
+ throw NOT_EQUALS;
+ }
+ return mine;
+ }
+
+ @Override
+ public LongList visitLongList(LongList mine, LongList other) {
+ if (!mine.equals(other)) {
+ throw NOT_EQUALS;
+ }
+ return mine;
+ }
+
+ @Override
+ public FieldSet<ExtensionDescriptor> visitExtensions(
+ FieldSet<ExtensionDescriptor> mine,
+ FieldSet<ExtensionDescriptor> other) {
+ if (!mine.equals(other)) {
+ throw NOT_EQUALS;
+ }
+ return mine;
+ }
+
+ @Override
+ public UnknownFieldSetLite visitUnknownFields(
+ UnknownFieldSetLite mine,
+ UnknownFieldSetLite other) {
+ if (!mine.equals(other)) {
+ throw NOT_EQUALS;
+ }
+ return mine;
+ }
+
+ @Override
+ public <K, V> MapFieldLite<K, V> visitMap(MapFieldLite<K, V> mine, MapFieldLite<K, V> other) {
+ if (!mine.equals(other)) {
+ throw NOT_EQUALS;
+ }
+ return mine;
+ }
}
-
- protected static <E> ProtobufList<E> emptyProtobufList() {
- return ProtobufArrayList.emptyList();
+
+ /**
+ * Implements hashCode by accumulating state.
+ */
+ private static class HashCodeVisitor implements Visitor {
+
+ // The caller must ensure that the visitor is invoked parameterized with this and this such that
+ // other is this. This is required due to how oneof cases are handled. See the class comment
+ // on Visitor for more information.
+
+ private int hashCode = 0;
+
+ @Override
+ public boolean visitBoolean(
+ boolean minePresent, boolean mine, boolean otherPresent, boolean other) {
+ hashCode = (53 * hashCode) + Internal.hashBoolean(mine);
+ return mine;
+ }
+
+ @Override
+ public int visitInt(boolean minePresent, int mine, boolean otherPresent, int other) {
+ hashCode = (53 * hashCode) + mine;
+ return mine;
+ }
+
+ @Override
+ public double visitDouble(
+ boolean minePresent, double mine, boolean otherPresent, double other) {
+ hashCode = (53 * hashCode) + Internal.hashLong(Double.doubleToLongBits(mine));
+ return mine;
+ }
+
+ @Override
+ public float visitFloat(boolean minePresent, float mine, boolean otherPresent, float other) {
+ hashCode = (53 * hashCode) + Float.floatToIntBits(mine);
+ return mine;
+ }
+
+ @Override
+ public long visitLong(boolean minePresent, long mine, boolean otherPresent, long other) {
+ hashCode = (53 * hashCode) + Internal.hashLong(mine);
+ return mine;
+ }
+
+ @Override
+ public String visitString(
+ boolean minePresent, String mine, boolean otherPresent, String other) {
+ hashCode = (53 * hashCode) + mine.hashCode();
+ return mine;
+ }
+
+ @Override
+ public ByteString visitByteString(
+ boolean minePresent, ByteString mine, boolean otherPresent, ByteString other) {
+ hashCode = (53 * hashCode) + mine.hashCode();
+ return mine;
+ }
+
+ @Override
+ public Object visitOneofBoolean(boolean minePresent, Object mine, Object other) {
+ hashCode = (53 * hashCode) + Internal.hashBoolean(((Boolean) mine));
+ return mine;
+ }
+
+ @Override
+ public Object visitOneofInt(boolean minePresent, Object mine, Object other) {
+ hashCode = (53 * hashCode) + (Integer) mine;
+ return mine;
+ }
+
+ @Override
+ public Object visitOneofDouble(boolean minePresent, Object mine, Object other) {
+ hashCode = (53 * hashCode) + Internal.hashLong(Double.doubleToLongBits((Double) mine));
+ return mine;
+ }
+
+ @Override
+ public Object visitOneofFloat(boolean minePresent, Object mine, Object other) {
+ hashCode = (53 * hashCode) + Float.floatToIntBits((Float) mine);
+ return mine;
+ }
+
+ @Override
+ public Object visitOneofLong(boolean minePresent, Object mine, Object other) {
+ hashCode = (53 * hashCode) + Internal.hashLong((Long) mine);
+ return mine;
+ }
+
+ @Override
+ public Object visitOneofString(boolean minePresent, Object mine, Object other) {
+ hashCode = (53 * hashCode) + mine.hashCode();
+ return mine;
+ }
+
+ @Override
+ public Object visitOneofByteString(boolean minePresent, Object mine, Object other) {
+ hashCode = (53 * hashCode) + mine.hashCode();
+ return mine;
+ }
+
+ @Override
+ public Object visitOneofLazyMessage(boolean minePresent, Object mine, Object other) {
+ hashCode = (53 * hashCode) + mine.hashCode();
+ return mine;
+ }
+
+ @Override
+ public Object visitOneofMessage(boolean minePresent, Object mine, Object other) {
+ return visitMessage((MessageLite) mine, (MessageLite) other);
+ }
+
+ @Override
+ public void visitOneofNotSet(boolean minePresent) {
+ if (minePresent) {
+ throw new IllegalStateException(); // Can't happen if other == this.
+ }
+ }
+
+ @Override
+ public <T extends MessageLite> T visitMessage(T mine, T other) {
+ final int protoHash;
+ if (mine != null) {
+ if (mine instanceof GeneratedMessageLite) {
+ protoHash = ((GeneratedMessageLite) mine).hashCode(this);
+ } else {
+ protoHash = mine.hashCode();
+ }
+ } else {
+ protoHash = 37;
+ }
+ hashCode = (53 * hashCode) + protoHash;
+ return mine;
+ }
+
+ @Override
+ public LazyFieldLite visitLazyMessage(
+ boolean minePresent, LazyFieldLite mine, boolean otherPresent, LazyFieldLite other) {
+ hashCode = (53 * hashCode) + mine.hashCode();
+ return mine;
+ }
+
+ @Override
+ public <T> ProtobufList<T> visitList(ProtobufList<T> mine, ProtobufList<T> other) {
+ hashCode = (53 * hashCode) + mine.hashCode();
+ return mine;
+ }
+
+ @Override
+ public BooleanList visitBooleanList(BooleanList mine, BooleanList other) {
+ hashCode = (53 * hashCode) + mine.hashCode();
+ return mine;
+ }
+
+ @Override
+ public IntList visitIntList(IntList mine, IntList other) {
+ hashCode = (53 * hashCode) + mine.hashCode();
+ return mine;
+ }
+
+ @Override
+ public DoubleList visitDoubleList(DoubleList mine, DoubleList other) {
+ hashCode = (53 * hashCode) + mine.hashCode();
+ return mine;
+ }
+
+ @Override
+ public FloatList visitFloatList(FloatList mine, FloatList other) {
+ hashCode = (53 * hashCode) + mine.hashCode();
+ return mine;
+ }
+
+ @Override
+ public LongList visitLongList(LongList mine, LongList other) {
+ hashCode = (53 * hashCode) + mine.hashCode();
+ return mine;
+ }
+
+ @Override
+ public FieldSet<ExtensionDescriptor> visitExtensions(
+ FieldSet<ExtensionDescriptor> mine,
+ FieldSet<ExtensionDescriptor> other) {
+ hashCode = (53 * hashCode) + mine.hashCode();
+ return mine;
+ }
+
+ @Override
+ public UnknownFieldSetLite visitUnknownFields(
+ UnknownFieldSetLite mine,
+ UnknownFieldSetLite other) {
+ hashCode = (53 * hashCode) + mine.hashCode();
+ return mine;
+ }
+
+ @Override
+ public <K, V> MapFieldLite<K, V> visitMap(MapFieldLite<K, V> mine, MapFieldLite<K, V> other) {
+ hashCode = (53 * hashCode) + mine.hashCode();
+ return mine;
+ }
}
-
- protected static LazyStringArrayList emptyLazyStringArrayList() {
- return LazyStringArrayList.emptyList();
+
+ /**
+ * Implements field merging semantics over the visitor interface.
+ */
+ protected static class MergeFromVisitor implements Visitor {
+
+ public static final MergeFromVisitor INSTANCE = new MergeFromVisitor();
+
+ private MergeFromVisitor() {}
+
+ @Override
+ public boolean visitBoolean(
+ boolean minePresent, boolean mine, boolean otherPresent, boolean other) {
+ return otherPresent ? other : mine;
+ }
+
+ @Override
+ public int visitInt(boolean minePresent, int mine, boolean otherPresent, int other) {
+ return otherPresent ? other : mine;
+ }
+
+ @Override
+ public double visitDouble(
+ boolean minePresent, double mine, boolean otherPresent, double other) {
+ return otherPresent ? other : mine;
+ }
+
+ @Override
+ public float visitFloat(boolean minePresent, float mine, boolean otherPresent, float other) {
+ return otherPresent ? other : mine;
+ }
+
+ @Override
+ public long visitLong(boolean minePresent, long mine, boolean otherPresent, long other) {
+ return otherPresent ? other : mine;
+ }
+
+ @Override
+ public String visitString(
+ boolean minePresent, String mine, boolean otherPresent, String other) {
+ return otherPresent ? other : mine;
+ }
+
+ @Override
+ public ByteString visitByteString(
+ boolean minePresent, ByteString mine, boolean otherPresent, ByteString other) {
+ return otherPresent ? other : mine;
+ }
+
+ @Override
+ public Object visitOneofBoolean(boolean minePresent, Object mine, Object other) {
+ return other;
+ }
+
+ @Override
+ public Object visitOneofInt(boolean minePresent, Object mine, Object other) {
+ return other;
+ }
+
+ @Override
+ public Object visitOneofDouble(boolean minePresent, Object mine, Object other) {
+ return other;
+ }
+
+ @Override
+ public Object visitOneofFloat(boolean minePresent, Object mine, Object other) {
+ return other;
+ }
+
+ @Override
+ public Object visitOneofLong(boolean minePresent, Object mine, Object other) {
+ return other;
+ }
+
+ @Override
+ public Object visitOneofString(boolean minePresent, Object mine, Object other) {
+ return other;
+ }
+
+ @Override
+ public Object visitOneofByteString(boolean minePresent, Object mine, Object other) {
+ return other;
+ }
+
+ @Override
+ public Object visitOneofLazyMessage(boolean minePresent, Object mine, Object other) {
+ if (minePresent) {
+ LazyFieldLite lazy = (LazyFieldLite) mine;
+ lazy.merge((LazyFieldLite) other);
+ return lazy;
+ }
+ return other;
+ }
+
+ @Override
+ public Object visitOneofMessage(boolean minePresent, Object mine, Object other) {
+ if (minePresent) {
+ return visitMessage((MessageLite) mine, (MessageLite) other);
+ }
+ return other;
+ }
+
+ @Override
+ public void visitOneofNotSet(boolean minePresent) {
+ return;
+ }
+
+ @SuppressWarnings("unchecked") // Guaranteed by runtime.
+ @Override
+ public <T extends MessageLite> T visitMessage(T mine, T other) {
+ if (mine != null && other != null) {
+ return (T) mine.toBuilder().mergeFrom(other).build();
+ }
+
+ return mine != null ? mine : other;
+ }
+
+ @Override
+ public LazyFieldLite visitLazyMessage(
+ boolean minePresent, LazyFieldLite mine, boolean otherPresent, LazyFieldLite other) {
+ // LazyFieldLite's are never null so we can just copy across. Necessary to avoid leakage
+ // from builder into immutable message.
+ // TODO(dweis): Change to null sentinels?
+ mine.merge(other);
+ return mine;
+ }
+
+ @Override
+ public <T> ProtobufList<T> visitList(ProtobufList<T> mine, ProtobufList<T> other) {
+ int size = mine.size();
+ int otherSize = other.size();
+ if (size > 0 && otherSize > 0) {
+ if (!mine.isModifiable()) {
+ mine = mine.mutableCopyWithCapacity(size + otherSize);
+ }
+ mine.addAll(other);
+ }
+
+ return size > 0 ? mine : other;
+ }
+
+ @Override
+ public BooleanList visitBooleanList(BooleanList mine, BooleanList other) {
+ int size = mine.size();
+ int otherSize = other.size();
+ if (size > 0 && otherSize > 0) {
+ if (!mine.isModifiable()) {
+ mine = mine.mutableCopyWithCapacity(size + otherSize);
+ }
+ mine.addAll(other);
+ }
+
+ return size > 0 ? mine : other;
+ }
+
+ @Override
+ public IntList visitIntList(IntList mine, IntList other) {
+ int size = mine.size();
+ int otherSize = other.size();
+ if (size > 0 && otherSize > 0) {
+ if (!mine.isModifiable()) {
+ mine = mine.mutableCopyWithCapacity(size + otherSize);
+ }
+ mine.addAll(other);
+ }
+
+ return size > 0 ? mine : other;
+ }
+
+ @Override
+ public DoubleList visitDoubleList(DoubleList mine, DoubleList other) {
+ int size = mine.size();
+ int otherSize = other.size();
+ if (size > 0 && otherSize > 0) {
+ if (!mine.isModifiable()) {
+ mine = mine.mutableCopyWithCapacity(size + otherSize);
+ }
+ mine.addAll(other);
+ }
+
+ return size > 0 ? mine : other;
+ }
+
+ @Override
+ public FloatList visitFloatList(FloatList mine, FloatList other) {
+ int size = mine.size();
+ int otherSize = other.size();
+ if (size > 0 && otherSize > 0) {
+ if (!mine.isModifiable()) {
+ mine = mine.mutableCopyWithCapacity(size + otherSize);
+ }
+ mine.addAll(other);
+ }
+
+ return size > 0 ? mine : other;
+ }
+
+ @Override
+ public LongList visitLongList(LongList mine, LongList other) {
+ int size = mine.size();
+ int otherSize = other.size();
+ if (size > 0 && otherSize > 0) {
+ if (!mine.isModifiable()) {
+ mine = mine.mutableCopyWithCapacity(size + otherSize);
+ }
+ mine.addAll(other);
+ }
+
+ return size > 0 ? mine : other;
+ }
+
+ @Override
+ public FieldSet<ExtensionDescriptor> visitExtensions(
+ FieldSet<ExtensionDescriptor> mine,
+ FieldSet<ExtensionDescriptor> other) {
+ if (mine.isImmutable()) {
+ mine = mine.clone();
+ }
+ mine.mergeFrom(other);
+ return mine;
+ }
+
+ @Override
+ public UnknownFieldSetLite visitUnknownFields(
+ UnknownFieldSetLite mine,
+ UnknownFieldSetLite other) {
+ return other == UnknownFieldSetLite.getDefaultInstance()
+ ? mine : UnknownFieldSetLite.mutableCopyOf(mine, other);
+ }
+
+ @Override
+ public <K, V> MapFieldLite<K, V> visitMap(MapFieldLite<K, V> mine, MapFieldLite<K, V> other) {
+ mine.mergeFrom(other);
+ return mine;
+ }
}
}
diff --git a/java/core/src/main/java/com/google/protobuf/IntArrayList.java b/java/core/src/main/java/com/google/protobuf/IntArrayList.java
index f4e68ed8..6d6ece5a 100644
--- a/java/core/src/main/java/com/google/protobuf/IntArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/IntArrayList.java
@@ -34,7 +34,6 @@ import com.google.protobuf.Internal.IntList;
import java.util.Arrays;
import java.util.Collection;
-import java.util.List;
import java.util.RandomAccess;
/**
@@ -44,8 +43,6 @@ import java.util.RandomAccess;
*/
final class IntArrayList extends AbstractProtobufList<Integer> implements IntList, RandomAccess {
- private static final int DEFAULT_CAPACITY = 10;
-
private static final IntArrayList EMPTY_LIST = new IntArrayList();
static {
EMPTY_LIST.makeImmutable();
@@ -70,32 +67,55 @@ final class IntArrayList extends AbstractProtobufList<Integer> implements IntLis
* Constructs a new mutable {@code IntArrayList} with default capacity.
*/
IntArrayList() {
- this(DEFAULT_CAPACITY);
- }
-
- /**
- * Constructs a new mutable {@code IntArrayList} with the provided capacity.
- */
- IntArrayList(int capacity) {
- array = new int[capacity];
- size = 0;
+ this(new int[DEFAULT_CAPACITY], 0);
}
/**
* Constructs a new mutable {@code IntArrayList} containing the same elements as {@code other}.
*/
- IntArrayList(List<Integer> other) {
- if (other instanceof IntArrayList) {
- IntArrayList list = (IntArrayList) other;
- array = list.array.clone();
- size = list.size;
- } else {
- size = other.size();
- array = new int[size];
- for (int i = 0; i < size; i++) {
- array[i] = other.get(i);
+ private IntArrayList(int[] array, int size) {
+ this.array = array;
+ this.size = size;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof IntArrayList)) {
+ return super.equals(o);
+ }
+ IntArrayList other = (IntArrayList) o;
+ if (size != other.size) {
+ return false;
+ }
+
+ final int[] arr = other.array;
+ for (int i = 0; i < size; i++) {
+ if (array[i] != arr[i]) {
+ return false;
}
}
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 1;
+ for (int i = 0; i < size; i++) {
+ result = (31 * result) + array[i];
+ }
+ return result;
+ }
+
+ @Override
+ public IntList mutableCopyWithCapacity(int capacity) {
+ if (capacity < size) {
+ throw new IllegalArgumentException();
+ }
+ return new IntArrayList(Arrays.copyOf(array, capacity), size);
}
@Override
diff --git a/java/core/src/main/java/com/google/protobuf/Internal.java b/java/core/src/main/java/com/google/protobuf/Internal.java
index e19b6dca..d1de375e 100644
--- a/java/core/src/main/java/com/google/protobuf/Internal.java
+++ b/java/core/src/main/java/com/google/protobuf/Internal.java
@@ -41,6 +41,7 @@ import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.RandomAccess;
import java.util.Set;
/**
@@ -51,10 +52,12 @@ import java.util.Set;
*
* @author kenton@google.com (Kenton Varda)
*/
-public class Internal {
+public final class Internal {
- protected static final Charset UTF_8 = Charset.forName("UTF-8");
- protected static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
+ private Internal() {}
+
+ static final Charset UTF_8 = Charset.forName("UTF-8");
+ static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
/**
* Helper called by generated code to construct default values for string
@@ -406,6 +409,7 @@ public class Internal {
public static final CodedInputStream EMPTY_CODED_INPUT_STREAM =
CodedInputStream.newInstance(EMPTY_BYTE_ARRAY);
+
/**
* Provides an immutable view of {@code List<T>} around a {@code List<F>}.
*
@@ -454,10 +458,13 @@ public class Internal {
public static <T extends EnumLite> Converter<Integer, T> newEnumConverter(
final EnumLiteMap<T> enumMap, final T unrecognizedValue) {
return new Converter<Integer, T>() {
+ @Override
public T doForward(Integer value) {
T result = enumMap.findValueByNumber(value);
return result == null ? unrecognizedValue : result;
}
+
+ @Override
public Integer doBackward(T value) {
return value.getNumber();
}
@@ -570,8 +577,10 @@ public class Internal {
/**
* Extends {@link List} to add the capability to make the list immutable and inspect if it is
* modifiable.
+ * <p>
+ * All implementations must support efficient random access.
*/
- public static interface ProtobufList<E> extends List<E> {
+ public static interface ProtobufList<E> extends List<E>, RandomAccess {
/**
* Makes this list immutable. All subsequent modifications will throw an
@@ -583,6 +592,11 @@ public class Internal {
* Returns whether this list can be modified via the publicly accessible {@link List} methods.
*/
boolean isModifiable();
+
+ /**
+ * Returns a mutable clone of this list with the specified capacity.
+ */
+ ProtobufList<E> mutableCopyWithCapacity(int capacity);
}
/**
@@ -597,14 +611,20 @@ public class Internal {
int getInt(int index);
/**
- * Like {@link #add(Object)} but more efficient in that it doesn't box the element.
+ * Like {@link #add(Integer)} but more efficient in that it doesn't box the element.
*/
void addInt(int element);
/**
- * Like {@link #set(int, Object)} but more efficient in that it doesn't box the element.
+ * Like {@link #set(int, Integer)} but more efficient in that it doesn't box the element.
*/
int setInt(int index, int element);
+
+ /**
+ * Returns a mutable clone of this list with the specified capacity.
+ */
+ @Override
+ IntList mutableCopyWithCapacity(int capacity);
}
/**
@@ -619,14 +639,20 @@ public class Internal {
boolean getBoolean(int index);
/**
- * Like {@link #add(Object)} but more efficient in that it doesn't box the element.
+ * Like {@link #add(Boolean)} but more efficient in that it doesn't box the element.
*/
void addBoolean(boolean element);
/**
- * Like {@link #set(int, Object)} but more efficient in that it doesn't box the element.
+ * Like {@link #set(int, Boolean)} but more efficient in that it doesn't box the element.
*/
boolean setBoolean(int index, boolean element);
+
+ /**
+ * Returns a mutable clone of this list with the specified capacity.
+ */
+ @Override
+ BooleanList mutableCopyWithCapacity(int capacity);
}
/**
@@ -641,14 +667,20 @@ public class Internal {
long getLong(int index);
/**
- * Like {@link #add(Object)} but more efficient in that it doesn't box the element.
+ * Like {@link #add(Long)} but more efficient in that it doesn't box the element.
*/
void addLong(long element);
/**
- * Like {@link #set(int, Object)} but more efficient in that it doesn't box the element.
+ * Like {@link #set(int, Long)} but more efficient in that it doesn't box the element.
*/
long setLong(int index, long element);
+
+ /**
+ * Returns a mutable clone of this list with the specified capacity.
+ */
+ @Override
+ LongList mutableCopyWithCapacity(int capacity);
}
/**
@@ -663,14 +695,20 @@ public class Internal {
double getDouble(int index);
/**
- * Like {@link #add(Object)} but more efficient in that it doesn't box the element.
+ * Like {@link #add(Double)} but more efficient in that it doesn't box the element.
*/
void addDouble(double element);
/**
- * Like {@link #set(int, Object)} but more efficient in that it doesn't box the element.
+ * Like {@link #set(int, Double)} but more efficient in that it doesn't box the element.
*/
double setDouble(int index, double element);
+
+ /**
+ * Returns a mutable clone of this list with the specified capacity.
+ */
+ @Override
+ DoubleList mutableCopyWithCapacity(int capacity);
}
/**
@@ -685,13 +723,19 @@ public class Internal {
float getFloat(int index);
/**
- * Like {@link #add(Object)} but more efficient in that it doesn't box the element.
+ * Like {@link #add(Float)} but more efficient in that it doesn't box the element.
*/
void addFloat(float element);
/**
- * Like {@link #set(int, Object)} but more efficient in that it doesn't box the element.
+ * Like {@link #set(int, Float)} but more efficient in that it doesn't box the element.
*/
float setFloat(int index, float element);
+
+ /**
+ * Returns a mutable clone of this list with the specified capacity.
+ */
+ @Override
+ FloatList mutableCopyWithCapacity(int capacity);
}
}
diff --git a/java/core/src/main/java/com/google/protobuf/LazyField.java b/java/core/src/main/java/com/google/protobuf/LazyField.java
index 5e0a485c..98e13ca1 100644
--- a/java/core/src/main/java/com/google/protobuf/LazyField.java
+++ b/java/core/src/main/java/com/google/protobuf/LazyField.java
@@ -39,14 +39,14 @@ import java.util.Map.Entry;
*
* Most of key methods are implemented in {@link LazyFieldLite} but this class
* can contain default instance of the message to provide {@code hashCode()},
- * {@code equals()} and {@code toString()}.
+ * {@code euqals()} and {@code toString()}.
*
* @author xiangl@google.com (Xiang Li)
*/
public class LazyField extends LazyFieldLite {
/**
- * Carry a message's default instance which is used by {@code hashCode()}, {@code equals()} and
+ * Carry a message's default instance which is used by {@code hashCode()}, {@code euqals()} and
* {@code toString()}.
*/
private final MessageLite defaultInstance;
@@ -95,12 +95,12 @@ public class LazyField extends LazyFieldLite {
this.entry = entry;
}
- // @Override
+ @Override
public K getKey() {
return entry.getKey();
}
- // @Override
+ @Override
public Object getValue() {
LazyField field = entry.getValue();
if (field == null) {
@@ -113,7 +113,7 @@ public class LazyField extends LazyFieldLite {
return entry.getValue();
}
- // @Override
+ @Override
public Object setValue(Object value) {
if (!(value instanceof MessageLite)) {
throw new IllegalArgumentException(
@@ -131,13 +131,13 @@ public class LazyField extends LazyFieldLite {
this.iterator = iterator;
}
- // @Override
+ @Override
public boolean hasNext() {
return iterator.hasNext();
}
+ @Override
@SuppressWarnings("unchecked")
- // @Override
public Entry<K, Object> next() {
Entry<K, ?> entry = iterator.next();
if (entry.getValue() instanceof LazyField) {
@@ -146,7 +146,7 @@ public class LazyField extends LazyFieldLite {
return (Entry<K, Object>) entry;
}
- // @Override
+ @Override
public void remove() {
iterator.remove();
}
diff --git a/java/core/src/main/java/com/google/protobuf/LazyFieldLite.java b/java/core/src/main/java/com/google/protobuf/LazyFieldLite.java
index eea1fe3c..2febaace 100644
--- a/java/core/src/main/java/com/google/protobuf/LazyFieldLite.java
+++ b/java/core/src/main/java/com/google/protobuf/LazyFieldLite.java
@@ -30,14 +30,26 @@
package com.google.protobuf;
+import java.io.IOException;
+
/**
* LazyFieldLite encapsulates the logic of lazily parsing message fields. It stores
- * the message in a ByteString initially and then parse it on-demand.
+ * the message in a ByteString initially and then parses it on-demand.
+ *
+ * LazyFieldLite is thread-compatible: concurrent reads are safe once the proto that this
+ * LazyFieldLite is a part of is no longer being mutated by its Builder. However, explicit
+ * synchronization is needed under read/write situations.
*
- * LazyField is thread-compatible e.g. concurrent read are safe, however,
- * synchronizations are needed under read/write situations.
+ * When a LazyFieldLite is used in the context of a MessageLite object, its behavior is considered
+ * to be immutable and none of the setter methods in its API are expected to be invoked. All of the
+ * getters are expected to be thread-safe. When used in the context of a MessageLite.Builder,
+ * setters can be invoked, but there is no guarantee of thread safety.
+ *
+ * TODO(yatin,dweis): Consider splitting this class's functionality and put the mutable methods
+ * into a separate builder class to allow us to give stronger compile-time guarantees.
*
- * This class is internal implementation detail, so you don't need to use it directly.
+ * This class is internal implementation detail of the protobuf library, so you don't need to use it
+ * directly.
*
* @author xiangl@google.com (Xiang Li)
*/
@@ -46,8 +58,34 @@ public class LazyFieldLite {
ExtensionRegistryLite.getEmptyRegistry();
/**
- * A delayed-parsed version of the bytes. When this is non-null then {@code extensionRegistry } is
- * also non-null and {@code value} and {@code memoizedBytes} are null.
+ * The value associated with the LazyFieldLite object is stored in one or more of the following
+ * three fields (delayedBytes, value, memoizedBytes). They should together be interpreted as
+ * follows.
+ * 1) delayedBytes can be non-null, while value and memoizedBytes is null. The object will be in
+ * this state while the value for the object has not yet been parsed.
+ * 2) Both delayedBytes and value are non-null. The object transitions to this state as soon as
+ * some caller needs to access the value (by invoking getValue()).
+ * 3) memoizedBytes is merely an optimization for calls to LazyFieldLite.toByteString() to avoid
+ * recomputing the ByteString representation on each call. Instead, when the value is parsed
+ * from delayedBytes, we will also assign the contents of delayedBytes to memoizedBytes (since
+ * that is the ByteString representation of value).
+ * 4) Finally, if the LazyFieldLite was created directly with a parsed MessageLite value, then
+ * delayedBytes will be null, and memoizedBytes will be initialized only upon the first call to
+ * LazyFieldLite.toByteString().
+ *
+ * Given the above conditions, any caller that needs a serialized representation of this object
+ * must first check if the memoizedBytes or delayedBytes ByteString is non-null and use it
+ * directly; if both of those are null, it can look at the parsed value field. Similarly, any
+ * caller that needs a parsed value must first check if the value field is already non-null, if
+ * not it must parse the value from delayedBytes.
+ */
+
+ /**
+ * A delayed-parsed version of the contents of this field. When this field is non-null, then the
+ * "value" field is allowed to be null until the time that the value needs to be read.
+ *
+ * When delayedBytes is non-null then {@code extensionRegistry} is required to also be non-null.
+ * {@code value} and {@code memoizedBytes} will be initialized lazily.
*/
private ByteString delayedBytes;
@@ -60,12 +98,15 @@ public class LazyFieldLite {
private ExtensionRegistryLite extensionRegistry;
/**
- * The parsed value. When this is non-null then {@code delayedBytes} will be null.
+ * The parsed value. When this is null and a caller needs access to the MessageLite value, then
+ * {@code delayedBytes} will be parsed lazily at that time.
*/
protected volatile MessageLite value;
/**
- * The memoized bytes for {@code value}. Will be null when {@code value} is null.
+ * The memoized bytes for {@code value}. This is an optimization for the toByteString() method to
+ * not have to recompute its return-value on each invocation.
+ * TODO(yatin): Figure out whether this optimization is actually necessary.
*/
private volatile ByteString memoizedBytes;
@@ -94,6 +135,43 @@ public class LazyFieldLite {
return lf;
}
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+
+ if (!(o instanceof LazyFieldLite)) {
+ return false;
+ }
+
+ LazyFieldLite other = (LazyFieldLite) o;
+
+ // Lazy fields do not work well with equals... If both are delayedBytes, we do not have a
+ // mechanism to deserialize them so we rely on bytes equality. Otherwise we coerce into an
+ // actual message (if necessary) and call equals on the message itself. This implies that two
+ // messages can by unequal but then be turned equal simply be invoking a getter on a lazy field.
+ MessageLite value1 = value;
+ MessageLite value2 = other.value;
+ if (value1 == null && value2 == null) {
+ return toByteString().equals(other.toByteString());
+ } else if (value1 != null && value2 != null) {
+ return value1.equals(value2);
+ } else if (value1 != null) {
+ return value1.equals(other.getValue(value1.getDefaultInstanceForType()));
+ } else {
+ return getValue(value2.getDefaultInstanceForType()).equals(value2);
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ // We can't provide a memoizable hash code for lazy fields. The byte strings may have different
+ // hash codes but evaluate to equivalent messages. And we have no facility for constructing
+ // a message here if we were not already holding a value.
+ return 1;
+ }
+
/**
* Determines whether this LazyFieldLite instance represents the default instance of this type.
*/
@@ -230,6 +308,46 @@ public class LazyFieldLite {
return;
}
}
+
+ /**
+ * Merges another instance's contents from a stream.
+ *
+ * <p>LazyField is not thread-safe for write access. Synchronizations are needed
+ * under read/write situations.
+ */
+ public void mergeFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry)
+ throws IOException {
+ if (this.containsDefaultInstance()) {
+ setByteString(input.readBytes(), extensionRegistry);
+ return;
+ }
+
+ // If the other field has an extension registry but this does not, copy over the other extension
+ // registry.
+ if (this.extensionRegistry == null) {
+ this.extensionRegistry = extensionRegistry;
+ }
+
+ // In the case that both of them are not parsed we simply concatenate the bytes to save time. In
+ // the (probably rare) case that they have different extension registries there is a chance that
+ // some of the extensions may be dropped, but the tradeoff of making this operation fast seems
+ // to outway the benefits of combining the extension registries, which is not normally done for
+ // lite protos anyways.
+ if (this.delayedBytes != null) {
+ setByteString(this.delayedBytes.concat(input.readBytes()), this.extensionRegistry);
+ return;
+ }
+
+ // We are parsed and both contain data. We won't drop any extensions here directly, but in the
+ // case that the extension registries are not the same then we might in the future if we
+ // need to serialize and parse a message again.
+ try {
+ setValue(value.toBuilder().mergeFrom(input, extensionRegistry).build());
+ } catch (InvalidProtocolBufferException e) {
+ // Nothing is logged and no exceptions are thrown. Clients will be unaware that a proto
+ // was invalid.
+ }
+ }
private static MessageLite mergeValueAndBytes(
MessageLite value, ByteString otherBytes, ExtensionRegistryLite extensionRegistry) {
@@ -259,10 +377,12 @@ public class LazyFieldLite {
* parsed. Be careful when using this method.
*/
public int getSerializedSize() {
- if (delayedBytes != null) {
- return delayedBytes.size();
- } else if (memoizedBytes != null) {
+ // We *must* return delayed bytes size if it was ever set because the dependent messages may
+ // have memoized serialized size based off of it.
+ if (memoizedBytes != null) {
return memoizedBytes.size();
+ } else if (delayedBytes != null) {
+ return delayedBytes.size();
} else if (value != null) {
return value.getSerializedSize();
} else {
@@ -274,12 +394,14 @@ public class LazyFieldLite {
* Returns a BytesString for this field in a thread-safe way.
*/
public ByteString toByteString() {
- if (delayedBytes != null) {
- return delayedBytes;
- }
if (memoizedBytes != null) {
return memoizedBytes;
}
+ // We *must* return delayed bytes if it was set because the dependent messages may have
+ // memoized serialized size based off of it.
+ if (delayedBytes != null) {
+ return delayedBytes;
+ }
synchronized (this) {
if (memoizedBytes != null) {
return memoizedBytes;
@@ -311,18 +433,15 @@ public class LazyFieldLite {
.parseFrom(delayedBytes, extensionRegistry);
this.value = parsedValue;
this.memoizedBytes = delayedBytes;
- this.delayedBytes = null;
} else {
this.value = defaultInstance;
this.memoizedBytes = ByteString.EMPTY;
- this.delayedBytes = null;
}
} catch (InvalidProtocolBufferException e) {
// Nothing is logged and no exceptions are thrown. Clients will be unaware that this proto
// was invalid.
this.value = defaultInstance;
this.memoizedBytes = ByteString.EMPTY;
- this.delayedBytes = null;
}
}
}
diff --git a/java/core/src/main/java/com/google/protobuf/LazyStringArrayList.java b/java/core/src/main/java/com/google/protobuf/LazyStringArrayList.java
index c3be3cca..d474c51e 100644
--- a/java/core/src/main/java/com/google/protobuf/LazyStringArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/LazyStringArrayList.java
@@ -30,12 +30,12 @@
package com.google.protobuf;
-import java.util.Arrays;
-import java.util.List;
import java.util.AbstractList;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.List;
import java.util.RandomAccess;
/**
@@ -64,7 +64,7 @@ import java.util.RandomAccess;
*/
public class LazyStringArrayList extends AbstractProtobufList<String>
implements LazyStringList, RandomAccess {
-
+
private static final LazyStringArrayList EMPTY_LIST = new LazyStringArrayList();
static {
EMPTY_LIST.makeImmutable();
@@ -80,11 +80,11 @@ public class LazyStringArrayList extends AbstractProtobufList<String>
private final List<Object> list;
public LazyStringArrayList() {
- list = new ArrayList<Object>();
+ this(DEFAULT_CAPACITY);
}
public LazyStringArrayList(int intialCapacity) {
- list = new ArrayList<Object>(intialCapacity);
+ this(new ArrayList<Object>(intialCapacity));
}
public LazyStringArrayList(LazyStringList from) {
@@ -93,7 +93,21 @@ public class LazyStringArrayList extends AbstractProtobufList<String>
}
public LazyStringArrayList(List<String> from) {
- list = new ArrayList<Object>(from);
+ this(new ArrayList<Object>(from));
+ }
+
+ private LazyStringArrayList(ArrayList<Object> list) {
+ this.list = list;
+ }
+
+ @Override
+ public LazyStringArrayList mutableCopyWithCapacity(int capacity) {
+ if (capacity < size()) {
+ throw new IllegalArgumentException();
+ }
+ ArrayList<Object> newList = new ArrayList<Object>(capacity);
+ newList.addAll(list);
+ return new LazyStringArrayList(newList);
}
@Override
@@ -170,7 +184,7 @@ public class LazyStringArrayList extends AbstractProtobufList<String>
return ret;
}
- // @Override
+ @Override
public boolean addAllByteString(Collection<? extends ByteString> values) {
ensureIsMutable();
boolean ret = list.addAll(values);
@@ -178,7 +192,7 @@ public class LazyStringArrayList extends AbstractProtobufList<String>
return ret;
}
- // @Override
+ @Override
public boolean addAllByteArray(Collection<byte[]> c) {
ensureIsMutable();
boolean ret = list.addAll(c);
@@ -201,14 +215,14 @@ public class LazyStringArrayList extends AbstractProtobufList<String>
modCount++;
}
- // @Override
+ @Override
public void add(ByteString element) {
ensureIsMutable();
list.add(element);
modCount++;
}
- // @Override
+ @Override
public void add(byte[] element) {
ensureIsMutable();
list.add(element);
@@ -220,7 +234,7 @@ public class LazyStringArrayList extends AbstractProtobufList<String>
return list.get(index);
}
- // @Override
+ @Override
public ByteString getByteString(int index) {
Object o = list.get(index);
ByteString b = asByteString(o);
@@ -230,7 +244,7 @@ public class LazyStringArrayList extends AbstractProtobufList<String>
return b;
}
- // @Override
+ @Override
public byte[] getByteArray(int index) {
Object o = list.get(index);
byte[] b = asByteArray(o);
@@ -240,7 +254,7 @@ public class LazyStringArrayList extends AbstractProtobufList<String>
return b;
}
- // @Override
+ @Override
public void set(int index, ByteString s) {
setAndReturn(index, s);
}
@@ -250,7 +264,7 @@ public class LazyStringArrayList extends AbstractProtobufList<String>
return list.set(index, s);
}
- // @Override
+ @Override
public void set(int index, byte[] s) {
setAndReturn(index, s);
}
@@ -290,12 +304,12 @@ public class LazyStringArrayList extends AbstractProtobufList<String>
}
}
- // @Override
+ @Override
public List<?> getUnderlyingElements() {
return Collections.unmodifiableList(list);
}
- // @Override
+ @Override
public void mergeFrom(LazyStringList other) {
ensureIsMutable();
for (Object o : other.getUnderlyingElements()) {
@@ -349,7 +363,7 @@ public class LazyStringArrayList extends AbstractProtobufList<String>
}
}
- // @Override
+ @Override
public List<byte[]> asByteArrayList() {
return new ByteArrayListView(this);
}
@@ -393,12 +407,12 @@ public class LazyStringArrayList extends AbstractProtobufList<String>
}
}
- // @Override
+ @Override
public List<ByteString> asByteStringList() {
return new ByteStringListView(this);
}
- // @Override
+ @Override
public LazyStringList getUnmodifiableView() {
if (isModifiable()) {
return new UnmodifiableLazyStringList(this);
diff --git a/java/core/src/main/java/com/google/protobuf/LongArrayList.java b/java/core/src/main/java/com/google/protobuf/LongArrayList.java
index ebe62029..bc4475d1 100644
--- a/java/core/src/main/java/com/google/protobuf/LongArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/LongArrayList.java
@@ -34,7 +34,6 @@ import com.google.protobuf.Internal.LongList;
import java.util.Arrays;
import java.util.Collection;
-import java.util.List;
import java.util.RandomAccess;
/**
@@ -44,8 +43,6 @@ import java.util.RandomAccess;
*/
final class LongArrayList extends AbstractProtobufList<Long> implements LongList, RandomAccess {
- private static final int DEFAULT_CAPACITY = 10;
-
private static final LongArrayList EMPTY_LIST = new LongArrayList();
static {
EMPTY_LIST.makeImmutable();
@@ -70,32 +67,55 @@ final class LongArrayList extends AbstractProtobufList<Long> implements LongList
* Constructs a new mutable {@code LongArrayList} with default capacity.
*/
LongArrayList() {
- this(DEFAULT_CAPACITY);
- }
-
- /**
- * Constructs a new mutable {@code LongArrayList} with the provided capacity.
- */
- LongArrayList(int capacity) {
- array = new long[capacity];
- size = 0;
+ this(new long[DEFAULT_CAPACITY], 0);
}
/**
* Constructs a new mutable {@code LongArrayList} containing the same elements as {@code other}.
*/
- LongArrayList(List<Long> other) {
- if (other instanceof LongArrayList) {
- LongArrayList list = (LongArrayList) other;
- array = list.array.clone();
- size = list.size;
- } else {
- size = other.size();
- array = new long[size];
- for (int i = 0; i < size; i++) {
- array[i] = other.get(i);
+ private LongArrayList(long[] array, int size) {
+ this.array = array;
+ this.size = size;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof IntArrayList)) {
+ return super.equals(o);
+ }
+ LongArrayList other = (LongArrayList) o;
+ if (size != other.size) {
+ return false;
+ }
+
+ final long[] arr = other.array;
+ for (int i = 0; i < size; i++) {
+ if (array[i] != arr[i]) {
+ return false;
}
}
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 1;
+ for (int i = 0; i < size; i++) {
+ result = (31 * result) + Internal.hashLong(array[i]);
+ }
+ return result;
+ }
+
+ @Override
+ public LongList mutableCopyWithCapacity(int capacity) {
+ if (capacity < size) {
+ throw new IllegalArgumentException();
+ }
+ return new LongArrayList(Arrays.copyOf(array, capacity), size);
}
@Override
diff --git a/java/core/src/main/java/com/google/protobuf/MapEntryLite.java b/java/core/src/main/java/com/google/protobuf/MapEntryLite.java
index bcffa946..12c64abb 100644
--- a/java/core/src/main/java/com/google/protobuf/MapEntryLite.java
+++ b/java/core/src/main/java/com/google/protobuf/MapEntryLite.java
@@ -41,7 +41,8 @@ import java.io.IOException;
*
* Protobuf internal. Users shouldn't use.
*/
-public class MapEntryLite<K, V> extends AbstractMessageLite {
+public class MapEntryLite<K, V>
+ extends AbstractMessageLite<MapEntryLite<K, V>, MapEntryLite.Builder<K, V>> {
private static class Metadata<K, V> {
public final MapEntryLite<K, V> defaultInstance;
public final WireFormat.FieldType keyType;
@@ -233,7 +234,7 @@ public class MapEntryLite<K, V> extends AbstractMessageLite {
* Builder used to create {@link MapEntryLite} messages.
*/
public static class Builder<K, V>
- extends AbstractMessageLite.Builder<Builder<K, V>> {
+ extends AbstractMessageLite.Builder<MapEntryLite<K, V>, Builder<K, V>> {
private final Metadata<K, V> metadata;
private K key;
private V value;
@@ -327,5 +328,10 @@ public class MapEntryLite<K, V> extends AbstractMessageLite {
this.value = entry.value;
return this;
}
+
+ @Override
+ protected Builder<K, V> internalMergeFrom(MapEntryLite<K, V> message) {
+ throw new UnsupportedOperationException();
+ }
}
}
diff --git a/java/core/src/main/java/com/google/protobuf/MapField.java b/java/core/src/main/java/com/google/protobuf/MapField.java
index b290993c..907f0f71 100644
--- a/java/core/src/main/java/com/google/protobuf/MapField.java
+++ b/java/core/src/main/java/com/google/protobuf/MapField.java
@@ -93,15 +93,18 @@ public class MapField<K, V> implements MutabilityOracle {
this.defaultEntry = defaultEntry;
}
+ @Override
public Message convertKeyAndValueToMessage(K key, V value) {
return defaultEntry.newBuilderForType().setKey(key).setValue(value).buildPartial();
}
+ @Override
public void convertMessageToKeyAndValue(Message message, Map<K, V> map) {
MapEntry<K, V> entry = (MapEntry<K, V>) message;
map.put(entry.getKey(), entry.getValue());
}
+ @Override
public Message getMessageDefaultInstance() {
return defaultEntry;
}
diff --git a/java/core/src/main/java/com/google/protobuf/Message.java b/java/core/src/main/java/com/google/protobuf/Message.java
index 9516d71f..94590fb9 100644
--- a/java/core/src/main/java/com/google/protobuf/Message.java
+++ b/java/core/src/main/java/com/google/protobuf/Message.java
@@ -51,6 +51,7 @@ import java.util.Map;
public interface Message extends MessageLite, MessageOrBuilder {
// (From MessageLite, re-declared here only for return type covariance.)
+ @Override
Parser<? extends Message> getParserForType();
@@ -97,7 +98,10 @@ public interface Message extends MessageLite, MessageOrBuilder {
// Builders
// (From MessageLite, re-declared here only for return type covariance.)
+ @Override
Builder newBuilderForType();
+
+ @Override
Builder toBuilder();
/**
@@ -106,6 +110,7 @@ public interface Message extends MessageLite, MessageOrBuilder {
interface Builder extends MessageLite.Builder, MessageOrBuilder {
// (From MessageLite.Builder, re-declared here only for return type
// covariance.)
+ @Override
Builder clear();
/**
@@ -131,18 +136,27 @@ public interface Message extends MessageLite, MessageOrBuilder {
// (From MessageLite.Builder, re-declared here only for return type
// covariance.)
+ @Override
Message build();
+
+ @Override
Message buildPartial();
+
+ @Override
Builder clone();
+
+ @Override
Builder mergeFrom(CodedInputStream input) throws IOException;
- Builder mergeFrom(CodedInputStream input,
- ExtensionRegistryLite extensionRegistry)
- throws IOException;
+
+ @Override
+ Builder mergeFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry)
+ throws IOException;
/**
* Get the message's type's descriptor.
* See {@link Message#getDescriptorForType()}.
*/
+ @Override
Descriptors.Descriptor getDescriptorForType();
/**
@@ -240,27 +254,39 @@ public interface Message extends MessageLite, MessageOrBuilder {
// (From MessageLite.Builder, re-declared here only for return type
// covariance.)
+ @Override
Builder mergeFrom(ByteString data) throws InvalidProtocolBufferException;
- Builder mergeFrom(ByteString data,
- ExtensionRegistryLite extensionRegistry)
- throws InvalidProtocolBufferException;
+
+ @Override
+ Builder mergeFrom(ByteString data, ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException;
+
+ @Override
Builder mergeFrom(byte[] data) throws InvalidProtocolBufferException;
- Builder mergeFrom(byte[] data, int off, int len)
- throws InvalidProtocolBufferException;
- Builder mergeFrom(byte[] data,
- ExtensionRegistryLite extensionRegistry)
- throws InvalidProtocolBufferException;
- Builder mergeFrom(byte[] data, int off, int len,
- ExtensionRegistryLite extensionRegistry)
- throws InvalidProtocolBufferException;
+
+ @Override
+ Builder mergeFrom(byte[] data, int off, int len) throws InvalidProtocolBufferException;
+
+ @Override
+ Builder mergeFrom(byte[] data, ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException;
+
+ @Override
+ Builder mergeFrom(byte[] data, int off, int len, ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException;
+
+ @Override
Builder mergeFrom(InputStream input) throws IOException;
- Builder mergeFrom(InputStream input,
- ExtensionRegistryLite extensionRegistry)
- throws IOException;
- boolean mergeDelimitedFrom(InputStream input)
- throws IOException;
- boolean mergeDelimitedFrom(InputStream input,
- ExtensionRegistryLite extensionRegistry)
- throws IOException;
+
+ @Override
+ Builder mergeFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
+ throws IOException;
+
+ @Override
+ boolean mergeDelimitedFrom(InputStream input) throws IOException;
+
+ @Override
+ boolean mergeDelimitedFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
+ throws IOException;
}
}
diff --git a/java/core/src/main/java/com/google/protobuf/MessageLite.java b/java/core/src/main/java/com/google/protobuf/MessageLite.java
index 798b7943..88f531df 100644
--- a/java/core/src/main/java/com/google/protobuf/MessageLite.java
+++ b/java/core/src/main/java/com/google/protobuf/MessageLite.java
@@ -295,6 +295,27 @@ public interface MessageLite extends MessageLiteOrBuilder {
Builder mergeFrom(InputStream input,
ExtensionRegistryLite extensionRegistry)
throws IOException;
+
+ /**
+ * Merge {@code other} into the message being built. {@code other} must
+ * have the exact same type as {@code this} (i.e.
+ * {@code getClass().equals(getDefaultInstanceForType().getClass())}).
+ *
+ * Merging occurs as follows. For each field:<br>
+ * * For singular primitive fields, if the field is set in {@code other},
+ * then {@code other}'s value overwrites the value in this message.<br>
+ * * For singular message fields, if the field is set in {@code other},
+ * it is merged into the corresponding sub-message of this message
+ * using the same merging rules.<br>
+ * * For repeated fields, the elements in {@code other} are concatenated
+ * with the elements in this message.
+ * * For oneof groups, if the other message has one of the fields set,
+ * the group of this message is cleared and replaced by the field
+ * of the other message, so that the oneof constraint is preserved.
+ *
+ * This is equivalent to the {@code Message::MergeFrom} method in C++.
+ */
+ Builder mergeFrom(MessageLite other);
/**
* Like {@link #mergeFrom(InputStream)}, but does not read until EOF.
diff --git a/java/core/src/main/java/com/google/protobuf/MessageLiteToString.java b/java/core/src/main/java/com/google/protobuf/MessageLiteToString.java
index e69de29b..43847651 100644
--- a/java/core/src/main/java/com/google/protobuf/MessageLiteToString.java
+++ b/java/core/src/main/java/com/google/protobuf/MessageLiteToString.java
@@ -0,0 +1,239 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+/**
+ * Helps generate {@link String} representations of {@link MessageLite} protos.
+ */
+// TODO(dweis): Fix map fields.
+final class MessageLiteToString {
+
+ private static final String LIST_SUFFIX = "List";
+ private static final String BUILDER_LIST_SUFFIX = "OrBuilderList";
+ private static final String BYTES_SUFFIX = "Bytes";
+
+ /**
+ * Returns a {@link String} representation of the {@link MessageLite} object. The first line of
+ * the {@code String} representation representation includes a comment string to uniquely identify
+ * the objcet instance. This acts as an indicator that this should not be relied on for
+ * comparisons.
+ *
+ * <p>For use by generated code only.
+ */
+ static String toString(MessageLite messageLite, String commentString) {
+ StringBuilder buffer = new StringBuilder();
+ buffer.append("# ").append(commentString);
+ reflectivePrintWithIndent(messageLite, buffer, 0);
+ return buffer.toString();
+ }
+
+ /**
+ * Reflectively prints the {@link MessageLite} to the buffer at given {@code indent} level.
+ *
+ * @param buffer the buffer to write to
+ * @param indent the number of spaces to indent the proto by
+ */
+ private static void reflectivePrintWithIndent(
+ MessageLite messageLite, StringBuilder buffer, int indent) {
+ // Build a map of method name to method. We're looking for methods like getFoo(), hasFoo(), and
+ // getFooList() which might be useful for building an object's string representation.
+ Map<String, Method> nameToNoArgMethod = new HashMap<String, Method>();
+ Map<String, Method> nameToMethod = new HashMap<String, Method>();
+ Set<String> getters = new TreeSet<String>();
+ for (Method method : messageLite.getClass().getDeclaredMethods()) {
+ nameToMethod.put(method.getName(), method);
+ if (method.getParameterTypes().length == 0) {
+ nameToNoArgMethod.put(method.getName(), method);
+
+ if (method.getName().startsWith("get")) {
+ getters.add(method.getName());
+ }
+ }
+ }
+
+ for (String getter : getters) {
+ String suffix = getter.replaceFirst("get", "");
+ if (suffix.endsWith(LIST_SUFFIX) && !suffix.endsWith(BUILDER_LIST_SUFFIX)) {
+ String camelCase = suffix.substring(0, 1).toLowerCase()
+ + suffix.substring(1, suffix.length() - LIST_SUFFIX.length());
+ // Try to reflectively get the value and toString() the field as if it were repeated. This
+ // only works if the method names have not be proguarded out or renamed.
+ Method listMethod = nameToNoArgMethod.get("get" + suffix);
+ if (listMethod != null) {
+ printField(
+ buffer,
+ indent,
+ camelCaseToSnakeCase(camelCase),
+ GeneratedMessageLite.invokeOrDie(listMethod, messageLite));
+ continue;
+ }
+ }
+
+ Method setter = nameToMethod.get("set" + suffix);
+ if (setter == null) {
+ continue;
+ }
+ if (suffix.endsWith(BYTES_SUFFIX)
+ && nameToNoArgMethod.containsKey(
+ "get" + suffix.substring(0, suffix.length() - "Bytes".length()))) {
+ // Heuristic to skip bytes based accessors for string fields.
+ continue;
+ }
+
+ String camelCase = suffix.substring(0, 1).toLowerCase() + suffix.substring(1);
+
+ // Try to reflectively get the value and toString() the field as if it were optional. This
+ // only works if the method names have not be proguarded out or renamed.
+ Method getMethod = nameToNoArgMethod.get("get" + suffix);
+ Method hasMethod = nameToNoArgMethod.get("has" + suffix);
+ // TODO(dweis): Fix proto3 semantics.
+ if (getMethod != null) {
+ Object value = GeneratedMessageLite.invokeOrDie(getMethod, messageLite);
+ final boolean hasValue = hasMethod == null
+ ? !isDefaultValue(value)
+ : (Boolean) GeneratedMessageLite.invokeOrDie(hasMethod, messageLite);
+ // TODO(dweis): This doesn't stop printing oneof case twice: value and enum style.
+ if (hasValue) {
+ printField(
+ buffer,
+ indent,
+ camelCaseToSnakeCase(camelCase),
+ value);
+ }
+ continue;
+ }
+ }
+
+ if (messageLite instanceof GeneratedMessageLite.ExtendableMessage) {
+ Iterator<Map.Entry<GeneratedMessageLite.ExtensionDescriptor, Object>> iter =
+ ((GeneratedMessageLite.ExtendableMessage<?, ?>) messageLite).extensions.iterator();
+ while (iter.hasNext()) {
+ Map.Entry<GeneratedMessageLite.ExtensionDescriptor, Object> entry = iter.next();
+ printField(buffer, indent, "[" + entry.getKey().getNumber() + "]", entry.getValue());
+ }
+ }
+
+ if (((GeneratedMessageLite<?, ?>) messageLite).unknownFields != null) {
+ ((GeneratedMessageLite<?, ?>) messageLite).unknownFields.printWithIndent(buffer, indent);
+ }
+ }
+
+ private static boolean isDefaultValue(Object o) {
+ if (o instanceof Boolean) {
+ return !((Boolean) o);
+ }
+ if (o instanceof Integer) {
+ return ((Integer) o) == 0;
+ }
+ if (o instanceof Float) {
+ return ((Float) o) == 0f;
+ }
+ if (o instanceof Double) {
+ return ((Double) o) == 0d;
+ }
+ if (o instanceof String) {
+ return o.equals("");
+ }
+ if (o instanceof ByteString) {
+ return o.equals(ByteString.EMPTY);
+ }
+ if (o instanceof MessageLite) { // Can happen in oneofs.
+ return o == ((MessageLite) o).getDefaultInstanceForType();
+ }
+ if (o instanceof java.lang.Enum<?>) { // Catches oneof enums.
+ return ((java.lang.Enum<?>) o).ordinal() == 0;
+ }
+
+ return false;
+ }
+
+ /**
+ * Formats a text proto field.
+ *
+ * <p>For use by generated code only.
+ *
+ * @param buffer the buffer to write to
+ * @param indent the number of spaces the proto should be indented by
+ * @param name the field name (in lower underscore case)
+ * @param object the object value of the field
+ */
+ static final void printField(StringBuilder buffer, int indent, String name, Object object) {
+ if (object instanceof List<?>) {
+ List<?> list = (List<?>) object;
+ for (Object entry : list) {
+ printField(buffer, indent, name, entry);
+ }
+ return;
+ }
+
+ buffer.append('\n');
+ for (int i = 0; i < indent; i++) {
+ buffer.append(' ');
+ }
+ buffer.append(name);
+
+ if (object instanceof String) {
+ buffer.append(": \"").append(TextFormatEscaper.escapeText((String) object)).append('"');
+ } else if (object instanceof ByteString) {
+ buffer.append(": \"").append(TextFormatEscaper.escapeBytes((ByteString) object)).append('"');
+ } else if (object instanceof GeneratedMessageLite) {
+ buffer.append(" {");
+ reflectivePrintWithIndent((GeneratedMessageLite<?, ?>) object, buffer, indent + 2);
+ buffer.append("\n");
+ for (int i = 0; i < indent; i++) {
+ buffer.append(' ');
+ }
+ buffer.append("}");
+ } else {
+ buffer.append(": ").append(object.toString());
+ }
+ }
+
+ private static final String camelCaseToSnakeCase(String camelCase) {
+ StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < camelCase.length(); i++) {
+ char ch = camelCase.charAt(i);
+ if (Character.isUpperCase(ch)) {
+ builder.append("_");
+ }
+ builder.append(Character.toLowerCase(ch));
+ }
+ return builder.toString();
+ }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/MessageOrBuilder.java b/java/core/src/main/java/com/google/protobuf/MessageOrBuilder.java
index f0fc4859..5e7d7821 100644
--- a/java/core/src/main/java/com/google/protobuf/MessageOrBuilder.java
+++ b/java/core/src/main/java/com/google/protobuf/MessageOrBuilder.java
@@ -42,7 +42,7 @@ import java.util.Map;
public interface MessageOrBuilder extends MessageLiteOrBuilder {
// (From MessageLite, re-declared here only for return type covariance.)
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
Message getDefaultInstanceForType();
/**
diff --git a/java/core/src/main/java/com/google/protobuf/MessageReflection.java b/java/core/src/main/java/com/google/protobuf/MessageReflection.java
index de4bfd3e..7b791d9e 100644
--- a/java/core/src/main/java/com/google/protobuf/MessageReflection.java
+++ b/java/core/src/main/java/com/google/protobuf/MessageReflection.java
@@ -364,12 +364,14 @@ class MessageReflection {
* Finishes the merge and returns the underlying object.
*/
Object finish();
+
}
static class BuilderAdapter implements MergeTarget {
private final Message.Builder builder;
+ @Override
public Descriptors.Descriptor getDescriptorForType() {
return builder.getDescriptorForType();
}
@@ -378,6 +380,7 @@ class MessageReflection {
this.builder = builder;
}
+ @Override
public Object getField(Descriptors.FieldDescriptor field) {
return builder.getField(field);
}
@@ -387,25 +390,27 @@ class MessageReflection {
return builder.hasField(field);
}
- public MergeTarget setField(Descriptors.FieldDescriptor field,
- Object value) {
+ @Override
+ public MergeTarget setField(Descriptors.FieldDescriptor field, Object value) {
builder.setField(field, value);
return this;
}
+ @Override
public MergeTarget clearField(Descriptors.FieldDescriptor field) {
builder.clearField(field);
return this;
}
+ @Override
public MergeTarget setRepeatedField(
Descriptors.FieldDescriptor field, int index, Object value) {
builder.setRepeatedField(field, index, value);
return this;
}
- public MergeTarget addRepeatedField(
- Descriptors.FieldDescriptor field, Object value) {
+ @Override
+ public MergeTarget addRepeatedField(Descriptors.FieldDescriptor field, Object value) {
builder.addRepeatedField(field, value);
return this;
}
@@ -426,25 +431,30 @@ class MessageReflection {
return builder.getOneofFieldDescriptor(oneof);
}
+ @Override
public ContainerType getContainerType() {
return ContainerType.MESSAGE;
}
+ @Override
public ExtensionRegistry.ExtensionInfo findExtensionByName(
ExtensionRegistry registry, String name) {
return registry.findImmutableExtensionByName(name);
}
+ @Override
public ExtensionRegistry.ExtensionInfo findExtensionByNumber(
- ExtensionRegistry registry, Descriptors.Descriptor containingType,
- int fieldNumber) {
+ ExtensionRegistry registry, Descriptors.Descriptor containingType, int fieldNumber) {
return registry.findImmutableExtensionByNumber(containingType,
fieldNumber);
}
- public Object parseGroup(CodedInputStream input,
+ @Override
+ public Object parseGroup(
+ CodedInputStream input,
ExtensionRegistryLite extensionRegistry,
- Descriptors.FieldDescriptor field, Message defaultInstance)
+ Descriptors.FieldDescriptor field,
+ Message defaultInstance)
throws IOException {
Message.Builder subBuilder;
// When default instance is not null. The field is an extension field.
@@ -463,9 +473,12 @@ class MessageReflection {
return subBuilder.buildPartial();
}
- public Object parseMessage(CodedInputStream input,
+ @Override
+ public Object parseMessage(
+ CodedInputStream input,
ExtensionRegistryLite extensionRegistry,
- Descriptors.FieldDescriptor field, Message defaultInstance)
+ Descriptors.FieldDescriptor field,
+ Message defaultInstance)
throws IOException {
Message.Builder subBuilder;
// When default instance is not null. The field is an extension field.
@@ -484,9 +497,12 @@ class MessageReflection {
return subBuilder.buildPartial();
}
- public Object parseMessageFromBytes(ByteString bytes,
+ @Override
+ public Object parseMessageFromBytes(
+ ByteString bytes,
ExtensionRegistryLite extensionRegistry,
- Descriptors.FieldDescriptor field, Message defaultInstance)
+ Descriptors.FieldDescriptor field,
+ Message defaultInstance)
throws IOException {
Message.Builder subBuilder;
// When default instance is not null. The field is an extension field.
@@ -505,8 +521,9 @@ class MessageReflection {
return subBuilder.buildPartial();
}
- public MergeTarget newMergeTargetForField(Descriptors.FieldDescriptor field,
- Message defaultInstance) {
+ @Override
+ public MergeTarget newMergeTargetForField(
+ Descriptors.FieldDescriptor field, Message defaultInstance) {
if (defaultInstance != null) {
return new BuilderAdapter(
defaultInstance.newBuilderForType());
@@ -515,8 +532,8 @@ class MessageReflection {
}
}
- public WireFormat.Utf8Validation
- getUtf8Validation(Descriptors.FieldDescriptor descriptor) {
+ @Override
+ public WireFormat.Utf8Validation getUtf8Validation(Descriptors.FieldDescriptor descriptor) {
if (descriptor.needsUtf8Check()) {
return WireFormat.Utf8Validation.STRICT;
}
@@ -528,9 +545,11 @@ class MessageReflection {
return WireFormat.Utf8Validation.LOOSE;
}
+ @Override
public Object finish() {
return builder.buildPartial();
}
+
}
@@ -542,38 +561,43 @@ class MessageReflection {
this.extensions = extensions;
}
+ @Override
public Descriptors.Descriptor getDescriptorForType() {
throw new UnsupportedOperationException(
"getDescriptorForType() called on FieldSet object");
}
+ @Override
public Object getField(Descriptors.FieldDescriptor field) {
return extensions.getField(field);
}
+ @Override
public boolean hasField(Descriptors.FieldDescriptor field) {
return extensions.hasField(field);
}
- public MergeTarget setField(Descriptors.FieldDescriptor field,
- Object value) {
+ @Override
+ public MergeTarget setField(Descriptors.FieldDescriptor field, Object value) {
extensions.setField(field, value);
return this;
}
+ @Override
public MergeTarget clearField(Descriptors.FieldDescriptor field) {
extensions.clearField(field);
return this;
}
+ @Override
public MergeTarget setRepeatedField(
Descriptors.FieldDescriptor field, int index, Object value) {
extensions.setRepeatedField(field, index, value);
return this;
}
- public MergeTarget addRepeatedField(
- Descriptors.FieldDescriptor field, Object value) {
+ @Override
+ public MergeTarget addRepeatedField(Descriptors.FieldDescriptor field, Object value) {
extensions.addRepeatedField(field, value);
return this;
}
@@ -594,25 +618,31 @@ class MessageReflection {
return null;
}
+ @Override
public ContainerType getContainerType() {
return ContainerType.EXTENSION_SET;
}
+ @Override
public ExtensionRegistry.ExtensionInfo findExtensionByName(
ExtensionRegistry registry, String name) {
return registry.findImmutableExtensionByName(name);
}
+ @Override
public ExtensionRegistry.ExtensionInfo findExtensionByNumber(
- ExtensionRegistry registry, Descriptors.Descriptor containingType,
- int fieldNumber) {
+ ExtensionRegistry registry, Descriptors.Descriptor containingType, int fieldNumber) {
return registry.findImmutableExtensionByNumber(containingType,
fieldNumber);
}
- public Object parseGroup(CodedInputStream input,
- ExtensionRegistryLite registry, Descriptors.FieldDescriptor field,
- Message defaultInstance) throws IOException {
+ @Override
+ public Object parseGroup(
+ CodedInputStream input,
+ ExtensionRegistryLite registry,
+ Descriptors.FieldDescriptor field,
+ Message defaultInstance)
+ throws IOException {
Message.Builder subBuilder =
defaultInstance.newBuilderForType();
if (!field.isRepeated()) {
@@ -625,9 +655,13 @@ class MessageReflection {
return subBuilder.buildPartial();
}
- public Object parseMessage(CodedInputStream input,
- ExtensionRegistryLite registry, Descriptors.FieldDescriptor field,
- Message defaultInstance) throws IOException {
+ @Override
+ public Object parseMessage(
+ CodedInputStream input,
+ ExtensionRegistryLite registry,
+ Descriptors.FieldDescriptor field,
+ Message defaultInstance)
+ throws IOException {
Message.Builder subBuilder =
defaultInstance.newBuilderForType();
if (!field.isRepeated()) {
@@ -640,9 +674,13 @@ class MessageReflection {
return subBuilder.buildPartial();
}
- public Object parseMessageFromBytes(ByteString bytes,
- ExtensionRegistryLite registry, Descriptors.FieldDescriptor field,
- Message defaultInstance) throws IOException {
+ @Override
+ public Object parseMessageFromBytes(
+ ByteString bytes,
+ ExtensionRegistryLite registry,
+ Descriptors.FieldDescriptor field,
+ Message defaultInstance)
+ throws IOException {
Message.Builder subBuilder = defaultInstance.newBuilderForType();
if (!field.isRepeated()) {
Message originalMessage = (Message) getField(field);
@@ -654,14 +692,15 @@ class MessageReflection {
return subBuilder.buildPartial();
}
+ @Override
public MergeTarget newMergeTargetForField(
Descriptors.FieldDescriptor descriptor, Message defaultInstance) {
throw new UnsupportedOperationException(
"newMergeTargetForField() called on FieldSet object");
}
- public WireFormat.Utf8Validation
- getUtf8Validation(Descriptors.FieldDescriptor descriptor) {
+ @Override
+ public WireFormat.Utf8Validation getUtf8Validation(Descriptors.FieldDescriptor descriptor) {
if (descriptor.needsUtf8Check()) {
return WireFormat.Utf8Validation.STRICT;
}
@@ -669,10 +708,12 @@ class MessageReflection {
return WireFormat.Utf8Validation.LOOSE;
}
+ @Override
public Object finish() {
throw new UnsupportedOperationException(
"finish() called on FieldSet object");
}
+
}
/**
diff --git a/java/core/src/main/java/com/google/protobuf/NioByteString.java b/java/core/src/main/java/com/google/protobuf/NioByteString.java
index f71e41b2..6163c7b1 100644
--- a/java/core/src/main/java/com/google/protobuf/NioByteString.java
+++ b/java/core/src/main/java/com/google/protobuf/NioByteString.java
@@ -30,15 +30,14 @@
package com.google.protobuf;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
import java.nio.InvalidMarkException;
-import java.nio.channels.Channels;
import java.nio.charset.Charset;
import java.util.Collections;
import java.util.List;
@@ -54,7 +53,7 @@ final class NioByteString extends ByteString.LeafByteString {
throw new NullPointerException("buffer");
}
- this.buffer = buffer.slice();
+ this.buffer = buffer.slice().order(ByteOrder.nativeOrder());
}
// =================================================================
@@ -119,7 +118,7 @@ final class NioByteString extends ByteString.LeafByteString {
@Override
public void writeTo(OutputStream out) throws IOException {
- writeToInternal(out, buffer.position(), buffer.remaining());
+ out.write(toByteArray());
}
@Override
@@ -137,14 +136,12 @@ final class NioByteString extends ByteString.LeafByteString {
return;
}
- // Slow path
- if (out instanceof FileOutputStream || numberToWrite >= 8192) {
- // Use a channel to write out the ByteBuffer.
- Channels.newChannel(out).write(slice(sourceOffset, sourceOffset + numberToWrite));
- } else {
- // Just copy the data to an array and write it.
- out.write(toByteArray());
- }
+ ByteBufferWriter.write(slice(sourceOffset, sourceOffset + numberToWrite), out);
+ }
+
+ @Override
+ void writeTo(ByteOutput output) throws IOException {
+ output.writeLazy(buffer.slice());
}
@Override
@@ -159,46 +156,30 @@ final class NioByteString extends ByteString.LeafByteString {
@Override
protected String toStringInternal(Charset charset) {
- byte[] bytes;
- int offset;
+ final byte[] bytes;
+ final int offset;
+ final int length;
if (buffer.hasArray()) {
bytes = buffer.array();
offset = buffer.arrayOffset() + buffer.position();
+ length = buffer.remaining();
} else {
+ // TODO(nathanmittler): Can we optimize this?
bytes = toByteArray();
offset = 0;
+ length = bytes.length;
}
- return new String(bytes, offset, size(), charset);
+ return new String(bytes, offset, length, charset);
}
@Override
public boolean isValidUtf8() {
- // TODO(nathanmittler): add a ByteBuffer fork for Utf8.isValidUtf8 to avoid the copy
- byte[] bytes;
- int startIndex;
- if (buffer.hasArray()) {
- bytes = buffer.array();
- startIndex = buffer.arrayOffset() + buffer.position();
- } else {
- bytes = toByteArray();
- startIndex = 0;
- }
- return Utf8.isValidUtf8(bytes, startIndex, startIndex + size());
+ return Utf8.isValidUtf8(buffer);
}
@Override
protected int partialIsValidUtf8(int state, int offset, int length) {
- // TODO(nathanmittler): TODO add a ByteBuffer fork for Utf8.partialIsValidUtf8 to avoid the copy
- byte[] bytes;
- int startIndex;
- if (buffer.hasArray()) {
- bytes = buffer.array();
- startIndex = buffer.arrayOffset() + buffer.position();
- } else {
- bytes = toByteArray();
- startIndex = 0;
- }
- return Utf8.partialIsValidUtf8(state, bytes, startIndex, startIndex + size());
+ return Utf8.partialIsValidUtf8(state, buffer, offset, offset + length);
}
@Override
diff --git a/java/core/src/main/java/com/google/protobuf/Parser.java b/java/core/src/main/java/com/google/protobuf/Parser.java
index 3fa11c3b..6db69247 100644
--- a/java/core/src/main/java/com/google/protobuf/Parser.java
+++ b/java/core/src/main/java/com/google/protobuf/Parser.java
@@ -30,7 +30,6 @@
package com.google.protobuf;
-import java.io.IOException;
import java.io.InputStream;
/**
diff --git a/java/core/src/main/java/com/google/protobuf/ProtobufArrayList.java b/java/core/src/main/java/com/google/protobuf/ProtobufArrayList.java
index d2f82ac5..81255ec2 100644
--- a/java/core/src/main/java/com/google/protobuf/ProtobufArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/ProtobufArrayList.java
@@ -38,7 +38,7 @@ import java.util.List;
/**
* Implements {@link ProtobufList} for non-primitive and {@link String} types.
*/
-class ProtobufArrayList<E> extends AbstractProtobufList<E> {
+final class ProtobufArrayList<E> extends AbstractProtobufList<E> {
private static final ProtobufArrayList<Object> EMPTY_LIST = new ProtobufArrayList<Object>();
static {
@@ -51,17 +51,23 @@ class ProtobufArrayList<E> extends AbstractProtobufList<E> {
}
private final List<E> list;
-
+
ProtobufArrayList() {
- list = new ArrayList<E>();
+ this(new ArrayList<E>(DEFAULT_CAPACITY));
}
- ProtobufArrayList(List<E> toCopy) {
- list = new ArrayList<E>(toCopy);
+ private ProtobufArrayList(List<E> list) {
+ this.list = list;
}
-
- ProtobufArrayList(int capacity) {
- list = new ArrayList<E>(capacity);
+
+ @Override
+ public ProtobufArrayList<E> mutableCopyWithCapacity(int capacity) {
+ if (capacity < size()) {
+ throw new IllegalArgumentException();
+ }
+ List<E> newList = new ArrayList<E>(capacity);
+ newList.addAll(list);
+ return new ProtobufArrayList<E>(newList);
}
@Override
diff --git a/java/core/src/main/java/com/google/protobuf/ProtocolMessageEnum.java b/java/core/src/main/java/com/google/protobuf/ProtocolMessageEnum.java
index 0c8df989..a596d301 100644
--- a/java/core/src/main/java/com/google/protobuf/ProtocolMessageEnum.java
+++ b/java/core/src/main/java/com/google/protobuf/ProtocolMessageEnum.java
@@ -42,6 +42,7 @@ public interface ProtocolMessageEnum extends Internal.EnumLite {
/**
* Return the value's numeric value as defined in the .proto file.
*/
+ @Override
int getNumber();
/**
diff --git a/java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java b/java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java
index f91cdbce..29f567dc 100644
--- a/java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java
+++ b/java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java
@@ -579,7 +579,7 @@ public class RepeatedFieldBuilder
}
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public void markDirty() {
onChanged();
}
@@ -621,10 +621,12 @@ public class RepeatedFieldBuilder
this.builder = builder;
}
+ @Override
public int size() {
return this.builder.getCount();
}
+ @Override
public MType get(int index) {
return builder.getMessage(index);
}
@@ -654,10 +656,12 @@ public class RepeatedFieldBuilder
this.builder = builder;
}
+ @Override
public int size() {
return this.builder.getCount();
}
+ @Override
public BType get(int index) {
return builder.getBuilder(index);
}
@@ -687,10 +691,12 @@ public class RepeatedFieldBuilder
this.builder = builder;
}
+ @Override
public int size() {
return this.builder.getCount();
}
+ @Override
public IType get(int index) {
return builder.getMessageOrBuilder(index);
}
diff --git a/java/core/src/main/java/com/google/protobuf/RopeByteString.java b/java/core/src/main/java/com/google/protobuf/RopeByteString.java
index 8badfabd..3f3e9bd1 100644
--- a/java/core/src/main/java/com/google/protobuf/RopeByteString.java
+++ b/java/core/src/main/java/com/google/protobuf/RopeByteString.java
@@ -48,10 +48,11 @@ import java.util.Stack;
/**
* Class to represent {@code ByteStrings} formed by concatenation of other
* ByteStrings, without copying the data in the pieces. The concatenation is
- * represented as a tree whose leaf nodes are each a {@link LiteralByteString}.
+ * represented as a tree whose leaf nodes are each a
+ * {@link com.google.protobuf.ByteString.LeafByteString}.
*
* <p>Most of the operation here is inspired by the now-famous paper <a
- * href="http://www.cs.ubc.ca/local/reading/proceedings/spe91-95/spe/vol25/issue12/spe986.pdf">
+ * href="https://web.archive.org/web/20060202015456/http://www.cs.ubc.ca/local/reading/proceedings/spe91-95/spe/vol25/issue12/spe986.pdf">
* BAP95 </a> Ropes: an Alternative to Strings hans-j. boehm, russ atkinson and
* michael plass
*
@@ -139,8 +140,9 @@ final class RopeByteString extends ByteString {
/**
* Concatenate the given strings while performing various optimizations to
* slow the growth rate of tree depth and tree node count. The result is
- * either a {@link LiteralByteString} or a {@link RopeByteString}
- * depending on which optimizations, if any, were applied.
+ * either a {@link com.google.protobuf.ByteString.LeafByteString} or a
+ * {@link RopeByteString} depending on which optimizations, if any, were
+ * applied.
*
* <p>Small pieces of length less than {@link
* ByteString#CONCATENATE_BY_COPY_SIZE} may be copied by value here, as in
@@ -294,8 +296,7 @@ final class RopeByteString extends ByteString {
*
* <p>Substrings of {@code length < 2} should result in at most a single
* recursive call chain, terminating at a leaf node. Thus the result will be a
- * {@link LiteralByteString}. {@link #RopeByteString(ByteString,
- * ByteString)}.
+ * {@link com.google.protobuf.ByteString.LeafByteString}.
*
* @param beginIndex start at this index
* @param endIndex the last character is the one before this index
@@ -368,7 +369,7 @@ final class RopeByteString extends ByteString {
@Override
public List<ByteBuffer> asReadOnlyByteBufferList() {
- // Walk through the list of LiteralByteString's that make up this
+ // Walk through the list of LeafByteString's that make up this
// rope, and add each one as a read-only ByteBuffer.
List<ByteBuffer> result = new ArrayList<ByteBuffer>();
PieceIterator pieces = new PieceIterator(this);
@@ -400,6 +401,12 @@ final class RopeByteString extends ByteString {
}
@Override
+ void writeTo(ByteOutput output) throws IOException {
+ left.writeTo(output);
+ right.writeTo(output);
+ }
+
+ @Override
protected String toStringInternal(Charset charset) {
return new String(toByteArray(), charset);
}
@@ -709,9 +716,10 @@ final class RopeByteString extends ByteString {
}
/**
- * Returns the next item and advances one {@code LiteralByteString}.
+ * Returns the next item and advances one
+ * {@link com.google.protobuf.ByteString.LeafByteString}.
*
- * @return next non-empty LiteralByteString or {@code null}
+ * @return next non-empty LeafByteString or {@code null}
*/
@Override
public LeafByteString next() {
diff --git a/java/core/src/main/java/com/google/protobuf/RpcUtil.java b/java/core/src/main/java/com/google/protobuf/RpcUtil.java
index 694b8d13..f7d555ae 100644
--- a/java/core/src/main/java/com/google/protobuf/RpcUtil.java
+++ b/java/core/src/main/java/com/google/protobuf/RpcUtil.java
@@ -71,6 +71,7 @@ public final class RpcUtil {
final Class<Type> originalClass,
final Type defaultInstance) {
return new RpcCallback<Message>() {
+ @Override
public void run(final Message parameter) {
Type typedParameter;
try {
@@ -107,8 +108,9 @@ public final class RpcUtil {
return new RpcCallback<ParameterType>() {
private boolean alreadyCalled = false;
+ @Override
public void run(final ParameterType parameter) {
- synchronized(this) {
+ synchronized (this) {
if (alreadyCalled) {
throw new AlreadyCalledException();
}
diff --git a/java/core/src/main/java/com/google/protobuf/SingleFieldBuilder.java b/java/core/src/main/java/com/google/protobuf/SingleFieldBuilder.java
index aba65e32..941b5def 100644
--- a/java/core/src/main/java/com/google/protobuf/SingleFieldBuilder.java
+++ b/java/core/src/main/java/com/google/protobuf/SingleFieldBuilder.java
@@ -234,7 +234,7 @@ public class SingleFieldBuilder
}
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public void markDirty() {
onChanged();
}
diff --git a/java/core/src/main/java/com/google/protobuf/SmallSortedMap.java b/java/core/src/main/java/com/google/protobuf/SmallSortedMap.java
index 0674d2e2..409fec10 100644
--- a/java/core/src/main/java/com/google/protobuf/SmallSortedMap.java
+++ b/java/core/src/main/java/com/google/protobuf/SmallSortedMap.java
@@ -35,12 +35,12 @@ import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
-import java.util.TreeMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.SortedMap;
+import java.util.TreeMap;
/**
* A custom map implementation from FieldDescriptor to Object optimized to
@@ -411,22 +411,22 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> {
this.value = value;
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public K getKey() {
return key;
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public V getValue() {
return value;
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public int compareTo(Entry other) {
return getKey().compareTo(other.getKey());
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public V setValue(V newValue) {
checkMutable();
final V oldValue = this.value;
@@ -535,13 +535,13 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> {
private boolean nextCalledBeforeRemove;
private Iterator<Map.Entry<K, V>> lazyOverflowIterator;
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public boolean hasNext() {
return (pos + 1) < entryList.size() ||
getOverflowIterator().hasNext();
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public Map.Entry<K, V> next() {
nextCalledBeforeRemove = true;
// Always increment pos so that we know whether the last returned value
@@ -552,7 +552,7 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> {
return getOverflowIterator().next();
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public void remove() {
if (!nextCalledBeforeRemove) {
throw new IllegalStateException("remove() was called before next()");
@@ -588,31 +588,83 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> {
*/
private static class EmptySet {
- private static final Iterator<Object> ITERATOR = new Iterator<Object>() {
- //@Override (Java 1.6 override semantics, but we must support 1.5)
- public boolean hasNext() {
- return false;
- }
- //@Override (Java 1.6 override semantics, but we must support 1.5)
- public Object next() {
- throw new NoSuchElementException();
- }
- //@Override (Java 1.6 override semantics, but we must support 1.5)
- public void remove() {
- throw new UnsupportedOperationException();
- }
- };
+ private static final Iterator<Object> ITERATOR =
+ new Iterator<Object>() {
+ @Override
+ public boolean hasNext() {
+ return false;
+ }
+ @Override
+ public Object next() {
+ throw new NoSuchElementException();
+ }
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
- private static final Iterable<Object> ITERABLE = new Iterable<Object>() {
- //@Override (Java 1.6 override semantics, but we must support 1.5)
- public Iterator<Object> iterator() {
- return ITERATOR;
- }
- };
+ private static final Iterable<Object> ITERABLE =
+ new Iterable<Object>() {
+ @Override
+ public Iterator<Object> iterator() {
+ return ITERATOR;
+ }
+ };
@SuppressWarnings("unchecked")
static <T> Iterable<T> iterable() {
return (Iterable<T>) ITERABLE;
}
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+
+ if (!(o instanceof SmallSortedMap)) {
+ return super.equals(o);
+ }
+
+ SmallSortedMap<?, ?> other = (SmallSortedMap<?, ?>) o;
+ final int size = size();
+ if (size != other.size()) {
+ return false;
+ }
+
+ // Best effort try to avoid allocating an entry set.
+ final int numArrayEntries = getNumArrayEntries();
+ if (numArrayEntries != other.getNumArrayEntries()) {
+ return entrySet().equals(other.entrySet());
+ }
+
+ for (int i = 0; i < numArrayEntries; i++) {
+ if (!getArrayEntryAt(i).equals(other.getArrayEntryAt(i))) {
+ return false;
+ }
+ }
+
+ if (numArrayEntries != size) {
+ return overflowEntries.equals(other.overflowEntries);
+ }
+
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int h = 0;
+ final int listSize = getNumArrayEntries();
+ for (int i = 0; i < listSize; i++) {
+ h += entryList.get(i).hashCode();
+ }
+ // Avoid the iterator allocation if possible.
+ if (getNumOverflowEntries() > 0) {
+ h += overflowEntries.hashCode();
+ }
+ return h;
+ }
}
diff --git a/java/core/src/main/java/com/google/protobuf/TextFormat.java b/java/core/src/main/java/com/google/protobuf/TextFormat.java
index c99b5285..c1c328fc 100644
--- a/java/core/src/main/java/com/google/protobuf/TextFormat.java
+++ b/java/core/src/main/java/com/google/protobuf/TextFormat.java
@@ -425,7 +425,7 @@ public final class TextFormat {
case STRING:
generator.print("\"");
generator.print(escapeNonAscii
- ? escapeText((String) value)
+ ? TextFormatEscaper.escapeText((String) value)
: escapeDoubleQuotesAndBackslashes((String) value)
.replace("\n", "\\n"));
generator.print("\"");
@@ -661,6 +661,14 @@ public final class TextFormat {
nextToken();
}
+ int getLine() {
+ return line;
+ }
+
+ int getColumn() {
+ return column;
+ }
+
/** Are we at the end of the input? */
public boolean atEnd() {
return currentToken.length() == 0;
@@ -957,11 +965,13 @@ public final class TextFormat {
*/
public boolean consumeBoolean() throws ParseException {
if (currentToken.equals("true")
+ || currentToken.equals("True")
|| currentToken.equals("t")
|| currentToken.equals("1")) {
nextToken();
return true;
} else if (currentToken.equals("false")
+ || currentToken.equals("False")
|| currentToken.equals("f")
|| currentToken.equals("0")) {
nextToken();
@@ -1074,7 +1084,7 @@ public final class TextFormat {
private ParseException floatParseException(final NumberFormatException e) {
return parseException("Couldn't parse number: " + e.getMessage());
}
-
+
/**
* Returns a {@link UnknownFieldParseException} with the line and column
* numbers of the previous token in the description, and the unknown field
@@ -1133,7 +1143,7 @@ public final class TextFormat {
return column;
}
}
-
+
/**
* Thrown when encountering an unknown field while parsing
* a text format message.
@@ -1257,11 +1267,14 @@ public final class TextFormat {
private final boolean allowUnknownFields;
private final SingularOverwritePolicy singularOverwritePolicy;
+ private TextFormatParseInfoTree.Builder parseInfoTreeBuilder;
- private Parser(boolean allowUnknownFields,
- SingularOverwritePolicy singularOverwritePolicy) {
+ private Parser(
+ boolean allowUnknownFields, SingularOverwritePolicy singularOverwritePolicy,
+ TextFormatParseInfoTree.Builder parseInfoTreeBuilder) {
this.allowUnknownFields = allowUnknownFields;
this.singularOverwritePolicy = singularOverwritePolicy;
+ this.parseInfoTreeBuilder = parseInfoTreeBuilder;
}
/**
@@ -1278,6 +1291,7 @@ public final class TextFormat {
private boolean allowUnknownFields = false;
private SingularOverwritePolicy singularOverwritePolicy =
SingularOverwritePolicy.ALLOW_SINGULAR_OVERWRITES;
+ private TextFormatParseInfoTree.Builder parseInfoTreeBuilder = null;
/**
@@ -1288,8 +1302,15 @@ public final class TextFormat {
return this;
}
+ public Builder setParseInfoTreeBuilder(
+ TextFormatParseInfoTree.Builder parseInfoTreeBuilder) {
+ this.parseInfoTreeBuilder = parseInfoTreeBuilder;
+ return this;
+ }
+
public Parser build() {
- return new Parser(allowUnknownFields, singularOverwritePolicy);
+ return new Parser(
+ allowUnknownFields, singularOverwritePolicy, parseInfoTreeBuilder);
}
}
@@ -1380,7 +1401,21 @@ public final class TextFormat {
final ExtensionRegistry extensionRegistry,
final MessageReflection.MergeTarget target)
throws ParseException {
+ mergeField(tokenizer, extensionRegistry, target, parseInfoTreeBuilder);
+ }
+
+ /**
+ * Parse a single field from {@code tokenizer} and merge it into
+ * {@code builder}.
+ */
+ private void mergeField(final Tokenizer tokenizer,
+ final ExtensionRegistry extensionRegistry,
+ final MessageReflection.MergeTarget target,
+ TextFormatParseInfoTree.Builder parseTreeBuilder)
+ throws ParseException {
FieldDescriptor field = null;
+ int startLine = tokenizer.getLine();
+ int startColumn = tokenizer.getColumn();
final Descriptor type = target.getDescriptorForType();
ExtensionRegistry.ExtensionInfo extension = null;
@@ -1472,14 +1507,51 @@ public final class TextFormat {
// Handle potential ':'.
if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
tokenizer.tryConsume(":"); // optional
+ if (parseTreeBuilder != null) {
+ TextFormatParseInfoTree.Builder childParseTreeBuilder =
+ parseTreeBuilder.getBuilderForSubMessageField(field);
+ consumeFieldValues(tokenizer, extensionRegistry, target, field, extension,
+ childParseTreeBuilder);
+ } else {
+ consumeFieldValues(tokenizer, extensionRegistry, target, field, extension,
+ parseTreeBuilder);
+ }
} else {
tokenizer.consume(":"); // required
+ consumeFieldValues(
+ tokenizer, extensionRegistry, target, field, extension, parseTreeBuilder);
}
+
+ if (parseTreeBuilder != null) {
+ parseTreeBuilder.setLocation(
+ field, TextFormatParseLocation.create(startLine, startColumn));
+ }
+
+ // For historical reasons, fields may optionally be separated by commas or
+ // semicolons.
+ if (!tokenizer.tryConsume(";")) {
+ tokenizer.tryConsume(",");
+ }
+ }
+
+ /**
+ * Parse a one or more field values from {@code tokenizer} and merge it into
+ * {@code builder}.
+ */
+ private void consumeFieldValues(
+ final Tokenizer tokenizer,
+ final ExtensionRegistry extensionRegistry,
+ final MessageReflection.MergeTarget target,
+ final FieldDescriptor field,
+ final ExtensionRegistry.ExtensionInfo extension,
+ final TextFormatParseInfoTree.Builder parseTreeBuilder)
+ throws ParseException {
// Support specifying repeated field values as a comma-separated list.
// Ex."foo: [1, 2, 3]"
if (field.isRepeated() && tokenizer.tryConsume("[")) {
while (true) {
- consumeFieldValue(tokenizer, extensionRegistry, target, field, extension);
+ consumeFieldValue(tokenizer, extensionRegistry, target, field, extension,
+ parseTreeBuilder);
if (tokenizer.tryConsume("]")) {
// End of list.
break;
@@ -1487,13 +1559,8 @@ public final class TextFormat {
tokenizer.consume(",");
}
} else {
- consumeFieldValue(tokenizer, extensionRegistry, target, field, extension);
- }
-
- // For historical reasons, fields may optionally be separated by commas or
- // semicolons.
- if (!tokenizer.tryConsume(";")) {
- tokenizer.tryConsume(",");
+ consumeFieldValue(
+ tokenizer, extensionRegistry, target, field, extension, parseTreeBuilder);
}
}
@@ -1506,7 +1573,8 @@ public final class TextFormat {
final ExtensionRegistry extensionRegistry,
final MessageReflection.MergeTarget target,
final FieldDescriptor field,
- final ExtensionRegistry.ExtensionInfo extension)
+ final ExtensionRegistry.ExtensionInfo extension,
+ final TextFormatParseInfoTree.Builder parseTreeBuilder)
throws ParseException {
Object value = null;
@@ -1528,7 +1596,7 @@ public final class TextFormat {
throw tokenizer.parseException(
"Expected \"" + endToken + "\".");
}
- mergeField(tokenizer, extensionRegistry, subField);
+ mergeField(tokenizer, extensionRegistry, subField, parseTreeBuilder);
}
value = subField.finish();
@@ -1704,52 +1772,6 @@ public final class TextFormat {
// Some of these methods are package-private because Descriptors.java uses
// them.
- private interface ByteSequence {
- int size();
- byte byteAt(int offset);
- }
-
- /**
- * Escapes bytes in the format used in protocol buffer text format, which
- * is the same as the format used for C string literals. All bytes
- * that are not printable 7-bit ASCII characters are escaped, as well as
- * backslash, single-quote, and double-quote characters. Characters for
- * which no defined short-hand escape sequence is defined will be escaped
- * using 3-digit octal sequences.
- */
- public static String escapeBytes(final ByteSequence input) {
- final StringBuilder builder = new StringBuilder(input.size());
- for (int i = 0; i < input.size(); i++) {
- final byte b = input.byteAt(i);
- switch (b) {
- // Java does not recognize \a or \v, apparently.
- case 0x07: builder.append("\\a"); break;
- case '\b': builder.append("\\b"); break;
- case '\f': builder.append("\\f"); break;
- case '\n': builder.append("\\n"); break;
- case '\r': builder.append("\\r"); break;
- case '\t': builder.append("\\t"); break;
- case 0x0b: builder.append("\\v"); break;
- case '\\': builder.append("\\\\"); break;
- case '\'': builder.append("\\\'"); break;
- case '"' : builder.append("\\\""); break;
- default:
- // Only ASCII characters between 0x20 (space) and 0x7e (tilde) are
- // printable. Other byte values must be escaped.
- if (b >= 0x20 && b <= 0x7e) {
- builder.append((char) b);
- } else {
- builder.append('\\');
- builder.append((char) ('0' + ((b >>> 6) & 3)));
- builder.append((char) ('0' + ((b >>> 3) & 7)));
- builder.append((char) ('0' + (b & 7)));
- }
- break;
- }
- }
- return builder.toString();
- }
-
/**
* Escapes bytes in the format used in protocol buffer text format, which
* is the same as the format used for C string literals. All bytes
@@ -1758,33 +1780,15 @@ public final class TextFormat {
* which no defined short-hand escape sequence is defined will be escaped
* using 3-digit octal sequences.
*/
- public static String escapeBytes(final ByteString input) {
- return escapeBytes(new ByteSequence() {
- @Override
- public int size() {
- return input.size();
- }
- @Override
- public byte byteAt(int offset) {
- return input.byteAt(offset);
- }
- });
+ public static String escapeBytes(ByteString input) {
+ return TextFormatEscaper.escapeBytes(input);
}
/**
* Like {@link #escapeBytes(ByteString)}, but used for byte array.
*/
- public static String escapeBytes(final byte[] input) {
- return escapeBytes(new ByteSequence() {
- @Override
- public int size() {
- return input.length;
- }
- @Override
- public byte byteAt(int offset) {
- return input[offset];
- }
- });
+ public static String escapeBytes(byte[] input) {
+ return TextFormatEscaper.escapeBytes(input);
}
/**
@@ -1868,7 +1872,9 @@ public final class TextFormat {
}
}
- return ByteString.copyFrom(result, 0, pos);
+ return result.length == pos
+ ? ByteString.wrap(result) // This reference has not been out of our control.
+ : ByteString.copyFrom(result, 0, pos);
}
/**
@@ -1896,7 +1902,7 @@ public final class TextFormat {
* Escape double quotes and backslashes in a String for unicode output of a message.
*/
public static String escapeDoubleQuotesAndBackslashes(final String input) {
- return input.replace("\\", "\\\\").replace("\"", "\\\"");
+ return TextFormatEscaper.escapeDoubleQuotesAndBackslashes(input);
}
/**
diff --git a/java/core/src/main/java/com/google/protobuf/TextFormatEscaper.java b/java/core/src/main/java/com/google/protobuf/TextFormatEscaper.java
index e69de29b..da9ceadd 100644
--- a/java/core/src/main/java/com/google/protobuf/TextFormatEscaper.java
+++ b/java/core/src/main/java/com/google/protobuf/TextFormatEscaper.java
@@ -0,0 +1,137 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+/**
+ * Provide text format escaping support for proto2 instances.
+ */
+final class TextFormatEscaper {
+ private TextFormatEscaper() {}
+
+ private interface ByteSequence {
+ int size();
+ byte byteAt(int offset);
+ }
+
+ /**
+ * Escapes bytes in the format used in protocol buffer text format, which
+ * is the same as the format used for C string literals. All bytes
+ * that are not printable 7-bit ASCII characters are escaped, as well as
+ * backslash, single-quote, and double-quote characters. Characters for
+ * which no defined short-hand escape sequence is defined will be escaped
+ * using 3-digit octal sequences.
+ */
+ static String escapeBytes(final ByteSequence input) {
+ final StringBuilder builder = new StringBuilder(input.size());
+ for (int i = 0; i < input.size(); i++) {
+ final byte b = input.byteAt(i);
+ switch (b) {
+ // Java does not recognize \a or \v, apparently.
+ case 0x07: builder.append("\\a"); break;
+ case '\b': builder.append("\\b"); break;
+ case '\f': builder.append("\\f"); break;
+ case '\n': builder.append("\\n"); break;
+ case '\r': builder.append("\\r"); break;
+ case '\t': builder.append("\\t"); break;
+ case 0x0b: builder.append("\\v"); break;
+ case '\\': builder.append("\\\\"); break;
+ case '\'': builder.append("\\\'"); break;
+ case '"' : builder.append("\\\""); break;
+ default:
+ // Only ASCII characters between 0x20 (space) and 0x7e (tilde) are
+ // printable. Other byte values must be escaped.
+ if (b >= 0x20 && b <= 0x7e) {
+ builder.append((char) b);
+ } else {
+ builder.append('\\');
+ builder.append((char) ('0' + ((b >>> 6) & 3)));
+ builder.append((char) ('0' + ((b >>> 3) & 7)));
+ builder.append((char) ('0' + (b & 7)));
+ }
+ break;
+ }
+ }
+ return builder.toString();
+ }
+
+ /**
+ * Escapes bytes in the format used in protocol buffer text format, which
+ * is the same as the format used for C string literals. All bytes
+ * that are not printable 7-bit ASCII characters are escaped, as well as
+ * backslash, single-quote, and double-quote characters. Characters for
+ * which no defined short-hand escape sequence is defined will be escaped
+ * using 3-digit octal sequences.
+ */
+ static String escapeBytes(final ByteString input) {
+ return escapeBytes(new ByteSequence() {
+ @Override
+ public int size() {
+ return input.size();
+ }
+ @Override
+ public byte byteAt(int offset) {
+ return input.byteAt(offset);
+ }
+ });
+ }
+
+ /**
+ * Like {@link #escapeBytes(ByteString)}, but used for byte array.
+ */
+ static String escapeBytes(final byte[] input) {
+ return escapeBytes(new ByteSequence() {
+ @Override
+ public int size() {
+ return input.length;
+ }
+ @Override
+ public byte byteAt(int offset) {
+ return input[offset];
+ }
+ });
+ }
+
+ /**
+ * Like {@link #escapeBytes(ByteString)}, but escapes a text string.
+ * Non-ASCII characters are first encoded as UTF-8, then each byte is escaped
+ * individually as a 3-digit octal escape. Yes, it's weird.
+ */
+ static String escapeText(final String input) {
+ return escapeBytes(ByteString.copyFromUtf8(input));
+ }
+
+ /**
+ * Escape double quotes and backslashes in a String for unicode output of a message.
+ */
+ static String escapeDoubleQuotesAndBackslashes(final String input) {
+ return input.replace("\\", "\\\\").replace("\"", "\\\"");
+ }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/TextFormatParseInfoTree.java b/java/core/src/main/java/com/google/protobuf/TextFormatParseInfoTree.java
new file mode 100644
index 00000000..2ecf912e
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/TextFormatParseInfoTree.java
@@ -0,0 +1,225 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.FieldDescriptor;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+
+/**
+ * Data structure which is populated with the locations of each field value parsed from the text.
+ *
+ * <p>The locations of primary fields values are retrieved by {@code getLocation} or
+ * {@code getLocations}. The locations of sub message values are within nested
+ * {@code TextFormatParseInfoTree}s and are retrieve by {@getNestedTree} or {code @getNestedTrees}.
+ *
+ * <p>The {@code TextFormatParseInfoTree} is created by a Builder.
+ */
+public class TextFormatParseInfoTree {
+
+ // Defines a mapping between each field's descriptor to the list of locations where
+ // its value(s) were was encountered.
+ private Map<FieldDescriptor, List<TextFormatParseLocation>> locationsFromField;
+
+ // Defines a mapping between a field's descriptor to a list of TextFormatParseInfoTrees for
+ // sub message location information.
+ Map<FieldDescriptor, List<TextFormatParseInfoTree>> subtreesFromField;
+
+ /**
+ * Construct a {@code TextFormatParseInfoTree}.
+ *
+ * @param locationsFromField a map of fields to location in the source code
+ * @param subtreeBuildersFromField a map of fields to parse tree location information builders
+ */
+ private TextFormatParseInfoTree(
+ Map<FieldDescriptor, List<TextFormatParseLocation>> locationsFromField,
+ Map<FieldDescriptor, List<TextFormatParseInfoTree.Builder>> subtreeBuildersFromField) {
+
+ // The maps are unmodifiable. The values in the maps are unmodifiable.
+ Map<FieldDescriptor, List<TextFormatParseLocation>> locs =
+ new HashMap<FieldDescriptor, List<TextFormatParseLocation>>();
+ for (Entry<FieldDescriptor, List<TextFormatParseLocation>> kv : locationsFromField.entrySet()) {
+ locs.put(kv.getKey(), Collections.unmodifiableList(kv.getValue()));
+ }
+ this.locationsFromField = Collections.unmodifiableMap(locs);
+
+ Map<FieldDescriptor, List<TextFormatParseInfoTree>> subs =
+ new HashMap<FieldDescriptor, List<TextFormatParseInfoTree>>();
+ for (Entry<FieldDescriptor, List<Builder>> kv : subtreeBuildersFromField.entrySet()) {
+ List<TextFormatParseInfoTree> submessagesOfField = new ArrayList<TextFormatParseInfoTree>();
+ for (Builder subBuilder : kv.getValue()) {
+ submessagesOfField.add(subBuilder.build());
+ }
+ subs.put(kv.getKey(), Collections.unmodifiableList(submessagesOfField));
+ }
+ this.subtreesFromField = Collections.unmodifiableMap(subs);
+ }
+
+ /**
+ * Retrieve all the locations of a field.
+ *
+ * @param fieldDescriptor the the @{link FieldDescriptor} of the desired field
+ * @return a list of the locations of values of the field. If there are not values
+ * or the field doesn't exist, an empty list is returned.
+ */
+ public List<TextFormatParseLocation> getLocations(final FieldDescriptor fieldDescriptor) {
+ List<TextFormatParseLocation> result = locationsFromField.get(fieldDescriptor);
+ return (result == null) ? Collections.<TextFormatParseLocation>emptyList() : result;
+ }
+
+ /**
+ * Get the location in the source of a field's value.
+ *
+ * <p>Returns the {@link TextFormatParseLocation} for index-th value of the field in the parsed
+ * text.
+ *
+ * @param fieldDescriptor the @{link FieldDescriptor} of the desired field
+ * @param index the index of the value.
+ * @return the {@link TextFormatParseLocation} of the value
+ * @throws IllegalArgumentException index is out of range
+ */
+ public TextFormatParseLocation getLocation(final FieldDescriptor fieldDescriptor, int index) {
+ return getFromList(getLocations(fieldDescriptor), index, fieldDescriptor);
+ }
+
+ /**
+ * Retrieve a list of all the location information trees for a sub message field.
+ *
+ * @param fieldDescriptor the @{link FieldDescriptor} of the desired field
+ * @return A list of {@link TextFormatParseInfoTree}
+ */
+ public List<TextFormatParseInfoTree> getNestedTrees(final FieldDescriptor fieldDescriptor) {
+ List<TextFormatParseInfoTree> result = subtreesFromField.get(fieldDescriptor);
+ return result == null ? Collections.<TextFormatParseInfoTree>emptyList() : result;
+ }
+
+ /**
+ * Returns the parse info tree for the given field, which must be a message type.
+ *
+ * @param fieldDescriptor the @{link FieldDescriptor} of the desired sub message
+ * @param index the index of message value.
+ * @return the {@code ParseInfoTree} of the message value. {@code null} is returned if the field
+ * doesn't exist or the index is out of range.
+ * @throws IllegalArgumentException if index is out of range
+ */
+ public TextFormatParseInfoTree getNestedTree(final FieldDescriptor fieldDescriptor, int index) {
+ return getFromList(getNestedTrees(fieldDescriptor), index, fieldDescriptor);
+ }
+
+ /**
+ * Create a builder for a {@code ParseInfoTree}.
+ *
+ * @return the builder
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ private static <T> T getFromList(List<T> list, int index, FieldDescriptor fieldDescriptor) {
+ if (index >= list.size() || index < 0) {
+ throw new IllegalArgumentException(String.format("Illegal index field: %s, index %d",
+ fieldDescriptor == null ? "<null>" : fieldDescriptor.getName(), index));
+ }
+ return list.get(index);
+ }
+
+ /**
+ * Builder for a {@link TextFormatParseInfoTree}.
+ */
+ public static class Builder {
+
+ private Map<FieldDescriptor, List<TextFormatParseLocation>> locationsFromField;
+
+ // Defines a mapping between a field's descriptor to a list of ParseInfoTrees builders for
+ // sub message location information.
+ private Map<FieldDescriptor, List<Builder>> subtreeBuildersFromField;
+
+ /**
+ * Create a root level {@ParseInfoTree} builder.
+ */
+ private Builder() {
+ locationsFromField = new HashMap<FieldDescriptor, List<TextFormatParseLocation>>();
+ subtreeBuildersFromField = new HashMap<FieldDescriptor, List<Builder>>();
+ }
+
+ /**
+ * Record the starting location of a single value for a field.
+ *
+ * @param fieldDescriptor the field
+ * @param location source code location information
+ */
+ public Builder setLocation(
+ final FieldDescriptor fieldDescriptor, TextFormatParseLocation location) {
+ List<TextFormatParseLocation> fieldLocations = locationsFromField.get(fieldDescriptor);
+ if (fieldLocations == null) {
+ fieldLocations = new ArrayList<TextFormatParseLocation>();
+ locationsFromField.put(fieldDescriptor, fieldLocations);
+ }
+ fieldLocations.add(location);
+ return this;
+ }
+
+ /**
+ * Set for a sub message.
+ *
+ * <p>A new builder is created for a sub message. The builder that is returned is a new builder.
+ * The return is <emph>not</emph> the invoked {@code builder.getBuilderForSubMessageField}.
+ *
+ * @param fieldDescriptor the field whose value is the submessage
+ * @return a new Builder for the sub message
+ */
+ public Builder getBuilderForSubMessageField(final FieldDescriptor fieldDescriptor) {
+ List<Builder> submessageBuilders = subtreeBuildersFromField.get(fieldDescriptor);
+ if (submessageBuilders == null) {
+ submessageBuilders = new ArrayList<Builder>();
+ subtreeBuildersFromField.put(fieldDescriptor, submessageBuilders);
+ }
+ Builder subtreeBuilder = new Builder();
+ submessageBuilders.add(subtreeBuilder);
+ return subtreeBuilder;
+ }
+
+ /**
+ * Build the {@code TextFormatParseInfoTree}.
+ *
+ * @return the {@code TextFormatParseInfoTree}
+ */
+ public TextFormatParseInfoTree build() {
+ return new TextFormatParseInfoTree(locationsFromField, subtreeBuildersFromField);
+ }
+ }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/TextFormatParseLocation.java b/java/core/src/main/java/com/google/protobuf/TextFormatParseLocation.java
new file mode 100644
index 00000000..cce286e1
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/TextFormatParseLocation.java
@@ -0,0 +1,104 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import java.util.Arrays;
+
+/**
+ * A location in the source code.
+ *
+ * <p>A location is the starting line number and starting column number.
+ */
+public final class TextFormatParseLocation {
+
+ /**
+ * The empty location.
+ */
+ public static final TextFormatParseLocation EMPTY = new TextFormatParseLocation(-1, -1);
+
+ /**
+ * Create a location.
+ *
+ * @param line the starting line number
+ * @param column the starting column number
+ * @return a {@code ParseLocation}
+ */
+ static TextFormatParseLocation create(int line, int column) {
+ if (line == -1 && column == -1) {
+ return EMPTY;
+ }
+ if (line < 0 || column < 0) {
+ throw new IllegalArgumentException(
+ String.format("line and column values must be >= 0: line %d, column: %d", line, column));
+ }
+ return new TextFormatParseLocation(line, column);
+ }
+
+ private final int line;
+ private final int column;
+
+ private TextFormatParseLocation(int line, int column) {
+ this.line = line;
+ this.column = column;
+ }
+
+ public int getLine() {
+ return line;
+ }
+
+ public int getColumn() {
+ return column;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("ParseLocation{line=%d, column=%d}", line, column);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (!(o instanceof TextFormatParseLocation)) {
+ return false;
+ }
+ TextFormatParseLocation that = (TextFormatParseLocation) o;
+ return (this.line == that.getLine())
+ && (this.column == that.getColumn());
+ }
+
+ @Override
+ public int hashCode() {
+ int[] values = {line, column};
+ return Arrays.hashCode(values);
+ }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java b/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java
index 7cd2250e..c906420d 100644
--- a/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java
+++ b/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java
@@ -76,6 +76,7 @@ public final class UnknownFieldSet implements MessageLite {
public static UnknownFieldSet getDefaultInstance() {
return defaultInstance;
}
+ @Override
public UnknownFieldSet getDefaultInstanceForType() {
return defaultInstance;
}
@@ -126,6 +127,7 @@ public final class UnknownFieldSet implements MessageLite {
}
/** Serializes the set and writes it to {@code output}. */
+ @Override
public void writeTo(final CodedOutputStream output) throws IOException {
for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
entry.getValue().writeTo(entry.getKey(), output);
@@ -146,6 +148,7 @@ public final class UnknownFieldSet implements MessageLite {
* Serializes the message to a {@code ByteString} and returns it. This is
* just a trivial wrapper around {@link #writeTo(CodedOutputStream)}.
*/
+ @Override
public ByteString toByteString() {
try {
final ByteString.CodedBuilder out =
@@ -163,6 +166,7 @@ public final class UnknownFieldSet implements MessageLite {
* Serializes the message to a {@code byte} array and returns it. This is
* just a trivial wrapper around {@link #writeTo(CodedOutputStream)}.
*/
+ @Override
public byte[] toByteArray() {
try {
final byte[] result = new byte[getSerializedSize()];
@@ -181,12 +185,14 @@ public final class UnknownFieldSet implements MessageLite {
* Serializes the message and writes it to {@code output}. This is just a
* trivial wrapper around {@link #writeTo(CodedOutputStream)}.
*/
+ @Override
public void writeTo(final OutputStream output) throws IOException {
final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
writeTo(codedOutput);
codedOutput.flush();
}
+ @Override
public void writeDelimitedTo(OutputStream output) throws IOException {
final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
codedOutput.writeRawVarint32(getSerializedSize());
@@ -195,6 +201,7 @@ public final class UnknownFieldSet implements MessageLite {
}
/** Get the number of bytes required to encode this set. */
+ @Override
public int getSerializedSize() {
int result = 0;
for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
@@ -228,6 +235,7 @@ public final class UnknownFieldSet implements MessageLite {
return result;
}
+ @Override
public boolean isInitialized() {
// UnknownFieldSets do not have required fields, so they are always
// initialized.
@@ -258,10 +266,12 @@ public final class UnknownFieldSet implements MessageLite {
return newBuilder().mergeFrom(input).build();
}
+ @Override
public Builder newBuilderForType() {
return newBuilder();
}
+ @Override
public Builder toBuilder() {
return newBuilder().mergeFrom(this);
}
@@ -329,6 +339,7 @@ public final class UnknownFieldSet implements MessageLite {
* in undefined behavior and can cause a {@code NullPointerException} to be
* thrown.
*/
+ @Override
public UnknownFieldSet build() {
getFieldBuilder(0); // Force lastField to be built.
final UnknownFieldSet result;
@@ -341,6 +352,7 @@ public final class UnknownFieldSet implements MessageLite {
return result;
}
+ @Override
public UnknownFieldSet buildPartial() {
// No required fields, so this is the same as build().
return build();
@@ -353,6 +365,7 @@ public final class UnknownFieldSet implements MessageLite {
new UnknownFieldSet(fields));
}
+ @Override
public UnknownFieldSet getDefaultInstanceForType() {
return UnknownFieldSet.getDefaultInstance();
}
@@ -364,6 +377,7 @@ public final class UnknownFieldSet implements MessageLite {
}
/** Reset the builder to an empty set. */
+ @Override
public Builder clear() {
reinitialize();
return this;
@@ -487,6 +501,7 @@ public final class UnknownFieldSet implements MessageLite {
* Parse an entire message from {@code input} and merge its fields into
* this set.
*/
+ @Override
public Builder mergeFrom(final CodedInputStream input) throws IOException {
while (true) {
final int tag = input.readTag();
@@ -536,8 +551,8 @@ public final class UnknownFieldSet implements MessageLite {
* set being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream)}.
*/
- public Builder mergeFrom(final ByteString data)
- throws InvalidProtocolBufferException {
+ @Override
+ public Builder mergeFrom(final ByteString data) throws InvalidProtocolBufferException {
try {
final CodedInputStream input = data.newCodedInput();
mergeFrom(input);
@@ -557,8 +572,8 @@ public final class UnknownFieldSet implements MessageLite {
* set being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream)}.
*/
- public Builder mergeFrom(final byte[] data)
- throws InvalidProtocolBufferException {
+ @Override
+ public Builder mergeFrom(final byte[] data) throws InvalidProtocolBufferException {
try {
final CodedInputStream input = CodedInputStream.newInstance(data);
mergeFrom(input);
@@ -578,6 +593,7 @@ public final class UnknownFieldSet implements MessageLite {
* set being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream)}.
*/
+ @Override
public Builder mergeFrom(final InputStream input) throws IOException {
final CodedInputStream codedInput = CodedInputStream.newInstance(input);
mergeFrom(codedInput);
@@ -585,8 +601,8 @@ public final class UnknownFieldSet implements MessageLite {
return this;
}
- public boolean mergeDelimitedFrom(InputStream input)
- throws IOException {
+ @Override
+ public boolean mergeDelimitedFrom(InputStream input) throws IOException {
final int firstByte = input.read();
if (firstByte == -1) {
return false;
@@ -597,30 +613,29 @@ public final class UnknownFieldSet implements MessageLite {
return true;
}
- public boolean mergeDelimitedFrom(
- InputStream input,
- ExtensionRegistryLite extensionRegistry) throws IOException {
+ @Override
+ public boolean mergeDelimitedFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
+ throws IOException {
// UnknownFieldSet has no extensions.
return mergeDelimitedFrom(input);
}
- public Builder mergeFrom(
- CodedInputStream input,
- ExtensionRegistryLite extensionRegistry) throws IOException {
+ @Override
+ public Builder mergeFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry)
+ throws IOException {
// UnknownFieldSet has no extensions.
return mergeFrom(input);
}
- public Builder mergeFrom(
- ByteString data,
- ExtensionRegistryLite extensionRegistry)
+ @Override
+ public Builder mergeFrom(ByteString data, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
// UnknownFieldSet has no extensions.
return mergeFrom(data);
}
- public Builder mergeFrom(byte[] data, int off, int len)
- throws InvalidProtocolBufferException {
+ @Override
+ public Builder mergeFrom(byte[] data, int off, int len) throws InvalidProtocolBufferException {
try {
final CodedInputStream input =
CodedInputStream.newInstance(data, off, len);
@@ -636,29 +651,37 @@ public final class UnknownFieldSet implements MessageLite {
}
}
- public Builder mergeFrom(
- byte[] data,
- ExtensionRegistryLite extensionRegistry)
+ @Override
+ public Builder mergeFrom(byte[] data, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
// UnknownFieldSet has no extensions.
return mergeFrom(data);
}
- public Builder mergeFrom(
- byte[] data, int off, int len,
- ExtensionRegistryLite extensionRegistry)
+ @Override
+ public Builder mergeFrom(byte[] data, int off, int len, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
// UnknownFieldSet has no extensions.
return mergeFrom(data, off, len);
}
- public Builder mergeFrom(
- InputStream input,
- ExtensionRegistryLite extensionRegistry) throws IOException {
+ @Override
+ public Builder mergeFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
+ throws IOException {
// UnknownFieldSet has no extensions.
return mergeFrom(input);
}
+ @Override
+ public Builder mergeFrom(MessageLite m) {
+ if (m instanceof UnknownFieldSet) {
+ return mergeFrom((UnknownFieldSet) m);
+ }
+ throw new IllegalArgumentException(
+ "mergeFrom(MessageLite) can only merge messages of the same type.");
+ }
+
+ @Override
public boolean isInitialized() {
// UnknownFieldSets do not have required fields, so they are always
// initialized.
@@ -987,6 +1010,7 @@ public final class UnknownFieldSet implements MessageLite {
* Parser to implement MessageLite interface.
*/
public static final class Parser extends AbstractParser<UnknownFieldSet> {
+ @Override
public UnknownFieldSet parsePartialFrom(
CodedInputStream input, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
@@ -1004,6 +1028,7 @@ public final class UnknownFieldSet implements MessageLite {
}
private static final Parser PARSER = new Parser();
+ @Override
public final Parser getParserForType() {
return PARSER;
}
diff --git a/java/core/src/main/java/com/google/protobuf/UnknownFieldSetLite.java b/java/core/src/main/java/com/google/protobuf/UnknownFieldSetLite.java
index 435ad4d4..9500f905 100644
--- a/java/core/src/main/java/com/google/protobuf/UnknownFieldSetLite.java
+++ b/java/core/src/main/java/com/google/protobuf/UnknownFieldSetLite.java
@@ -61,15 +61,6 @@ public final class UnknownFieldSetLite {
public static UnknownFieldSetLite getDefaultInstance() {
return DEFAULT_INSTANCE;
}
-
- /**
- * 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.
@@ -262,6 +253,21 @@ public final class UnknownFieldSetLite {
return hashCode;
}
+ /**
+ * Prints a String representation of the unknown field set.
+ *
+ * <p>For use by generated code only.
+ *
+ * @param buffer the buffer to write to
+ * @param indent the number of spaces the fields should be indented by
+ */
+ final void printWithIndent(StringBuilder buffer, int indent) {
+ for (int i = 0; i < count; i++) {
+ int fieldNumber = WireFormat.getTagFieldNumber(tags[i]);
+ MessageLiteToString.printField(buffer, indent, String.valueOf(fieldNumber), objects[i]);
+ }
+ }
+
private void storeField(int tag, Object value) {
ensureCapacity();
@@ -369,90 +375,4 @@ public final class UnknownFieldSetLite {
}
return this;
}
-
- /**
- * Builder for {@link UnknownFieldSetLite}s.
- *
- * <p>Use {@link UnknownFieldSet#newBuilder()} to construct a {@code Builder}.
- *
- * <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 {
-
- private UnknownFieldSetLite set;
-
- private Builder() {
- this.set = null;
- }
-
- /**
- * Ensures internal state is initialized for use.
- */
- private void ensureNotBuilt() {
- if (set == null) {
- set = new UnknownFieldSetLite();
- }
-
- set.checkMutable();
- }
-
- /**
- * 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 {
- ensureNotBuilt();
- return set.mergeFieldFrom(tag, input);
- }
-
- /**
- * 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.
- */
- Builder mergeVarintField(int fieldNumber, int value) {
- ensureNotBuilt();
- 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) {
- ensureNotBuilt();
- set.mergeLengthDelimitedField(fieldNumber, value);
- 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 an
- * {@code UnsupportedOperationException} to be thrown.
- *
- * <p>For use by generated code only.
- */
- public UnknownFieldSetLite build() {
- if (set == null) {
- return DEFAULT_INSTANCE;
- }
-
- set.checkMutable();
- set.makeImmutable();
-
- return set;
- }
- }
}
diff --git a/java/core/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java b/java/core/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java
index 5257c5a2..30e87911 100644
--- a/java/core/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java
+++ b/java/core/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java
@@ -68,42 +68,42 @@ public class UnmodifiableLazyStringList extends AbstractList<String>
return list.size();
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public ByteString getByteString(int index) {
return list.getByteString(index);
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public void add(ByteString element) {
throw new UnsupportedOperationException();
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public void set(int index, ByteString element) {
throw new UnsupportedOperationException();
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public boolean addAllByteString(Collection<? extends ByteString> element) {
throw new UnsupportedOperationException();
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public byte[] getByteArray(int index) {
return list.getByteArray(index);
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public void add(byte[] element) {
throw new UnsupportedOperationException();
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public void set(int index, byte[] element) {
throw new UnsupportedOperationException();
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public boolean addAllByteArray(Collection<byte[]> element) {
throw new UnsupportedOperationException();
}
@@ -113,47 +113,47 @@ public class UnmodifiableLazyStringList extends AbstractList<String>
return new ListIterator<String>() {
ListIterator<String> iter = list.listIterator(index);
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public boolean hasNext() {
return iter.hasNext();
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public String next() {
return iter.next();
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public boolean hasPrevious() {
return iter.hasPrevious();
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public String previous() {
return iter.previous();
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public int nextIndex() {
return iter.nextIndex();
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public int previousIndex() {
return iter.previousIndex();
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public void remove() {
throw new UnsupportedOperationException();
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public void set(String o) {
throw new UnsupportedOperationException();
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public void add(String o) {
throw new UnsupportedOperationException();
}
@@ -165,45 +165,45 @@ public class UnmodifiableLazyStringList extends AbstractList<String>
return new Iterator<String>() {
Iterator<String> iter = list.iterator();
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public boolean hasNext() {
return iter.hasNext();
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public String next() {
return iter.next();
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public List<?> getUnderlyingElements() {
// The returned value is already unmodifiable.
return list.getUnderlyingElements();
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public void mergeFrom(LazyStringList other) {
throw new UnsupportedOperationException();
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public List<byte[]> asByteArrayList() {
return Collections.unmodifiableList(list.asByteArrayList());
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public List<ByteString> asByteStringList() {
return Collections.unmodifiableList(list.asByteStringList());
}
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public LazyStringList getUnmodifiableView() {
return this;
}
diff --git a/java/core/src/main/java/com/google/protobuf/UnsafeByteOperations.java b/java/core/src/main/java/com/google/protobuf/UnsafeByteOperations.java
index f443ee39..0fbf4d40 100644
--- a/java/core/src/main/java/com/google/protobuf/UnsafeByteOperations.java
+++ b/java/core/src/main/java/com/google/protobuf/UnsafeByteOperations.java
@@ -30,6 +30,7 @@
package com.google.protobuf;
+import java.io.IOException;
import java.nio.ByteBuffer;
/**
@@ -49,8 +50,8 @@ public final class UnsafeByteOperations {
/**
* An unsafe operation that returns a {@link ByteString} that is backed by the provided buffer.
*
- * @param buffer the Java NIO buffer to be wrapped.
- * @return a {@link ByteString} backed by the provided buffer.
+ * @param buffer the Java NIO buffer to be wrapped
+ * @return a {@link ByteString} backed by the provided buffer
*/
public static ByteString unsafeWrap(ByteBuffer buffer) {
if (buffer.hasArray()) {
@@ -60,4 +61,24 @@ public final class UnsafeByteOperations {
return new NioByteString(buffer);
}
}
+
+ /**
+ * Writes the given {@link ByteString} to the provided {@link ByteOutput}. Calling this method may
+ * result in multiple operations on the target {@link ByteOutput}
+ * (i.e. for roped {@link ByteString}s).
+ *
+ * <p>This method exposes the internal backing buffer(s) of the {@link ByteString} to the {@link
+ * ByteOutput} in order to avoid additional copying overhead. It would be possible for a malicious
+ * {@link ByteOutput} to corrupt the {@link ByteString}. Use with caution!
+ *
+ * <p> NOTE: The {@link ByteOutput} <strong>MUST NOT</strong> modify the provided buffers. Doing
+ * so may result in corrupted data, which would be difficult to debug.
+ *
+ * @param bytes the {@link ByteString} to be written
+ * @param output the output to receive the bytes
+ * @throws IOException if an I/O error occurs
+ */
+ public static void unsafeWriteTo(ByteString bytes, ByteOutput output) throws IOException {
+ bytes.writeTo(output);
+ }
}
diff --git a/java/core/src/main/java/com/google/protobuf/Utf8.java b/java/core/src/main/java/com/google/protobuf/Utf8.java
index 48c7e9e6..308c69e9 100644
--- a/java/core/src/main/java/com/google/protobuf/Utf8.java
+++ b/java/core/src/main/java/com/google/protobuf/Utf8.java
@@ -30,6 +30,19 @@
package com.google.protobuf;
+import static java.lang.Character.MAX_SURROGATE;
+import static java.lang.Character.MIN_SURROGATE;
+import static java.lang.Character.isSurrogatePair;
+import static java.lang.Character.toCodePoint;
+
+import java.lang.reflect.Field;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.security.AccessController;
+import java.security.PrivilegedExceptionAction;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
/**
* A set of low-level, high-performance static utility methods related
* to the UTF-8 character encoding. This class has no dependencies
@@ -64,9 +77,24 @@ package com.google.protobuf;
*
* @author martinrb@google.com (Martin Buchholz)
*/
+// TODO(nathanmittler): Copy changes in this class back to Guava
final class Utf8 {
- private Utf8() {}
-
+ private static final Logger logger = Logger.getLogger(Utf8.class.getName());
+
+ /**
+ * UTF-8 is a runtime hot spot so we attempt to provide heavily optimized implementations
+ * depending on what is available on the platform. The processor is the platform-optimized
+ * delegate for which all methods are delegated directly to.
+ */
+ private static final Processor processor =
+ UnsafeProcessor.isAvailable() ? new UnsafeProcessor() : new SafeProcessor();
+
+ /**
+ * A mask used when performing unsafe reads to determine if a long value contains any non-ASCII
+ * characters (i.e. any byte >= 0x80).
+ */
+ private static final long ASCII_MASK_LONG = 0x8080808080808080L;
+
/**
* Maximum number of bytes per Java UTF-16 char in UTF-8.
* @see java.nio.charset.CharsetEncoder#maxBytesPerChar()
@@ -85,6 +113,18 @@ final class Utf8 {
*/
public static final int MALFORMED = -1;
+ /**
+ * Used by {@code Unsafe} UTF-8 string validation logic to determine the minimum string length
+ * above which to employ an optimized algorithm for counting ASCII characters. The reason for this
+ * threshold is that for small strings, the optimization may not be beneficial or may even
+ * negatively impact performance since it requires additional logic to avoid unaligned reads
+ * (when calling {@code Unsafe.getLong}). This threshold guarantees that even if the initial
+ * offset is unaligned, we're guaranteed to make at least one call to {@code Unsafe.getLong()}
+ * which provides a performance improvement that entirely subsumes the cost of the additional
+ * logic.
+ */
+ private static final int UNSAFE_COUNT_ASCII_THRESHOLD = 16;
+
// Other state values include the partial bytes of the incomplete
// character to be decoded in the simplest way: we pack the bytes
// into the state int in little-endian order. For example:
@@ -112,7 +152,7 @@ final class Utf8 {
* isValidUtf8(bytes, 0, bytes.length)}.
*/
public static boolean isValidUtf8(byte[] bytes) {
- return isValidUtf8(bytes, 0, bytes.length);
+ return processor.isValidUtf8(bytes, 0, bytes.length);
}
/**
@@ -125,7 +165,7 @@ final class Utf8 {
* partialIsValidUtf8(bytes, index, limit) == Utf8.COMPLETE}.
*/
public static boolean isValidUtf8(byte[] bytes, int index, int limit) {
- return partialIsValidUtf8(bytes, index, limit) == COMPLETE;
+ return processor.isValidUtf8(bytes, index, limit);
}
/**
@@ -146,183 +186,8 @@ final class Utf8 {
* decode the character when passed to a subsequent invocation of a
* partial decoding method.
*/
- public static int partialIsValidUtf8(
- int state, byte[] bytes, int index, int limit) {
- if (state != COMPLETE) {
- // The previous decoding operation was incomplete (or malformed).
- // We look for a well-formed sequence consisting of bytes from
- // the previous decoding operation (stored in state) together
- // with bytes from the array slice.
- //
- // We expect such "straddler characters" to be rare.
-
- if (index >= limit) { // No bytes? No progress.
- return state;
- }
- int byte1 = (byte) state;
- // byte1 is never ASCII.
- if (byte1 < (byte) 0xE0) {
- // two-byte form
-
- // Simultaneously checks for illegal trailing-byte in
- // leading position and overlong 2-byte form.
- if (byte1 < (byte) 0xC2 ||
- // byte2 trailing-byte test
- bytes[index++] > (byte) 0xBF) {
- return MALFORMED;
- }
- } else if (byte1 < (byte) 0xF0) {
- // three-byte form
-
- // Get byte2 from saved state or array
- int byte2 = (byte) ~(state >> 8);
- if (byte2 == 0) {
- byte2 = bytes[index++];
- if (index >= limit) {
- return incompleteStateFor(byte1, byte2);
- }
- }
- if (byte2 > (byte) 0xBF ||
- // overlong? 5 most significant bits must not all be zero
- (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0) ||
- // illegal surrogate codepoint?
- (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0) ||
- // byte3 trailing-byte test
- bytes[index++] > (byte) 0xBF) {
- return MALFORMED;
- }
- } else {
- // four-byte form
-
- // Get byte2 and byte3 from saved state or array
- int byte2 = (byte) ~(state >> 8);
- int byte3 = 0;
- if (byte2 == 0) {
- byte2 = bytes[index++];
- if (index >= limit) {
- return incompleteStateFor(byte1, byte2);
- }
- } else {
- byte3 = (byte) (state >> 16);
- }
- if (byte3 == 0) {
- byte3 = bytes[index++];
- if (index >= limit) {
- return incompleteStateFor(byte1, byte2, byte3);
- }
- }
-
- // If we were called with state == MALFORMED, then byte1 is 0xFF,
- // which never occurs in well-formed UTF-8, and so we will return
- // MALFORMED again below.
-
- if (byte2 > (byte) 0xBF ||
- // Check that 1 <= plane <= 16. Tricky optimized form of:
- // if (byte1 > (byte) 0xF4 ||
- // byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
- // byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
- (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0 ||
- // byte3 trailing-byte test
- byte3 > (byte) 0xBF ||
- // byte4 trailing-byte test
- bytes[index++] > (byte) 0xBF) {
- return MALFORMED;
- }
- }
- }
-
- return partialIsValidUtf8(bytes, index, limit);
- }
-
- /**
- * Tells whether the given byte array slice is a well-formed,
- * malformed, or incomplete UTF-8 byte sequence. The range of bytes
- * to be checked extends from index {@code index}, inclusive, to
- * {@code limit}, exclusive.
- *
- * <p>This is a convenience method, equivalent to a call to {@code
- * partialIsValidUtf8(Utf8.COMPLETE, bytes, index, limit)}.
- *
- * @return {@link #MALFORMED} if the partial byte sequence is
- * definitely not well-formed, {@link #COMPLETE} if it is well-formed
- * (no additional input needed), or if the byte sequence is
- * "incomplete", i.e. apparently terminated in the middle of a character,
- * an opaque integer "state" value containing enough information to
- * decode the character when passed to a subsequent invocation of a
- * partial decoding method.
- */
- public static int partialIsValidUtf8(
- byte[] bytes, int index, int limit) {
- // Optimize for 100% ASCII.
- // Hotspot loves small simple top-level loops like this.
- while (index < limit && bytes[index] >= 0) {
- index++;
- }
-
- return (index >= limit) ? COMPLETE :
- partialIsValidUtf8NonAscii(bytes, index, limit);
- }
-
- private static int partialIsValidUtf8NonAscii(
- byte[] bytes, int index, int limit) {
- for (;;) {
- int byte1, byte2;
-
- // Optimize for interior runs of ASCII bytes.
- do {
- if (index >= limit) {
- return COMPLETE;
- }
- } while ((byte1 = bytes[index++]) >= 0);
-
- if (byte1 < (byte) 0xE0) {
- // two-byte form
-
- if (index >= limit) {
- return byte1;
- }
-
- // Simultaneously checks for illegal trailing-byte in
- // leading position and overlong 2-byte form.
- if (byte1 < (byte) 0xC2 ||
- bytes[index++] > (byte) 0xBF) {
- return MALFORMED;
- }
- } else if (byte1 < (byte) 0xF0) {
- // three-byte form
-
- if (index >= limit - 1) { // incomplete sequence
- return incompleteStateFor(bytes, index, limit);
- }
- if ((byte2 = bytes[index++]) > (byte) 0xBF ||
- // overlong? 5 most significant bits must not all be zero
- (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0) ||
- // check for illegal surrogate codepoints
- (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0) ||
- // byte3 trailing-byte test
- bytes[index++] > (byte) 0xBF) {
- return MALFORMED;
- }
- } else {
- // four-byte form
-
- if (index >= limit - 2) { // incomplete sequence
- return incompleteStateFor(bytes, index, limit);
- }
- if ((byte2 = bytes[index++]) > (byte) 0xBF ||
- // Check that 1 <= plane <= 16. Tricky optimized form of:
- // if (byte1 > (byte) 0xF4 ||
- // byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
- // byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
- (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0 ||
- // byte3 trailing-byte test
- bytes[index++] > (byte) 0xBF ||
- // byte4 trailing-byte test
- bytes[index++] > (byte) 0xBF) {
- return MALFORMED;
- }
- }
- }
+ public static int partialIsValidUtf8(int state, byte[] bytes, int index, int limit) {
+ return processor.partialIsValidUtf8(state, bytes, index, limit);
}
private static int incompleteStateFor(int byte1) {
@@ -352,19 +217,31 @@ final class Utf8 {
default: throw new AssertionError();
}
}
-
+
+ private static int incompleteStateFor(
+ final ByteBuffer buffer, final int byte1, final int index, final int remaining) {
+ switch (remaining) {
+ case 0:
+ return incompleteStateFor(byte1);
+ case 1:
+ return incompleteStateFor(byte1, buffer.get(index));
+ case 2:
+ return incompleteStateFor(byte1, buffer.get(index), buffer.get(index + 1));
+ default:
+ throw new AssertionError();
+ }
+ }
// These UTF-8 handling methods are copied from Guava's Utf8 class with a modification to throw
// a protocol buffer local exception. This exception is then caught in CodedOutputStream so it can
// fallback to more lenient behavior.
static class UnpairedSurrogateException extends IllegalArgumentException {
-
private UnpairedSurrogateException(int index, int length) {
super("Unpaired surrogate at index " + index + " of " + length);
}
}
-
+
/**
* Returns the number of bytes in the UTF-8-encoded form of {@code sequence}. For a string,
* this method is equivalent to {@code string.getBytes(UTF_8).length}, but is more efficient in
@@ -426,56 +303,1381 @@ final class Utf8 {
return utf8Length;
}
- static int encode(CharSequence sequence, byte[] bytes, int offset, int length) {
- int utf16Length = sequence.length();
- int j = offset;
- int i = 0;
- int limit = offset + length;
- // Designed to take advantage of
- // https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination
- for (char c; i < utf16Length && i + j < limit && (c = sequence.charAt(i)) < 0x80; i++) {
- bytes[j + i] = (byte) c;
- }
- if (i == utf16Length) {
- return j + utf16Length;
- }
- j += i;
- for (char c; i < utf16Length; i++) {
- c = sequence.charAt(i);
- if (c < 0x80 && j < limit) {
- bytes[j++] = (byte) c;
- } else if (c < 0x800 && j <= limit - 2) { // 11 bits, two UTF-8 bytes
- bytes[j++] = (byte) ((0xF << 6) | (c >>> 6));
- bytes[j++] = (byte) (0x80 | (0x3F & c));
- } else if ((c < Character.MIN_SURROGATE || Character.MAX_SURROGATE < c) && j <= limit - 3) {
- // Maximum single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes
- bytes[j++] = (byte) ((0xF << 5) | (c >>> 12));
- bytes[j++] = (byte) (0x80 | (0x3F & (c >>> 6)));
- bytes[j++] = (byte) (0x80 | (0x3F & c));
- } else if (j <= limit - 4) {
- // Minimum code point represented by a surrogate pair is 0x10000, 17 bits, four UTF-8 bytes
- final char low;
- if (i + 1 == sequence.length()
- || !Character.isSurrogatePair(c, (low = sequence.charAt(++i)))) {
- throw new UnpairedSurrogateException((i - 1), utf16Length);
- }
- int codePoint = Character.toCodePoint(c, low);
- bytes[j++] = (byte) ((0xF << 4) | (codePoint >>> 18));
- bytes[j++] = (byte) (0x80 | (0x3F & (codePoint >>> 12)));
- bytes[j++] = (byte) (0x80 | (0x3F & (codePoint >>> 6)));
- bytes[j++] = (byte) (0x80 | (0x3F & codePoint));
+ static int encode(CharSequence in, byte[] out, int offset, int length) {
+ return processor.encodeUtf8(in, out, offset, length);
+ }
+ // End Guava UTF-8 methods.
+
+ /**
+ * Determines if the given {@link ByteBuffer} is a valid UTF-8 string.
+ *
+ * <p>Selects an optimal algorithm based on the type of {@link ByteBuffer} (i.e. heap or direct)
+ * and the capabilities of the platform.
+ *
+ * @param buffer the buffer to check.
+ * @see Utf8#isValidUtf8(byte[], int, int)
+ */
+ static boolean isValidUtf8(ByteBuffer buffer) {
+ return processor.isValidUtf8(buffer, buffer.position(), buffer.remaining());
+ }
+
+ /**
+ * Determines if the given {@link ByteBuffer} is a partially valid UTF-8 string.
+ *
+ * <p>Selects an optimal algorithm based on the type of {@link ByteBuffer} (i.e. heap or direct)
+ * and the capabilities of the platform.
+ *
+ * @param buffer the buffer to check.
+ * @see Utf8#partialIsValidUtf8(int, byte[], int, int)
+ */
+ static int partialIsValidUtf8(int state, ByteBuffer buffer, int index, int limit) {
+ return processor.partialIsValidUtf8(state, buffer, index, limit);
+ }
+
+ /**
+ * Encodes the given characters to the target {@link ByteBuffer} using UTF-8 encoding.
+ *
+ * <p>Selects an optimal algorithm based on the type of {@link ByteBuffer} (i.e. heap or direct)
+ * and the capabilities of the platform.
+ *
+ * @param in the source string to be encoded
+ * @param out the target buffer to receive the encoded string.
+ * @see Utf8#encode(CharSequence, byte[], int, int)
+ */
+ static void encodeUtf8(CharSequence in, ByteBuffer out) {
+ processor.encodeUtf8(in, out);
+ }
+
+ /**
+ * Counts (approximately) the number of consecutive ASCII characters in the given buffer.
+ * The byte order of the {@link ByteBuffer} does not matter, so performance can be improved if
+ * native byte order is used (i.e. no byte-swapping in {@link ByteBuffer#getLong(int)}).
+ *
+ * @param buffer the buffer to be scanned for ASCII chars
+ * @param index the starting index of the scan
+ * @param limit the limit within buffer for the scan
+ * @return the number of ASCII characters found. The stopping position will be at or
+ * before the first non-ASCII byte.
+ */
+ private static int estimateConsecutiveAscii(ByteBuffer buffer, int index, int limit) {
+ int i = index;
+ final int lim = limit - 7;
+ // This simple loop stops when we encounter a byte >= 0x80 (i.e. non-ASCII).
+ // To speed things up further, we're reading longs instead of bytes so we use a mask to
+ // determine if any byte in the current long is non-ASCII.
+ for (; i < lim && (buffer.getLong(i) & ASCII_MASK_LONG) == 0; i += 8) {}
+ return i - index;
+ }
+
+ /**
+ * A processor of UTF-8 strings, providing methods for checking validity and encoding.
+ */
+ // TODO(nathanmittler): Add support for Memory/MemoryBlock on Android.
+ abstract static class Processor {
+ /**
+ * Returns {@code true} if the given byte array slice is a
+ * well-formed UTF-8 byte sequence. The range of bytes to be
+ * checked extends from index {@code index}, inclusive, to {@code
+ * limit}, exclusive.
+ *
+ * <p>This is a convenience method, equivalent to {@code
+ * partialIsValidUtf8(bytes, index, limit) == Utf8.COMPLETE}.
+ */
+ final boolean isValidUtf8(byte[] bytes, int index, int limit) {
+ return partialIsValidUtf8(COMPLETE, bytes, index, limit) == COMPLETE;
+ }
+
+ /**
+ * Tells whether the given byte array slice is a well-formed,
+ * malformed, or incomplete UTF-8 byte sequence. The range of bytes
+ * to be checked extends from index {@code index}, inclusive, to
+ * {@code limit}, exclusive.
+ *
+ * @param state either {@link Utf8#COMPLETE} (if this is the initial decoding
+ * operation) or the value returned from a call to a partial decoding method
+ * for the previous bytes
+ *
+ * @return {@link #MALFORMED} if the partial byte sequence is
+ * definitely not well-formed, {@link #COMPLETE} if it is well-formed
+ * (no additional input needed), or if the byte sequence is
+ * "incomplete", i.e. apparently terminated in the middle of a character,
+ * an opaque integer "state" value containing enough information to
+ * decode the character when passed to a subsequent invocation of a
+ * partial decoding method.
+ */
+ abstract int partialIsValidUtf8(int state, byte[] bytes, int index, int limit);
+
+ /**
+ * Returns {@code true} if the given portion of the {@link ByteBuffer} is a
+ * well-formed UTF-8 byte sequence. The range of bytes to be
+ * checked extends from index {@code index}, inclusive, to {@code
+ * limit}, exclusive.
+ *
+ * <p>This is a convenience method, equivalent to {@code
+ * partialIsValidUtf8(bytes, index, limit) == Utf8.COMPLETE}.
+ */
+ final boolean isValidUtf8(ByteBuffer buffer, int index, int limit) {
+ return partialIsValidUtf8(COMPLETE, buffer, index, limit) == COMPLETE;
+ }
+
+ /**
+ * Indicates whether or not the given buffer contains a valid UTF-8 string.
+ *
+ * @param buffer the buffer to check.
+ * @return {@code true} if the given buffer contains a valid UTF-8 string.
+ */
+ final int partialIsValidUtf8(
+ final int state, final ByteBuffer buffer, int index, final int limit) {
+ if (buffer.hasArray()) {
+ final int offset = buffer.arrayOffset();
+ return partialIsValidUtf8(state, buffer.array(), offset + index, offset + limit);
+ } else if (buffer.isDirect()){
+ return partialIsValidUtf8Direct(state, buffer, index, limit);
+ }
+ return partialIsValidUtf8Default(state, buffer, index, limit);
+ }
+
+ /**
+ * Performs validation for direct {@link ByteBuffer} instances.
+ */
+ abstract int partialIsValidUtf8Direct(
+ final int state, final ByteBuffer buffer, int index, final int limit);
+
+ /**
+ * Performs validation for {@link ByteBuffer} instances using the {@link ByteBuffer} API rather
+ * than potentially faster approaches. This first completes validation for the current
+ * character (provided by {@code state}) and then finishes validation for the sequence.
+ */
+ final int partialIsValidUtf8Default(
+ final int state, final ByteBuffer buffer, int index, final int limit) {
+ if (state != COMPLETE) {
+ // The previous decoding operation was incomplete (or malformed).
+ // We look for a well-formed sequence consisting of bytes from
+ // the previous decoding operation (stored in state) together
+ // with bytes from the array slice.
+ //
+ // We expect such "straddler characters" to be rare.
+
+ if (index >= limit) { // No bytes? No progress.
+ return state;
+ }
+
+ byte byte1 = (byte) state;
+ // byte1 is never ASCII.
+ if (byte1 < (byte) 0xE0) {
+ // two-byte form
+
+ // Simultaneously checks for illegal trailing-byte in
+ // leading position and overlong 2-byte form.
+ if (byte1 < (byte) 0xC2
+ // byte2 trailing-byte test
+ || buffer.get(index++) > (byte) 0xBF) {
+ return MALFORMED;
+ }
+ } else if (byte1 < (byte) 0xF0) {
+ // three-byte form
+
+ // Get byte2 from saved state or array
+ byte byte2 = (byte) ~(state >> 8);
+ if (byte2 == 0) {
+ byte2 = buffer.get(index++);
+ if (index >= limit) {
+ return incompleteStateFor(byte1, byte2);
+ }
+ }
+ if (byte2 > (byte) 0xBF
+ // overlong? 5 most significant bits must not all be zero
+ || (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0)
+ // illegal surrogate codepoint?
+ || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0)
+ // byte3 trailing-byte test
+ || buffer.get(index++) > (byte) 0xBF) {
+ return MALFORMED;
+ }
+ } else {
+ // four-byte form
+
+ // Get byte2 and byte3 from saved state or array
+ byte byte2 = (byte) ~(state >> 8);
+ byte byte3 = 0;
+ if (byte2 == 0) {
+ byte2 = buffer.get(index++);
+ if (index >= limit) {
+ return incompleteStateFor(byte1, byte2);
+ }
+ } else {
+ byte3 = (byte) (state >> 16);
+ }
+ if (byte3 == 0) {
+ byte3 = buffer.get(index++);
+ if (index >= limit) {
+ return incompleteStateFor(byte1, byte2, byte3);
+ }
+ }
+
+ // If we were called with state == MALFORMED, then byte1 is 0xFF,
+ // which never occurs in well-formed UTF-8, and so we will return
+ // MALFORMED again below.
+
+ if (byte2 > (byte) 0xBF
+ // Check that 1 <= plane <= 16. Tricky optimized form of:
+ // if (byte1 > (byte) 0xF4 ||
+ // byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
+ // byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
+ || (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0
+ // byte3 trailing-byte test
+ || byte3 > (byte) 0xBF
+ // byte4 trailing-byte test
+ || buffer.get(index++) > (byte) 0xBF) {
+ return MALFORMED;
+ }
+ }
+ }
+
+ // Finish validation for the sequence.
+ return partialIsValidUtf8(buffer, index, limit);
+ }
+
+ /**
+ * Performs validation for {@link ByteBuffer} instances using the {@link ByteBuffer} API rather
+ * than potentially faster approaches.
+ */
+ private static int partialIsValidUtf8(final ByteBuffer buffer, int index, final int limit) {
+ index += estimateConsecutiveAscii(buffer, index, limit);
+
+ for (;;) {
+ // Optimize for interior runs of ASCII bytes.
+ // TODO(nathanmittler): Consider checking 8 bytes at a time after some threshold?
+ // Maybe after seeing a few in a row that are ASCII, go back to fast mode?
+ int byte1;
+ do {
+ if (index >= limit) {
+ return COMPLETE;
+ }
+ } while ((byte1 = buffer.get(index++)) >= 0);
+
+ // If we're here byte1 is not ASCII. Only need to handle 2-4 byte forms.
+ if (byte1 < (byte) 0xE0) {
+ // Two-byte form (110xxxxx 10xxxxxx)
+ if (index >= limit) {
+ // Incomplete sequence
+ return byte1;
+ }
+
+ // Simultaneously checks for illegal trailing-byte in
+ // leading position and overlong 2-byte form.
+ if (byte1 < (byte) 0xC2 || buffer.get(index) > (byte) 0xBF) {
+ return MALFORMED;
+ }
+ index++;
+ } else if (byte1 < (byte) 0xF0) {
+ // Three-byte form (1110xxxx 10xxxxxx 10xxxxxx)
+ if (index >= limit - 1) {
+ // Incomplete sequence
+ return incompleteStateFor(buffer, byte1, index, limit - index);
+ }
+
+ final byte byte2 = buffer.get(index++);
+ if (byte2 > (byte) 0xBF
+ // overlong? 5 most significant bits must not all be zero
+ || (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0)
+ // check for illegal surrogate codepoints
+ || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0)
+ // byte3 trailing-byte test
+ || buffer.get(index) > (byte) 0xBF) {
+ return MALFORMED;
+ }
+ index++;
+ } else {
+ // Four-byte form (1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx)
+ if (index >= limit - 2) {
+ // Incomplete sequence
+ return incompleteStateFor(buffer, byte1, index, limit - index);
+ }
+
+ // TODO(nathanmittler): Consider using getInt() to improve performance.
+ final int byte2 = buffer.get(index++);
+ if (byte2 > (byte) 0xBF
+ // Check that 1 <= plane <= 16. Tricky optimized form of:
+ // if (byte1 > (byte) 0xF4 ||
+ // byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
+ // byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
+ || (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0
+ // byte3 trailing-byte test
+ || buffer.get(index++) > (byte) 0xBF
+ // byte4 trailing-byte test
+ || buffer.get(index++) > (byte) 0xBF) {
+ return MALFORMED;
+ }
+ }
+ }
+ }
+
+ /**
+ * Encodes an input character sequence ({@code in}) to UTF-8 in the target array ({@code out}).
+ * For a string, this method is similar to
+ * <pre>{@code
+ * byte[] a = string.getBytes(UTF_8);
+ * System.arraycopy(a, 0, bytes, offset, a.length);
+ * return offset + a.length;
+ * }</pre>
+ *
+ * but is more efficient in both time and space. One key difference is that this method
+ * requires paired surrogates, and therefore does not support chunking.
+ * While {@code String.getBytes(UTF_8)} replaces unpaired surrogates with the default
+ * replacement character, this method throws {@link UnpairedSurrogateException}.
+ *
+ * <p>To ensure sufficient space in the output buffer, either call {@link #encodedLength} to
+ * compute the exact amount needed, or leave room for
+ * {@code Utf8.MAX_BYTES_PER_CHAR * sequence.length()}, which is the largest possible number
+ * of bytes that any input can be encoded to.
+ *
+ * @param in the input character sequence to be encoded
+ * @param out the target array
+ * @param offset the starting offset in {@code bytes} to start writing at
+ * @param length the length of the {@code bytes}, starting from {@code offset}
+ * @throws UnpairedSurrogateException if {@code sequence} contains ill-formed UTF-16 (unpaired
+ * surrogates)
+ * @throws ArrayIndexOutOfBoundsException if {@code sequence} encoded in UTF-8 is longer than
+ * {@code bytes.length - offset}
+ * @return the new offset, equivalent to {@code offset + Utf8.encodedLength(sequence)}
+ */
+ abstract int encodeUtf8(CharSequence in, byte[] out, int offset, int length);
+
+ /**
+ * Encodes an input character sequence ({@code in}) to UTF-8 in the target buffer ({@code out}).
+ * Upon returning from this method, the {@code out} position will point to the position after
+ * the last encoded byte. This method requires paired surrogates, and therefore does not
+ * support chunking.
+ *
+ * <p>To ensure sufficient space in the output buffer, either call {@link #encodedLength} to
+ * compute the exact amount needed, or leave room for
+ * {@code Utf8.MAX_BYTES_PER_CHAR * in.length()}, which is the largest possible number
+ * of bytes that any input can be encoded to.
+ *
+ * @param in the source character sequence to be encoded
+ * @param out the target buffer
+ * @throws UnpairedSurrogateException if {@code in} contains ill-formed UTF-16 (unpaired
+ * surrogates)
+ * @throws ArrayIndexOutOfBoundsException if {@code in} encoded in UTF-8 is longer than
+ * {@code out.remaining()}
+ */
+ final void encodeUtf8(CharSequence in, ByteBuffer out) {
+ if (out.hasArray()) {
+ final int offset = out.arrayOffset();
+ int endIndex =
+ Utf8.encode(in, out.array(), offset + out.position(), out.remaining());
+ out.position(endIndex - offset);
+ } else if (out.isDirect()) {
+ encodeUtf8Direct(in, out);
} else {
- // If we are surrogates and we're not a surrogate pair, always throw an
- // IllegalArgumentException instead of an ArrayOutOfBoundsException.
- if ((Character.MIN_SURROGATE <= c && c <= Character.MAX_SURROGATE)
- && (i + 1 == sequence.length()
- || !Character.isSurrogatePair(c, sequence.charAt(i + 1)))) {
- throw new UnpairedSurrogateException(i, utf16Length);
+ encodeUtf8Default(in, out);
+ }
+ }
+
+ /**
+ * Encodes the input character sequence to a direct {@link ByteBuffer} instance.
+ */
+ abstract void encodeUtf8Direct(CharSequence in, ByteBuffer out);
+
+ /**
+ * Encodes the input character sequence to a {@link ByteBuffer} instance using the {@link
+ * ByteBuffer} API, rather than potentially faster approaches.
+ */
+ final void encodeUtf8Default(CharSequence in, ByteBuffer out) {
+ final int inLength = in.length();
+ int outIx = out.position();
+ int inIx = 0;
+
+ // Since ByteBuffer.putXXX() already checks boundaries for us, no need to explicitly check
+ // access. Assume the buffer is big enough and let it handle the out of bounds exception
+ // if it occurs.
+ try {
+ // Designed to take advantage of
+ // https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination
+ for (char c; inIx < inLength && (c = in.charAt(inIx)) < 0x80; ++inIx) {
+ out.put(outIx + inIx, (byte) c);
}
- throw new ArrayIndexOutOfBoundsException("Failed writing " + c + " at index " + j);
+ if (inIx == inLength) {
+ // Successfully encoded the entire string.
+ out.position(outIx + inIx);
+ return;
+ }
+
+ outIx += inIx;
+ for (char c; inIx < inLength; ++inIx, ++outIx) {
+ c = in.charAt(inIx);
+ if (c < 0x80) {
+ // One byte (0xxx xxxx)
+ out.put(outIx, (byte) c);
+ } else if (c < 0x800) {
+ // Two bytes (110x xxxx 10xx xxxx)
+
+ // Benchmarks show put performs better than putShort here (for HotSpot).
+ out.put(outIx++, (byte) (0xC0 | (c >>> 6)));
+ out.put(outIx, (byte) (0x80 | (0x3F & c)));
+ } else if (c < MIN_SURROGATE || MAX_SURROGATE < c) {
+ // Three bytes (1110 xxxx 10xx xxxx 10xx xxxx)
+ // Maximum single-char code point is 0xFFFF, 16 bits.
+
+ // Benchmarks show put performs better than putShort here (for HotSpot).
+ out.put(outIx++, (byte) (0xE0 | (c >>> 12)));
+ out.put(outIx++, (byte) (0x80 | (0x3F & (c >>> 6))));
+ out.put(outIx, (byte) (0x80 | (0x3F & c)));
+ } else {
+ // Four bytes (1111 xxxx 10xx xxxx 10xx xxxx 10xx xxxx)
+
+ // Minimum code point represented by a surrogate pair is 0x10000, 17 bits, four UTF-8
+ // bytes
+ final char low;
+ if (inIx + 1 == inLength || !isSurrogatePair(c, (low = in.charAt(++inIx)))) {
+ throw new UnpairedSurrogateException(inIx, inLength);
+ }
+ // TODO(nathanmittler): Consider using putInt() to improve performance.
+ int codePoint = toCodePoint(c, low);
+ out.put(outIx++, (byte) ((0xF << 4) | (codePoint >>> 18)));
+ out.put(outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 12))));
+ out.put(outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 6))));
+ out.put(outIx, (byte) (0x80 | (0x3F & codePoint)));
+ }
+ }
+
+ // Successfully encoded the entire string.
+ out.position(outIx);
+ } catch (IndexOutOfBoundsException e) {
+ // TODO(nathanmittler): Consider making the API throw IndexOutOfBoundsException instead.
+
+ // If we failed in the outer ASCII loop, outIx will not have been updated. In this case,
+ // use inIx to determine the bad write index.
+ int badWriteIndex = out.position() + Math.max(inIx, outIx - out.position() + 1);
+ throw new ArrayIndexOutOfBoundsException(
+ "Failed writing " + in.charAt(inIx) + " at index " + badWriteIndex);
}
}
- return j;
}
- // End Guava UTF-8 methods.
+
+ /**
+ * {@link Processor} implementation that does not use any {@code sun.misc.Unsafe} methods.
+ */
+ static final class SafeProcessor extends Processor {
+ @Override
+ int partialIsValidUtf8(int state, byte[] bytes, int index, int limit) {
+ if (state != COMPLETE) {
+ // The previous decoding operation was incomplete (or malformed).
+ // We look for a well-formed sequence consisting of bytes from
+ // the previous decoding operation (stored in state) together
+ // with bytes from the array slice.
+ //
+ // We expect such "straddler characters" to be rare.
+
+ if (index >= limit) { // No bytes? No progress.
+ return state;
+ }
+ int byte1 = (byte) state;
+ // byte1 is never ASCII.
+ if (byte1 < (byte) 0xE0) {
+ // two-byte form
+
+ // Simultaneously checks for illegal trailing-byte in
+ // leading position and overlong 2-byte form.
+ if (byte1 < (byte) 0xC2
+ // byte2 trailing-byte test
+ || bytes[index++] > (byte) 0xBF) {
+ return MALFORMED;
+ }
+ } else if (byte1 < (byte) 0xF0) {
+ // three-byte form
+
+ // Get byte2 from saved state or array
+ int byte2 = (byte) ~(state >> 8);
+ if (byte2 == 0) {
+ byte2 = bytes[index++];
+ if (index >= limit) {
+ return incompleteStateFor(byte1, byte2);
+ }
+ }
+ if (byte2 > (byte) 0xBF
+ // overlong? 5 most significant bits must not all be zero
+ || (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0)
+ // illegal surrogate codepoint?
+ || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0)
+ // byte3 trailing-byte test
+ || bytes[index++] > (byte) 0xBF) {
+ return MALFORMED;
+ }
+ } else {
+ // four-byte form
+
+ // Get byte2 and byte3 from saved state or array
+ int byte2 = (byte) ~(state >> 8);
+ int byte3 = 0;
+ if (byte2 == 0) {
+ byte2 = bytes[index++];
+ if (index >= limit) {
+ return incompleteStateFor(byte1, byte2);
+ }
+ } else {
+ byte3 = (byte) (state >> 16);
+ }
+ if (byte3 == 0) {
+ byte3 = bytes[index++];
+ if (index >= limit) {
+ return incompleteStateFor(byte1, byte2, byte3);
+ }
+ }
+
+ // If we were called with state == MALFORMED, then byte1 is 0xFF,
+ // which never occurs in well-formed UTF-8, and so we will return
+ // MALFORMED again below.
+
+ if (byte2 > (byte) 0xBF
+ // Check that 1 <= plane <= 16. Tricky optimized form of:
+ // if (byte1 > (byte) 0xF4 ||
+ // byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
+ // byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
+ || (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0
+ // byte3 trailing-byte test
+ || byte3 > (byte) 0xBF
+ // byte4 trailing-byte test
+ || bytes[index++] > (byte) 0xBF) {
+ return MALFORMED;
+ }
+ }
+ }
+
+ return partialIsValidUtf8(bytes, index, limit);
+ }
+
+ @Override
+ int partialIsValidUtf8Direct(int state, ByteBuffer buffer, int index, int limit) {
+ // For safe processing, we have to use the ByteBuffer API.
+ return partialIsValidUtf8Default(state, buffer, index, limit);
+ }
+
+ @Override
+ int encodeUtf8(CharSequence in, byte[] out, int offset, int length) {
+ int utf16Length = in.length();
+ int j = offset;
+ int i = 0;
+ int limit = offset + length;
+ // Designed to take advantage of
+ // https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination
+ for (char c; i < utf16Length && i + j < limit && (c = in.charAt(i)) < 0x80; i++) {
+ out[j + i] = (byte) c;
+ }
+ if (i == utf16Length) {
+ return j + utf16Length;
+ }
+ j += i;
+ for (char c; i < utf16Length; i++) {
+ c = in.charAt(i);
+ if (c < 0x80 && j < limit) {
+ out[j++] = (byte) c;
+ } else if (c < 0x800 && j <= limit - 2) { // 11 bits, two UTF-8 bytes
+ out[j++] = (byte) ((0xF << 6) | (c >>> 6));
+ out[j++] = (byte) (0x80 | (0x3F & c));
+ } else if ((c < Character.MIN_SURROGATE || Character.MAX_SURROGATE < c) && j <= limit - 3) {
+ // Maximum single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes
+ out[j++] = (byte) ((0xF << 5) | (c >>> 12));
+ out[j++] = (byte) (0x80 | (0x3F & (c >>> 6)));
+ out[j++] = (byte) (0x80 | (0x3F & c));
+ } else if (j <= limit - 4) {
+ // Minimum code point represented by a surrogate pair is 0x10000, 17 bits,
+ // four UTF-8 bytes
+ final char low;
+ if (i + 1 == in.length()
+ || !Character.isSurrogatePair(c, (low = in.charAt(++i)))) {
+ throw new UnpairedSurrogateException((i - 1), utf16Length);
+ }
+ int codePoint = Character.toCodePoint(c, low);
+ out[j++] = (byte) ((0xF << 4) | (codePoint >>> 18));
+ out[j++] = (byte) (0x80 | (0x3F & (codePoint >>> 12)));
+ out[j++] = (byte) (0x80 | (0x3F & (codePoint >>> 6)));
+ out[j++] = (byte) (0x80 | (0x3F & codePoint));
+ } else {
+ // If we are surrogates and we're not a surrogate pair, always throw an
+ // UnpairedSurrogateException instead of an ArrayOutOfBoundsException.
+ if ((Character.MIN_SURROGATE <= c && c <= Character.MAX_SURROGATE)
+ && (i + 1 == in.length()
+ || !Character.isSurrogatePair(c, in.charAt(i + 1)))) {
+ throw new UnpairedSurrogateException(i, utf16Length);
+ }
+ throw new ArrayIndexOutOfBoundsException("Failed writing " + c + " at index " + j);
+ }
+ }
+ return j;
+ }
+
+ @Override
+ void encodeUtf8Direct(CharSequence in, ByteBuffer out) {
+ // For safe processing, we have to use the ByteBuffer API.
+ encodeUtf8Default(in, out);
+ }
+
+ private static int partialIsValidUtf8(byte[] bytes, int index, int limit) {
+ // Optimize for 100% ASCII (Hotspot loves small simple top-level loops like this).
+ // This simple loop stops when we encounter a byte >= 0x80 (i.e. non-ASCII).
+ while (index < limit && bytes[index] >= 0) {
+ index++;
+ }
+
+ return (index >= limit) ? COMPLETE : partialIsValidUtf8NonAscii(bytes, index, limit);
+ }
+
+ private static int partialIsValidUtf8NonAscii(byte[] bytes, int index, int limit) {
+ for (;;) {
+ int byte1, byte2;
+
+ // Optimize for interior runs of ASCII bytes.
+ do {
+ if (index >= limit) {
+ return COMPLETE;
+ }
+ } while ((byte1 = bytes[index++]) >= 0);
+
+ if (byte1 < (byte) 0xE0) {
+ // two-byte form
+
+ if (index >= limit) {
+ // Incomplete sequence
+ return byte1;
+ }
+
+ // Simultaneously checks for illegal trailing-byte in
+ // leading position and overlong 2-byte form.
+ if (byte1 < (byte) 0xC2
+ || bytes[index++] > (byte) 0xBF) {
+ return MALFORMED;
+ }
+ } else if (byte1 < (byte) 0xF0) {
+ // three-byte form
+
+ if (index >= limit - 1) { // incomplete sequence
+ return incompleteStateFor(bytes, index, limit);
+ }
+ if ((byte2 = bytes[index++]) > (byte) 0xBF
+ // overlong? 5 most significant bits must not all be zero
+ || (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0)
+ // check for illegal surrogate codepoints
+ || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0)
+ // byte3 trailing-byte test
+ || bytes[index++] > (byte) 0xBF) {
+ return MALFORMED;
+ }
+ } else {
+ // four-byte form
+
+ if (index >= limit - 2) { // incomplete sequence
+ return incompleteStateFor(bytes, index, limit);
+ }
+ if ((byte2 = bytes[index++]) > (byte) 0xBF
+ // Check that 1 <= plane <= 16. Tricky optimized form of:
+ // if (byte1 > (byte) 0xF4 ||
+ // byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
+ // byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
+ || (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0
+ // byte3 trailing-byte test
+ || bytes[index++] > (byte) 0xBF
+ // byte4 trailing-byte test
+ || bytes[index++] > (byte) 0xBF) {
+ return MALFORMED;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * {@link Processor} that uses {@code sun.misc.Unsafe} where possible to improve performance.
+ */
+ static final class UnsafeProcessor extends Processor {
+ private static final sun.misc.Unsafe UNSAFE = getUnsafe();
+ private static final long BUFFER_ADDRESS_OFFSET =
+ fieldOffset(field(Buffer.class, "address"));
+ private static final int ARRAY_BASE_OFFSET = byteArrayBaseOffset();
+
+ /**
+ * We only use Unsafe operations if we have access to direct {@link ByteBuffer}'s address
+ * and the array base offset is a multiple of 8 (needed by Unsafe.getLong()).
+ */
+ private static final boolean AVAILABLE =
+ BUFFER_ADDRESS_OFFSET != -1 && ARRAY_BASE_OFFSET % 8 == 0;
+
+ /**
+ * Indicates whether or not all required unsafe operations are supported on this platform.
+ */
+ static boolean isAvailable() {
+ return AVAILABLE;
+ }
+
+ @Override
+ int partialIsValidUtf8(int state, byte[] bytes, final int index, final int limit) {
+ if ((index | limit | bytes.length - limit) < 0) {
+ throw new ArrayIndexOutOfBoundsException(
+ String.format("Array length=%d, index=%d, limit=%d", bytes.length, index, limit));
+ }
+ long offset = ARRAY_BASE_OFFSET + index;
+ final long offsetLimit = ARRAY_BASE_OFFSET + limit;
+ if (state != COMPLETE) {
+ // The previous decoding operation was incomplete (or malformed).
+ // We look for a well-formed sequence consisting of bytes from
+ // the previous decoding operation (stored in state) together
+ // with bytes from the array slice.
+ //
+ // We expect such "straddler characters" to be rare.
+
+ if (offset >= offsetLimit) { // No bytes? No progress.
+ return state;
+ }
+ int byte1 = (byte) state;
+ // byte1 is never ASCII.
+ if (byte1 < (byte) 0xE0) {
+ // two-byte form
+
+ // Simultaneously checks for illegal trailing-byte in
+ // leading position and overlong 2-byte form.
+ if (byte1 < (byte) 0xC2
+ // byte2 trailing-byte test
+ || UNSAFE.getByte(bytes, offset++) > (byte) 0xBF) {
+ return MALFORMED;
+ }
+ } else if (byte1 < (byte) 0xF0) {
+ // three-byte form
+
+ // Get byte2 from saved state or array
+ int byte2 = (byte) ~(state >> 8);
+ if (byte2 == 0) {
+ byte2 = UNSAFE.getByte(bytes, offset++);
+ if (offset >= offsetLimit) {
+ return incompleteStateFor(byte1, byte2);
+ }
+ }
+ if (byte2 > (byte) 0xBF
+ // overlong? 5 most significant bits must not all be zero
+ || (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0)
+ // illegal surrogate codepoint?
+ || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0)
+ // byte3 trailing-byte test
+ || UNSAFE.getByte(bytes, offset++) > (byte) 0xBF) {
+ return MALFORMED;
+ }
+ } else {
+ // four-byte form
+
+ // Get byte2 and byte3 from saved state or array
+ int byte2 = (byte) ~(state >> 8);
+ int byte3 = 0;
+ if (byte2 == 0) {
+ byte2 = UNSAFE.getByte(bytes, offset++);
+ if (offset >= offsetLimit) {
+ return incompleteStateFor(byte1, byte2);
+ }
+ } else {
+ byte3 = (byte) (state >> 16);
+ }
+ if (byte3 == 0) {
+ byte3 = UNSAFE.getByte(bytes, offset++);
+ if (offset >= offsetLimit) {
+ return incompleteStateFor(byte1, byte2, byte3);
+ }
+ }
+
+ // If we were called with state == MALFORMED, then byte1 is 0xFF,
+ // which never occurs in well-formed UTF-8, and so we will return
+ // MALFORMED again below.
+
+ if (byte2 > (byte) 0xBF
+ // Check that 1 <= plane <= 16. Tricky optimized form of:
+ // if (byte1 > (byte) 0xF4 ||
+ // byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
+ // byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
+ || (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0
+ // byte3 trailing-byte test
+ || byte3 > (byte) 0xBF
+ // byte4 trailing-byte test
+ || UNSAFE.getByte(bytes, offset++) > (byte) 0xBF) {
+ return MALFORMED;
+ }
+ }
+ }
+
+ return partialIsValidUtf8(bytes, offset, (int) (offsetLimit - offset));
+ }
+
+ @Override
+ int partialIsValidUtf8Direct(
+ final int state, ByteBuffer buffer, final int index, final int limit) {
+ if ((index | limit | buffer.limit() - limit) < 0) {
+ throw new ArrayIndexOutOfBoundsException(
+ String.format("buffer limit=%d, index=%d, limit=%d", buffer.limit(), index, limit));
+ }
+ long address = addressOffset(buffer) + index;
+ final long addressLimit = address + (limit - index);
+ if (state != COMPLETE) {
+ // The previous decoding operation was incomplete (or malformed).
+ // We look for a well-formed sequence consisting of bytes from
+ // the previous decoding operation (stored in state) together
+ // with bytes from the array slice.
+ //
+ // We expect such "straddler characters" to be rare.
+
+ if (address >= addressLimit) { // No bytes? No progress.
+ return state;
+ }
+
+ final int byte1 = (byte) state;
+ // byte1 is never ASCII.
+ if (byte1 < (byte) 0xE0) {
+ // two-byte form
+
+ // Simultaneously checks for illegal trailing-byte in
+ // leading position and overlong 2-byte form.
+ if (byte1 < (byte) 0xC2
+ // byte2 trailing-byte test
+ || UNSAFE.getByte(address++) > (byte) 0xBF) {
+ return MALFORMED;
+ }
+ } else if (byte1 < (byte) 0xF0) {
+ // three-byte form
+
+ // Get byte2 from saved state or array
+ int byte2 = (byte) ~(state >> 8);
+ if (byte2 == 0) {
+ byte2 = UNSAFE.getByte(address++);
+ if (address >= addressLimit) {
+ return incompleteStateFor(byte1, byte2);
+ }
+ }
+ if (byte2 > (byte) 0xBF
+ // overlong? 5 most significant bits must not all be zero
+ || (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0)
+ // illegal surrogate codepoint?
+ || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0)
+ // byte3 trailing-byte test
+ || UNSAFE.getByte(address++) > (byte) 0xBF) {
+ return MALFORMED;
+ }
+ } else {
+ // four-byte form
+
+ // Get byte2 and byte3 from saved state or array
+ int byte2 = (byte) ~(state >> 8);
+ int byte3 = 0;
+ if (byte2 == 0) {
+ byte2 = UNSAFE.getByte(address++);
+ if (address >= addressLimit) {
+ return incompleteStateFor(byte1, byte2);
+ }
+ } else {
+ byte3 = (byte) (state >> 16);
+ }
+ if (byte3 == 0) {
+ byte3 = UNSAFE.getByte(address++);
+ if (address >= addressLimit) {
+ return incompleteStateFor(byte1, byte2, byte3);
+ }
+ }
+
+ // If we were called with state == MALFORMED, then byte1 is 0xFF,
+ // which never occurs in well-formed UTF-8, and so we will return
+ // MALFORMED again below.
+
+ if (byte2 > (byte) 0xBF
+ // Check that 1 <= plane <= 16. Tricky optimized form of:
+ // if (byte1 > (byte) 0xF4 ||
+ // byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
+ // byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
+ || (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0
+ // byte3 trailing-byte test
+ || byte3 > (byte) 0xBF
+ // byte4 trailing-byte test
+ || UNSAFE.getByte(address++) > (byte) 0xBF) {
+ return MALFORMED;
+ }
+ }
+ }
+
+ return partialIsValidUtf8(address, (int) (addressLimit - address));
+ }
+
+ @Override
+ int encodeUtf8(final CharSequence in, final byte[] out, final int offset, final int length) {
+ long outIx = ARRAY_BASE_OFFSET + offset;
+ final long outLimit = outIx + length;
+ final int inLimit = in.length();
+ if (inLimit > length || out.length - length < offset) {
+ // Not even enough room for an ASCII-encoded string.
+ throw new ArrayIndexOutOfBoundsException(
+ "Failed writing " + in.charAt(inLimit - 1) + " at index " + (offset + length));
+ }
+
+ // Designed to take advantage of
+ // https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination
+ int inIx = 0;
+ for (char c; inIx < inLimit && (c = in.charAt(inIx)) < 0x80; ++inIx) {
+ UNSAFE.putByte(out, outIx++, (byte) c);
+ }
+ if (inIx == inLimit) {
+ // We're done, it was ASCII encoded.
+ return (int) (outIx - ARRAY_BASE_OFFSET);
+ }
+
+ for (char c; inIx < inLimit; ++inIx) {
+ c = in.charAt(inIx);
+ if (c < 0x80 && outIx < outLimit) {
+ UNSAFE.putByte(out, outIx++, (byte) c);
+ } else if (c < 0x800 && outIx <= outLimit - 2L) { // 11 bits, two UTF-8 bytes
+ UNSAFE.putByte(out, outIx++, (byte) ((0xF << 6) | (c >>> 6)));
+ UNSAFE.putByte(out, outIx++, (byte) (0x80 | (0x3F & c)));
+ } else if ((c < MIN_SURROGATE || MAX_SURROGATE < c) && outIx <= outLimit - 3L) {
+ // Maximum single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes
+ UNSAFE.putByte(out, outIx++, (byte) ((0xF << 5) | (c >>> 12)));
+ UNSAFE.putByte(out, outIx++, (byte) (0x80 | (0x3F & (c >>> 6))));
+ UNSAFE.putByte(out, outIx++, (byte) (0x80 | (0x3F & c)));
+ } else if (outIx <= outLimit - 4L) {
+ // Minimum code point represented by a surrogate pair is 0x10000, 17 bits, four UTF-8
+ // bytes
+ final char low;
+ if (inIx + 1 == inLimit || !isSurrogatePair(c, (low = in.charAt(++inIx)))) {
+ throw new UnpairedSurrogateException((inIx - 1), inLimit);
+ }
+ int codePoint = toCodePoint(c, low);
+ UNSAFE.putByte(out, outIx++, (byte) ((0xF << 4) | (codePoint >>> 18)));
+ UNSAFE.putByte(out, outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 12))));
+ UNSAFE.putByte(out, outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 6))));
+ UNSAFE.putByte(out, outIx++, (byte) (0x80 | (0x3F & codePoint)));
+ } else {
+ if ((MIN_SURROGATE <= c && c <= MAX_SURROGATE)
+ && (inIx + 1 == inLimit || !isSurrogatePair(c, in.charAt(inIx + 1)))) {
+ // We are surrogates and we're not a surrogate pair.
+ throw new UnpairedSurrogateException(inIx, inLimit);
+ }
+ // Not enough space in the output buffer.
+ throw new ArrayIndexOutOfBoundsException("Failed writing " + c + " at index " + outIx);
+ }
+ }
+
+ // All bytes have been encoded.
+ return (int) (outIx - ARRAY_BASE_OFFSET);
+ }
+
+ @Override
+ void encodeUtf8Direct(CharSequence in, ByteBuffer out) {
+ final long address = addressOffset(out);
+ long outIx = address + out.position();
+ final long outLimit = address + out.limit();
+ final int inLimit = in.length();
+ if (inLimit > outLimit - outIx) {
+ // Not even enough room for an ASCII-encoded string.
+ throw new ArrayIndexOutOfBoundsException(
+ "Failed writing " + in.charAt(inLimit - 1) + " at index " + out.limit());
+ }
+
+ // Designed to take advantage of
+ // https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination
+ int inIx = 0;
+ for (char c; inIx < inLimit && (c = in.charAt(inIx)) < 0x80; ++inIx) {
+ UNSAFE.putByte(outIx++, (byte) c);
+ }
+ if (inIx == inLimit) {
+ // We're done, it was ASCII encoded.
+ out.position((int) (outIx - address));
+ return;
+ }
+
+ for (char c; inIx < inLimit; ++inIx) {
+ c = in.charAt(inIx);
+ if (c < 0x80 && outIx < outLimit) {
+ UNSAFE.putByte(outIx++, (byte) c);
+ } else if (c < 0x800 && outIx <= outLimit - 2L) { // 11 bits, two UTF-8 bytes
+ UNSAFE.putByte(outIx++, (byte) ((0xF << 6) | (c >>> 6)));
+ UNSAFE.putByte(outIx++, (byte) (0x80 | (0x3F & c)));
+ } else if ((c < MIN_SURROGATE || MAX_SURROGATE < c) && outIx <= outLimit - 3L) {
+ // Maximum single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes
+ UNSAFE.putByte(outIx++, (byte) ((0xF << 5) | (c >>> 12)));
+ UNSAFE.putByte(outIx++, (byte) (0x80 | (0x3F & (c >>> 6))));
+ UNSAFE.putByte(outIx++, (byte) (0x80 | (0x3F & c)));
+ } else if (outIx <= outLimit - 4L) {
+ // Minimum code point represented by a surrogate pair is 0x10000, 17 bits, four UTF-8
+ // bytes
+ final char low;
+ if (inIx + 1 == inLimit || !isSurrogatePair(c, (low = in.charAt(++inIx)))) {
+ throw new UnpairedSurrogateException((inIx - 1), inLimit);
+ }
+ int codePoint = toCodePoint(c, low);
+ UNSAFE.putByte(outIx++, (byte) ((0xF << 4) | (codePoint >>> 18)));
+ UNSAFE.putByte(outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 12))));
+ UNSAFE.putByte(outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 6))));
+ UNSAFE.putByte(outIx++, (byte) (0x80 | (0x3F & codePoint)));
+ } else {
+ if ((MIN_SURROGATE <= c && c <= MAX_SURROGATE)
+ && (inIx + 1 == inLimit || !isSurrogatePair(c, in.charAt(inIx + 1)))) {
+ // We are surrogates and we're not a surrogate pair.
+ throw new UnpairedSurrogateException(inIx, inLimit);
+ }
+ // Not enough space in the output buffer.
+ throw new ArrayIndexOutOfBoundsException("Failed writing " + c + " at index " + outIx);
+ }
+ }
+
+ // All bytes have been encoded.
+ out.position((int) (outIx - address));
+ }
+
+ /**
+ * Counts (approximately) the number of consecutive ASCII characters starting from the given
+ * position, using the most efficient method available to the platform.
+ *
+ * @param bytes the array containing the character sequence
+ * @param offset the offset position of the index (same as index + arrayBaseOffset)
+ * @param maxChars the maximum number of characters to count
+ * @return the number of ASCII characters found. The stopping position will be at or
+ * before the first non-ASCII byte.
+ */
+ private static int unsafeEstimateConsecutiveAscii(
+ byte[] bytes, long offset, final int maxChars) {
+ int remaining = maxChars;
+ if (remaining < UNSAFE_COUNT_ASCII_THRESHOLD) {
+ // Don't bother with small strings.
+ return 0;
+ }
+
+ // Read bytes until 8-byte aligned so that we can read longs in the loop below.
+ // Byte arrays are already either 8 or 16-byte aligned, so we just need to make sure that
+ // the index (relative to the start of the array) is also 8-byte aligned. We do this by
+ // ANDing the index with 7 to determine the number of bytes that need to be read before
+ // we're 8-byte aligned.
+ final int unaligned = (int) offset & 7;
+ for (int j = unaligned; j > 0; j--) {
+ if (UNSAFE.getByte(bytes, offset++) < 0) {
+ return unaligned - j;
+ }
+ }
+
+ // This simple loop stops when we encounter a byte >= 0x80 (i.e. non-ASCII).
+ // To speed things up further, we're reading longs instead of bytes so we use a mask to
+ // determine if any byte in the current long is non-ASCII.
+ remaining -= unaligned;
+ for (; remaining >= 8 && (UNSAFE.getLong(bytes, offset) & ASCII_MASK_LONG) == 0;
+ offset += 8, remaining -= 8) {}
+ return maxChars - remaining;
+ }
+
+ /**
+ * Same as {@link Utf8#estimateConsecutiveAscii(ByteBuffer, int, int)} except that it uses the
+ * most efficient method available to the platform.
+ */
+ private static int unsafeEstimateConsecutiveAscii(long address, final int maxChars) {
+ int remaining = maxChars;
+ if (remaining < UNSAFE_COUNT_ASCII_THRESHOLD) {
+ // Don't bother with small strings.
+ return 0;
+ }
+
+ // Read bytes until 8-byte aligned so that we can read longs in the loop below.
+ // We do this by ANDing the address with 7 to determine the number of bytes that need to
+ // be read before we're 8-byte aligned.
+ final int unaligned = (int) address & 7;
+ for (int j = unaligned; j > 0; j--) {
+ if (UNSAFE.getByte(address++) < 0) {
+ return unaligned - j;
+ }
+ }
+
+ // This simple loop stops when we encounter a byte >= 0x80 (i.e. non-ASCII).
+ // To speed things up further, we're reading longs instead of bytes so we use a mask to
+ // determine if any byte in the current long is non-ASCII.
+ remaining -= unaligned;
+ for (; remaining >= 8 && (UNSAFE.getLong(address) & ASCII_MASK_LONG) == 0;
+ address += 8, remaining -= 8) {}
+ return maxChars - remaining;
+ }
+
+ private static int partialIsValidUtf8(final byte[] bytes, long offset, int remaining) {
+ // Skip past ASCII characters as quickly as possible.
+ final int skipped = unsafeEstimateConsecutiveAscii(bytes, offset, remaining);
+ remaining -= skipped;
+ offset += skipped;
+
+ for (;;) {
+ // Optimize for interior runs of ASCII bytes.
+ // TODO(nathanmittler): Consider checking 8 bytes at a time after some threshold?
+ // Maybe after seeing a few in a row that are ASCII, go back to fast mode?
+ int byte1 = 0;
+ for (; remaining > 0 && (byte1 = UNSAFE.getByte(bytes, offset++)) >= 0; --remaining) {
+ }
+ if (remaining == 0) {
+ return COMPLETE;
+ }
+ remaining--;
+
+ // If we're here byte1 is not ASCII. Only need to handle 2-4 byte forms.
+ if (byte1 < (byte) 0xE0) {
+ // Two-byte form (110xxxxx 10xxxxxx)
+ if (remaining == 0) {
+ // Incomplete sequence
+ return byte1;
+ }
+ remaining--;
+
+ // Simultaneously checks for illegal trailing-byte in
+ // leading position and overlong 2-byte form.
+ if (byte1 < (byte) 0xC2
+ || UNSAFE.getByte(bytes, offset++) > (byte) 0xBF) {
+ return MALFORMED;
+ }
+ } else if (byte1 < (byte) 0xF0) {
+ // Three-byte form (1110xxxx 10xxxxxx 10xxxxxx)
+ if (remaining < 2) {
+ // Incomplete sequence
+ return unsafeIncompleteStateFor(bytes, byte1, offset, remaining);
+ }
+ remaining -= 2;
+
+ final int byte2;
+ if ((byte2 = UNSAFE.getByte(bytes, offset++)) > (byte) 0xBF
+ // overlong? 5 most significant bits must not all be zero
+ || (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0)
+ // check for illegal surrogate codepoints
+ || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0)
+ // byte3 trailing-byte test
+ || UNSAFE.getByte(bytes, offset++) > (byte) 0xBF) {
+ return MALFORMED;
+ }
+ } else {
+ // Four-byte form (1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx)
+ if (remaining < 3) {
+ // Incomplete sequence
+ return unsafeIncompleteStateFor(bytes, byte1, offset, remaining);
+ }
+ remaining -= 3;
+
+ final int byte2;
+ if ((byte2 = UNSAFE.getByte(bytes, offset++)) > (byte) 0xBF
+ // Check that 1 <= plane <= 16. Tricky optimized form of:
+ // if (byte1 > (byte) 0xF4 ||
+ // byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
+ // byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
+ || (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0
+ // byte3 trailing-byte test
+ || UNSAFE.getByte(bytes, offset++) > (byte) 0xBF
+ // byte4 trailing-byte test
+ || UNSAFE.getByte(bytes, offset++) > (byte) 0xBF) {
+ return MALFORMED;
+ }
+ }
+ }
+ }
+
+ private static int partialIsValidUtf8(long address, int remaining) {
+ // Skip past ASCII characters as quickly as possible.
+ final int skipped = unsafeEstimateConsecutiveAscii(address, remaining);
+ address += skipped;
+ remaining -= skipped;
+
+ for (;;) {
+ // Optimize for interior runs of ASCII bytes.
+ // TODO(nathanmittler): Consider checking 8 bytes at a time after some threshold?
+ // Maybe after seeing a few in a row that are ASCII, go back to fast mode?
+ int byte1 = 0;
+ for (; remaining > 0 && (byte1 = UNSAFE.getByte(address++)) >= 0; --remaining) {
+ }
+ if (remaining == 0) {
+ return COMPLETE;
+ }
+ remaining--;
+
+ if (byte1 < (byte) 0xE0) {
+ // Two-byte form
+
+ if (remaining == 0) {
+ // Incomplete sequence
+ return byte1;
+ }
+ remaining--;
+
+ // Simultaneously checks for illegal trailing-byte in
+ // leading position and overlong 2-byte form.
+ if (byte1 < (byte) 0xC2 || UNSAFE.getByte(address++) > (byte) 0xBF) {
+ return MALFORMED;
+ }
+ } else if (byte1 < (byte) 0xF0) {
+ // Three-byte form
+
+ if (remaining < 2) {
+ // Incomplete sequence
+ return unsafeIncompleteStateFor(address, byte1, remaining);
+ }
+ remaining -= 2;
+
+ final byte byte2 = UNSAFE.getByte(address++);
+ if (byte2 > (byte) 0xBF
+ // overlong? 5 most significant bits must not all be zero
+ || (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0)
+ // check for illegal surrogate codepoints
+ || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0)
+ // byte3 trailing-byte test
+ || UNSAFE.getByte(address++) > (byte) 0xBF) {
+ return MALFORMED;
+ }
+ } else {
+ // Four-byte form
+
+ if (remaining < 3) {
+ // Incomplete sequence
+ return unsafeIncompleteStateFor(address, byte1, remaining);
+ }
+ remaining -= 3;
+
+ final byte byte2 = UNSAFE.getByte(address++);
+ if (byte2 > (byte) 0xBF
+ // Check that 1 <= plane <= 16. Tricky optimized form of:
+ // if (byte1 > (byte) 0xF4 ||
+ // byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
+ // byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
+ || (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0
+ // byte3 trailing-byte test
+ || UNSAFE.getByte(address++) > (byte) 0xBF
+ // byte4 trailing-byte test
+ || UNSAFE.getByte(address++) > (byte) 0xBF) {
+ return MALFORMED;
+ }
+ }
+ }
+ }
+
+ private static int unsafeIncompleteStateFor(byte[] bytes, int byte1, long offset,
+ int remaining) {
+ switch (remaining) {
+ case 0: {
+ return incompleteStateFor(byte1);
+ }
+ case 1: {
+ return incompleteStateFor(byte1, UNSAFE.getByte(bytes, offset));
+ }
+ case 2: {
+ return incompleteStateFor(byte1, UNSAFE.getByte(bytes, offset),
+ UNSAFE.getByte(bytes, offset + 1));
+ }
+ default: {
+ throw new AssertionError();
+ }
+ }
+ }
+
+ private static int unsafeIncompleteStateFor(long address, final int byte1, int remaining) {
+ switch (remaining) {
+ case 0: {
+ return incompleteStateFor(byte1);
+ }
+ case 1: {
+ return incompleteStateFor(byte1, UNSAFE.getByte(address));
+ }
+ case 2: {
+ return incompleteStateFor(byte1, UNSAFE.getByte(address), UNSAFE.getByte(address + 1));
+ }
+ default: {
+ throw new AssertionError();
+ }
+ }
+ }
+
+ /**
+ * Gets the field with the given name within the class, or {@code null} if not found. If
+ * found, the field is made accessible.
+ */
+ private static Field field(Class<?> clazz, String fieldName) {
+ Field field;
+ try {
+ field = clazz.getDeclaredField(fieldName);
+ field.setAccessible(true);
+ } catch (Throwable t) {
+ // Failed to access the fields.
+ field = null;
+ }
+ logger.log(Level.FINEST, "{0}.{1}: {2}",
+ new Object[] {clazz.getName(), fieldName, (field != null ? "available" : "unavailable")});
+ return field;
+ }
+
+ /**
+ * Returns the offset of the provided field, or {@code -1} if {@code sun.misc.Unsafe} is not
+ * available.
+ */
+ private static long fieldOffset(Field field) {
+ return field == null || UNSAFE == null ? -1 : UNSAFE.objectFieldOffset(field);
+ }
+
+ /**
+ * Get the base offset for byte arrays, or {@code -1} if {@code sun.misc.Unsafe} is not
+ * available.
+ */
+ private static <T> int byteArrayBaseOffset() {
+ return UNSAFE == null ? -1 : UNSAFE.arrayBaseOffset(byte[].class);
+ }
+
+ /**
+ * Gets the offset of the {@code address} field of the given direct {@link ByteBuffer}.
+ */
+ private static long addressOffset(ByteBuffer buffer) {
+ return UNSAFE.getLong(buffer, BUFFER_ADDRESS_OFFSET);
+ }
+
+ /**
+ * Gets the {@code sun.misc.Unsafe} instance, or {@code null} if not available on this
+ * platform.
+ */
+ private static sun.misc.Unsafe getUnsafe() {
+ sun.misc.Unsafe unsafe = null;
+ try {
+ unsafe = AccessController.doPrivileged(new PrivilegedExceptionAction<sun.misc.Unsafe>() {
+ @Override
+ public sun.misc.Unsafe run() throws Exception {
+ Class<sun.misc.Unsafe> k = sun.misc.Unsafe.class;
+
+ // Check that this platform supports all of the required unsafe methods.
+ checkRequiredMethods(k);
+
+ for (Field f : k.getDeclaredFields()) {
+ f.setAccessible(true);
+ Object x = f.get(null);
+ if (k.isInstance(x)) {
+ return k.cast(x);
+ }
+ }
+ // The sun.misc.Unsafe field does not exist.
+ return null;
+ }
+ });
+ } catch (Throwable e) {
+ // Catching Throwable here due to the fact that Google AppEngine raises NoClassDefFoundError
+ // for Unsafe.
+ }
+
+ logger.log(Level.FINEST, "sun.misc.Unsafe: {}",
+ unsafe != null ? "available" : "unavailable");
+ return unsafe;
+ }
+
+ /**
+ * Verifies that all required methods of {@code sun.misc.Unsafe} are available on this platform.
+ */
+ private static void checkRequiredMethods(Class<sun.misc.Unsafe> clazz)
+ throws NoSuchMethodException, SecurityException {
+ // Needed for Unsafe byte[] access
+ clazz.getMethod("arrayBaseOffset", Class.class);
+ clazz.getMethod("getByte", Object.class, long.class);
+ clazz.getMethod("putByte", Object.class, long.class, byte.class);
+ clazz.getMethod("getLong", Object.class, long.class);
+
+ // Needed for Unsafe Direct ByteBuffer access
+ clazz.getMethod("objectFieldOffset", Field.class);
+ clazz.getMethod("getByte", long.class);
+ clazz.getMethod("getLong", Object.class, long.class);
+ clazz.getMethod("putByte", long.class, byte.class);
+ clazz.getMethod("getLong", long.class);
+ }
+ }
+
+ private Utf8() {}
}
diff --git a/java/core/src/main/java/com/google/protobuf/WireFormat.java b/java/core/src/main/java/com/google/protobuf/WireFormat.java
index 8dbe1ae3..6a58b081 100644
--- a/java/core/src/main/java/com/google/protobuf/WireFormat.java
+++ b/java/core/src/main/java/com/google/protobuf/WireFormat.java
@@ -116,16 +116,24 @@ public final class WireFormat {
FIXED32 (JavaType.INT , WIRETYPE_FIXED32 ),
BOOL (JavaType.BOOLEAN , WIRETYPE_VARINT ),
STRING (JavaType.STRING , WIRETYPE_LENGTH_DELIMITED) {
- public boolean isPackable() { return false; }
+ @Override
+ public boolean isPackable() {
+ return false; }
},
GROUP (JavaType.MESSAGE , WIRETYPE_START_GROUP ) {
- public boolean isPackable() { return false; }
+ @Override
+ public boolean isPackable() {
+ return false; }
},
MESSAGE (JavaType.MESSAGE , WIRETYPE_LENGTH_DELIMITED) {
- public boolean isPackable() { return false; }
+ @Override
+ public boolean isPackable() {
+ return false; }
},
BYTES (JavaType.BYTE_STRING, WIRETYPE_LENGTH_DELIMITED) {
- public boolean isPackable() { return false; }
+ @Override
+ public boolean isPackable() {
+ return false; }
},
UINT32 (JavaType.INT , WIRETYPE_VARINT ),
ENUM (JavaType.ENUM , WIRETYPE_VARINT ),
@@ -170,18 +178,21 @@ public final class WireFormat {
enum Utf8Validation {
/** Eagerly parses to String; silently accepts invalid UTF8 bytes. */
LOOSE {
+ @Override
Object readString(CodedInputStream input) throws IOException {
return input.readString();
}
},
/** Eagerly parses to String; throws an IOException on invalid bytes. */
STRICT {
+ @Override
Object readString(CodedInputStream input) throws IOException {
return input.readStringRequireUtf8();
}
},
/** Keep data as ByteString; validation/conversion to String is lazy. */
LAZY {
+ @Override
Object readString(CodedInputStream input) throws IOException {
return input.readBytes();
}
diff --git a/java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java b/java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java
index d964ef59..7dc9fc15 100644
--- a/java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java
+++ b/java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java
@@ -40,7 +40,6 @@ import protobuf_unittest.UnittestProto.TestPackedTypes;
import protobuf_unittest.UnittestProto.TestRequired;
import protobuf_unittest.UnittestProto.TestRequiredForeign;
import protobuf_unittest.UnittestProto.TestUnpackedTypes;
-
import junit.framework.TestCase;
import java.util.Map;
@@ -65,35 +64,44 @@ public class AbstractMessageTest extends TestCase {
this.wrappedMessage = wrappedMessage;
}
+ @Override
public Descriptors.Descriptor getDescriptorForType() {
return wrappedMessage.getDescriptorForType();
}
+ @Override
public AbstractMessageWrapper getDefaultInstanceForType() {
return new AbstractMessageWrapper(
wrappedMessage.getDefaultInstanceForType());
}
+ @Override
public Map<Descriptors.FieldDescriptor, Object> getAllFields() {
return wrappedMessage.getAllFields();
}
+ @Override
public boolean hasField(Descriptors.FieldDescriptor field) {
return wrappedMessage.hasField(field);
}
+ @Override
public Object getField(Descriptors.FieldDescriptor field) {
return wrappedMessage.getField(field);
}
+ @Override
public int getRepeatedFieldCount(Descriptors.FieldDescriptor field) {
return wrappedMessage.getRepeatedFieldCount(field);
}
- public Object getRepeatedField(
- Descriptors.FieldDescriptor field, int index) {
+ @Override
+ public Object getRepeatedField(Descriptors.FieldDescriptor field, int index) {
return wrappedMessage.getRepeatedField(field, index);
}
+ @Override
public UnknownFieldSet getUnknownFields() {
return wrappedMessage.getUnknownFields();
}
+ @Override
public Builder newBuilderForType() {
return new Builder(wrappedMessage.newBuilderForType());
}
+ @Override
public Builder toBuilder() {
return new Builder(wrappedMessage.toBuilder());
}
@@ -105,65 +113,80 @@ public class AbstractMessageTest extends TestCase {
this.wrappedBuilder = wrappedBuilder;
}
+ @Override
public AbstractMessageWrapper build() {
return new AbstractMessageWrapper(wrappedBuilder.build());
}
+ @Override
public AbstractMessageWrapper buildPartial() {
return new AbstractMessageWrapper(wrappedBuilder.buildPartial());
}
+ @Override
public Builder clone() {
return new Builder(wrappedBuilder.clone());
}
+ @Override
public boolean isInitialized() {
return clone().buildPartial().isInitialized();
}
+ @Override
public Descriptors.Descriptor getDescriptorForType() {
return wrappedBuilder.getDescriptorForType();
}
+ @Override
public AbstractMessageWrapper getDefaultInstanceForType() {
return new AbstractMessageWrapper(
wrappedBuilder.getDefaultInstanceForType());
}
+ @Override
public Map<Descriptors.FieldDescriptor, Object> getAllFields() {
return wrappedBuilder.getAllFields();
}
+ @Override
public Builder newBuilderForField(Descriptors.FieldDescriptor field) {
return new Builder(wrappedBuilder.newBuilderForField(field));
}
+ @Override
public boolean hasField(Descriptors.FieldDescriptor field) {
return wrappedBuilder.hasField(field);
}
+ @Override
public Object getField(Descriptors.FieldDescriptor field) {
return wrappedBuilder.getField(field);
}
+ @Override
public Builder setField(Descriptors.FieldDescriptor field, Object value) {
wrappedBuilder.setField(field, value);
return this;
}
+ @Override
public Builder clearField(Descriptors.FieldDescriptor field) {
wrappedBuilder.clearField(field);
return this;
}
+ @Override
public int getRepeatedFieldCount(Descriptors.FieldDescriptor field) {
return wrappedBuilder.getRepeatedFieldCount(field);
}
- public Object getRepeatedField(
- Descriptors.FieldDescriptor field, int index) {
+ @Override
+ public Object getRepeatedField(Descriptors.FieldDescriptor field, int index) {
return wrappedBuilder.getRepeatedField(field, index);
}
- public Builder setRepeatedField(Descriptors.FieldDescriptor field,
- int index, Object value) {
+ @Override
+ public Builder setRepeatedField(Descriptors.FieldDescriptor field, int index, Object value) {
wrappedBuilder.setRepeatedField(field, index, value);
return this;
}
- public Builder addRepeatedField(
- Descriptors.FieldDescriptor field, Object value) {
+ @Override
+ public Builder addRepeatedField(Descriptors.FieldDescriptor field, Object value) {
wrappedBuilder.addRepeatedField(field, value);
return this;
}
+ @Override
public UnknownFieldSet getUnknownFields() {
return wrappedBuilder.getUnknownFields();
}
+ @Override
public Builder setUnknownFields(UnknownFieldSet unknownFields) {
wrappedBuilder.setUnknownFields(unknownFields);
return this;
@@ -173,6 +196,7 @@ public class AbstractMessageTest extends TestCase {
return wrappedBuilder.getFieldBuilder(field);
}
}
+ @Override
public Parser<? extends Message> getParserForType() {
return wrappedMessage.getParserForType();
}
diff --git a/java/core/src/test/java/com/google/protobuf/AnyTest.java b/java/core/src/test/java/com/google/protobuf/AnyTest.java
index e169f69d..cf91ed91 100644
--- a/java/core/src/test/java/com/google/protobuf/AnyTest.java
+++ b/java/core/src/test/java/com/google/protobuf/AnyTest.java
@@ -75,6 +75,51 @@ public class AnyTest extends TestCase {
}
}
+ public void testCustomTypeUrls() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ TestUtil.setAllFields(builder);
+ TestAllTypes message = builder.build();
+
+ TestAny container = TestAny.newBuilder()
+ .setValue(Any.pack(message, "xxx.com")).build();
+
+ assertEquals(
+ "xxx.com/" + TestAllTypes.getDescriptor().getFullName(),
+ container.getValue().getTypeUrl());
+
+ assertTrue(container.getValue().is(TestAllTypes.class));
+ assertFalse(container.getValue().is(TestAny.class));
+
+ TestAllTypes result = container.getValue().unpack(TestAllTypes.class);
+ TestUtil.assertAllFieldsSet(result);
+
+ container = TestAny.newBuilder()
+ .setValue(Any.pack(message, "yyy.com/")).build();
+
+ assertEquals(
+ "yyy.com/" + TestAllTypes.getDescriptor().getFullName(),
+ container.getValue().getTypeUrl());
+
+ assertTrue(container.getValue().is(TestAllTypes.class));
+ assertFalse(container.getValue().is(TestAny.class));
+
+ result = container.getValue().unpack(TestAllTypes.class);
+ TestUtil.assertAllFieldsSet(result);
+
+ container = TestAny.newBuilder()
+ .setValue(Any.pack(message, "")).build();
+
+ assertEquals(
+ "/" + TestAllTypes.getDescriptor().getFullName(),
+ container.getValue().getTypeUrl());
+
+ assertTrue(container.getValue().is(TestAllTypes.class));
+ assertFalse(container.getValue().is(TestAny.class));
+
+ result = container.getValue().unpack(TestAllTypes.class);
+ TestUtil.assertAllFieldsSet(result);
+ }
+
public void testCachedUnpackResult() throws Exception {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
TestUtil.setAllFields(builder);
diff --git a/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java b/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java
index b8ad1fe4..24b96c60 100644
--- a/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java
@@ -73,20 +73,6 @@ public class BooleanArrayListTest extends TestCase {
assertImmutable(list);
}
- public void testCopyConstructor() {
- BooleanArrayList copy = new BooleanArrayList(TERTIARY_LIST);
- assertEquals(TERTIARY_LIST, copy);
-
- copy = new BooleanArrayList(BooleanArrayList.emptyList());
- assertEquals(BooleanArrayList.emptyList(), copy);
-
- copy = new BooleanArrayList(asList(false, false, true));
- assertEquals(asList(false, false, true), copy);
-
- copy = new BooleanArrayList(Collections.<Boolean>emptyList());
- assertEquals(BooleanArrayList.emptyList(), copy);
- }
-
public void testModificationWithIteration() {
list.addAll(asList(true, false, false, true));
Iterator<Boolean> iterator = list.iterator();
diff --git a/java/core/src/test/java/com/google/protobuf/BoundedByteStringTest.java b/java/core/src/test/java/com/google/protobuf/BoundedByteStringTest.java
index 7a8a0a5e..db10ee74 100644
--- a/java/core/src/test/java/com/google/protobuf/BoundedByteStringTest.java
+++ b/java/core/src/test/java/com/google/protobuf/BoundedByteStringTest.java
@@ -37,7 +37,6 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.UnsupportedEncodingException;
-
/**
* This class tests {@link BoundedByteString}, which extends {@link LiteralByteString},
* by inheriting the tests from {@link LiteralByteStringTest}. The only method which
diff --git a/java/core/src/test/java/com/google/protobuf/ByteBufferWriterTest.java b/java/core/src/test/java/com/google/protobuf/ByteBufferWriterTest.java
new file mode 100644
index 00000000..cbe742e5
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/ByteBufferWriterTest.java
@@ -0,0 +1,81 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.Random;
+
+/**
+ * Tests for {@link ByteBufferWriter}.
+ */
+public class ByteBufferWriterTest extends TestCase {
+
+ public void testHeapBuffer() throws IOException {
+ // Test a small and large buffer.
+ testWrite(ByteBuffer.allocate(100));
+ testWrite(ByteBuffer.allocate(1024 * 100));
+ }
+
+ public void testDirectBuffer() throws IOException {
+ // Test a small and large buffer.
+ testWrite(ByteBuffer.allocateDirect(100));
+ testWrite(ByteBuffer.allocateDirect(1024 * 100));
+ }
+
+ private void testWrite(ByteBuffer buffer) throws IOException {
+ fillRandom(buffer);
+ ByteArrayOutputStream os = new ByteArrayOutputStream(buffer.remaining());
+ ByteBufferWriter.write(buffer, os);
+ assertEquals(0, buffer.position());
+ assertTrue(Arrays.equals(toArray(buffer), os.toByteArray()));
+ }
+
+ private void fillRandom(ByteBuffer buf) {
+ byte[] bytes = new byte[buf.remaining()];
+ new Random().nextBytes(bytes);
+ buf.put(bytes);
+ buf.flip();
+ return;
+ }
+
+ private byte[] toArray(ByteBuffer buf) {
+ int originalPosition = buf.position();
+ byte[] bytes = new byte[buf.remaining()];
+ buf.get(bytes);
+ buf.position(originalPosition);
+ return bytes;
+ }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/ByteStringTest.java b/java/core/src/test/java/com/google/protobuf/ByteStringTest.java
index 5267c160..ad9f266e 100644
--- a/java/core/src/test/java/com/google/protobuf/ByteStringTest.java
+++ b/java/core/src/test/java/com/google/protobuf/ByteStringTest.java
@@ -39,6 +39,7 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.ArrayList;
@@ -757,4 +758,17 @@ public class ByteStringTest extends TestCase {
assertEquals((byte) 2, result[dataSize - dataSize / 2]);
assertEquals((byte) 2, result[dataSize - 1]);
}
+
+ /**
+ * Tests ByteString uses Arrays based byte copier when running under Hotstop VM.
+ */
+ public void testByteArrayCopier() throws Exception {
+ Field field = ByteString.class.getDeclaredField("byteArrayCopier");
+ field.setAccessible(true);
+ Object byteArrayCopier = field.get(null);
+ assertNotNull(byteArrayCopier);
+ assertTrue(
+ byteArrayCopier.toString(),
+ byteArrayCopier.getClass().getSimpleName().endsWith("ArraysByteArrayCopier"));
+ }
}
diff --git a/java/core/src/test/java/com/google/protobuf/CheckUtf8Test.java b/java/core/src/test/java/com/google/protobuf/CheckUtf8Test.java
index 3d6381c9..cc65d19a 100644
--- a/java/core/src/test/java/com/google/protobuf/CheckUtf8Test.java
+++ b/java/core/src/test/java/com/google/protobuf/CheckUtf8Test.java
@@ -34,6 +34,7 @@ import proto2_test_check_utf8.TestCheckUtf8.BytesWrapper;
import proto2_test_check_utf8.TestCheckUtf8.StringWrapper;
import proto2_test_check_utf8_size.TestCheckUtf8Size.BytesWrapperSize;
import proto2_test_check_utf8_size.TestCheckUtf8Size.StringWrapperSize;
+
import junit.framework.TestCase;
/**
diff --git a/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java b/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
index 18d8142c..ca940ced 100644
--- a/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
+++ b/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
@@ -81,10 +81,12 @@ public class CodedInputStreamTest extends TestCase {
this.blockSize = blockSize;
}
+ @Override
public int read(byte[] b) throws IOException {
return super.read(b, 0, Math.min(b.length, blockSize));
}
+ @Override
public int read(byte[] b, int off, int len) throws IOException {
return super.read(b, off, Math.min(len, blockSize));
}
@@ -547,6 +549,56 @@ public class CodedInputStreamTest extends TestCase {
}
}
+ public void testReadString() throws Exception {
+ String lorem = "Lorem ipsum dolor sit amet ";
+ StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < 4096; i += lorem.length()) {
+ builder.append(lorem);
+ }
+ lorem = builder.toString().substring(0, 4096);
+ byte[] bytes = lorem.getBytes("UTF-8");
+ ByteString.Output rawOutput = ByteString.newOutput();
+ CodedOutputStream output = CodedOutputStream.newInstance(rawOutput, bytes.length);
+
+ int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ output.writeRawVarint32(tag);
+ output.writeRawVarint32(bytes.length);
+ output.writeRawBytes(bytes);
+ output.flush();
+
+ CodedInputStream input =
+ CodedInputStream.newInstance(
+ new ByteArrayInputStream(rawOutput.toByteString().toByteArray()));
+ assertEquals(tag, input.readTag());
+ String text = input.readString();
+ assertEquals(lorem, text);
+ }
+
+ public void testReadStringRequireUtf8() throws Exception {
+ String lorem = "Lorem ipsum dolor sit amet ";
+ StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < 4096; i += lorem.length()) {
+ builder.append(lorem);
+ }
+ lorem = builder.toString().substring(0, 4096);
+ byte[] bytes = lorem.getBytes("UTF-8");
+ ByteString.Output rawOutput = ByteString.newOutput();
+ CodedOutputStream output = CodedOutputStream.newInstance(rawOutput, bytes.length);
+
+ int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ output.writeRawVarint32(tag);
+ output.writeRawVarint32(bytes.length);
+ output.writeRawBytes(bytes);
+ output.flush();
+
+ CodedInputStream input =
+ CodedInputStream.newInstance(
+ new ByteArrayInputStream(rawOutput.toByteString().toByteArray()));
+ assertEquals(tag, input.readTag());
+ String text = input.readStringRequireUtf8();
+ assertEquals(lorem, text);
+ }
+
/**
* Tests that if we readString invalid UTF-8 bytes, no exception
* is thrown. Instead, the invalid bytes are replaced with the Unicode
diff --git a/java/core/src/test/java/com/google/protobuf/CodedOutputStreamTest.java b/java/core/src/test/java/com/google/protobuf/CodedOutputStreamTest.java
index 6018ea55..33aa4357 100644
--- a/java/core/src/test/java/com/google/protobuf/CodedOutputStreamTest.java
+++ b/java/core/src/test/java/com/google/protobuf/CodedOutputStreamTest.java
@@ -30,6 +30,7 @@
package com.google.protobuf;
+import com.google.protobuf.CodedOutputStream.OutOfSpaceException;
import protobuf_unittest.UnittestProto.SparseEnumMessage;
import protobuf_unittest.UnittestProto.TestAllTypes;
import protobuf_unittest.UnittestProto.TestPackedTypes;
@@ -50,118 +51,180 @@ import java.util.List;
* @author kenton@google.com Kenton Varda
*/
public class CodedOutputStreamTest extends TestCase {
- /**
- * Helper to construct a byte array from a bunch of bytes. The inputs are
- * actually ints so that I can use hex notation and not get stupid errors
- * about precision.
- */
- private byte[] bytes(int... bytesAsInts) {
- byte[] bytes = new byte[bytesAsInts.length];
- for (int i = 0; i < bytesAsInts.length; i++) {
- bytes[i] = (byte) bytesAsInts[i];
- }
- return bytes;
+ private interface Coder {
+ CodedOutputStream stream();
+
+ byte[] toByteArray();
+
+ OutputType getOutputType();
}
- /** Arrays.asList() does not work with arrays of primitives. :( */
- private List<Byte> toList(byte[] bytes) {
- List<Byte> result = new ArrayList<Byte>();
- for (byte b : bytes) {
- result.add(b);
+ private static final class OutputStreamCoder implements Coder {
+ private final CodedOutputStream stream;
+ private final ByteArrayOutputStream output;
+
+ OutputStreamCoder(int size) {
+ output = new ByteArrayOutputStream();
+ stream = CodedOutputStream.newInstance(output, size);
+ }
+
+ @Override
+ public CodedOutputStream stream() {
+ return stream;
+ }
+
+ @Override
+ public byte[] toByteArray() {
+ return output.toByteArray();
+ }
+
+ @Override
+ public OutputType getOutputType() {
+ return OutputType.STREAM;
}
- return result;
}
- private void assertEqualBytes(byte[] a, byte[] b) {
- assertEquals(toList(a), toList(b));
+ private static final class ArrayCoder implements Coder {
+ private final CodedOutputStream stream;
+ private final byte[] bytes;
+
+ ArrayCoder(int size) {
+ bytes = new byte[size];
+ stream = CodedOutputStream.newInstance(bytes);
+ }
+
+ @Override
+ public CodedOutputStream stream() {
+ return stream;
+ }
+
+ @Override
+ public byte[] toByteArray() {
+ return Arrays.copyOf(bytes, stream.getTotalBytesWritten());
+ }
+
+ @Override
+ public OutputType getOutputType() {
+ return OutputType.ARRAY;
+ }
}
- /**
- * Writes the given value using writeRawVarint32() and writeRawVarint64() and
- * checks that the result matches the given bytes.
- */
- private void assertWriteVarint(byte[] data, long value) throws Exception {
- // Only test 32-bit write if the value fits into an int.
- if (value == (int) value) {
- ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
- CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
- output.writeRawVarint32((int) value);
- output.flush();
- assertEqualBytes(data, rawOutput.toByteArray());
+ private static final class NioHeapCoder implements Coder {
+ private final CodedOutputStream stream;
+ private final ByteBuffer buffer;
+ private final int initialPosition;
- // Also try computing size.
- assertEquals(data.length,
- CodedOutputStream.computeRawVarint32Size((int) value));
+ NioHeapCoder(int size) {
+ this(size, 0);
}
- {
- ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
- CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
- output.writeRawVarint64(value);
- output.flush();
- assertEqualBytes(data, rawOutput.toByteArray());
+ NioHeapCoder(int size, int initialPosition) {
+ this.initialPosition = initialPosition;
+ buffer = ByteBuffer.allocate(size);
+ buffer.position(initialPosition);
+ stream = CodedOutputStream.newInstance(buffer);
+ }
- // Also try computing size.
- assertEquals(data.length,
- CodedOutputStream.computeRawVarint64Size(value));
+ @Override
+ public CodedOutputStream stream() {
+ return stream;
}
- // Try different block sizes.
- for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
- // Only test 32-bit write if the value fits into an int.
- if (value == (int) value) {
- ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
- CodedOutputStream output =
- CodedOutputStream.newInstance(rawOutput, blockSize);
- output.writeRawVarint32((int) value);
- output.flush();
- assertEqualBytes(data, rawOutput.toByteArray());
- }
+ @Override
+ public byte[] toByteArray() {
+ ByteBuffer dup = buffer.duplicate();
+ dup.position(initialPosition);
+ dup.limit(buffer.position());
- {
- ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
- CodedOutputStream output =
- CodedOutputStream.newInstance(rawOutput, blockSize);
- output.writeRawVarint64(value);
- output.flush();
- assertEqualBytes(data, rawOutput.toByteArray());
- }
+ byte[] bytes = new byte[dup.remaining()];
+ dup.get(bytes);
+ return bytes;
+ }
+
+ @Override
+ public OutputType getOutputType() {
+ return OutputType.NIO_HEAP;
}
}
- private void assertVarintRoundTrip(long value) throws Exception {
- {
- ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
- CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
- output.writeRawVarint64(value);
- output.flush();
- byte[] bytes = rawOutput.toByteArray();
- assertEquals(bytes.length, CodedOutputStream.computeRawVarint64Size(value));
- CodedInputStream input = CodedInputStream.newInstance(new ByteArrayInputStream(bytes));
- assertEquals(value, input.readRawVarint64());
+ private static final class NioDirectCoder implements Coder {
+ private final int initialPosition;
+ private final CodedOutputStream stream;
+ private final ByteBuffer buffer;
+
+ NioDirectCoder(int size) {
+ this(size, 0);
}
- if (value == (int) value) {
- ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
- CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
- output.writeRawVarint32((int) value);
- output.flush();
- byte[] bytes = rawOutput.toByteArray();
- assertEquals(bytes.length, CodedOutputStream.computeRawVarint32Size((int) value));
- CodedInputStream input = CodedInputStream.newInstance(new ByteArrayInputStream(bytes));
- assertEquals(value, input.readRawVarint32());
+ NioDirectCoder(int size, int initialPosition) {
+ this.initialPosition = initialPosition;
+ buffer = ByteBuffer.allocateDirect(size);
+ buffer.position(initialPosition);
+ stream = CodedOutputStream.newInstance(buffer);
+ }
+
+ @Override
+ public CodedOutputStream stream() {
+ return stream;
+ }
+
+ @Override
+ public byte[] toByteArray() {
+ ByteBuffer dup = buffer.duplicate();
+ dup.position(initialPosition);
+ dup.limit(buffer.position());
+
+ byte[] bytes = new byte[dup.remaining()];
+ dup.get(bytes);
+ return bytes;
+ }
+
+ @Override
+ public OutputType getOutputType() {
+ return OutputType.NIO_DIRECT;
}
}
+ private enum OutputType {
+ ARRAY() {
+ @Override
+ Coder newCoder(int size) {
+ return new ArrayCoder(size);
+ }
+ },
+ NIO_HEAP() {
+ @Override
+ Coder newCoder(int size) {
+ return new NioHeapCoder(size);
+ }
+ },
+ NIO_DIRECT() {
+ @Override
+ Coder newCoder(int size) {
+ return new NioDirectCoder(size);
+ }
+ },
+ STREAM() {
+ @Override
+ Coder newCoder(int size) {
+ return new OutputStreamCoder(size);
+ }
+ };
+
+ abstract Coder newCoder(int size);
+ }
+
/** Checks that invariants are maintained for varint round trip input and output. */
public void testVarintRoundTrips() throws Exception {
- assertVarintRoundTrip(0L);
- for (int bits = 0; bits < 64; bits++) {
- long value = 1L << bits;
- assertVarintRoundTrip(value);
- assertVarintRoundTrip(value + 1);
- assertVarintRoundTrip(value - 1);
- assertVarintRoundTrip(-value);
+ for (OutputType outputType : OutputType.values()) {
+ assertVarintRoundTrip(outputType, 0L);
+ for (int bits = 0; bits < 64; bits++) {
+ long value = 1L << bits;
+ assertVarintRoundTrip(outputType, value);
+ assertVarintRoundTrip(outputType, value + 1);
+ assertVarintRoundTrip(outputType, value - 1);
+ assertVarintRoundTrip(outputType, -value);
+ }
}
}
@@ -173,70 +236,25 @@ public class CodedOutputStreamTest extends TestCase {
// 14882
assertWriteVarint(bytes(0xa2, 0x74), (0x22 << 0) | (0x74 << 7));
// 2961488830
- assertWriteVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b),
- (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
- (0x0bL << 28));
+ assertWriteVarint(
+ bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b),
+ (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | (0x0bL << 28));
// 64-bit
// 7256456126
- assertWriteVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b),
- (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
- (0x1bL << 28));
+ assertWriteVarint(
+ bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b),
+ (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | (0x1bL << 28));
// 41256202580718336
assertWriteVarint(
- bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49),
- (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) |
- (0x43L << 28) | (0x49L << 35) | (0x24L << 42) | (0x49L << 49));
+ bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49),
+ (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) | (0x43L << 28) | (0x49L << 35)
+ | (0x24L << 42) | (0x49L << 49));
// 11964378330978735131
assertWriteVarint(
- bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01),
- (0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) |
- (0x3bL << 28) | (0x56L << 35) | (0x00L << 42) |
- (0x05L << 49) | (0x26L << 56) | (0x01L << 63));
- }
-
- /**
- * Parses the given bytes using writeRawLittleEndian32() and checks
- * that the result matches the given value.
- */
- private void assertWriteLittleEndian32(byte[] data, int value)
- throws Exception {
- ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
- CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
- output.writeRawLittleEndian32(value);
- output.flush();
- assertEqualBytes(data, rawOutput.toByteArray());
-
- // Try different block sizes.
- for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
- rawOutput = new ByteArrayOutputStream();
- output = CodedOutputStream.newInstance(rawOutput, blockSize);
- output.writeRawLittleEndian32(value);
- output.flush();
- assertEqualBytes(data, rawOutput.toByteArray());
- }
- }
-
- /**
- * Parses the given bytes using writeRawLittleEndian64() and checks
- * that the result matches the given value.
- */
- private void assertWriteLittleEndian64(byte[] data, long value)
- throws Exception {
- ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
- CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
- output.writeRawLittleEndian64(value);
- output.flush();
- assertEqualBytes(data, rawOutput.toByteArray());
-
- // Try different block sizes.
- for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
- rawOutput = new ByteArrayOutputStream();
- output = CodedOutputStream.newInstance(rawOutput, blockSize);
- output.writeRawLittleEndian64(value);
- output.flush();
- assertEqualBytes(data, rawOutput.toByteArray());
- }
+ bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01),
+ (0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) | (0x3bL << 28) | (0x56L << 35)
+ | (0x00L << 42) | (0x05L << 49) | (0x26L << 56) | (0x01L << 63));
}
/** Tests writeRawLittleEndian32() and writeRawLittleEndian64(). */
@@ -245,141 +263,138 @@ public class CodedOutputStreamTest extends TestCase {
assertWriteLittleEndian32(bytes(0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef0);
assertWriteLittleEndian64(
- bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12),
- 0x123456789abcdef0L);
+ bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12), 0x123456789abcdef0L);
assertWriteLittleEndian64(
- bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a),
- 0x9abcdef012345678L);
+ bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef012345678L);
}
/** Test encodeZigZag32() and encodeZigZag64(). */
public void testEncodeZigZag() throws Exception {
- assertEquals(0, CodedOutputStream.encodeZigZag32( 0));
+ assertEquals(0, CodedOutputStream.encodeZigZag32(0));
assertEquals(1, CodedOutputStream.encodeZigZag32(-1));
- assertEquals(2, CodedOutputStream.encodeZigZag32( 1));
+ assertEquals(2, CodedOutputStream.encodeZigZag32(1));
assertEquals(3, CodedOutputStream.encodeZigZag32(-2));
assertEquals(0x7FFFFFFE, CodedOutputStream.encodeZigZag32(0x3FFFFFFF));
assertEquals(0x7FFFFFFF, CodedOutputStream.encodeZigZag32(0xC0000000));
assertEquals(0xFFFFFFFE, CodedOutputStream.encodeZigZag32(0x7FFFFFFF));
assertEquals(0xFFFFFFFF, CodedOutputStream.encodeZigZag32(0x80000000));
- assertEquals(0, CodedOutputStream.encodeZigZag64( 0));
+ assertEquals(0, CodedOutputStream.encodeZigZag64(0));
assertEquals(1, CodedOutputStream.encodeZigZag64(-1));
- assertEquals(2, CodedOutputStream.encodeZigZag64( 1));
+ assertEquals(2, CodedOutputStream.encodeZigZag64(1));
assertEquals(3, CodedOutputStream.encodeZigZag64(-2));
- assertEquals(0x000000007FFFFFFEL,
- CodedOutputStream.encodeZigZag64(0x000000003FFFFFFFL));
- assertEquals(0x000000007FFFFFFFL,
- CodedOutputStream.encodeZigZag64(0xFFFFFFFFC0000000L));
- assertEquals(0x00000000FFFFFFFEL,
- CodedOutputStream.encodeZigZag64(0x000000007FFFFFFFL));
- assertEquals(0x00000000FFFFFFFFL,
- CodedOutputStream.encodeZigZag64(0xFFFFFFFF80000000L));
- assertEquals(0xFFFFFFFFFFFFFFFEL,
- CodedOutputStream.encodeZigZag64(0x7FFFFFFFFFFFFFFFL));
- assertEquals(0xFFFFFFFFFFFFFFFFL,
- CodedOutputStream.encodeZigZag64(0x8000000000000000L));
+ assertEquals(0x000000007FFFFFFEL, CodedOutputStream.encodeZigZag64(0x000000003FFFFFFFL));
+ assertEquals(0x000000007FFFFFFFL, CodedOutputStream.encodeZigZag64(0xFFFFFFFFC0000000L));
+ assertEquals(0x00000000FFFFFFFEL, CodedOutputStream.encodeZigZag64(0x000000007FFFFFFFL));
+ assertEquals(0x00000000FFFFFFFFL, CodedOutputStream.encodeZigZag64(0xFFFFFFFF80000000L));
+ assertEquals(0xFFFFFFFFFFFFFFFEL, CodedOutputStream.encodeZigZag64(0x7FFFFFFFFFFFFFFFL));
+ assertEquals(0xFFFFFFFFFFFFFFFFL, CodedOutputStream.encodeZigZag64(0x8000000000000000L));
// Some easier-to-verify round-trip tests. The inputs (other than 0, 1, -1)
// were chosen semi-randomly via keyboard bashing.
- assertEquals(0,
- CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(0)));
- assertEquals(1,
- CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(1)));
- assertEquals(-1,
- CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(-1)));
- assertEquals(14927,
- CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(14927)));
- assertEquals(-3612,
- CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(-3612)));
-
- assertEquals(0,
- CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(0)));
- assertEquals(1,
- CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(1)));
- assertEquals(-1,
- CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(-1)));
- assertEquals(14927,
- CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(14927)));
- assertEquals(-3612,
- CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(-3612)));
-
- assertEquals(856912304801416L,
- CodedOutputStream.encodeZigZag64(
- CodedInputStream.decodeZigZag64(
- 856912304801416L)));
- assertEquals(-75123905439571256L,
- CodedOutputStream.encodeZigZag64(
- CodedInputStream.decodeZigZag64(
- -75123905439571256L)));
+ assertEquals(0, CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(0)));
+ assertEquals(1, CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(1)));
+ assertEquals(-1, CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(-1)));
+ assertEquals(14927, CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(14927)));
+ assertEquals(-3612, CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(-3612)));
+
+ assertEquals(0, CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(0)));
+ assertEquals(1, CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(1)));
+ assertEquals(-1, CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(-1)));
+ assertEquals(14927, CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(14927)));
+ assertEquals(-3612, CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(-3612)));
+
+ assertEquals(
+ 856912304801416L,
+ CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(856912304801416L)));
+ assertEquals(
+ -75123905439571256L,
+ CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(-75123905439571256L)));
}
/** Tests writing a whole message with every field type. */
public void testWriteWholeMessage() throws Exception {
+ final byte[] expectedBytes = TestUtil.getGoldenMessage().toByteArray();
TestAllTypes message = TestUtil.getAllSet();
- byte[] rawBytes = message.toByteArray();
- assertEqualBytes(TestUtil.getGoldenMessage().toByteArray(), rawBytes);
+ for (OutputType outputType : OutputType.values()) {
+ Coder coder = outputType.newCoder(message.getSerializedSize());
+ message.writeTo(coder.stream());
+ coder.stream().flush();
+ byte[] rawBytes = coder.toByteArray();
+ assertEqualBytes(outputType, expectedBytes, rawBytes);
+ }
// Try different block sizes.
for (int blockSize = 1; blockSize < 256; blockSize *= 2) {
- ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
- CodedOutputStream output =
- CodedOutputStream.newInstance(rawOutput, blockSize);
- message.writeTo(output);
- output.flush();
- assertEqualBytes(rawBytes, rawOutput.toByteArray());
+ Coder coder = OutputType.STREAM.newCoder(blockSize);
+ message.writeTo(coder.stream());
+ coder.stream().flush();
+ assertEqualBytes(OutputType.STREAM, expectedBytes, coder.toByteArray());
}
}
- /** Tests writing a whole message with every packed field type. Ensures the
- * wire format of packed fields is compatible with C++. */
+ /**
+ * Tests writing a whole message with every packed field type. Ensures the
+ * wire format of packed fields is compatible with C++.
+ */
public void testWriteWholePackedFieldsMessage() throws Exception {
+ byte[] expectedBytes = TestUtil.getGoldenPackedFieldsMessage().toByteArray();
TestPackedTypes message = TestUtil.getPackedSet();
- byte[] rawBytes = message.toByteArray();
- assertEqualBytes(TestUtil.getGoldenPackedFieldsMessage().toByteArray(),
- rawBytes);
+ for (OutputType outputType : OutputType.values()) {
+ Coder coder = outputType.newCoder(message.getSerializedSize());
+ message.writeTo(coder.stream());
+ coder.stream().flush();
+ byte[] rawBytes = coder.toByteArray();
+ assertEqualBytes(outputType, expectedBytes, rawBytes);
+ }
}
- /** Test writing a message containing a negative enum value. This used to
+ /**
+ * Test writing a message containing a negative enum value. This used to
* fail because the size was not properly computed as a sign-extended varint.
*/
public void testWriteMessageWithNegativeEnumValue() throws Exception {
- SparseEnumMessage message = SparseEnumMessage.newBuilder()
- .setSparseEnum(TestSparseEnum.SPARSE_E) .build();
+ SparseEnumMessage message =
+ SparseEnumMessage.newBuilder().setSparseEnum(TestSparseEnum.SPARSE_E).build();
assertTrue(message.getSparseEnum().getNumber() < 0);
- byte[] rawBytes = message.toByteArray();
- SparseEnumMessage message2 = SparseEnumMessage.parseFrom(rawBytes);
- assertEquals(TestSparseEnum.SPARSE_E, message2.getSparseEnum());
+ for (OutputType outputType : OutputType.values()) {
+ Coder coder = outputType.newCoder(message.getSerializedSize());
+ message.writeTo(coder.stream());
+ coder.stream().flush();
+ byte[] rawBytes = coder.toByteArray();
+ SparseEnumMessage message2 = SparseEnumMessage.parseFrom(rawBytes);
+ assertEquals(TestSparseEnum.SPARSE_E, message2.getSparseEnum());
+ }
}
/** Test getTotalBytesWritten() */
public void testGetTotalBytesWritten() throws Exception {
- final int BUFFER_SIZE = 4 * 1024;
- ByteArrayOutputStream outputStream = new ByteArrayOutputStream(BUFFER_SIZE);
- CodedOutputStream codedStream = CodedOutputStream.newInstance(outputStream);
+ Coder coder = OutputType.STREAM.newCoder(4 * 1024);
+
+ // Write some some bytes (more than the buffer can hold) and verify that totalWritten
+ // is correct.
byte[] value = "abcde".getBytes(Internal.UTF_8);
for (int i = 0; i < 1024; ++i) {
- codedStream.writeRawBytes(value, 0, value.length);
+ coder.stream().writeRawBytes(value, 0, value.length);
}
+ assertEquals(value.length * 1024, coder.stream().getTotalBytesWritten());
+
+ // Now write an encoded string.
String string =
"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz";
// Ensure we take the slower fast path.
- assertTrue(CodedOutputStream.computeRawVarint32Size(string.length())
- != CodedOutputStream.computeRawVarint32Size(string.length() * Utf8.MAX_BYTES_PER_CHAR));
-
- codedStream.writeStringNoTag(string);
+ assertTrue(CodedOutputStream.computeUInt32SizeNoTag(string.length())
+ != CodedOutputStream.computeUInt32SizeNoTag(string.length() * Utf8.MAX_BYTES_PER_CHAR));
+
+ coder.stream().writeStringNoTag(string);
int stringSize = CodedOutputStream.computeStringSizeNoTag(string);
-
- // Make sure we have written more bytes than the buffer could hold. This is
- // to make the test complete.
- assertTrue(codedStream.getTotalBytesWritten() > BUFFER_SIZE);
-
+
// Verify that the total bytes written is correct
- assertEquals((value.length * 1024) + stringSize, codedStream.getTotalBytesWritten());
+ assertEquals((value.length * 1024) + stringSize, coder.stream().getTotalBytesWritten());
}
-
+
// TODO(dweis): Write a comprehensive test suite for CodedOutputStream that covers more than just
// this case.
public void testWriteStringNoTag_fastpath() throws Exception {
@@ -390,14 +405,16 @@ public class CodedOutputStreamTest extends TestCase {
string += threeBytesPer;
}
// These checks ensure we will tickle the slower fast path.
- assertEquals(1, CodedOutputStream.computeRawVarint32Size(string.length()));
+ assertEquals(1, CodedOutputStream.computeUInt32SizeNoTag(string.length()));
assertEquals(
- 2, CodedOutputStream.computeRawVarint32Size(string.length() * Utf8.MAX_BYTES_PER_CHAR));
+ 2, CodedOutputStream.computeUInt32SizeNoTag(string.length() * Utf8.MAX_BYTES_PER_CHAR));
assertEquals(bufferSize, string.length() * Utf8.MAX_BYTES_PER_CHAR);
-
- CodedOutputStream output =
- CodedOutputStream.newInstance(ByteBuffer.allocate(bufferSize), bufferSize);
- output.writeStringNoTag(string);
+
+ for (OutputType outputType : OutputType.values()) {
+ Coder coder = outputType.newCoder(bufferSize + 2);
+ coder.stream().writeStringNoTag(string);
+ coder.stream().flush();
+ }
}
public void testWriteToByteBuffer() throws Exception {
@@ -464,83 +481,296 @@ public class CodedOutputStreamTest extends TestCase {
byte[] destination = new byte[4];
CodedOutputStream codedStream = CodedOutputStream.newInstance(destination);
codedStream.writeByteArrayNoTag(fullArray, 2, 2);
- assertEqualBytes(bytes(0x02, 0x33, 0x44, 0x00), destination);
+ assertEqualBytes(OutputType.ARRAY, bytes(0x02, 0x33, 0x44, 0x00), destination);
assertEquals(3, codedStream.getTotalBytesWritten());
}
-
+
+ public void testSerializeUtf8_MultipleSmallWrites() throws Exception {
+ final String source = "abcdefghijklmnopqrstuvwxyz";
+
+ // Generate the expected output if the source string is written 2 bytes at a time.
+ ByteArrayOutputStream expectedBytesStream = new ByteArrayOutputStream();
+ for (int pos = 0; pos < source.length(); pos += 2) {
+ String substr = source.substring(pos, pos + 2);
+ expectedBytesStream.write(2);
+ expectedBytesStream.write(substr.getBytes(Internal.UTF_8));
+ }
+ final byte[] expectedBytes = expectedBytesStream.toByteArray();
+
+ // For each output type, write the source string 2 bytes at a time and verify the output.
+ for (OutputType outputType : OutputType.values()) {
+ Coder coder = outputType.newCoder(expectedBytes.length);
+ for (int pos = 0; pos < source.length(); pos += 2) {
+ String substr = source.substring(pos, pos + 2);
+ coder.stream().writeStringNoTag(substr);
+ }
+ coder.stream().flush();
+ assertEqualBytes(outputType, expectedBytes, coder.toByteArray());
+ }
+ }
+
public void testSerializeInvalidUtf8() throws Exception {
- String[] invalidStrings = new String[] {
- newString(Character.MIN_HIGH_SURROGATE),
- "foobar" + newString(Character.MIN_HIGH_SURROGATE),
- newString(Character.MIN_LOW_SURROGATE),
+ String[] invalidStrings = new String[] {newString(Character.MIN_HIGH_SURROGATE),
+ "foobar" + newString(Character.MIN_HIGH_SURROGATE), newString(Character.MIN_LOW_SURROGATE),
"foobar" + newString(Character.MIN_LOW_SURROGATE),
- newString(Character.MIN_HIGH_SURROGATE, Character.MIN_HIGH_SURROGATE)
- };
-
+ newString(Character.MIN_HIGH_SURROGATE, Character.MIN_HIGH_SURROGATE)};
+
CodedOutputStream outputWithStream = CodedOutputStream.newInstance(new ByteArrayOutputStream());
CodedOutputStream outputWithArray = CodedOutputStream.newInstance(new byte[10000]);
+ CodedOutputStream outputWithByteBuffer =
+ CodedOutputStream.newInstance(ByteBuffer.allocate(10000));
for (String s : invalidStrings) {
// TODO(dweis): These should all fail; instead they are corrupting data.
CodedOutputStream.computeStringSizeNoTag(s);
outputWithStream.writeStringNoTag(s);
outputWithArray.writeStringNoTag(s);
+ outputWithByteBuffer.writeStringNoTag(s);
}
}
-
- private static String newString(char... chars) {
- return new String(chars);
+
+ // TODO(nathanmittler): This test can be deleted once we properly throw IOException while
+ // encoding invalid UTF-8 strings.
+ public void testSerializeInvalidUtf8FollowedByOutOfSpace() throws Exception {
+ final int notEnoughBytes = 4;
+ CodedOutputStream outputWithArray = CodedOutputStream.newInstance(new byte[notEnoughBytes]);
+ CodedOutputStream outputWithByteBuffer =
+ CodedOutputStream.newInstance(ByteBuffer.allocate(notEnoughBytes));
+
+ String invalidString = newString(Character.MIN_HIGH_SURROGATE, 'f', 'o', 'o', 'b', 'a', 'r');
+ try {
+ outputWithArray.writeStringNoTag(invalidString);
+ fail("Expected OutOfSpaceException");
+ } catch (OutOfSpaceException e) {
+ assertTrue(e.getCause() instanceof IndexOutOfBoundsException);
+ }
+ try {
+ outputWithByteBuffer.writeStringNoTag(invalidString);
+ fail("Expected OutOfSpaceException");
+ } catch (OutOfSpaceException e) {
+ assertTrue(e.getCause() instanceof IndexOutOfBoundsException);
+ }
}
/** Regression test for https://github.com/google/protobuf/issues/292 */
public void testCorrectExceptionThrowWhenEncodingStringsWithoutEnoughSpace() throws Exception {
String testCase = "Foooooooo";
- assertEquals(CodedOutputStream.computeRawVarint32Size(testCase.length()),
- CodedOutputStream.computeRawVarint32Size(testCase.length() * 3));
+ assertEquals(
+ CodedOutputStream.computeUInt32SizeNoTag(testCase.length()),
+ CodedOutputStream.computeUInt32SizeNoTag(testCase.length() * 3));
assertEquals(11, CodedOutputStream.computeStringSize(1, testCase));
// Tag is one byte, varint describing string length is 1 byte, string length is 9 bytes.
// An array of size 1 will cause a failure when trying to write the varint.
- for (int i = 0; i < 11; i++) {
- CodedOutputStream output = CodedOutputStream.newInstance(new byte[i]);
- try {
- output.writeString(1, testCase);
- fail("Should have thrown an out of space exception");
- } catch (CodedOutputStream.OutOfSpaceException expected) {}
+ for (OutputType outputType :
+ new OutputType[] {OutputType.ARRAY, OutputType.NIO_HEAP, OutputType.NIO_DIRECT}) {
+ for (int i = 0; i < 11; i++) {
+ Coder coder = outputType.newCoder(i);
+ try {
+ coder.stream().writeString(1, testCase);
+ fail("Should have thrown an out of space exception");
+ } catch (CodedOutputStream.OutOfSpaceException expected) {
+ }
+ }
}
}
-
+
public void testDifferentStringLengths() throws Exception {
// Test string serialization roundtrip using strings of the following lengths,
// with ASCII and Unicode characters requiring different UTF-8 byte counts per
// char, hence causing the length delimiter varint to sometimes require more
// bytes for the Unicode strings than the ASCII string of the same length.
int[] lengths = new int[] {
- 0,
- 1,
- (1 << 4) - 1, // 1 byte for ASCII and Unicode
- (1 << 7) - 1, // 1 byte for ASCII, 2 bytes for Unicode
- (1 << 11) - 1, // 2 bytes for ASCII and Unicode
- (1 << 14) - 1, // 2 bytes for ASCII, 3 bytes for Unicode
- (1 << 17) - 1, // 3 bytes for ASCII and Unicode
+ 0,
+ 1,
+ (1 << 4) - 1, // 1 byte for ASCII and Unicode
+ (1 << 7) - 1, // 1 byte for ASCII, 2 bytes for Unicode
+ (1 << 11) - 1, // 2 bytes for ASCII and Unicode
+ (1 << 14) - 1, // 2 bytes for ASCII, 3 bytes for Unicode
+ (1 << 17) - 1,
+ // 3 bytes for ASCII and Unicode
};
- for (int i : lengths) {
- testEncodingOfString('q', i); // 1 byte per char
- testEncodingOfString('\u07FF', i); // 2 bytes per char
- testEncodingOfString('\u0981', i); // 3 bytes per char
+ for (OutputType outputType : OutputType.values()) {
+ for (int i : lengths) {
+ testEncodingOfString(outputType, 'q', i); // 1 byte per char
+ testEncodingOfString(outputType, '\u07FF', i); // 2 bytes per char
+ testEncodingOfString(outputType, '\u0981', i); // 3 bytes per char
+ }
}
}
- private void testEncodingOfString(char c, int length) throws Exception {
+ public void testNioEncodersWithInitialOffsets() throws Exception {
+ String value = "abc";
+ for (Coder coder : new Coder[] {new NioHeapCoder(10, 2), new NioDirectCoder(10, 2)}) {
+ coder.stream().writeStringNoTag(value);
+ coder.stream().flush();
+ assertEqualBytes(coder.getOutputType(), new byte[]{3, 'a', 'b', 'c'}, coder.toByteArray());
+ }
+ }
+
+ /**
+ * Parses the given bytes using writeRawLittleEndian32() and checks
+ * that the result matches the given value.
+ */
+ private static void assertWriteLittleEndian32(byte[] data, int value) throws Exception {
+ for (OutputType outputType : OutputType.values()) {
+ Coder coder = outputType.newCoder(data.length);
+ coder.stream().writeFixed32NoTag(value);
+ coder.stream().flush();
+ assertEqualBytes(outputType, data, coder.toByteArray());
+ }
+
+ // Try different block sizes.
+ for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+ Coder coder = OutputType.STREAM.newCoder(blockSize);
+ coder.stream().writeFixed32NoTag(value);
+ coder.stream().flush();
+ assertEqualBytes(OutputType.STREAM, data, coder.toByteArray());
+ }
+ }
+
+ /**
+ * Parses the given bytes using writeRawLittleEndian64() and checks
+ * that the result matches the given value.
+ */
+ private static void assertWriteLittleEndian64(byte[] data, long value) throws Exception {
+ for (OutputType outputType : OutputType.values()) {
+ Coder coder = outputType.newCoder(data.length);
+ coder.stream().writeFixed64NoTag(value);
+ coder.stream().flush();
+ assertEqualBytes(outputType, data, coder.toByteArray());
+ }
+
+ // Try different block sizes.
+ for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+ Coder coder = OutputType.STREAM.newCoder(blockSize);
+ coder.stream().writeFixed64NoTag(value);
+ coder.stream().flush();
+ assertEqualBytes(OutputType.STREAM, data, coder.toByteArray());
+ }
+ }
+
+ private static String newString(char... chars) {
+ return new String(chars);
+ }
+
+ private static void testEncodingOfString(OutputType outputType, char c, int length)
+ throws Exception {
String fullString = fullString(c, length);
- TestAllTypes testAllTypes = TestAllTypes.newBuilder()
- .setOptionalString(fullString)
- .build();
+ TestAllTypes testAllTypes = TestAllTypes.newBuilder().setOptionalString(fullString).build();
+ Coder coder = outputType.newCoder(testAllTypes.getSerializedSize());
+ testAllTypes.writeTo(coder.stream());
+ coder.stream().flush();
assertEquals(
- fullString, TestAllTypes.parseFrom(testAllTypes.toByteArray()).getOptionalString());
+ "OuputType: " + outputType,
+ fullString,
+ TestAllTypes.parseFrom(coder.toByteArray()).getOptionalString());
}
- private String fullString(char c, int length) {
+ private static String fullString(char c, int length) {
char[] result = new char[length];
Arrays.fill(result, c);
return new String(result);
}
+
+ /**
+ * Helper to construct a byte array from a bunch of bytes. The inputs are
+ * actually ints so that I can use hex notation and not get stupid errors
+ * about precision.
+ */
+ private static byte[] bytes(int... bytesAsInts) {
+ byte[] bytes = new byte[bytesAsInts.length];
+ for (int i = 0; i < bytesAsInts.length; i++) {
+ bytes[i] = (byte) bytesAsInts[i];
+ }
+ return bytes;
+ }
+
+ /** Arrays.asList() does not work with arrays of primitives. :( */
+ private static List<Byte> toList(byte[] bytes) {
+ List<Byte> result = new ArrayList<Byte>();
+ for (byte b : bytes) {
+ result.add(b);
+ }
+ return result;
+ }
+
+ private static void assertEqualBytes(OutputType outputType, byte[] a, byte[] b) {
+ assertEquals(outputType.name(), toList(a), toList(b));
+ }
+
+ /**
+ * Writes the given value using writeRawVarint32() and writeRawVarint64() and
+ * checks that the result matches the given bytes.
+ */
+ private static void assertWriteVarint(byte[] data, long value) throws Exception {
+ for (OutputType outputType : OutputType.values()) {
+ // Only test 32-bit write if the value fits into an int.
+ if (value == (int) value) {
+ Coder coder = outputType.newCoder(10);
+ coder.stream().writeUInt32NoTag((int) value);
+ coder.stream().flush();
+ assertEqualBytes(outputType, data, coder.toByteArray());
+
+ // Also try computing size.
+ assertEquals(data.length, CodedOutputStream.computeUInt32SizeNoTag((int) value));
+ }
+
+ {
+ Coder coder = outputType.newCoder(10);
+ coder.stream().writeUInt64NoTag(value);
+ coder.stream().flush();
+ assertEqualBytes(outputType, data, coder.toByteArray());
+
+ // Also try computing size.
+ assertEquals(data.length, CodedOutputStream.computeUInt64SizeNoTag(value));
+ }
+ }
+
+ // Try different block sizes.
+ for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+ // Only test 32-bit write if the value fits into an int.
+ if (value == (int) value) {
+ Coder coder = OutputType.STREAM.newCoder(blockSize);
+ coder.stream().writeUInt64NoTag((int) value);
+ coder.stream().flush();
+ assertEqualBytes(OutputType.STREAM, data, coder.toByteArray());
+
+ ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
+ CodedOutputStream output = CodedOutputStream.newInstance(rawOutput, blockSize);
+ output.writeUInt32NoTag((int) value);
+ output.flush();
+ assertEqualBytes(OutputType.STREAM, data, rawOutput.toByteArray());
+ }
+
+ {
+ Coder coder = OutputType.STREAM.newCoder(blockSize);
+ coder.stream().writeUInt64NoTag(value);
+ coder.stream().flush();
+ assertEqualBytes(OutputType.STREAM, data, coder.toByteArray());
+ }
+ }
+ }
+
+ private static void assertVarintRoundTrip(OutputType outputType, long value) throws Exception {
+ {
+ Coder coder = outputType.newCoder(10);
+ coder.stream().writeUInt64NoTag(value);
+ coder.stream().flush();
+ byte[] bytes = coder.toByteArray();
+ assertEquals(
+ outputType.name(), bytes.length, CodedOutputStream.computeUInt64SizeNoTag(value));
+ CodedInputStream input = CodedInputStream.newInstance(new ByteArrayInputStream(bytes));
+ assertEquals(outputType.name(), value, input.readRawVarint64());
+ }
+
+ if (value == (int) value) {
+ Coder coder = outputType.newCoder(10);
+ coder.stream().writeUInt32NoTag((int) value);
+ coder.stream().flush();
+ byte[] bytes = coder.toByteArray();
+ assertEquals(
+ outputType.name(), bytes.length, CodedOutputStream.computeUInt32SizeNoTag((int) value));
+ CodedInputStream input = CodedInputStream.newInstance(new ByteArrayInputStream(bytes));
+ assertEquals(outputType.name(), value, input.readRawVarint32());
+ }
+ }
}
diff --git a/java/core/src/test/java/com/google/protobuf/DeprecatedFieldTest.java b/java/core/src/test/java/com/google/protobuf/DeprecatedFieldTest.java
index e7905f79..ce85ae2e 100644
--- a/java/core/src/test/java/com/google/protobuf/DeprecatedFieldTest.java
+++ b/java/core/src/test/java/com/google/protobuf/DeprecatedFieldTest.java
@@ -36,6 +36,7 @@ import junit.framework.TestCase;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
+
/**
* Test field deprecation
*
diff --git a/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java b/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
index 82ff34af..ef89b389 100644
--- a/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
+++ b/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
@@ -59,7 +59,6 @@ import protobuf_unittest.UnittestProto.TestMultipleExtensionRanges;
import protobuf_unittest.UnittestProto.TestRequired;
import protobuf_unittest.UnittestProto.TestReservedFields;
import protobuf_unittest.UnittestProto.TestService;
-
import junit.framework.TestCase;
import java.util.Arrays;
@@ -573,6 +572,42 @@ public class DescriptorsTest extends TestCase {
}
}
+ public void testUnknownFieldsDenied() throws Exception {
+ FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
+ .setName("foo.proto")
+ .addMessageType(DescriptorProto.newBuilder()
+ .setName("Foo")
+ .addField(FieldDescriptorProto.newBuilder()
+ .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+ .setTypeName("Bar")
+ .setName("bar")
+ .setNumber(1)))
+ .build();
+
+ try {
+ Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0]);
+ fail("DescriptorValidationException expected");
+ } catch (DescriptorValidationException e) {
+ assertTrue(e.getMessage().indexOf("Bar") != -1);
+ assertTrue(e.getMessage().indexOf("is not defined") != -1);
+ }
+ }
+
+ public void testUnknownFieldsAllowed() throws Exception {
+ FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
+ .setName("foo.proto")
+ .addDependency("bar.proto")
+ .addMessageType(DescriptorProto.newBuilder()
+ .setName("Foo")
+ .addField(FieldDescriptorProto.newBuilder()
+ .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+ .setTypeName("Bar")
+ .setName("bar")
+ .setNumber(1)))
+ .build();
+ Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0], true);
+ }
+
public void testHiddenDependency() throws Exception {
FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
.setName("bar.proto")
diff --git a/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java b/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java
index d3deaa07..85b418c4 100644
--- a/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java
@@ -73,20 +73,6 @@ public class DoubleArrayListTest extends TestCase {
assertImmutable(list);
}
- public void testCopyConstructor() {
- DoubleArrayList copy = new DoubleArrayList(TERTIARY_LIST);
- assertEquals(TERTIARY_LIST, copy);
-
- copy = new DoubleArrayList(DoubleArrayList.emptyList());
- assertEquals(DoubleArrayList.emptyList(), copy);
-
- copy = new DoubleArrayList(asList(1D, 2D, 3D));
- assertEquals(asList(1D, 2D, 3D), copy);
-
- copy = new DoubleArrayList(Collections.<Double>emptyList());
- assertEquals(DoubleArrayList.emptyList(), copy);
- }
-
public void testModificationWithIteration() {
list.addAll(asList(1D, 2D, 3D, 4D));
Iterator<Double> iterator = list.iterator();
diff --git a/java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java b/java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java
index 55144e7c..8f3a74c1 100644
--- a/java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java
+++ b/java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java
@@ -33,13 +33,13 @@ package com.google.protobuf;
import com.google.protobuf.Descriptors.EnumDescriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.Descriptors.OneofDescriptor;
-
import protobuf_unittest.UnittestProto.TestAllExtensions;
import protobuf_unittest.UnittestProto.TestAllTypes;
import protobuf_unittest.UnittestProto.TestEmptyMessage;
import protobuf_unittest.UnittestProto.TestPackedTypes;
import junit.framework.TestCase;
+
import java.util.Arrays;
/**
diff --git a/java/core/src/test/java/com/google/protobuf/EnumTest.java b/java/core/src/test/java/com/google/protobuf/EnumTest.java
new file mode 100644
index 00000000..14c7406b
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/EnumTest.java
@@ -0,0 +1,76 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import com.google.protobuf.UnittestLite.ForeignEnumLite;
+import com.google.protobuf.UnittestLite.TestAllTypesLite;
+import protobuf_unittest.UnittestProto.ForeignEnum;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+
+import junit.framework.TestCase;
+
+public class EnumTest extends TestCase {
+
+ public void testForNumber() {
+ ForeignEnum e = ForeignEnum.forNumber(ForeignEnum.FOREIGN_BAR.getNumber());
+ assertEquals(ForeignEnum.FOREIGN_BAR, e);
+
+ e = ForeignEnum.forNumber(1000);
+ assertEquals(null, e);
+ }
+
+ public void testForNumber_oneof() {
+ TestAllTypes.OneofFieldCase e = TestAllTypes.OneofFieldCase.forNumber(
+ TestAllTypes.OneofFieldCase.ONEOF_NESTED_MESSAGE.getNumber());
+ assertEquals(TestAllTypes.OneofFieldCase.ONEOF_NESTED_MESSAGE, e);
+
+ e = TestAllTypes.OneofFieldCase.forNumber(1000);
+ assertEquals(null, e);
+ }
+
+ public void testForNumberLite() {
+ ForeignEnumLite e = ForeignEnumLite.forNumber(ForeignEnumLite.FOREIGN_LITE_BAR.getNumber());
+ assertEquals(ForeignEnumLite.FOREIGN_LITE_BAR, e);
+
+ e = ForeignEnumLite.forNumber(1000);
+ assertEquals(null, e);
+ }
+
+ public void testForNumberLite_oneof() {
+ TestAllTypesLite.OneofFieldCase e = TestAllTypesLite.OneofFieldCase.forNumber(
+ TestAllTypesLite.OneofFieldCase.ONEOF_NESTED_MESSAGE.getNumber());
+ assertEquals(TestAllTypesLite.OneofFieldCase.ONEOF_NESTED_MESSAGE, e);
+
+ e = TestAllTypesLite.OneofFieldCase.forNumber(1000);
+ assertEquals(null, e);
+ }
+}
+
diff --git a/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java b/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java
index eaeec0b8..304cec4f 100644
--- a/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java
+++ b/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java
@@ -44,9 +44,9 @@ import junit.framework.TestCase;
* non-message fields.
*/
public class FieldPresenceTest extends TestCase {
- private static boolean hasMethod(Class clazz, String name) {
+ private static boolean hasMethod(Class<?> clazz, String name) {
try {
- if (clazz.getMethod(name, new Class[]{}) != null) {
+ if (clazz.getMethod(name) != null) {
return true;
} else {
return false;
@@ -56,90 +56,90 @@ public class FieldPresenceTest extends TestCase {
}
}
- private static boolean isHasMethodRemoved(
- Class classWithFieldPresence,
- Class classWithoutFieldPresence,
+ private static void assertHasMethodRemoved(
+ Class<?> classWithFieldPresence,
+ Class<?> classWithoutFieldPresence,
String camelName) {
- return hasMethod(classWithFieldPresence, "get" + camelName)
- && hasMethod(classWithFieldPresence, "has" + camelName)
- && hasMethod(classWithoutFieldPresence, "get" + camelName)
- && !hasMethod(classWithoutFieldPresence, "has" + camelName);
+ assertTrue(hasMethod(classWithFieldPresence, "get" + camelName));
+ assertTrue(hasMethod(classWithFieldPresence, "has" + camelName));
+ assertTrue(hasMethod(classWithoutFieldPresence, "get" + camelName));
+ assertFalse(hasMethod(classWithoutFieldPresence, "has" + camelName));
}
public void testHasMethod() {
// Optional non-message fields don't have a hasFoo() method generated.
- assertTrue(isHasMethodRemoved(
+ assertHasMethodRemoved(
UnittestProto.TestAllTypes.class,
TestAllTypes.class,
- "OptionalInt32"));
- assertTrue(isHasMethodRemoved(
+ "OptionalInt32");
+ assertHasMethodRemoved(
UnittestProto.TestAllTypes.class,
TestAllTypes.class,
- "OptionalString"));
- assertTrue(isHasMethodRemoved(
+ "OptionalString");
+ assertHasMethodRemoved(
UnittestProto.TestAllTypes.class,
TestAllTypes.class,
- "OptionalBytes"));
- assertTrue(isHasMethodRemoved(
+ "OptionalBytes");
+ assertHasMethodRemoved(
UnittestProto.TestAllTypes.class,
TestAllTypes.class,
- "OptionalNestedEnum"));
+ "OptionalNestedEnum");
- assertTrue(isHasMethodRemoved(
+ assertHasMethodRemoved(
UnittestProto.TestAllTypes.Builder.class,
TestAllTypes.Builder.class,
- "OptionalInt32"));
- assertTrue(isHasMethodRemoved(
+ "OptionalInt32");
+ assertHasMethodRemoved(
UnittestProto.TestAllTypes.Builder.class,
TestAllTypes.Builder.class,
- "OptionalString"));
- assertTrue(isHasMethodRemoved(
+ "OptionalString");
+ assertHasMethodRemoved(
UnittestProto.TestAllTypes.Builder.class,
TestAllTypes.Builder.class,
- "OptionalBytes"));
- assertTrue(isHasMethodRemoved(
+ "OptionalBytes");
+ assertHasMethodRemoved(
UnittestProto.TestAllTypes.Builder.class,
TestAllTypes.Builder.class,
- "OptionalNestedEnum"));
+ "OptionalNestedEnum");
// message fields still have the hasFoo() method generated.
assertFalse(TestAllTypes.newBuilder().build().hasOptionalNestedMessage());
assertFalse(TestAllTypes.newBuilder().hasOptionalNestedMessage());
// oneof fields don't have hasFoo() methods (even for message types).
- assertTrue(isHasMethodRemoved(
+ assertHasMethodRemoved(
UnittestProto.TestAllTypes.class,
TestAllTypes.class,
- "OneofUint32"));
- assertTrue(isHasMethodRemoved(
+ "OneofUint32");
+ assertHasMethodRemoved(
UnittestProto.TestAllTypes.class,
TestAllTypes.class,
- "OneofString"));
- assertTrue(isHasMethodRemoved(
+ "OneofString");
+ assertHasMethodRemoved(
UnittestProto.TestAllTypes.class,
TestAllTypes.class,
- "OneofBytes"));
- assertTrue(isHasMethodRemoved(
+ "OneofBytes");
+ assertHasMethodRemoved(
UnittestProto.TestAllTypes.class,
TestAllTypes.class,
- "OneofNestedMessage"));
+ "OneofNestedMessage");
- assertTrue(isHasMethodRemoved(
+ assertHasMethodRemoved(
UnittestProto.TestAllTypes.Builder.class,
TestAllTypes.Builder.class,
- "OneofUint32"));
- assertTrue(isHasMethodRemoved(
+ "OneofUint32");
+ assertHasMethodRemoved(
UnittestProto.TestAllTypes.Builder.class,
TestAllTypes.Builder.class,
- "OneofString"));
- assertTrue(isHasMethodRemoved(
+ "OneofString");
+ assertHasMethodRemoved(
UnittestProto.TestAllTypes.Builder.class,
TestAllTypes.Builder.class,
- "OneofBytes"));
- assertTrue(isHasMethodRemoved(
+ "OneofBytes");
+ assertHasMethodRemoved(
UnittestProto.TestAllTypes.Builder.class,
TestAllTypes.Builder.class,
- "OneofNestedMessage"));
+ "OneofNestedMessage");
}
public void testOneofEquals() throws Exception {
@@ -232,24 +232,24 @@ public class FieldPresenceTest extends TestCase {
assertTrue(message.hasField(optionalNestedEnumField));
assertEquals(4, message.getAllFields().size());
}
-
+
public void testMessageField() {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
assertFalse(builder.hasOptionalNestedMessage());
assertFalse(builder.build().hasOptionalNestedMessage());
-
+
TestAllTypes.NestedMessage.Builder nestedBuilder =
builder.getOptionalNestedMessageBuilder();
assertTrue(builder.hasOptionalNestedMessage());
assertTrue(builder.build().hasOptionalNestedMessage());
-
+
nestedBuilder.setValue(1);
assertEquals(1, builder.build().getOptionalNestedMessage().getValue());
-
+
builder.clearOptionalNestedMessage();
assertFalse(builder.hasOptionalNestedMessage());
assertFalse(builder.build().hasOptionalNestedMessage());
-
+
// Unlike non-message fields, if we set a message field to its default value (i.e.,
// default instance), the field should be seen as present.
builder.setOptionalNestedMessage(TestAllTypes.NestedMessage.getDefaultInstance());
@@ -340,7 +340,7 @@ public class FieldPresenceTest extends TestCase {
assertTrue(builder.buildPartial().isInitialized());
}
-
+
// Test that unknown fields are dropped.
public void testUnknownFields() throws Exception {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
@@ -348,7 +348,7 @@ public class FieldPresenceTest extends TestCase {
builder.addRepeatedInt32(5678);
TestAllTypes message = builder.build();
ByteString data = message.toByteString();
-
+
TestOptionalFieldsOnly optionalOnlyMessage =
TestOptionalFieldsOnly.parseFrom(data);
// UnknownFieldSet should be empty.
@@ -360,7 +360,7 @@ public class FieldPresenceTest extends TestCase {
// The repeated field is discarded because it's unknown to the optional-only
// message.
assertEquals(0, message.getRepeatedInt32Count());
-
+
DynamicMessage dynamicOptionalOnlyMessage =
DynamicMessage.getDefaultInstance(
TestOptionalFieldsOnly.getDescriptor())
diff --git a/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java b/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java
index a5e65424..88a75743 100644
--- a/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java
@@ -73,20 +73,6 @@ public class FloatArrayListTest extends TestCase {
assertImmutable(list);
}
- public void testCopyConstructor() {
- FloatArrayList copy = new FloatArrayList(TERTIARY_LIST);
- assertEquals(TERTIARY_LIST, copy);
-
- copy = new FloatArrayList(FloatArrayList.emptyList());
- assertEquals(FloatArrayList.emptyList(), copy);
-
- copy = new FloatArrayList(asList(1F, 2F, 3F));
- assertEquals(asList(1F, 2F, 3F), copy);
-
- copy = new FloatArrayList(Collections.<Float>emptyList());
- assertEquals(FloatArrayList.emptyList(), copy);
- }
-
public void testModificationWithIteration() {
list.addAll(asList(1F, 2F, 3F, 4F));
Iterator<Float> iterator = list.iterator();
diff --git a/java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java b/java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java
index a92ba374..b7eaebf5 100644
--- a/java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java
+++ b/java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java
@@ -41,7 +41,7 @@ package com.google.protobuf;
*/
public class ForceFieldBuildersPreRun implements Runnable {
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public void run() {
GeneratedMessage.enableAlwaysUseFieldBuildersForTesting();
}
diff --git a/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java b/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java
index 70812b95..a9b8b638 100644
--- a/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java
+++ b/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java
@@ -620,6 +620,21 @@ public class GeneratedMessageTest extends TestCase {
TestUtil.assertExtensionsClear(TestAllExtensions.newBuilder().build());
}
+ public void testUnsetRepeatedExtensionGetField() {
+ TestAllExtensions message = TestAllExtensions.getDefaultInstance();
+ Object value;
+
+ value = message.getField(UnittestProto.repeatedStringExtension.getDescriptor());
+ assertTrue(value instanceof List);
+ assertTrue(((List<?>) value).isEmpty());
+ assertIsUnmodifiable((List<?>) value);
+
+ value = message.getField(UnittestProto.repeatedNestedMessageExtension.getDescriptor());
+ assertTrue(value instanceof List);
+ assertTrue(((List<?>) value).isEmpty());
+ assertIsUnmodifiable((List<?>) value);
+ }
+
public void testExtensionReflectionGetters() throws Exception {
TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
TestUtil.setAllExtensions(builder);
@@ -708,7 +723,7 @@ public class GeneratedMessageTest extends TestCase {
public void testLiteExtensionMessageOrBuilder() throws Exception {
TestAllExtensionsLite.Builder builder = TestAllExtensionsLite.newBuilder();
- TestUtil.setAllExtensions(builder);
+ TestUtilLite.setAllExtensions(builder);
TestUtil.assertAllExtensionsSet(builder);
TestAllExtensionsLite message = builder.build();
@@ -717,8 +732,8 @@ public class GeneratedMessageTest extends TestCase {
public void testLiteExtensionRepeatedSetters() throws Exception {
TestAllExtensionsLite.Builder builder = TestAllExtensionsLite.newBuilder();
- TestUtil.setAllExtensions(builder);
- TestUtil.modifyRepeatedExtensions(builder);
+ TestUtilLite.setAllExtensions(builder);
+ TestUtilLite.modifyRepeatedExtensions(builder);
TestUtil.assertRepeatedExtensionsModified(builder);
TestAllExtensionsLite message = builder.build();
@@ -745,7 +760,7 @@ public class GeneratedMessageTest extends TestCase {
}
public void testLiteExtensionCopy() throws Exception {
- TestAllExtensionsLite original = TestUtil.getAllLiteExtensionsSet();
+ TestAllExtensionsLite original = TestUtilLite.getAllLiteExtensionsSet();
TestAllExtensionsLite copy =
TestAllExtensionsLite.newBuilder(original).build();
TestUtil.assertAllExtensionsSet(copy);
diff --git a/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java b/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java
index 3733eb30..efb8f3e2 100644
--- a/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java
@@ -72,20 +72,6 @@ public class IntArrayListTest extends TestCase {
list.makeImmutable();
assertImmutable(list);
}
-
- public void testCopyConstructor() {
- IntArrayList copy = new IntArrayList(TERTIARY_LIST);
- assertEquals(TERTIARY_LIST, copy);
-
- copy = new IntArrayList(IntArrayList.emptyList());
- assertEquals(IntArrayList.emptyList(), copy);
-
- copy = new IntArrayList(asList(1, 2, 3));
- assertEquals(asList(1, 2, 3), copy);
-
- copy = new IntArrayList(Collections.<Integer>emptyList());
- assertEquals(IntArrayList.emptyList(), copy);
- }
public void testModificationWithIteration() {
list.addAll(asList(1, 2, 3, 4));
diff --git a/java/core/src/test/java/com/google/protobuf/IsValidUtf8Test.java b/java/core/src/test/java/com/google/protobuf/IsValidUtf8Test.java
index 8751baae..756049b4 100644
--- a/java/core/src/test/java/com/google/protobuf/IsValidUtf8Test.java
+++ b/java/core/src/test/java/com/google/protobuf/IsValidUtf8Test.java
@@ -30,12 +30,18 @@
package com.google.protobuf;
+import static com.google.protobuf.IsValidUtf8TestUtil.DIRECT_NIO_FACTORY;
+import static com.google.protobuf.IsValidUtf8TestUtil.EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT;
+import static com.google.protobuf.IsValidUtf8TestUtil.EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT;
+import static com.google.protobuf.IsValidUtf8TestUtil.HEAP_NIO_FACTORY;
+import static com.google.protobuf.IsValidUtf8TestUtil.LITERAL_FACTORY;
+import static com.google.protobuf.IsValidUtf8TestUtil.testBytes;
+
+import com.google.protobuf.IsValidUtf8TestUtil.ByteStringFactory;
import com.google.protobuf.IsValidUtf8TestUtil.Shard;
import junit.framework.TestCase;
-import java.io.UnsupportedEncodingException;
-
/**
* Tests cases for {@link ByteString#isValidUtf8()}. This includes three
* brute force tests that actually test every permutation of one byte, two byte,
@@ -51,31 +57,33 @@ import java.io.UnsupportedEncodingException;
* @author martinrb@google.com (Martin Buchholz)
*/
public class IsValidUtf8Test extends TestCase {
-
/**
* Tests that round tripping of all two byte permutations work.
*/
- public void testIsValidUtf8_1Byte() throws UnsupportedEncodingException {
- IsValidUtf8TestUtil.testBytes(1,
- IsValidUtf8TestUtil.EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT);
+ public void testIsValidUtf8_1Byte() {
+ testBytes(LITERAL_FACTORY, 1, EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT);
+ testBytes(HEAP_NIO_FACTORY, 1, EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT);
+ testBytes(DIRECT_NIO_FACTORY, 1, EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT);
}
/**
* Tests that round tripping of all two byte permutations work.
*/
- public void testIsValidUtf8_2Bytes() throws UnsupportedEncodingException {
- IsValidUtf8TestUtil.testBytes(2,
- IsValidUtf8TestUtil.EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT);
+ public void testIsValidUtf8_2Bytes() {
+ testBytes(LITERAL_FACTORY, 2, IsValidUtf8TestUtil.EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT);
+ testBytes(HEAP_NIO_FACTORY, 2, IsValidUtf8TestUtil.EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT);
+ testBytes(DIRECT_NIO_FACTORY, 2, IsValidUtf8TestUtil.EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT);
}
/**
* Tests that round tripping of all three byte permutations work.
*/
- public void testIsValidUtf8_3Bytes() throws UnsupportedEncodingException {
+ public void testIsValidUtf8_3Bytes() {
// Travis' OOM killer doesn't like this test
if (System.getenv("TRAVIS") == null) {
- IsValidUtf8TestUtil.testBytes(3,
- IsValidUtf8TestUtil.EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT);
+ testBytes(LITERAL_FACTORY, 3, EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT);
+ testBytes(HEAP_NIO_FACTORY, 3, EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT);
+ testBytes(DIRECT_NIO_FACTORY, 3, EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT);
}
}
@@ -85,8 +93,7 @@ public class IsValidUtf8Test extends TestCase {
* {@link IsValidUtf8FourByteTest} is used for full coverage. This method
* tests specific four-byte cases.
*/
- public void testIsValidUtf8_4BytesSamples()
- throws UnsupportedEncodingException {
+ public void testIsValidUtf8_4BytesSamples() {
// Valid 4 byte.
assertValidUtf8(0xF0, 0xA4, 0xAD, 0xA2);
@@ -119,9 +126,7 @@ public class IsValidUtf8Test extends TestCase {
assertTrue(asBytes("\u024B62\u024B62").isValidUtf8());
// Mixed string
- assertTrue(
- asBytes("a\u020ac\u00a2b\\u024B62u020acc\u00a2de\u024B62")
- .isValidUtf8());
+ assertTrue(asBytes("a\u020ac\u00a2b\\u024B62u020acc\u00a2de\u024B62").isValidUtf8());
// Not a valid string
assertInvalidUtf8(-1, 0, -1, 0);
@@ -135,36 +140,35 @@ public class IsValidUtf8Test extends TestCase {
return realBytes;
}
- private ByteString toByteString(int... bytes) {
- return ByteString.copyFrom(toByteArray(bytes));
- }
-
- private void assertValidUtf8(int[] bytes, boolean not) {
+ private void assertValidUtf8(ByteStringFactory factory, int[] bytes, boolean not) {
byte[] realBytes = toByteArray(bytes);
assertTrue(not ^ Utf8.isValidUtf8(realBytes));
assertTrue(not ^ Utf8.isValidUtf8(realBytes, 0, bytes.length));
- ByteString lit = ByteString.copyFrom(realBytes);
- ByteString sub = lit.substring(0, bytes.length);
- assertTrue(not ^ lit.isValidUtf8());
+ ByteString leaf = factory.newByteString(realBytes);
+ ByteString sub = leaf.substring(0, bytes.length);
+ assertTrue(not ^ leaf.isValidUtf8());
assertTrue(not ^ sub.isValidUtf8());
ByteString[] ropes = {
- RopeByteString.newInstanceForTest(ByteString.EMPTY, lit),
- RopeByteString.newInstanceForTest(ByteString.EMPTY, sub),
- RopeByteString.newInstanceForTest(lit, ByteString.EMPTY),
- RopeByteString.newInstanceForTest(sub, ByteString.EMPTY),
- RopeByteString.newInstanceForTest(sub, lit)
- };
+ RopeByteString.newInstanceForTest(ByteString.EMPTY, leaf),
+ RopeByteString.newInstanceForTest(ByteString.EMPTY, sub),
+ RopeByteString.newInstanceForTest(leaf, ByteString.EMPTY),
+ RopeByteString.newInstanceForTest(sub, ByteString.EMPTY),
+ RopeByteString.newInstanceForTest(sub, leaf)};
for (ByteString rope : ropes) {
assertTrue(not ^ rope.isValidUtf8());
}
}
private void assertValidUtf8(int... bytes) {
- assertValidUtf8(bytes, false);
+ assertValidUtf8(LITERAL_FACTORY, bytes, false);
+ assertValidUtf8(HEAP_NIO_FACTORY, bytes, false);
+ assertValidUtf8(DIRECT_NIO_FACTORY, bytes, false);
}
private void assertInvalidUtf8(int... bytes) {
- assertValidUtf8(bytes, true);
+ assertValidUtf8(LITERAL_FACTORY, bytes, true);
+ assertValidUtf8(HEAP_NIO_FACTORY, bytes, true);
+ assertValidUtf8(DIRECT_NIO_FACTORY, bytes, true);
}
private static ByteString asBytes(String s) {
@@ -177,7 +181,6 @@ public class IsValidUtf8Test extends TestCase {
for (Shard shard : IsValidUtf8TestUtil.FOUR_BYTE_SHARDS) {
actual += shard.expected;
}
- assertEquals(IsValidUtf8TestUtil.EXPECTED_FOUR_BYTE_ROUNDTRIPPABLE_COUNT,
- actual);
+ assertEquals(IsValidUtf8TestUtil.EXPECTED_FOUR_BYTE_ROUNDTRIPPABLE_COUNT, actual);
}
}
diff --git a/java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java b/java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java
index 321669f3..16a808bf 100644
--- a/java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java
+++ b/java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java
@@ -30,9 +30,13 @@
package com.google.protobuf;
-import static junit.framework.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
-import java.io.UnsupportedEncodingException;
+import java.lang.ref.SoftReference;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharsetDecoder;
@@ -52,64 +56,105 @@ import java.util.logging.Logger;
* @author jonp@google.com (Jon Perlow)
* @author martinrb@google.com (Martin Buchholz)
*/
-class IsValidUtf8TestUtil {
- private static Logger logger = Logger.getLogger(
- IsValidUtf8TestUtil.class.getName());
+final class IsValidUtf8TestUtil {
+ private static Logger logger = Logger.getLogger(IsValidUtf8TestUtil.class.getName());
+
+ private IsValidUtf8TestUtil() {}
+
+ static interface ByteStringFactory {
+ ByteString newByteString(byte[] bytes);
+ }
+
+ static final ByteStringFactory LITERAL_FACTORY = new ByteStringFactory() {
+ @Override
+ public ByteString newByteString(byte[] bytes) {
+ return ByteString.wrap(bytes);
+ }
+ };
+
+ static final ByteStringFactory HEAP_NIO_FACTORY = new ByteStringFactory() {
+ @Override
+ public ByteString newByteString(byte[] bytes) {
+ return new NioByteString(ByteBuffer.wrap(bytes));
+ }
+ };
+
+ private static ThreadLocal<SoftReference<ByteBuffer>> directBuffer =
+ new ThreadLocal<SoftReference<ByteBuffer>>();
+
+ /**
+ * Factory for direct {@link ByteBuffer} instances. To reduce direct memory usage, this
+ * uses a thread local direct buffer. This means that each call will overwrite the buffer's
+ * contents from the previous call, so the calling code must be careful not to continue using
+ * a buffer returned from a previous invocation.
+ */
+ static final ByteStringFactory DIRECT_NIO_FACTORY = new ByteStringFactory() {
+ @Override
+ public ByteString newByteString(byte[] bytes) {
+ SoftReference<ByteBuffer> ref = directBuffer.get();
+ ByteBuffer buffer = ref == null ? null : ref.get();
+ if (buffer == null || buffer.capacity() < bytes.length) {
+ buffer = ByteBuffer.allocateDirect(bytes.length);
+ directBuffer.set(new SoftReference<ByteBuffer>(buffer));
+ }
+ buffer.clear();
+ buffer.put(bytes);
+ buffer.flip();
+ return new NioByteString(buffer);
+ }
+ };
// 128 - [chars 0x0000 to 0x007f]
- static long ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS = 0x007f - 0x0000 + 1;
+ static final long ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS = 0x007f - 0x0000 + 1;
// 128
- static long EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT =
- ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS;
+ static final long EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT = ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS;
// 1920 [chars 0x0080 to 0x07FF]
- static long TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS = 0x07FF - 0x0080 + 1;
+ static final long TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS = 0x07FF - 0x0080 + 1;
// 18,304
- static long EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT =
+ static final long EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT =
// Both bytes are one byte characters
(long) Math.pow(EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT, 2) +
// The possible number of two byte characters
TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS;
// 2048
- static long THREE_BYTE_SURROGATES = 2 * 1024;
+ static final long THREE_BYTE_SURROGATES = 2 * 1024;
// 61,440 [chars 0x0800 to 0xFFFF, minus surrogates]
- static long THREE_BYTE_ROUNDTRIPPABLE_CHARACTERS =
+ static final long THREE_BYTE_ROUNDTRIPPABLE_CHARACTERS =
0xFFFF - 0x0800 + 1 - THREE_BYTE_SURROGATES;
// 2,650,112
- static long EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT =
+ static final long EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT =
// All one byte characters
(long) Math.pow(EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT, 3) +
// One two byte character and a one byte character
- 2 * TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS *
- ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS +
- // Three byte characters
+ 2 * TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS * ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS +
+ // Three byte characters
THREE_BYTE_ROUNDTRIPPABLE_CHARACTERS;
// 1,048,576 [chars 0x10000L to 0x10FFFF]
- static long FOUR_BYTE_ROUNDTRIPPABLE_CHARACTERS = 0x10FFFF - 0x10000L + 1;
+ static final long FOUR_BYTE_ROUNDTRIPPABLE_CHARACTERS = 0x10FFFF - 0x10000L + 1;
// 289,571,839
- static long EXPECTED_FOUR_BYTE_ROUNDTRIPPABLE_COUNT =
+ static final long EXPECTED_FOUR_BYTE_ROUNDTRIPPABLE_COUNT =
// All one byte characters
(long) Math.pow(EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT, 4) +
// One and three byte characters
- 2 * THREE_BYTE_ROUNDTRIPPABLE_CHARACTERS *
- ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS +
+ 2 * THREE_BYTE_ROUNDTRIPPABLE_CHARACTERS * ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS +
// Two two byte characters
TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS * TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS +
// Permutations of one and two byte characters
- 3 * TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS *
- ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS *
- ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS +
+ 3 * TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS * ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS
+ * ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS
+ +
// Four byte characters
FOUR_BYTE_ROUNDTRIPPABLE_CHARACTERS;
- static class Shard {
+ static final class Shard {
final long index;
final long start;
final long lim;
@@ -138,7 +183,7 @@ class IsValidUtf8TestUtil {
// 97-111 are all 2342912
for (int i = 97; i <= 111; i++) {
- expected[i] = 2342912;
+ expected[i] = 2342912;
}
// 113-117 are all 1048576
@@ -158,22 +203,18 @@ class IsValidUtf8TestUtil {
return expected;
}
- static final List<Shard> FOUR_BYTE_SHARDS = generateFourByteShards(
- 128, FOUR_BYTE_SHARDS_EXPECTED_ROUNTRIPPABLES);
+ static final List<Shard> FOUR_BYTE_SHARDS =
+ generateFourByteShards(128, FOUR_BYTE_SHARDS_EXPECTED_ROUNTRIPPABLES);
- private static List<Shard> generateFourByteShards(
- int numShards, long[] expected) {
+ private static List<Shard> generateFourByteShards(int numShards, long[] expected) {
assertEquals(numShards, expected.length);
List<Shard> shards = new ArrayList<Shard>(numShards);
long LIM = 1L << 32;
long increment = LIM / numShards;
assertTrue(LIM % numShards == 0);
for (int i = 0; i < numShards; i++) {
- shards.add(new Shard(i,
- increment * i,
- increment * (i + 1),
- expected[i]));
+ shards.add(new Shard(i, increment * i, increment * (i + 1), expected[i]));
}
return shards;
}
@@ -182,12 +223,12 @@ class IsValidUtf8TestUtil {
* Helper to run the loop to test all the permutations for the number of bytes
* specified.
*
+ * @param factory the factory for {@link ByteString} instances.
* @param numBytes the number of bytes in the byte array
* @param expectedCount the expected number of roundtrippable permutations
*/
- static void testBytes(int numBytes, long expectedCount)
- throws UnsupportedEncodingException {
- testBytes(numBytes, expectedCount, 0, -1);
+ static void testBytes(ByteStringFactory factory, int numBytes, long expectedCount) {
+ testBytes(factory, numBytes, expectedCount, 0, -1);
}
/**
@@ -195,14 +236,15 @@ class IsValidUtf8TestUtil {
* specified. This overload is useful for debugging to get the loop to start
* at a certain character.
*
+ * @param factory the factory for {@link ByteString} instances.
* @param numBytes the number of bytes in the byte array
* @param expectedCount the expected number of roundtrippable permutations
* @param start the starting bytes encoded as a long as big-endian
* @param lim the limit of bytes to process encoded as a long as big-endian,
* or -1 to mean the max limit for numBytes
*/
- static void testBytes(int numBytes, long expectedCount, long start, long lim)
- throws UnsupportedEncodingException {
+ static void testBytes(
+ ByteStringFactory factory, int numBytes, long expectedCount, long start, long lim) {
Random rnd = new Random();
byte[] bytes = new byte[numBytes];
@@ -217,7 +259,7 @@ class IsValidUtf8TestUtil {
bytes[bytes.length - i - 1] = (byte) tmpByteChar;
tmpByteChar = tmpByteChar >> 8;
}
- ByteString bs = ByteString.copyFrom(bytes);
+ ByteString bs = factory.newByteString(bytes);
boolean isRoundTrippable = bs.isValidUtf8();
String s = new String(bytes, Internal.UTF_8);
byte[] bytesReencoded = s.getBytes(Internal.UTF_8);
@@ -236,14 +278,15 @@ class IsValidUtf8TestUtil {
int i = rnd.nextInt(numBytes);
int j = rnd.nextInt(numBytes);
if (j < i) {
- int tmp = i; i = j; j = tmp;
+ int tmp = i;
+ i = j;
+ j = tmp;
}
int state1 = Utf8.partialIsValidUtf8(Utf8.COMPLETE, bytes, 0, i);
int state2 = Utf8.partialIsValidUtf8(state1, bytes, i, j);
int state3 = Utf8.partialIsValidUtf8(state2, bytes, j, numBytes);
if (isRoundTrippable != (state3 == Utf8.COMPLETE)) {
- System.out.printf("state=%04x %04x %04x i=%d j=%d%n",
- state1, state2, state3, i, j);
+ System.out.printf("state=%04x %04x %04x i=%d j=%d%n", state1, state2, state3, i, j);
outputFailure(byteChar, bytes, bytesReencoded);
}
assertEquals(isRoundTrippable, (state3 == Utf8.COMPLETE));
@@ -251,36 +294,24 @@ class IsValidUtf8TestUtil {
// Test ropes built out of small partial sequences
ByteString rope = RopeByteString.newInstanceForTest(
bs.substring(0, i),
- RopeByteString.newInstanceForTest(
- bs.substring(i, j),
- bs.substring(j, numBytes)));
+ RopeByteString.newInstanceForTest(bs.substring(i, j), bs.substring(j, numBytes)));
assertSame(RopeByteString.class, rope.getClass());
- ByteString[] byteStrings = { bs, bs.substring(0, numBytes), rope };
+ ByteString[] byteStrings = {bs, bs.substring(0, numBytes), rope};
for (ByteString x : byteStrings) {
- assertEquals(isRoundTrippable,
- x.isValidUtf8());
- assertEquals(state3,
- x.partialIsValidUtf8(Utf8.COMPLETE, 0, numBytes));
-
- assertEquals(state1,
- x.partialIsValidUtf8(Utf8.COMPLETE, 0, i));
- assertEquals(state1,
- x.substring(0, i).partialIsValidUtf8(Utf8.COMPLETE, 0, i));
- assertEquals(state2,
- x.partialIsValidUtf8(state1, i, j - i));
- assertEquals(state2,
- x.substring(i, j).partialIsValidUtf8(state1, 0, j - i));
- assertEquals(state3,
- x.partialIsValidUtf8(state2, j, numBytes - j));
- assertEquals(state3,
- x.substring(j, numBytes)
- .partialIsValidUtf8(state2, 0, numBytes - j));
+ assertEquals(isRoundTrippable, x.isValidUtf8());
+ assertEquals(state3, x.partialIsValidUtf8(Utf8.COMPLETE, 0, numBytes));
+
+ assertEquals(state1, x.partialIsValidUtf8(Utf8.COMPLETE, 0, i));
+ assertEquals(state1, x.substring(0, i).partialIsValidUtf8(Utf8.COMPLETE, 0, i));
+ assertEquals(state2, x.partialIsValidUtf8(state1, i, j - i));
+ assertEquals(state2, x.substring(i, j).partialIsValidUtf8(state1, 0, j - i));
+ assertEquals(state3, x.partialIsValidUtf8(state2, j, numBytes - j));
+ assertEquals(state3, x.substring(j, numBytes).partialIsValidUtf8(state2, 0, numBytes - j));
}
// ByteString reduplication should not affect its UTF-8 validity.
- ByteString ropeADope =
- RopeByteString.newInstanceForTest(bs, bs.substring(0, numBytes));
+ ByteString ropeADope = RopeByteString.newInstanceForTest(bs, bs.substring(0, numBytes));
assertEquals(isRoundTrippable, ropeADope.isValidUtf8());
if (isRoundTrippable) {
@@ -288,8 +319,7 @@ class IsValidUtf8TestUtil {
}
count++;
if (byteChar != 0 && byteChar % 1000000L == 0) {
- logger.info("Processed " + (byteChar / 1000000L) +
- " million characters");
+ logger.info("Processed " + (byteChar / 1000000L) + " million characters");
}
}
logger.info("Round tripped " + countRoundTripped + " of " + count);
@@ -303,25 +333,26 @@ class IsValidUtf8TestUtil {
* actual String class, it's possible for incompatibilities to develop
* (although unlikely).
*
+ * @param factory the factory for {@link ByteString} instances.
* @param numBytes the number of bytes in the byte array
* @param expectedCount the expected number of roundtrippable permutations
* @param start the starting bytes encoded as a long as big-endian
* @param lim the limit of bytes to process encoded as a long as big-endian,
* or -1 to mean the max limit for numBytes
*/
- void testBytesUsingByteBuffers(
- int numBytes, long expectedCount, long start, long lim)
- throws UnsupportedEncodingException {
- CharsetDecoder decoder = Internal.UTF_8.newDecoder()
- .onMalformedInput(CodingErrorAction.REPLACE)
- .onUnmappableCharacter(CodingErrorAction.REPLACE);
- CharsetEncoder encoder = Internal.UTF_8.newEncoder()
- .onMalformedInput(CodingErrorAction.REPLACE)
- .onUnmappableCharacter(CodingErrorAction.REPLACE);
+ static void testBytesUsingByteBuffers(
+ ByteStringFactory factory, int numBytes, long expectedCount, long start, long lim) {
+ CharsetDecoder decoder =
+ Internal.UTF_8.newDecoder()
+ .onMalformedInput(CodingErrorAction.REPLACE)
+ .onUnmappableCharacter(CodingErrorAction.REPLACE);
+ CharsetEncoder encoder =
+ Internal.UTF_8.newEncoder()
+ .onMalformedInput(CodingErrorAction.REPLACE)
+ .onUnmappableCharacter(CodingErrorAction.REPLACE);
byte[] bytes = new byte[numBytes];
int maxChars = (int) (decoder.maxCharsPerByte() * numBytes) + 1;
- char[] charsDecoded =
- new char[(int) (decoder.maxCharsPerByte() * numBytes) + 1];
+ char[] charsDecoded = new char[(int) (decoder.maxCharsPerByte() * numBytes) + 1];
int maxBytes = (int) (encoder.maxBytesPerChar() * maxChars) + 1;
byte[] bytesReencoded = new byte[maxBytes];
@@ -347,7 +378,7 @@ class IsValidUtf8TestUtil {
bytes[bytes.length - i - 1] = (byte) tmpByteChar;
tmpByteChar = tmpByteChar >> 8;
}
- boolean isRoundTrippable = ByteString.copyFrom(bytes).isValidUtf8();
+ boolean isRoundTrippable = factory.newByteString(bytes).isValidUtf8();
CoderResult result = decoder.decode(bb, cb, true);
assertFalse(result.isError());
result = decoder.flush(cb);
@@ -382,8 +413,7 @@ class IsValidUtf8TestUtil {
countRoundTripped++;
}
if (byteChar != 0 && byteChar % 1000000 == 0) {
- logger.info("Processed " + (byteChar / 1000000) +
- " million characters");
+ logger.info("Processed " + (byteChar / 1000000) + " million characters");
}
}
logger.info("Round tripped " + countRoundTripped + " of " + count);
@@ -394,10 +424,9 @@ class IsValidUtf8TestUtil {
outputFailure(byteChar, bytes, after, after.length);
}
- private static void outputFailure(long byteChar, byte[] bytes, byte[] after,
- int len) {
- fail("Failure: (" + Long.toHexString(byteChar) + ") " +
- toHexString(bytes) + " => " + toHexString(after, len));
+ private static void outputFailure(long byteChar, byte[] bytes, byte[] after, int len) {
+ fail("Failure: (" + Long.toHexString(byteChar) + ") " + toHexString(bytes) + " => "
+ + toHexString(after, len));
}
private static String toHexString(byte[] b) {
@@ -416,5 +445,4 @@ class IsValidUtf8TestUtil {
s.append("\"");
return s.toString();
}
-
}
diff --git a/java/core/src/test/java/com/google/protobuf/LazyFieldLiteTest.java b/java/core/src/test/java/com/google/protobuf/LazyFieldLiteTest.java
index 211b5697..8d1de6dc 100644
--- a/java/core/src/test/java/com/google/protobuf/LazyFieldLiteTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LazyFieldLiteTest.java
@@ -36,9 +36,10 @@ import static protobuf_unittest.UnittestProto.optionalInt64Extension;
import protobuf_unittest.UnittestProto.TestAllExtensions;
import protobuf_unittest.UnittestProto.TestAllTypes;
-import java.io.IOException;
import junit.framework.TestCase;
+import java.io.IOException;
+
/**
* Unit test for {@link LazyFieldLite}.
*
diff --git a/java/core/src/test/java/com/google/protobuf/LazyFieldTest.java b/java/core/src/test/java/com/google/protobuf/LazyFieldTest.java
index 2b900065..ce473ae9 100644
--- a/java/core/src/test/java/com/google/protobuf/LazyFieldTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LazyFieldTest.java
@@ -33,9 +33,10 @@ package com.google.protobuf;
import protobuf_unittest.UnittestProto.TestAllExtensions;
import protobuf_unittest.UnittestProto.TestAllTypes;
-import java.io.IOException;
import junit.framework.TestCase;
+import java.io.IOException;
+
/**
* Unit test for {@link LazyField}.
*
diff --git a/java/core/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java b/java/core/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java
index 035917c8..29e8d875 100644
--- a/java/core/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java
@@ -33,6 +33,8 @@ package com.google.protobuf;
import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Bar;
import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.BarPrime;
import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Foo;
+import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.TestOneofEquals;
+import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.TestRecursiveOneof;
import junit.framework.TestCase;
@@ -83,6 +85,16 @@ public class LiteEqualsAndHashTest extends TestCase {
assertFalse(bar.equals(barPrime));
}
+ public void testOneofEquals() throws Exception {
+ TestOneofEquals.Builder builder = TestOneofEquals.newBuilder();
+ TestOneofEquals message1 = builder.build();
+ // Set message2's name field to default value. The two messages should be different when we
+ // check with the oneof case.
+ builder.setName("");
+ TestOneofEquals message2 = builder.build();
+ assertFalse(message1.equals(message2));
+ }
+
public void testEqualsAndHashCodeWithUnknownFields() throws InvalidProtocolBufferException {
Foo fooWithOnlyValue = Foo.newBuilder()
.setValue(1)
@@ -105,4 +117,9 @@ public class LiteEqualsAndHashTest extends TestCase {
assertFalse(o1.equals(o2));
assertFalse(o1.hashCode() == o2.hashCode());
}
+
+ public void testRecursiveHashcode() {
+ // This tests that we don't infinite loop.
+ TestRecursiveOneof.getDefaultInstance().hashCode();
+ }
}
diff --git a/java/core/src/test/java/com/google/protobuf/LiteTest.java b/java/core/src/test/java/com/google/protobuf/LiteTest.java
index b1f298ff..88c3e0b2 100644
--- a/java/core/src/test/java/com/google/protobuf/LiteTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LiteTest.java
@@ -33,22 +33,31 @@ package com.google.protobuf;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
+import com.google.protobuf.UnittestImportLite.ImportEnumLite;
+import com.google.protobuf.UnittestImportPublicLite.PublicImportMessageLite;
import com.google.protobuf.UnittestLite;
import com.google.protobuf.UnittestLite.ForeignEnumLite;
import com.google.protobuf.UnittestLite.ForeignMessageLite;
import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
import com.google.protobuf.UnittestLite.TestAllTypesLite;
+import com.google.protobuf.UnittestLite.TestAllTypesLite.NestedEnum;
import com.google.protobuf.UnittestLite.TestAllTypesLite.NestedMessage;
import com.google.protobuf.UnittestLite.TestAllTypesLite.OneofFieldCase;
import com.google.protobuf.UnittestLite.TestAllTypesLite.OptionalGroup;
import com.google.protobuf.UnittestLite.TestAllTypesLite.RepeatedGroup;
import com.google.protobuf.UnittestLite.TestAllTypesLiteOrBuilder;
import com.google.protobuf.UnittestLite.TestNestedExtensionLite;
+import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Bar;
+import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.BarPrime;
+import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Foo;
+import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.TestOneofEquals;
+import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.TestRecursiveOneof;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.io.NotSerializableException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
@@ -58,6 +67,7 @@ import java.io.ObjectOutputStream;
* @author kenton@google.com Kenton Varda
*/
public class LiteTest extends TestCase {
+ @Override
public void setUp() throws Exception {
// Test that nested extensions are initialized correctly even if the outer
// class has not been accessed directly. This was once a bug with lite
@@ -128,33 +138,7 @@ public class LiteTest extends TestCase {
assertEquals(7, message2.getExtension(
UnittestLite.optionalNestedMessageExtensionLite).getBb());
}
-
- public void testSerialize() throws Exception {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- TestAllTypesLite expected =
- TestAllTypesLite.newBuilder()
- .setOptionalInt32(123)
- .addRepeatedString("hello")
- .setOptionalNestedMessage(
- TestAllTypesLite.NestedMessage.newBuilder().setBb(7))
- .build();
- ObjectOutputStream out = new ObjectOutputStream(baos);
- try {
- out.writeObject(expected);
- } finally {
- out.close();
- }
- ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
- ObjectInputStream in = new ObjectInputStream(bais);
- TestAllTypesLite actual = (TestAllTypesLite) in.readObject();
- assertEquals(expected.getOptionalInt32(), actual.getOptionalInt32());
- assertEquals(expected.getRepeatedStringCount(),
- actual.getRepeatedStringCount());
- assertEquals(expected.getRepeatedString(0),
- actual.getRepeatedString(0));
- assertEquals(expected.getOptionalNestedMessage().getBb(),
- actual.getOptionalNestedMessage().getBb());
- }
+
public void testClone() {
TestAllTypesLite.Builder expected = TestAllTypesLite.newBuilder()
@@ -327,11 +311,9 @@ public class LiteTest extends TestCase {
assertEquals(
ForeignMessageLite.getDefaultInstance(),
message.getOptionalForeignMessage());
- // LITE_RUNTIME doesn't implement equals so we compare on a property and
- // ensure the property isn't set on foreignMessage.
- assertEquals(3, builder.getOptionalForeignMessage().getC());
+ assertEquals(foreignMessageBuilder.build(), builder.getOptionalForeignMessage());
messageAfterBuild = builder.build();
- assertEquals(3, messageAfterBuild.getOptionalForeignMessage().getC());
+ assertEquals(foreignMessageBuilder.build(), messageAfterBuild.getOptionalForeignMessage());
assertEquals(
ForeignMessageLite.getDefaultInstance(),
message.getOptionalForeignMessage());
@@ -339,7 +321,7 @@ public class LiteTest extends TestCase {
assertEquals(
ForeignMessageLite.getDefaultInstance(),
builder.getOptionalForeignMessage());
- assertEquals(3, messageAfterBuild.getOptionalForeignMessage().getC());
+ assertEquals(foreignMessageBuilder.build(), messageAfterBuild.getOptionalForeignMessage());
message = builder.build();
OptionalGroup optionalGroup = OptionalGroup.newBuilder()
@@ -364,17 +346,15 @@ public class LiteTest extends TestCase {
builder.setOptionalGroup(optionalGroupBuilder);
assertEquals(
OptionalGroup.getDefaultInstance(), message.getOptionalGroup());
- // LITE_RUNTIME doesn't implement equals so we compare on a property and
- // ensure the property isn't set on optionalGroup.
- assertEquals(3, builder.getOptionalGroup().getA());
+ assertEquals(optionalGroupBuilder.build(), builder.getOptionalGroup());
messageAfterBuild = builder.build();
- assertEquals(3, messageAfterBuild.getOptionalGroup().getA());
+ assertEquals(optionalGroupBuilder.build(), messageAfterBuild.getOptionalGroup());
assertEquals(
OptionalGroup.getDefaultInstance(), message.getOptionalGroup());
builder.clearOptionalGroup();
assertEquals(
OptionalGroup.getDefaultInstance(), builder.getOptionalGroup());
- assertEquals(3, messageAfterBuild.getOptionalGroup().getA());
+ assertEquals(optionalGroupBuilder.build(), messageAfterBuild.getOptionalGroup());
message = builder.build();
builder.setOptionalInt32(1);
@@ -425,17 +405,16 @@ public class LiteTest extends TestCase {
assertEquals(
NestedMessage.getDefaultInstance(),
message.getOptionalLazyMessage());
- // LITE_RUNTIME doesn't implement equals so we compare on a property.
- assertEquals(3, builder.getOptionalLazyMessage().getBb());
+ assertEquals(nestedMessageBuilder.build(), builder.getOptionalLazyMessage());
messageAfterBuild = builder.build();
- assertEquals(3, messageAfterBuild.getOptionalLazyMessage().getBb());
+ assertEquals(nestedMessageBuilder.build(), messageAfterBuild.getOptionalLazyMessage());
assertEquals(
NestedMessage.getDefaultInstance(),
message.getOptionalLazyMessage());
builder.clearOptionalLazyMessage();
assertEquals(
NestedMessage.getDefaultInstance(), builder.getOptionalLazyMessage());
- assertEquals(3, messageAfterBuild.getOptionalLazyMessage().getBb());
+ assertEquals(nestedMessageBuilder.build(), messageAfterBuild.getOptionalLazyMessage());
message = builder.build();
builder.setOptionalSfixed32(1);
@@ -1125,8 +1104,7 @@ public class LiteTest extends TestCase {
assertEquals(0, message.getRepeatedForeignMessageCount());
builder.setRepeatedForeignMessage(
0, ForeignMessageLite.getDefaultInstance());
- // LITE_RUNTIME doesn't implement equals so we compare on a property.
- assertEquals(3, messageAfterBuild.getRepeatedForeignMessage(0).getC());
+ assertEquals(foreignMessageBuilder.build(), messageAfterBuild.getRepeatedForeignMessage(0));
assertEquals(
ForeignMessageLite.getDefaultInstance(),
builder.getRepeatedForeignMessage(0));
@@ -1139,8 +1117,7 @@ public class LiteTest extends TestCase {
builder.setRepeatedForeignMessage(0, foreignMessageBuilder);
assertEquals(
foreignMessage, messageAfterBuild.getRepeatedForeignMessage(0));
- // LITE_RUNTIME doesn't implement equals so we compare on a property.
- assertEquals(3, builder.getRepeatedForeignMessage(0).getC());
+ assertEquals(foreignMessageBuilder.build(), builder.getRepeatedForeignMessage(0));
builder.clearRepeatedForeignMessage();
message = builder.build();
@@ -1173,9 +1150,7 @@ public class LiteTest extends TestCase {
messageAfterBuild = builder.build();
assertEquals(0, message.getRepeatedGroupCount());
builder.setRepeatedGroup(0, RepeatedGroup.getDefaultInstance());
- // LITE_RUNTIME doesn't implement equals so we compare on a property and
- // ensure the property isn't set on repeatedGroup.
- assertEquals(3, messageAfterBuild.getRepeatedGroup(0).getA());
+ assertEquals(repeatedGroupBuilder.build(), messageAfterBuild.getRepeatedGroup(0));
assertEquals(
RepeatedGroup.getDefaultInstance(), builder.getRepeatedGroup(0));
builder.clearRepeatedGroup();
@@ -1185,9 +1160,7 @@ public class LiteTest extends TestCase {
messageAfterBuild = builder.build();
assertEquals(0, message.getRepeatedGroupCount());
builder.setRepeatedGroup(0, RepeatedGroup.getDefaultInstance());
- // LITE_RUNTIME doesn't implement equals so we compare on a property and
- // ensure the property isn't set on repeatedGroup.
- assertEquals(3, messageAfterBuild.getRepeatedGroup(0).getA());
+ assertEquals(repeatedGroupBuilder.build(), messageAfterBuild.getRepeatedGroup(0));
assertEquals(
RepeatedGroup.getDefaultInstance(), builder.getRepeatedGroup(0));
builder.clearRepeatedGroup();
@@ -1235,9 +1208,7 @@ public class LiteTest extends TestCase {
messageAfterBuild = builder.build();
assertEquals(0, message.getRepeatedLazyMessageCount());
builder.setRepeatedLazyMessage(0, NestedMessage.getDefaultInstance());
- // LITE_RUNTIME doesn't implement equals so we compare on a property and
- // ensure the property isn't set on repeatedGroup.
- assertEquals(3, messageAfterBuild.getRepeatedLazyMessage(0).getBb());
+ assertEquals(nestedMessageBuilder.build(), messageAfterBuild.getRepeatedLazyMessage(0));
assertEquals(
NestedMessage.getDefaultInstance(), builder.getRepeatedLazyMessage(0));
builder.clearRepeatedLazyMessage();
@@ -1247,9 +1218,7 @@ public class LiteTest extends TestCase {
messageAfterBuild = builder.build();
assertEquals(0, message.getRepeatedLazyMessageCount());
builder.setRepeatedLazyMessage(0, NestedMessage.getDefaultInstance());
- // LITE_RUNTIME doesn't implement equals so we compare on a property and
- // ensure the property isn't set on repeatedGroup.
- assertEquals(3, messageAfterBuild.getRepeatedLazyMessage(0).getBb());
+ assertEquals(nestedMessageBuilder.build(), messageAfterBuild.getRepeatedLazyMessage(0));
assertEquals(
NestedMessage.getDefaultInstance(), builder.getRepeatedLazyMessage(0));
builder.clearRepeatedLazyMessage();
@@ -1459,4 +1428,802 @@ public class LiteTest extends TestCase {
11, (int) extendableMessage.getExtension(
UnittestLite.optionalFixed32ExtensionLite));
}
+
+ public void testToStringDefaultInstance() throws Exception {
+ assertToStringEquals("", TestAllTypesLite.getDefaultInstance());
+ }
+
+ public void testToStringPrimitives() throws Exception {
+ TestAllTypesLite proto = TestAllTypesLite.newBuilder()
+ .setOptionalInt32(1)
+ .setOptionalInt64(9223372036854775807L)
+ .build();
+ assertToStringEquals("optional_int32: 1\noptional_int64: 9223372036854775807", proto);
+
+ proto = TestAllTypesLite.newBuilder()
+ .setOptionalBool(true)
+ .setOptionalNestedEnum(TestAllTypesLite.NestedEnum.BAZ)
+ .build();
+ assertToStringEquals("optional_bool: true\noptional_nested_enum: BAZ", proto);
+
+ proto = TestAllTypesLite.newBuilder()
+ .setOptionalFloat(2.72f)
+ .setOptionalDouble(3.14)
+ .build();
+ assertToStringEquals("optional_double: 3.14\noptional_float: 2.72", proto);
+ }
+
+ public void testToStringStringFields() throws Exception {
+ TestAllTypesLite proto = TestAllTypesLite.newBuilder()
+ .setOptionalString("foo\"bar\nbaz\\")
+ .build();
+ assertToStringEquals("optional_string: \"foo\\\"bar\\nbaz\\\\\"", proto);
+
+ proto = TestAllTypesLite.newBuilder()
+ .setOptionalString("\u6587")
+ .build();
+ assertToStringEquals("optional_string: \"\\346\\226\\207\"", proto);
+ }
+
+ public void testToStringNestedMessage() throws Exception {
+ TestAllTypesLite proto = TestAllTypesLite.newBuilder()
+ .setOptionalNestedMessage(TestAllTypesLite.NestedMessage.getDefaultInstance())
+ .build();
+ assertToStringEquals("optional_nested_message {\n}", proto);
+
+ proto = TestAllTypesLite.newBuilder()
+ .setOptionalNestedMessage(
+ TestAllTypesLite.NestedMessage.newBuilder().setBb(7))
+ .build();
+ assertToStringEquals("optional_nested_message {\n bb: 7\n}", proto);
+ }
+
+ public void testToStringRepeatedFields() throws Exception {
+ TestAllTypesLite proto = TestAllTypesLite.newBuilder()
+ .addRepeatedInt32(32)
+ .addRepeatedInt32(32)
+ .addRepeatedInt64(64)
+ .build();
+ assertToStringEquals("repeated_int32: 32\nrepeated_int32: 32\nrepeated_int64: 64", proto);
+
+ proto = TestAllTypesLite.newBuilder()
+ .addRepeatedLazyMessage(
+ TestAllTypesLite.NestedMessage.newBuilder().setBb(7))
+ .addRepeatedLazyMessage(
+ TestAllTypesLite.NestedMessage.newBuilder().setBb(8))
+ .build();
+ assertToStringEquals(
+ "repeated_lazy_message {\n bb: 7\n}\nrepeated_lazy_message {\n bb: 8\n}",
+ proto);
+ }
+
+ public void testToStringForeignFields() throws Exception {
+ TestAllTypesLite proto = TestAllTypesLite.newBuilder()
+ .setOptionalForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR)
+ .setOptionalForeignMessage(
+ ForeignMessageLite.newBuilder()
+ .setC(3))
+ .build();
+ assertToStringEquals(
+ "optional_foreign_enum: FOREIGN_LITE_BAR\noptional_foreign_message {\n c: 3\n}",
+ proto);
+ }
+
+ public void testToStringExtensions() throws Exception {
+ TestAllExtensionsLite message = TestAllExtensionsLite.newBuilder()
+ .setExtension(UnittestLite.optionalInt32ExtensionLite, 123)
+ .addExtension(UnittestLite.repeatedStringExtensionLite, "spam")
+ .addExtension(UnittestLite.repeatedStringExtensionLite, "eggs")
+ .setExtension(UnittestLite.optionalNestedEnumExtensionLite,
+ TestAllTypesLite.NestedEnum.BAZ)
+ .setExtension(UnittestLite.optionalNestedMessageExtensionLite,
+ TestAllTypesLite.NestedMessage.newBuilder().setBb(7).build())
+ .build();
+ assertToStringEquals(
+ "[1]: 123\n[18] {\n bb: 7\n}\n[21]: 3\n[44]: \"spam\"\n[44]: \"eggs\"",
+ message);
+ }
+
+ public void testToStringUnknownFields() throws Exception {
+ TestAllExtensionsLite messageWithExtensions = TestAllExtensionsLite.newBuilder()
+ .setExtension(UnittestLite.optionalInt32ExtensionLite, 123)
+ .addExtension(UnittestLite.repeatedStringExtensionLite, "spam")
+ .addExtension(UnittestLite.repeatedStringExtensionLite, "eggs")
+ .setExtension(UnittestLite.optionalNestedEnumExtensionLite,
+ TestAllTypesLite.NestedEnum.BAZ)
+ .setExtension(UnittestLite.optionalNestedMessageExtensionLite,
+ TestAllTypesLite.NestedMessage.newBuilder().setBb(7).build())
+ .build();
+ TestAllExtensionsLite messageWithUnknownFields = TestAllExtensionsLite.parseFrom(
+ messageWithExtensions.toByteArray());
+ assertToStringEquals(
+ "1: 123\n18: \"\\b\\a\"\n21: 3\n44: \"spam\"\n44: \"eggs\"",
+ messageWithUnknownFields);
+ }
+
+ public void testToStringLazyMessage() throws Exception {
+ TestAllTypesLite message = TestAllTypesLite.newBuilder()
+ .setOptionalLazyMessage(NestedMessage.newBuilder().setBb(1).build())
+ .build();
+ assertToStringEquals("optional_lazy_message {\n bb: 1\n}", message);
+ }
+
+ public void testToStringGroup() throws Exception {
+ TestAllTypesLite message = TestAllTypesLite.newBuilder()
+ .setOptionalGroup(OptionalGroup.newBuilder().setA(1).build())
+ .build();
+ assertToStringEquals("optional_group {\n a: 1\n}", message);
+ }
+
+ public void testToStringOneof() throws Exception {
+ TestAllTypesLite message = TestAllTypesLite.newBuilder()
+ .setOneofString("hello")
+ .build();
+ assertToStringEquals("oneof_string: \"hello\"", message);
+ }
+
+ // Asserts that the toString() representation of the message matches the expected. This verifies
+ // the first line starts with a comment; but, does not factor in said comment as part of the
+ // comparison as it contains unstable addresses.
+ private static void assertToStringEquals(String expected, MessageLite message) {
+ String toString = message.toString();
+ assertEquals('#', toString.charAt(0));
+ if (toString.indexOf("\n") >= 0) {
+ toString = toString.substring(toString.indexOf("\n") + 1);
+ } else {
+ toString = "";
+ }
+ assertEquals(expected, toString);
+ }
+
+ public void testParseLazy() throws Exception {
+ ByteString bb = TestAllTypesLite.newBuilder()
+ .setOptionalLazyMessage(NestedMessage.newBuilder()
+ .setBb(11)
+ .build())
+ .build().toByteString();
+ ByteString cc = TestAllTypesLite.newBuilder()
+ .setOptionalLazyMessage(NestedMessage.newBuilder()
+ .setCc(22)
+ .build())
+ .build().toByteString();
+
+ ByteString concat = bb.concat(cc);
+ TestAllTypesLite message = TestAllTypesLite.parseFrom(concat);
+
+ assertEquals(11, message.getOptionalLazyMessage().getBb());
+ assertEquals(22L, message.getOptionalLazyMessage().getCc());
+ }
+
+ public void testParseLazy_oneOf() throws Exception {
+ ByteString bb = TestAllTypesLite.newBuilder()
+ .setOneofLazyNestedMessage(NestedMessage.newBuilder()
+ .setBb(11)
+ .build())
+ .build().toByteString();
+ ByteString cc = TestAllTypesLite.newBuilder()
+ .setOneofLazyNestedMessage(NestedMessage.newBuilder()
+ .setCc(22)
+ .build())
+ .build().toByteString();
+
+ ByteString concat = bb.concat(cc);
+ TestAllTypesLite message = TestAllTypesLite.parseFrom(concat);
+
+ assertEquals(11, message.getOneofLazyNestedMessage().getBb());
+ assertEquals(22L, message.getOneofLazyNestedMessage().getCc());
+ }
+
+ public void testMergeFromStream_repeatedField() throws Exception {
+ TestAllTypesLite.Builder builder = TestAllTypesLite.newBuilder()
+ .addRepeatedString("hello");
+ builder.mergeFrom(CodedInputStream.newInstance(builder.build().toByteArray()));
+
+ assertEquals(2, builder.getRepeatedStringCount());
+ }
+
+ public void testMergeFromStream_invalidBytes() throws Exception {
+ TestAllTypesLite.Builder builder = TestAllTypesLite.newBuilder()
+ .setDefaultBool(true);
+ try {
+ builder.mergeFrom(CodedInputStream.newInstance("Invalid bytes".getBytes(Internal.UTF_8)));
+ fail();
+ } catch (InvalidProtocolBufferException expected) {}
+ }
+
+ public void testMergeFrom_sanity() throws Exception {
+ TestAllTypesLite one = TestUtilLite.getAllLiteSetBuilder().build();
+ byte[] bytes = one.toByteArray();
+ TestAllTypesLite two = TestAllTypesLite.parseFrom(bytes);
+
+ one = one.toBuilder().mergeFrom(one).build();
+ two = two.toBuilder().mergeFrom(bytes).build();
+ assertEquals(one, two);
+ assertEquals(two, one);
+ assertEquals(one.hashCode(), two.hashCode());
+ }
+
+ public void testEquals_notEqual() throws Exception {
+ TestAllTypesLite one = TestUtilLite.getAllLiteSetBuilder().build();
+ byte[] bytes = one.toByteArray();
+ TestAllTypesLite two = one.toBuilder().mergeFrom(one).mergeFrom(bytes).build();
+
+ assertFalse(one.equals(two));
+ assertFalse(two.equals(one));
+
+ assertFalse(one.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(one));
+
+ TestAllTypesLite oneFieldSet = TestAllTypesLite.newBuilder()
+ .setDefaultBool(true)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setDefaultBytes(ByteString.EMPTY)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setDefaultCord("")
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setDefaultCordBytes(ByteString.EMPTY)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setDefaultDouble(0)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setDefaultFixed32(0)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setDefaultFixed64(0)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setDefaultFloat(0)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setDefaultForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setDefaultImportEnum(ImportEnumLite.IMPORT_LITE_BAR)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setDefaultInt32(0)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setDefaultInt64(0)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setDefaultNestedEnum(NestedEnum.BAR)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setDefaultSfixed32(0)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setDefaultSfixed64(0)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setDefaultSint32(0)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setDefaultSint64(0)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setDefaultString("")
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setDefaultStringBytes(ByteString.EMPTY)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setDefaultStringPiece("")
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setDefaultStringPieceBytes(ByteString.EMPTY)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setDefaultUint32(0)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setDefaultUint64(0)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .addRepeatedBool(true)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .addRepeatedBytes(ByteString.EMPTY)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .addRepeatedCord("")
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .addRepeatedCordBytes(ByteString.EMPTY)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .addRepeatedDouble(0)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .addRepeatedFixed32(0)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .addRepeatedFixed64(0)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .addRepeatedFloat(0)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .addRepeatedForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .addRepeatedImportEnum(ImportEnumLite.IMPORT_LITE_BAR)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .addRepeatedInt32(0)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .addRepeatedInt64(0)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .addRepeatedNestedEnum(NestedEnum.BAR)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .addRepeatedSfixed32(0)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .addRepeatedSfixed64(0)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .addRepeatedSint32(0)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .addRepeatedSint64(0)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .addRepeatedString("")
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .addRepeatedStringBytes(ByteString.EMPTY)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .addRepeatedStringPiece("")
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .addRepeatedStringPieceBytes(ByteString.EMPTY)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .addRepeatedUint32(0)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .addRepeatedUint64(0)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setOptionalBool(true)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setOptionalBytes(ByteString.EMPTY)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setOptionalCord("")
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setOptionalCordBytes(ByteString.EMPTY)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setOptionalDouble(0)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setOptionalFixed32(0)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setOptionalFixed64(0)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setOptionalFloat(0)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setOptionalForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setOptionalImportEnum(ImportEnumLite.IMPORT_LITE_BAR)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setOptionalInt32(0)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setOptionalInt64(0)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setOptionalNestedEnum(NestedEnum.BAR)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setOptionalSfixed32(0)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setOptionalSfixed64(0)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setOptionalSint32(0)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setOptionalSint64(0)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setOptionalString("")
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setOptionalStringBytes(ByteString.EMPTY)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setOptionalStringPiece("")
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setOptionalStringPieceBytes(ByteString.EMPTY)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setOptionalUint32(0)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setOptionalUint64(0)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setOneofBytes(ByteString.EMPTY)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setOneofLazyNestedMessage(NestedMessage.getDefaultInstance())
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setOneofNestedMessage(NestedMessage.getDefaultInstance())
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setOneofString("")
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setOneofStringBytes(ByteString.EMPTY)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setOneofUint32(0)
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setOptionalForeignMessage(ForeignMessageLite.getDefaultInstance())
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setOptionalGroup(OptionalGroup.getDefaultInstance())
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setOptionalPublicImportMessage(PublicImportMessageLite.getDefaultInstance())
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .setOptionalLazyMessage(NestedMessage.getDefaultInstance())
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+ oneFieldSet = TestAllTypesLite.newBuilder()
+ .addRepeatedLazyMessage(NestedMessage.getDefaultInstance())
+ .build();
+ assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+ assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+ }
+
+ public void testEquals() throws Exception {
+ // Check that two identical objs are equal.
+ Foo foo1a = Foo.newBuilder()
+ .setValue(1)
+ .addBar(Bar.newBuilder().setName("foo1"))
+ .build();
+ Foo foo1b = Foo.newBuilder()
+ .setValue(1)
+ .addBar(Bar.newBuilder().setName("foo1"))
+ .build();
+ Foo foo2 = Foo.newBuilder()
+ .setValue(1)
+ .addBar(Bar.newBuilder().setName("foo2"))
+ .build();
+
+ // Check that equals is doing value rather than object equality.
+ assertEquals(foo1a, foo1b);
+ assertEquals(foo1a.hashCode(), foo1b.hashCode());
+
+ // Check that a diffeent object is not equal.
+ assertFalse(foo1a.equals(foo2));
+
+ // Check that two objects which have different types but the same field values are not
+ // considered to be equal.
+ Bar bar = Bar.newBuilder().setName("bar").build();
+ BarPrime barPrime = BarPrime.newBuilder().setName("bar").build();
+ assertFalse(bar.equals(barPrime));
+ }
+
+ public void testOneofEquals() throws Exception {
+ TestOneofEquals.Builder builder = TestOneofEquals.newBuilder();
+ TestOneofEquals message1 = builder.build();
+ // Set message2's name field to default value. The two messages should be different when we
+ // check with the oneof case.
+ builder.setName("");
+ TestOneofEquals message2 = builder.build();
+ assertFalse(message1.equals(message2));
+ }
+
+ public void testEquals_sanity() throws Exception {
+ TestAllTypesLite one = TestUtilLite.getAllLiteSetBuilder().build();
+ TestAllTypesLite two = TestAllTypesLite.parseFrom(one.toByteArray());
+ assertEquals(one, two);
+ assertEquals(one.hashCode(), two.hashCode());
+
+ assertEquals(
+ one.toBuilder().mergeFrom(two).build(),
+ two.toBuilder().mergeFrom(two.toByteArray()).build());
+ }
+
+ public void testEqualsAndHashCodeWithUnknownFields() throws InvalidProtocolBufferException {
+ Foo fooWithOnlyValue = Foo.newBuilder()
+ .setValue(1)
+ .build();
+
+ Foo fooWithValueAndExtension = fooWithOnlyValue.toBuilder()
+ .setValue(1)
+ .setExtension(Bar.fooExt, Bar.newBuilder()
+ .setName("name")
+ .build())
+ .build();
+
+ Foo fooWithValueAndUnknownFields = Foo.parseFrom(fooWithValueAndExtension.toByteArray());
+
+ assertEqualsAndHashCodeAreFalse(fooWithOnlyValue, fooWithValueAndUnknownFields);
+ assertEqualsAndHashCodeAreFalse(fooWithValueAndExtension, fooWithValueAndUnknownFields);
+ }
+
+ // Test to ensure we avoid a class cast exception with oneofs.
+ public void testEquals_oneOfMessages() {
+ TestAllTypesLite mine = TestAllTypesLite.newBuilder()
+ .setOneofString("Hello")
+ .build();
+
+ TestAllTypesLite other = TestAllTypesLite.newBuilder()
+ .setOneofNestedMessage(NestedMessage.getDefaultInstance())
+ .build();
+
+ assertFalse(mine.equals(other));
+ assertFalse(other.equals(mine));
+ }
+
+ private void assertEqualsAndHashCodeAreFalse(Object o1, Object o2) {
+ assertFalse(o1.equals(o2));
+ assertFalse(o1.hashCode() == o2.hashCode());
+ }
+
+ public void testRecursiveHashcode() {
+ // This tests that we don't infinite loop.
+ TestRecursiveOneof.getDefaultInstance().hashCode();
+ }
}
diff --git a/java/core/src/test/java/com/google/protobuf/LiteralByteStringTest.java b/java/core/src/test/java/com/google/protobuf/LiteralByteStringTest.java
index 68b55ceb..2e7792a8 100644
--- a/java/core/src/test/java/com/google/protobuf/LiteralByteStringTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LiteralByteStringTest.java
@@ -47,9 +47,9 @@ import java.util.List;
import java.util.NoSuchElementException;
/**
- * Test {@link LiteralByteString} by setting up a reference string in {@link #setUp()}.
- * This class is designed to be extended for testing extensions of {@link LiteralByteString}
- * such as {@link BoundedByteString}, see {@link BoundedByteStringTest}.
+ * Test {@code LiteralByteString} by setting up a reference string in {@link #setUp()}.
+ * This class is designed to be extended for testing extensions of {@code LiteralByteString}
+ * such as {@code BoundedByteString}, see {@link BoundedByteStringTest}.
*
* @author carlanton@google.com (Carl Haverl)
*/
@@ -304,25 +304,75 @@ public class LiteralByteStringTest extends TestCase {
Arrays.equals(referenceBytes, roundTripBytes));
}
- public void testWriteTo_mutating() throws IOException {
+ public void testWriteToShouldNotExposeInternalBufferToOutputStream() throws IOException {
OutputStream os = new OutputStream() {
@Override
public void write(byte[] b, int off, int len) {
- for (int x = 0; x < len; ++x) {
- b[off + x] = (byte) 0;
- }
+ Arrays.fill(b, off, off + len, (byte) 0);
}
@Override
public void write(int b) {
- // Purposefully left blank.
+ throw new UnsupportedOperationException();
}
};
stringUnderTest.writeTo(os);
- byte[] newBytes = stringUnderTest.toByteArray();
assertTrue(classUnderTest + ".writeTo() must not grant access to underlying array",
- Arrays.equals(referenceBytes, newBytes));
+ Arrays.equals(referenceBytes, stringUnderTest.toByteArray()));
+ }
+
+ public void testWriteToInternalShouldExposeInternalBufferToOutputStream() throws IOException {
+ OutputStream os = new OutputStream() {
+ @Override
+ public void write(byte[] b, int off, int len) {
+ Arrays.fill(b, off, off + len, (byte) 0);
+ }
+
+ @Override
+ public void write(int b) {
+ throw new UnsupportedOperationException();
+ }
+ };
+
+ stringUnderTest.writeToInternal(os, 0, stringUnderTest.size());
+ byte[] allZeros = new byte[stringUnderTest.size()];
+ assertTrue(classUnderTest + ".writeToInternal() must grant access to underlying array",
+ Arrays.equals(allZeros, stringUnderTest.toByteArray()));
+ }
+
+ public void testWriteToShouldExposeInternalBufferToByteOutput() throws IOException {
+ ByteOutput out = new ByteOutput() {
+ @Override
+ public void write(byte value) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void write(byte[] value, int offset, int length) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void writeLazy(byte[] value, int offset, int length) throws IOException {
+ Arrays.fill(value, offset, offset + length, (byte) 0);
+ }
+
+ @Override
+ public void write(ByteBuffer value) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void writeLazy(ByteBuffer value) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+ };
+
+ stringUnderTest.writeTo(out);
+ byte[] allZeros = new byte[stringUnderTest.size()];
+ assertTrue(classUnderTest + ".writeToInternal() must grant access to underlying array",
+ Arrays.equals(allZeros, stringUnderTest.toByteArray()));
}
public void testNewOutput() throws IOException {
diff --git a/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java b/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java
index 1bd094f7..0a8f9ed2 100644
--- a/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java
@@ -73,20 +73,6 @@ public class LongArrayListTest extends TestCase {
assertImmutable(list);
}
- public void testCopyConstructor() {
- LongArrayList copy = new LongArrayList(TERTIARY_LIST);
- assertEquals(TERTIARY_LIST, copy);
-
- copy = new LongArrayList(LongArrayList.emptyList());
- assertEquals(LongArrayList.emptyList(), copy);
-
- copy = new LongArrayList(asList(1L, 2L, 3L));
- assertEquals(asList(1L, 2L, 3L), copy);
-
- copy = new LongArrayList(Collections.<Long>emptyList());
- assertEquals(LongArrayList.emptyList(), copy);
- }
-
public void testModificationWithIteration() {
list.addAll(asList(1L, 2L, 3L, 4L));
Iterator<Long> iterator = list.iterator();
diff --git a/java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java b/java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java
index 3d8c9bc4..d79d0029 100644
--- a/java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java
+++ b/java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java
@@ -432,7 +432,7 @@ public class MapForProto2LiteTest extends TestCase {
assertEquals(1, messageWithUnknownEnums.getInt32ToInt32Field().get(1).intValue());
assertEquals(54321, messageWithUnknownEnums.getInt32ToInt32Field().get(2).intValue());
}
-
+
public void testIterationOrder() throws Exception {
TestMap.Builder builder = TestMap.newBuilder();
diff --git a/java/core/src/test/java/com/google/protobuf/MapForProto2Test.java b/java/core/src/test/java/com/google/protobuf/MapForProto2Test.java
index 1fa3cbdb..73154c0f 100644
--- a/java/core/src/test/java/com/google/protobuf/MapForProto2Test.java
+++ b/java/core/src/test/java/com/google/protobuf/MapForProto2Test.java
@@ -36,7 +36,6 @@ import map_test.MapForProto2TestProto.TestMap.MessageValue;
import map_test.MapForProto2TestProto.TestMap.MessageWithRequiredFields;
import map_test.MapForProto2TestProto.TestRecursiveMap;
import map_test.MapForProto2TestProto.TestUnknownEnumValue;
-
import junit.framework.TestCase;
import java.util.ArrayList;
diff --git a/java/core/src/test/java/com/google/protobuf/MapTest.java b/java/core/src/test/java/com/google/protobuf/MapTest.java
index 0e5c1284..1dc5787d 100644
--- a/java/core/src/test/java/com/google/protobuf/MapTest.java
+++ b/java/core/src/test/java/com/google/protobuf/MapTest.java
@@ -37,7 +37,6 @@ import com.google.protobuf.Descriptors.FieldDescriptor;
import map_test.MapTestProto.TestMap;
import map_test.MapTestProto.TestMap.MessageValue;
import map_test.MapTestProto.TestOnChangeEventPropagation;
-
import junit.framework.TestCase;
import java.util.ArrayList;
diff --git a/java/core/src/test/java/com/google/protobuf/MessageTest.java b/java/core/src/test/java/com/google/protobuf/MessageTest.java
index abcd3a1d..dcd1aba7 100644
--- a/java/core/src/test/java/com/google/protobuf/MessageTest.java
+++ b/java/core/src/test/java/com/google/protobuf/MessageTest.java
@@ -30,11 +30,11 @@
package com.google.protobuf;
-import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.ForeignMessage;
import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestAllTypes;
import protobuf_unittest.UnittestProto.TestRequired;
import protobuf_unittest.UnittestProto.TestRequiredForeign;
-import protobuf_unittest.UnittestProto.ForeignMessage;
import junit.framework.TestCase;
diff --git a/java/core/src/test/java/com/google/protobuf/NestedBuildersTest.java b/java/core/src/test/java/com/google/protobuf/NestedBuildersTest.java
index 23653126..542e28c0 100644
--- a/java/core/src/test/java/com/google/protobuf/NestedBuildersTest.java
+++ b/java/core/src/test/java/com/google/protobuf/NestedBuildersTest.java
@@ -35,8 +35,8 @@ import protobuf_unittest.Wheel;
import junit.framework.TestCase;
-import java.util.List;
import java.util.ArrayList;
+import java.util.List;
/**
* Test cases that exercise end-to-end use cases involving
diff --git a/java/core/src/test/java/com/google/protobuf/NioByteStringTest.java b/java/core/src/test/java/com/google/protobuf/NioByteStringTest.java
index e40a3662..6be5b93c 100644
--- a/java/core/src/test/java/com/google/protobuf/NioByteStringTest.java
+++ b/java/core/src/test/java/com/google/protobuf/NioByteStringTest.java
@@ -41,6 +41,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
+import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
@@ -56,11 +57,12 @@ public class NioByteStringTest extends TestCase {
private static final String CLASSNAME = NioByteString.class.getSimpleName();
private static final byte[] BYTES = ByteStringTest.getTestBytes(1234, 11337766L);
private static final int EXPECTED_HASH = ByteString.wrap(BYTES).hashCode();
- private static final ByteBuffer BUFFER = ByteBuffer.wrap(BYTES.clone());
- private static final ByteString TEST_STRING = new NioByteString(BUFFER);
+
+ private final ByteBuffer backingBuffer = ByteBuffer.wrap(BYTES.clone());
+ private final ByteString testString = new NioByteString(backingBuffer);
public void testExpectedType() {
- String actualClassName = getActualClassName(TEST_STRING);
+ String actualClassName = getActualClassName(testString);
assertEquals(CLASSNAME + " should match type exactly", CLASSNAME, actualClassName);
}
@@ -73,14 +75,14 @@ public class NioByteStringTest extends TestCase {
public void testByteAt() {
boolean stillEqual = true;
for (int i = 0; stillEqual && i < BYTES.length; ++i) {
- stillEqual = (BYTES[i] == TEST_STRING.byteAt(i));
+ stillEqual = (BYTES[i] == testString.byteAt(i));
}
assertTrue(CLASSNAME + " must capture the right bytes", stillEqual);
}
public void testByteIterator() {
boolean stillEqual = true;
- ByteString.ByteIterator iter = TEST_STRING.iterator();
+ ByteString.ByteIterator iter = testString.iterator();
for (int i = 0; stillEqual && i < BYTES.length; ++i) {
stillEqual = (iter.hasNext() && BYTES[i] == iter.nextByte());
}
@@ -98,7 +100,7 @@ public class NioByteStringTest extends TestCase {
public void testByteIterable() {
boolean stillEqual = true;
int j = 0;
- for (byte quantum : TEST_STRING) {
+ for (byte quantum : testString) {
stillEqual = (BYTES[j] == quantum);
++j;
}
@@ -108,15 +110,15 @@ public class NioByteStringTest extends TestCase {
public void testSize() {
assertEquals(CLASSNAME + " must have the expected size", BYTES.length,
- TEST_STRING.size());
+ testString.size());
}
public void testGetTreeDepth() {
- assertEquals(CLASSNAME + " must have depth 0", 0, TEST_STRING.getTreeDepth());
+ assertEquals(CLASSNAME + " must have depth 0", 0, testString.getTreeDepth());
}
public void testIsBalanced() {
- assertTrue(CLASSNAME + " is technically balanced", TEST_STRING.isBalanced());
+ assertTrue(CLASSNAME + " is technically balanced", testString.isBalanced());
}
public void testCopyTo_ByteArrayOffsetLength() {
@@ -124,7 +126,7 @@ public class NioByteStringTest extends TestCase {
int length = 100;
byte[] destination = new byte[destinationOffset + length];
int sourceOffset = 213;
- TEST_STRING.copyTo(destination, sourceOffset, destinationOffset, length);
+ testString.copyTo(destination, sourceOffset, destinationOffset, length);
boolean stillEqual = true;
for (int i = 0; stillEqual && i < length; ++i) {
stillEqual = BYTES[i + sourceOffset] == destination[i + destinationOffset];
@@ -139,7 +141,7 @@ public class NioByteStringTest extends TestCase {
try {
// Copy one too many bytes
- TEST_STRING.copyTo(destination, TEST_STRING.size() + 1 - length,
+ testString.copyTo(destination, testString.size() + 1 - length,
destinationOffset, length);
fail("Should have thrown an exception when copying too many bytes of a "
+ CLASSNAME);
@@ -149,7 +151,7 @@ public class NioByteStringTest extends TestCase {
try {
// Copy with illegal negative sourceOffset
- TEST_STRING.copyTo(destination, -1, destinationOffset, length);
+ testString.copyTo(destination, -1, destinationOffset, length);
fail("Should have thrown an exception when given a negative sourceOffset in "
+ CLASSNAME);
} catch (IndexOutOfBoundsException expected) {
@@ -158,7 +160,7 @@ public class NioByteStringTest extends TestCase {
try {
// Copy with illegal negative destinationOffset
- TEST_STRING.copyTo(destination, 0, -1, length);
+ testString.copyTo(destination, 0, -1, length);
fail("Should have thrown an exception when given a negative destinationOffset in "
+ CLASSNAME);
} catch (IndexOutOfBoundsException expected) {
@@ -167,7 +169,7 @@ public class NioByteStringTest extends TestCase {
try {
// Copy with illegal negative size
- TEST_STRING.copyTo(destination, 0, 0, -1);
+ testString.copyTo(destination, 0, 0, -1);
fail("Should have thrown an exception when given a negative size in "
+ CLASSNAME);
} catch (IndexOutOfBoundsException expected) {
@@ -176,7 +178,7 @@ public class NioByteStringTest extends TestCase {
try {
// Copy with illegal too-large sourceOffset
- TEST_STRING.copyTo(destination, 2 * TEST_STRING.size(), 0, length);
+ testString.copyTo(destination, 2 * testString.size(), 0, length);
fail("Should have thrown an exception when the destinationOffset is too large in "
+ CLASSNAME);
} catch (IndexOutOfBoundsException expected) {
@@ -185,7 +187,7 @@ public class NioByteStringTest extends TestCase {
try {
// Copy with illegal too-large destinationOffset
- TEST_STRING.copyTo(destination, 0, 2 * destination.length, length);
+ testString.copyTo(destination, 0, 2 * destination.length, length);
fail("Should have thrown an exception when the destinationOffset is too large in "
+ CLASSNAME);
} catch (IndexOutOfBoundsException expected) {
@@ -196,21 +198,21 @@ public class NioByteStringTest extends TestCase {
public void testCopyTo_ByteBuffer() {
// Same length.
ByteBuffer myBuffer = ByteBuffer.allocate(BYTES.length);
- TEST_STRING.copyTo(myBuffer);
+ testString.copyTo(myBuffer);
myBuffer.flip();
assertEquals(CLASSNAME + ".copyTo(ByteBuffer) must give back the same bytes",
- BUFFER, myBuffer);
+ backingBuffer, myBuffer);
// Target buffer bigger than required.
- myBuffer = ByteBuffer.allocate(TEST_STRING.size() + 1);
- TEST_STRING.copyTo(myBuffer);
+ myBuffer = ByteBuffer.allocate(testString.size() + 1);
+ testString.copyTo(myBuffer);
myBuffer.flip();
- assertEquals(BUFFER, myBuffer);
+ assertEquals(backingBuffer, myBuffer);
// Target buffer has no space.
myBuffer = ByteBuffer.allocate(0);
try {
- TEST_STRING.copyTo(myBuffer);
+ testString.copyTo(myBuffer);
fail("Should have thrown an exception when target ByteBuffer has insufficient capacity");
} catch (BufferOverflowException e) {
// Expected.
@@ -219,7 +221,7 @@ public class NioByteStringTest extends TestCase {
// Target buffer too small.
myBuffer = ByteBuffer.allocate(1);
try {
- TEST_STRING.copyTo(myBuffer);
+ testString.copyTo(myBuffer);
fail("Should have thrown an exception when target ByteBuffer has insufficient capacity");
} catch (BufferOverflowException e) {
// Expected.
@@ -227,26 +229,26 @@ public class NioByteStringTest extends TestCase {
}
public void testMarkSupported() {
- InputStream stream = TEST_STRING.newInput();
+ InputStream stream = testString.newInput();
assertTrue(CLASSNAME + ".newInput() must support marking", stream.markSupported());
}
public void testMarkAndReset() throws IOException {
- int fraction = TEST_STRING.size() / 3;
+ int fraction = testString.size() / 3;
- InputStream stream = TEST_STRING.newInput();
- stream.mark(TEST_STRING.size()); // First, mark() the end.
+ InputStream stream = testString.newInput();
+ stream.mark(testString.size()); // First, mark() the end.
skipFully(stream, fraction); // Skip a large fraction, but not all.
assertEquals(
CLASSNAME + ": after skipping to the 'middle', half the bytes are available",
- (TEST_STRING.size() - fraction), stream.available());
+ (testString.size() - fraction), stream.available());
stream.reset();
assertEquals(
CLASSNAME + ": after resetting, all bytes are available",
- TEST_STRING.size(), stream.available());
+ testString.size(), stream.available());
- skipFully(stream, TEST_STRING.size()); // Skip to the end.
+ skipFully(stream, testString.size()); // Skip to the end.
assertEquals(
CLASSNAME + ": after skipping to the end, no more bytes are available",
0, stream.available());
@@ -284,7 +286,7 @@ public class NioByteStringTest extends TestCase {
}
public void testAsReadOnlyByteBuffer() {
- ByteBuffer byteBuffer = TEST_STRING.asReadOnlyByteBuffer();
+ ByteBuffer byteBuffer = testString.asReadOnlyByteBuffer();
byte[] roundTripBytes = new byte[BYTES.length];
assertTrue(byteBuffer.remaining() == BYTES.length);
assertTrue(byteBuffer.isReadOnly());
@@ -294,7 +296,7 @@ public class NioByteStringTest extends TestCase {
}
public void testAsReadOnlyByteBufferList() {
- List<ByteBuffer> byteBuffers = TEST_STRING.asReadOnlyByteBufferList();
+ List<ByteBuffer> byteBuffers = testString.asReadOnlyByteBufferList();
int bytesSeen = 0;
byte[] roundTripBytes = new byte[BYTES.length];
for (ByteBuffer byteBuffer : byteBuffers) {
@@ -310,25 +312,98 @@ public class NioByteStringTest extends TestCase {
}
public void testToByteArray() {
- byte[] roundTripBytes = TEST_STRING.toByteArray();
+ byte[] roundTripBytes = testString.toByteArray();
assertTrue(CLASSNAME + ".toByteArray() must give back the same bytes",
Arrays.equals(BYTES, roundTripBytes));
}
public void testWriteTo() throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
- TEST_STRING.writeTo(bos);
+ testString.writeTo(bos);
byte[] roundTripBytes = bos.toByteArray();
assertTrue(CLASSNAME + ".writeTo() must give back the same bytes",
Arrays.equals(BYTES, roundTripBytes));
}
+ public void testWriteToShouldNotExposeInternalBufferToOutputStream() throws IOException {
+ OutputStream os = new OutputStream() {
+ @Override
+ public void write(byte[] b, int off, int len) {
+ Arrays.fill(b, off, off + len, (byte) 0);
+ }
+
+ @Override
+ public void write(int b) {
+ throw new UnsupportedOperationException();
+ }
+ };
+
+ byte[] original = Arrays.copyOf(BYTES, BYTES.length);
+ testString.writeTo(os);
+ assertTrue(CLASSNAME + ".writeTo() must NOT grant access to underlying buffer",
+ Arrays.equals(original, BYTES));
+ }
+
+ public void testWriteToInternalShouldExposeInternalBufferToOutputStream() throws IOException {
+ OutputStream os = new OutputStream() {
+ @Override
+ public void write(byte[] b, int off, int len) {
+ Arrays.fill(b, off, off + len, (byte) 0);
+ }
+
+ @Override
+ public void write(int b) {
+ throw new UnsupportedOperationException();
+ }
+ };
+
+ testString.writeToInternal(os, 0, testString.size());
+ byte[] allZeros = new byte[testString.size()];
+ assertTrue(CLASSNAME + ".writeToInternal() must grant access to underlying buffer",
+ Arrays.equals(allZeros, backingBuffer.array()));
+ }
+
+ public void testWriteToShouldExposeInternalBufferToByteOutput() throws IOException {
+ ByteOutput out = new ByteOutput() {
+ @Override
+ public void write(byte value) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void write(byte[] value, int offset, int length) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void writeLazy(byte[] value, int offset, int length) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void write(ByteBuffer value) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void writeLazy(ByteBuffer value) throws IOException {
+ Arrays.fill(value.array(), value.arrayOffset(), value.arrayOffset() + value.limit(),
+ (byte) 0);
+ }
+ };
+
+ testString.writeTo(out);
+ byte[] allZeros = new byte[testString.size()];
+ assertTrue(CLASSNAME + ".writeTo() must grant access to underlying buffer",
+ Arrays.equals(allZeros, backingBuffer.array()));
+ }
+
public void testNewOutput() throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ByteString.Output output = ByteString.newOutput();
- TEST_STRING.writeTo(output);
+ testString.writeTo(output);
assertEquals("Output Size returns correct result",
- output.size(), TEST_STRING.size());
+ output.size(), testString.size());
output.writeTo(bos);
assertTrue("Output.writeTo() must give back the same bytes",
Arrays.equals(BYTES, bos.toByteArray()));
@@ -336,7 +411,7 @@ public class NioByteStringTest extends TestCase {
// write the output stream to itself! This should cause it to double
output.writeTo(output);
assertEquals("Writing an output stream to itself is successful",
- TEST_STRING.concat(TEST_STRING), output.toByteString());
+ testString.concat(testString), output.toByteString());
output.reset();
assertEquals("Output.reset() resets the output", 0, output.size());
@@ -373,7 +448,7 @@ public class NioByteStringTest extends TestCase {
}
try {
- TEST_STRING.toString("invalid");
+ testString.toString("invalid");
fail("Should have thrown an exception.");
} catch (UnsupportedEncodingException expected) {
// This is success
@@ -381,36 +456,36 @@ public class NioByteStringTest extends TestCase {
}
public void testEquals() {
- assertEquals(CLASSNAME + " must not equal null", false, TEST_STRING.equals(null));
- assertEquals(CLASSNAME + " must equal self", TEST_STRING, TEST_STRING);
+ assertEquals(CLASSNAME + " must not equal null", false, testString.equals(null));
+ assertEquals(CLASSNAME + " must equal self", testString, testString);
assertFalse(CLASSNAME + " must not equal the empty string",
- TEST_STRING.equals(EMPTY));
+ testString.equals(EMPTY));
assertEquals(CLASSNAME + " empty strings must be equal",
- EMPTY, TEST_STRING.substring(55, 55));
+ EMPTY, testString.substring(55, 55));
assertEquals(CLASSNAME + " must equal another string with the same value",
- TEST_STRING, new NioByteString(BUFFER));
+ testString, new NioByteString(backingBuffer));
byte[] mungedBytes = mungedBytes();
assertFalse(CLASSNAME + " must not equal every string with the same length",
- TEST_STRING.equals(new NioByteString(ByteBuffer.wrap(mungedBytes))));
+ testString.equals(new NioByteString(ByteBuffer.wrap(mungedBytes))));
}
public void testEqualsLiteralByteString() {
ByteString literal = ByteString.copyFrom(BYTES);
assertEquals(CLASSNAME + " must equal LiteralByteString with same value", literal,
- TEST_STRING);
- assertEquals(CLASSNAME + " must equal LiteralByteString with same value", TEST_STRING,
+ testString);
+ assertEquals(CLASSNAME + " must equal LiteralByteString with same value", testString,
literal);
assertFalse(CLASSNAME + " must not equal the empty string",
- TEST_STRING.equals(ByteString.EMPTY));
+ testString.equals(ByteString.EMPTY));
assertEquals(CLASSNAME + " empty strings must be equal",
- ByteString.EMPTY, TEST_STRING.substring(55, 55));
+ ByteString.EMPTY, testString.substring(55, 55));
literal = ByteString.copyFrom(mungedBytes());
assertFalse(CLASSNAME + " must not equal every LiteralByteString with the same length",
- TEST_STRING.equals(literal));
+ testString.equals(literal));
assertFalse(CLASSNAME + " must not equal every LiteralByteString with the same length",
- literal.equals(TEST_STRING));
+ literal.equals(testString));
}
public void testEqualsRopeByteString() {
@@ -419,22 +494,22 @@ public class NioByteStringTest extends TestCase {
ByteString rope = p1.concat(p2);
assertEquals(CLASSNAME + " must equal RopeByteString with same value", rope,
- TEST_STRING);
- assertEquals(CLASSNAME + " must equal RopeByteString with same value", TEST_STRING,
+ testString);
+ assertEquals(CLASSNAME + " must equal RopeByteString with same value", testString,
rope);
assertFalse(CLASSNAME + " must not equal the empty string",
- TEST_STRING.equals(ByteString.EMPTY.concat(ByteString.EMPTY)));
+ testString.equals(ByteString.EMPTY.concat(ByteString.EMPTY)));
assertEquals(CLASSNAME + " empty strings must be equal",
- ByteString.EMPTY.concat(ByteString.EMPTY), TEST_STRING.substring(55, 55));
+ ByteString.EMPTY.concat(ByteString.EMPTY), testString.substring(55, 55));
byte[] mungedBytes = mungedBytes();
p1 = ByteString.copyFrom(mungedBytes, 0, 5);
p2 = ByteString.copyFrom(mungedBytes, 5, mungedBytes.length - 5);
rope = p1.concat(p2);
assertFalse(CLASSNAME + " must not equal every RopeByteString with the same length",
- TEST_STRING.equals(rope));
+ testString.equals(rope));
assertFalse(CLASSNAME + " must not equal every RopeByteString with the same length",
- rope.equals(TEST_STRING));
+ rope.equals(testString));
}
private byte[] mungedBytes() {
@@ -445,12 +520,12 @@ public class NioByteStringTest extends TestCase {
}
public void testHashCode() {
- int hash = TEST_STRING.hashCode();
+ int hash = testString.hashCode();
assertEquals(CLASSNAME + " must have expected hashCode", EXPECTED_HASH, hash);
}
public void testPeekCachedHashCode() {
- ByteString newString = new NioByteString(BUFFER);
+ ByteString newString = new NioByteString(backingBuffer);
assertEquals(CLASSNAME + ".peekCachedHashCode() should return zero at first", 0,
newString.peekCachedHashCode());
newString.hashCode();
@@ -461,15 +536,15 @@ public class NioByteStringTest extends TestCase {
public void testPartialHash() {
// partialHash() is more strenuously tested elsewhere by testing hashes of substrings.
// This test would fail if the expected hash were 1. It's not.
- int hash = TEST_STRING.partialHash(TEST_STRING.size(), 0, TEST_STRING.size());
+ int hash = testString.partialHash(testString.size(), 0, testString.size());
assertEquals(CLASSNAME + ".partialHash() must yield expected hashCode",
EXPECTED_HASH, hash);
}
public void testNewInput() throws IOException {
- InputStream input = TEST_STRING.newInput();
+ InputStream input = testString.newInput();
assertEquals("InputStream.available() returns correct value",
- TEST_STRING.size(), input.available());
+ testString.size(), input.available());
boolean stillEqual = true;
for (byte referenceByte : BYTES) {
int expectedInt = (referenceByte & 0xFF);
@@ -482,8 +557,8 @@ public class NioByteStringTest extends TestCase {
}
public void testNewInput_skip() throws IOException {
- InputStream input = TEST_STRING.newInput();
- int stringSize = TEST_STRING.size();
+ InputStream input = testString.newInput();
+ int stringSize = testString.size();
int nearEndIndex = stringSize * 2 / 3;
long skipped1 = input.skip(nearEndIndex);
assertEquals("InputStream.skip()", skipped1, nearEndIndex);
@@ -492,7 +567,7 @@ public class NioByteStringTest extends TestCase {
assertTrue("InputStream.mark() is available", input.markSupported());
input.mark(0);
assertEquals("InputStream.skip(), read()",
- TEST_STRING.byteAt(nearEndIndex) & 0xFF, input.read());
+ testString.byteAt(nearEndIndex) & 0xFF, input.read());
assertEquals("InputStream.available()",
stringSize - skipped1 - 1, input.available());
long skipped2 = input.skip(stringSize);
@@ -504,11 +579,11 @@ public class NioByteStringTest extends TestCase {
assertEquals("InputStream.reset() succeded",
stringSize - skipped1, input.available());
assertEquals("InputStream.reset(), read()",
- TEST_STRING.byteAt(nearEndIndex) & 0xFF, input.read());
+ testString.byteAt(nearEndIndex) & 0xFF, input.read());
}
public void testNewCodedInput() throws IOException {
- CodedInputStream cis = TEST_STRING.newCodedInput();
+ CodedInputStream cis = testString.newCodedInput();
byte[] roundTripBytes = cis.readRawBytes(BYTES.length);
assertTrue(CLASSNAME + " must give the same bytes back from the CodedInputStream",
Arrays.equals(BYTES, roundTripBytes));
@@ -521,22 +596,22 @@ public class NioByteStringTest extends TestCase {
*/
public void testConcat_empty() {
assertSame(CLASSNAME + " concatenated with empty must give " + CLASSNAME,
- TEST_STRING.concat(EMPTY), TEST_STRING);
+ testString.concat(EMPTY), testString);
assertSame("empty concatenated with " + CLASSNAME + " must give " + CLASSNAME,
- EMPTY.concat(TEST_STRING), TEST_STRING);
+ EMPTY.concat(testString), testString);
}
public void testJavaSerialization() throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(out);
- oos.writeObject(TEST_STRING);
+ oos.writeObject(testString);
oos.close();
byte[] pickled = out.toByteArray();
InputStream in = new ByteArrayInputStream(pickled);
ObjectInputStream ois = new ObjectInputStream(in);
Object o = ois.readObject();
assertTrue("Didn't get a ByteString back", o instanceof ByteString);
- assertEquals("Should get an equal ByteString back", TEST_STRING, o);
+ assertEquals("Should get an equal ByteString back", testString, o);
}
private static ByteString forString(String str) {
diff --git a/java/core/src/test/java/com/google/protobuf/ParseExceptionsTest.java b/java/core/src/test/java/com/google/protobuf/ParseExceptionsTest.java
index 37fa242d..bf1f1d71 100644
--- a/java/core/src/test/java/com/google/protobuf/ParseExceptionsTest.java
+++ b/java/core/src/test/java/com/google/protobuf/ParseExceptionsTest.java
@@ -1,17 +1,51 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
package com.google.protobuf;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
import com.google.protobuf.DescriptorProtos.DescriptorProto;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
/**
* Tests the exceptions thrown when parsing from a stream. The methods on the {@link Parser}
@@ -22,6 +56,7 @@ import static org.junit.Assert.fail;
*
* @author jh@squareup.com (Joshua Humphries)
*/
+@RunWith(JUnit4.class)
public class ParseExceptionsTest {
private interface ParseTester {
@@ -46,116 +81,143 @@ public class ParseExceptionsTest {
@Test public void message_parseFrom_InputStream() {
setup();
- verifyExceptions(new ParseTester() {
- public DescriptorProto parse(InputStream in) throws IOException {
- return DescriptorProto.parseFrom(in);
- }
- });
+ verifyExceptions(
+ new ParseTester() {
+ @Override
+ public DescriptorProto parse(InputStream in) throws IOException {
+ return DescriptorProto.parseFrom(in);
+ }
+ });
}
@Test public void message_parseFrom_InputStreamAndExtensionRegistry() {
setup();
- verifyExceptions(new ParseTester() {
- public DescriptorProto parse(InputStream in) throws IOException {
- return DescriptorProto.parseFrom(in, ExtensionRegistry.newInstance());
- }
- });
+ verifyExceptions(
+ new ParseTester() {
+ @Override
+ public DescriptorProto parse(InputStream in) throws IOException {
+ return DescriptorProto.parseFrom(in, ExtensionRegistry.newInstance());
+ }
+ });
}
@Test public void message_parseFrom_CodedInputStream() {
setup();
- verifyExceptions(new ParseTester() {
- public DescriptorProto parse(InputStream in) throws IOException {
- return DescriptorProto.parseFrom(CodedInputStream.newInstance(in));
- }
- });
+ verifyExceptions(
+ new ParseTester() {
+ @Override
+ public DescriptorProto parse(InputStream in) throws IOException {
+ return DescriptorProto.parseFrom(CodedInputStream.newInstance(in));
+ }
+ });
}
@Test public void message_parseFrom_CodedInputStreamAndExtensionRegistry() {
setup();
- verifyExceptions(new ParseTester() {
- public DescriptorProto parse(InputStream in) throws IOException {
- return DescriptorProto.parseFrom(CodedInputStream.newInstance(in),
- ExtensionRegistry.newInstance());
- }
- });
+ verifyExceptions(
+ new ParseTester() {
+ @Override
+ public DescriptorProto parse(InputStream in) throws IOException {
+ return DescriptorProto.parseFrom(
+ CodedInputStream.newInstance(in), ExtensionRegistry.newInstance());
+ }
+ });
}
@Test public void message_parseDelimitedFrom_InputStream() {
setupDelimited();
- verifyExceptions(new ParseTester() {
- public DescriptorProto parse(InputStream in) throws IOException {
- return DescriptorProto.parseDelimitedFrom(in);
- }
- });
+ verifyExceptions(
+ new ParseTester() {
+ @Override
+ public DescriptorProto parse(InputStream in) throws IOException {
+ return DescriptorProto.parseDelimitedFrom(in);
+ }
+ });
}
@Test public void message_parseDelimitedFrom_InputStreamAndExtensionRegistry() {
setupDelimited();
- verifyExceptions(new ParseTester() {
- public DescriptorProto parse(InputStream in) throws IOException {
- return DescriptorProto.parseDelimitedFrom(in, ExtensionRegistry.newInstance());
- }
- });
+ verifyExceptions(
+ new ParseTester() {
+ @Override
+ public DescriptorProto parse(InputStream in) throws IOException {
+ return DescriptorProto.parseDelimitedFrom(in, ExtensionRegistry.newInstance());
+ }
+ });
}
@Test public void messageBuilder_mergeFrom_InputStream() {
setup();
- verifyExceptions(new ParseTester() {
- public DescriptorProto parse(InputStream in) throws IOException {
- return DescriptorProto.newBuilder().mergeFrom(in).build();
- }
- });
+ verifyExceptions(
+ new ParseTester() {
+ @Override
+ public DescriptorProto parse(InputStream in) throws IOException {
+ return DescriptorProto.newBuilder().mergeFrom(in).build();
+ }
+ });
}
@Test public void messageBuilder_mergeFrom_InputStreamAndExtensionRegistry() {
setup();
- verifyExceptions(new ParseTester() {
- public DescriptorProto parse(InputStream in) throws IOException {
- return DescriptorProto.newBuilder().mergeFrom(in, ExtensionRegistry.newInstance()).build();
- }
- });
+ verifyExceptions(
+ new ParseTester() {
+ @Override
+ public DescriptorProto parse(InputStream in) throws IOException {
+ return DescriptorProto.newBuilder()
+ .mergeFrom(in, ExtensionRegistry.newInstance())
+ .build();
+ }
+ });
}
@Test public void messageBuilder_mergeFrom_CodedInputStream() {
setup();
- verifyExceptions(new ParseTester() {
- public DescriptorProto parse(InputStream in) throws IOException {
- return DescriptorProto.newBuilder().mergeFrom(CodedInputStream.newInstance(in)).build();
- }
- });
+ verifyExceptions(
+ new ParseTester() {
+ @Override
+ public DescriptorProto parse(InputStream in) throws IOException {
+ return DescriptorProto.newBuilder().mergeFrom(CodedInputStream.newInstance(in)).build();
+ }
+ });
}
@Test public void messageBuilder_mergeFrom_CodedInputStreamAndExtensionRegistry() {
setup();
- verifyExceptions(new ParseTester() {
- public DescriptorProto parse(InputStream in) throws IOException {
- return DescriptorProto.newBuilder()
- .mergeFrom(CodedInputStream.newInstance(in), ExtensionRegistry.newInstance()).build();
- }
- });
+ verifyExceptions(
+ new ParseTester() {
+ @Override
+ public DescriptorProto parse(InputStream in) throws IOException {
+ return DescriptorProto.newBuilder()
+ .mergeFrom(CodedInputStream.newInstance(in), ExtensionRegistry.newInstance())
+ .build();
+ }
+ });
}
@Test public void messageBuilder_mergeDelimitedFrom_InputStream() {
setupDelimited();
- verifyExceptions(new ParseTester() {
- public DescriptorProto parse(InputStream in) throws IOException {
- DescriptorProto.Builder builder = DescriptorProto.newBuilder();
- builder.mergeDelimitedFrom(in);
- return builder.build();
- }
- });
+ verifyExceptions(
+ new ParseTester() {
+ @Override
+ public DescriptorProto parse(InputStream in) throws IOException {
+ DescriptorProto.Builder builder = DescriptorProto.newBuilder();
+ builder.mergeDelimitedFrom(in);
+ return builder.build();
+ }
+ });
}
@Test public void messageBuilder_mergeDelimitedFrom_InputStreamAndExtensionRegistry() {
setupDelimited();
- verifyExceptions(new ParseTester() {
- public DescriptorProto parse(InputStream in) throws IOException {
- DescriptorProto.Builder builder = DescriptorProto.newBuilder();
- builder.mergeDelimitedFrom(in, ExtensionRegistry.newInstance());
- return builder.build();
- }
- });
+ verifyExceptions(
+ new ParseTester() {
+ @Override
+ public DescriptorProto parse(InputStream in) throws IOException {
+ DescriptorProto.Builder builder = DescriptorProto.newBuilder();
+ builder.mergeDelimitedFrom(in, ExtensionRegistry.newInstance());
+ return builder.build();
+ }
+ });
}
private void verifyExceptions(ParseTester parseTester) {
diff --git a/java/core/src/test/java/com/google/protobuf/ParserTest.java b/java/core/src/test/java/com/google/protobuf/ParserTest.java
index 5a92bacf..30842d2c 100644
--- a/java/core/src/test/java/com/google/protobuf/ParserTest.java
+++ b/java/core/src/test/java/com/google/protobuf/ParserTest.java
@@ -33,15 +33,15 @@ package com.google.protobuf;
import com.google.protobuf.UnittestLite.TestAllTypesLite;
import com.google.protobuf.UnittestLite.TestPackedExtensionsLite;
import com.google.protobuf.UnittestLite.TestParsingMergeLite;
+import protobuf_unittest.UnittestOptimizeFor;
import protobuf_unittest.UnittestOptimizeFor.TestOptimizedForSize;
import protobuf_unittest.UnittestOptimizeFor.TestRequiredOptimizedForSize;
-import protobuf_unittest.UnittestOptimizeFor;
+import protobuf_unittest.UnittestProto;
import protobuf_unittest.UnittestProto.ForeignMessage;
import protobuf_unittest.UnittestProto.TestAllTypes;
import protobuf_unittest.UnittestProto.TestEmptyMessage;
import protobuf_unittest.UnittestProto.TestParsingMerge;
import protobuf_unittest.UnittestProto.TestRequired;
-import protobuf_unittest.UnittestProto;
import junit.framework.TestCase;
@@ -179,16 +179,16 @@ public class ParserTest extends TestCase {
public void testParseExtensions() throws Exception {
assertRoundTripEquals(TestUtil.getAllExtensionsSet(),
TestUtil.getExtensionRegistry());
- assertRoundTripEquals(TestUtil.getAllLiteExtensionsSet(),
- TestUtil.getExtensionRegistryLite());
+ assertRoundTripEquals(
+ TestUtilLite.getAllLiteExtensionsSet(), TestUtilLite.getExtensionRegistryLite());
}
public void testParsePacked() throws Exception {
assertRoundTripEquals(TestUtil.getPackedSet());
assertRoundTripEquals(TestUtil.getPackedExtensionsSet(),
TestUtil.getExtensionRegistry());
- assertRoundTripEquals(TestUtil.getLitePackedExtensionsSet(),
- TestUtil.getExtensionRegistryLite());
+ assertRoundTripEquals(
+ TestUtilLite.getLitePackedExtensionsSet(), TestUtilLite.getExtensionRegistryLite());
}
public void testParseDelimitedTo() throws Exception {
@@ -198,8 +198,7 @@ public class ParserTest extends TestCase {
normalMessage.writeDelimitedTo(output);
// Write MessageLite with packed extension fields.
- TestPackedExtensionsLite packedMessage =
- TestUtil.getLitePackedExtensionsSet();
+ TestPackedExtensionsLite packedMessage = TestUtilLite.getLitePackedExtensionsSet();
packedMessage.writeDelimitedTo(output);
InputStream input = new ByteArrayInputStream(output.toByteArray());
@@ -208,8 +207,9 @@ public class ParserTest extends TestCase {
normalMessage.getParserForType().parseDelimitedFrom(input));
assertMessageEquals(
packedMessage,
- packedMessage.getParserForType().parseDelimitedFrom(
- input, TestUtil.getExtensionRegistryLite()));
+ packedMessage
+ .getParserForType()
+ .parseDelimitedFrom(input, TestUtilLite.getExtensionRegistryLite()));
}
public void testParseUnknownFields() throws Exception {
diff --git a/java/core/src/test/java/com/google/protobuf/ProtobufArrayListTest.java b/java/core/src/test/java/com/google/protobuf/ProtobufArrayListTest.java
index 245c3dee..3f45e226 100644
--- a/java/core/src/test/java/com/google/protobuf/ProtobufArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/ProtobufArrayListTest.java
@@ -63,20 +63,6 @@ public class ProtobufArrayListTest extends TestCase {
assertImmutable(ProtobufArrayList.<Integer>emptyList());
}
- public void testCopyConstructor() {
- ProtobufArrayList<Integer> copy = new ProtobufArrayList<Integer>(TERTIARY_LIST);
- assertEquals(TERTIARY_LIST, copy);
-
- copy = new ProtobufArrayList<Integer>(IntArrayList.emptyList());
- assertEquals(ProtobufArrayList.emptyList(), copy);
-
- copy = new ProtobufArrayList<Integer>(asList(1, 2, 3));
- assertEquals(asList(1, 2, 3), copy);
-
- copy = new ProtobufArrayList<Integer>(Collections.<Integer>emptyList());
- assertEquals(ProtobufArrayList.emptyList(), copy);
- }
-
public void testModificationWithIteration() {
list.addAll(asList(1, 2, 3, 4));
Iterator<Integer> iterator = list.iterator();
diff --git a/java/core/src/test/java/com/google/protobuf/ServiceTest.java b/java/core/src/test/java/com/google/protobuf/ServiceTest.java
index ff980d66..b902737d 100644
--- a/java/core/src/test/java/com/google/protobuf/ServiceTest.java
+++ b/java/core/src/test/java/com/google/protobuf/ServiceTest.java
@@ -35,22 +35,22 @@ import com.google.protobuf.Descriptors.MethodDescriptor;
import google.protobuf.no_generic_services_test.UnittestNoGenericServices;
import protobuf_unittest.MessageWithNoOuter;
import protobuf_unittest.ServiceWithNoOuter;
-import protobuf_unittest.UnittestProto.TestAllTypes;
-import protobuf_unittest.UnittestProto.TestService;
-import protobuf_unittest.UnittestProto.FooRequest;
-import protobuf_unittest.UnittestProto.FooResponse;
import protobuf_unittest.UnittestProto.BarRequest;
import protobuf_unittest.UnittestProto.BarResponse;
+import protobuf_unittest.UnittestProto.FooRequest;
+import protobuf_unittest.UnittestProto.FooResponse;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestService;
+
+import junit.framework.TestCase;
import org.easymock.classextension.EasyMock;
-import org.easymock.classextension.IMocksControl;
import org.easymock.IArgumentMatcher;
+import org.easymock.classextension.IMocksControl;
import java.util.HashSet;
import java.util.Set;
-import junit.framework.TestCase;
-
/**
* Tests services and stubs.
*
@@ -175,12 +175,14 @@ public class ServiceTest extends TestCase {
MethodDescriptor fooMethod =
ServiceWithNoOuter.getDescriptor().findMethodByName("Foo");
MessageWithNoOuter request = MessageWithNoOuter.getDefaultInstance();
- RpcCallback<Message> callback = new RpcCallback<Message>() {
- public void run(Message parameter) {
- // No reason this should be run.
- fail();
- }
- };
+ RpcCallback<Message> callback =
+ new RpcCallback<Message>() {
+ @Override
+ public void run(Message parameter) {
+ // No reason this should be run.
+ fail();
+ }
+ };
RpcCallback<TestAllTypes> specializedCallback =
RpcUtil.specializeCallback(callback);
@@ -290,7 +292,9 @@ public class ServiceTest extends TestCase {
public boolean isCalled() { return called; }
public void reset() { called = false; }
- public void run(Type message) { called = true; }
+ @Override
+ public void run(Type message) {
+ called = true; }
}
/** Implementation of the wrapsCallback() argument matcher. */
@@ -301,6 +305,7 @@ public class ServiceTest extends TestCase {
this.callback = callback;
}
+ @Override
@SuppressWarnings("unchecked")
public boolean matches(Object actual) {
if (!(actual instanceof RpcCallback)) {
@@ -313,6 +318,7 @@ public class ServiceTest extends TestCase {
return callback.isCalled();
}
+ @Override
public void appendTo(StringBuffer buffer) {
buffer.append("wrapsCallback(mockCallback)");
}
diff --git a/java/core/src/test/java/com/google/protobuf/SmallSortedMapTest.java b/java/core/src/test/java/com/google/protobuf/SmallSortedMapTest.java
index 366086d3..e96ecd65 100644
--- a/java/core/src/test/java/com/google/protobuf/SmallSortedMapTest.java
+++ b/java/core/src/test/java/com/google/protobuf/SmallSortedMapTest.java
@@ -56,14 +56,17 @@ public class SmallSortedMapTest extends TestCase {
this.value = value;
}
+ @Override
public K getKey() {
return key;
}
+ @Override
public V getValue() {
return value;
}
+ @Override
public V setValue(V value) {
V oldValue = this.value;
this.value = value;
diff --git a/java/core/src/test/java/com/google/protobuf/TestUtil.java b/java/core/src/test/java/com/google/protobuf/TestUtil.java
index 01acb884..08b2a76d 100644
--- a/java/core/src/test/java/com/google/protobuf/TestUtil.java
+++ b/java/core/src/test/java/com/google/protobuf/TestUtil.java
@@ -30,205 +30,200 @@
package com.google.protobuf;
-import protobuf_unittest.UnittestProto;
-import com.google.protobuf.UnittestLite;
-
+import static com.google.protobuf.UnittestLite.defaultBoolExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultBytesExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultCordExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultDoubleExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultFixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultFixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultFloatExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultForeignEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultImportEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultInt32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultInt64ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultNestedEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultSfixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultSfixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultSint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultSint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultStringExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultStringPieceExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultUint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.oneofBytesExtensionLite;
+import static com.google.protobuf.UnittestLite.oneofNestedMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.oneofStringExtensionLite;
+import static com.google.protobuf.UnittestLite.oneofUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalBoolExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalBytesExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalCordExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalDoubleExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalFixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalFixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalFloatExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalForeignEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalForeignMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalGroupExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalImportEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalImportMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalInt32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalInt64ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalLazyMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalNestedEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalNestedMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalPublicImportMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalSfixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalSfixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalSint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalSint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalStringExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalStringPieceExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalUint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedBoolExtensionLite;
+import static com.google.protobuf.UnittestLite.packedDoubleExtensionLite;
+import static com.google.protobuf.UnittestLite.packedEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.packedFixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedFixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedFloatExtensionLite;
+import static com.google.protobuf.UnittestLite.packedInt32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedInt64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedSfixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedSfixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedSint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedSint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedUint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedBoolExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedBytesExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedCordExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedDoubleExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedFixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedFixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedFloatExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedForeignEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedForeignMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedGroupExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedImportEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedImportMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedInt32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedInt64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedLazyMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedNestedEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedNestedMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedSfixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedSfixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedSint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedSint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedStringExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedStringPieceExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedUint64ExtensionLite;
+import static protobuf_unittest.UnittestProto.OptionalGroup_extension;
+import static protobuf_unittest.UnittestProto.RepeatedGroup_extension;
+import static protobuf_unittest.UnittestProto.defaultBoolExtension;
+import static protobuf_unittest.UnittestProto.defaultBytesExtension;
+import static protobuf_unittest.UnittestProto.defaultCordExtension;
+import static protobuf_unittest.UnittestProto.defaultDoubleExtension;
+import static protobuf_unittest.UnittestProto.defaultFixed32Extension;
+import static protobuf_unittest.UnittestProto.defaultFixed64Extension;
+import static protobuf_unittest.UnittestProto.defaultFloatExtension;
+import static protobuf_unittest.UnittestProto.defaultForeignEnumExtension;
+import static protobuf_unittest.UnittestProto.defaultImportEnumExtension;
// The static imports are to avoid 100+ char lines. The following is roughly equivalent to
// import static protobuf_unittest.UnittestProto.*;
import static protobuf_unittest.UnittestProto.defaultInt32Extension;
import static protobuf_unittest.UnittestProto.defaultInt64Extension;
-import static protobuf_unittest.UnittestProto.defaultUint32Extension;
-import static protobuf_unittest.UnittestProto.defaultUint64Extension;
-import static protobuf_unittest.UnittestProto.defaultSint32Extension;
-import static protobuf_unittest.UnittestProto.defaultSint64Extension;
-import static protobuf_unittest.UnittestProto.defaultFixed32Extension;
-import static protobuf_unittest.UnittestProto.defaultFixed64Extension;
+import static protobuf_unittest.UnittestProto.defaultNestedEnumExtension;
import static protobuf_unittest.UnittestProto.defaultSfixed32Extension;
import static protobuf_unittest.UnittestProto.defaultSfixed64Extension;
-import static protobuf_unittest.UnittestProto.defaultFloatExtension;
-import static protobuf_unittest.UnittestProto.defaultDoubleExtension;
-import static protobuf_unittest.UnittestProto.defaultBoolExtension;
+import static protobuf_unittest.UnittestProto.defaultSint32Extension;
+import static protobuf_unittest.UnittestProto.defaultSint64Extension;
import static protobuf_unittest.UnittestProto.defaultStringExtension;
-import static protobuf_unittest.UnittestProto.defaultBytesExtension;
-import static protobuf_unittest.UnittestProto.defaultNestedEnumExtension;
-import static protobuf_unittest.UnittestProto.defaultForeignEnumExtension;
-import static protobuf_unittest.UnittestProto.defaultImportEnumExtension;
import static protobuf_unittest.UnittestProto.defaultStringPieceExtension;
-import static protobuf_unittest.UnittestProto.defaultCordExtension;
-
-import static protobuf_unittest.UnittestProto.oneofUint32Extension;
+import static protobuf_unittest.UnittestProto.defaultUint32Extension;
+import static protobuf_unittest.UnittestProto.defaultUint64Extension;
+import static protobuf_unittest.UnittestProto.oneofBytesExtension;
import static protobuf_unittest.UnittestProto.oneofNestedMessageExtension;
import static protobuf_unittest.UnittestProto.oneofStringExtension;
-import static protobuf_unittest.UnittestProto.oneofBytesExtension;
-
-import static protobuf_unittest.UnittestProto.optionalInt32Extension;
-import static protobuf_unittest.UnittestProto.optionalInt64Extension;
-import static protobuf_unittest.UnittestProto.optionalUint32Extension;
-import static protobuf_unittest.UnittestProto.optionalUint64Extension;
-import static protobuf_unittest.UnittestProto.optionalSint32Extension;
-import static protobuf_unittest.UnittestProto.optionalSint64Extension;
-import static protobuf_unittest.UnittestProto.optionalFixed32Extension;
-import static protobuf_unittest.UnittestProto.optionalFixed64Extension;
-import static protobuf_unittest.UnittestProto.optionalSfixed32Extension;
-import static protobuf_unittest.UnittestProto.optionalSfixed64Extension;
-import static protobuf_unittest.UnittestProto.optionalFloatExtension;
-import static protobuf_unittest.UnittestProto.optionalDoubleExtension;
+import static protobuf_unittest.UnittestProto.oneofUint32Extension;
import static protobuf_unittest.UnittestProto.optionalBoolExtension;
-import static protobuf_unittest.UnittestProto.optionalStringExtension;
import static protobuf_unittest.UnittestProto.optionalBytesExtension;
-import static protobuf_unittest.UnittestProto.optionalGroupExtension;
import static protobuf_unittest.UnittestProto.optionalCordExtension;
+import static protobuf_unittest.UnittestProto.optionalDoubleExtension;
+import static protobuf_unittest.UnittestProto.optionalFixed32Extension;
+import static protobuf_unittest.UnittestProto.optionalFixed64Extension;
+import static protobuf_unittest.UnittestProto.optionalFloatExtension;
import static protobuf_unittest.UnittestProto.optionalForeignEnumExtension;
import static protobuf_unittest.UnittestProto.optionalForeignMessageExtension;
+import static protobuf_unittest.UnittestProto.optionalGroupExtension;
import static protobuf_unittest.UnittestProto.optionalImportEnumExtension;
import static protobuf_unittest.UnittestProto.optionalImportMessageExtension;
+import static protobuf_unittest.UnittestProto.optionalInt32Extension;
+import static protobuf_unittest.UnittestProto.optionalInt64Extension;
+import static protobuf_unittest.UnittestProto.optionalLazyMessageExtension;
import static protobuf_unittest.UnittestProto.optionalNestedEnumExtension;
import static protobuf_unittest.UnittestProto.optionalNestedMessageExtension;
import static protobuf_unittest.UnittestProto.optionalPublicImportMessageExtension;
-import static protobuf_unittest.UnittestProto.optionalLazyMessageExtension;
+import static protobuf_unittest.UnittestProto.optionalSfixed32Extension;
+import static protobuf_unittest.UnittestProto.optionalSfixed64Extension;
+import static protobuf_unittest.UnittestProto.optionalSint32Extension;
+import static protobuf_unittest.UnittestProto.optionalSint64Extension;
+import static protobuf_unittest.UnittestProto.optionalStringExtension;
import static protobuf_unittest.UnittestProto.optionalStringPieceExtension;
-
-import static protobuf_unittest.UnittestProto.repeatedInt32Extension;
-import static protobuf_unittest.UnittestProto.repeatedInt64Extension;
-import static protobuf_unittest.UnittestProto.repeatedUint32Extension;
-import static protobuf_unittest.UnittestProto.repeatedUint64Extension;
-import static protobuf_unittest.UnittestProto.repeatedSint32Extension;
-import static protobuf_unittest.UnittestProto.repeatedSint64Extension;
+import static protobuf_unittest.UnittestProto.optionalUint32Extension;
+import static protobuf_unittest.UnittestProto.optionalUint64Extension;
+import static protobuf_unittest.UnittestProto.packedBoolExtension;
+import static protobuf_unittest.UnittestProto.packedDoubleExtension;
+import static protobuf_unittest.UnittestProto.packedEnumExtension;
+import static protobuf_unittest.UnittestProto.packedFixed32Extension;
+import static protobuf_unittest.UnittestProto.packedFixed64Extension;
+import static protobuf_unittest.UnittestProto.packedFloatExtension;
+import static protobuf_unittest.UnittestProto.packedInt32Extension;
+import static protobuf_unittest.UnittestProto.packedInt64Extension;
+import static protobuf_unittest.UnittestProto.packedSfixed32Extension;
+import static protobuf_unittest.UnittestProto.packedSfixed64Extension;
+import static protobuf_unittest.UnittestProto.packedSint32Extension;
+import static protobuf_unittest.UnittestProto.packedSint64Extension;
+import static protobuf_unittest.UnittestProto.packedUint32Extension;
+import static protobuf_unittest.UnittestProto.packedUint64Extension;
+import static protobuf_unittest.UnittestProto.repeatedBoolExtension;
+import static protobuf_unittest.UnittestProto.repeatedBytesExtension;
+import static protobuf_unittest.UnittestProto.repeatedCordExtension;
+import static protobuf_unittest.UnittestProto.repeatedDoubleExtension;
import static protobuf_unittest.UnittestProto.repeatedFixed32Extension;
import static protobuf_unittest.UnittestProto.repeatedFixed64Extension;
-import static protobuf_unittest.UnittestProto.repeatedSfixed32Extension;
-import static protobuf_unittest.UnittestProto.repeatedSfixed64Extension;
import static protobuf_unittest.UnittestProto.repeatedFloatExtension;
-import static protobuf_unittest.UnittestProto.repeatedDoubleExtension;
-import static protobuf_unittest.UnittestProto.repeatedBoolExtension;
-import static protobuf_unittest.UnittestProto.repeatedStringExtension;
-import static protobuf_unittest.UnittestProto.repeatedBytesExtension;
-import static protobuf_unittest.UnittestProto.repeatedGroupExtension;
-import static protobuf_unittest.UnittestProto.repeatedNestedMessageExtension;
+import static protobuf_unittest.UnittestProto.repeatedForeignEnumExtension;
import static protobuf_unittest.UnittestProto.repeatedForeignMessageExtension;
+import static protobuf_unittest.UnittestProto.repeatedGroupExtension;
+import static protobuf_unittest.UnittestProto.repeatedImportEnumExtension;
import static protobuf_unittest.UnittestProto.repeatedImportMessageExtension;
+import static protobuf_unittest.UnittestProto.repeatedInt32Extension;
+import static protobuf_unittest.UnittestProto.repeatedInt64Extension;
import static protobuf_unittest.UnittestProto.repeatedLazyMessageExtension;
import static protobuf_unittest.UnittestProto.repeatedNestedEnumExtension;
-import static protobuf_unittest.UnittestProto.repeatedForeignEnumExtension;
-import static protobuf_unittest.UnittestProto.repeatedImportEnumExtension;
+import static protobuf_unittest.UnittestProto.repeatedNestedMessageExtension;
+import static protobuf_unittest.UnittestProto.repeatedSfixed32Extension;
+import static protobuf_unittest.UnittestProto.repeatedSfixed64Extension;
+import static protobuf_unittest.UnittestProto.repeatedSint32Extension;
+import static protobuf_unittest.UnittestProto.repeatedSint64Extension;
+import static protobuf_unittest.UnittestProto.repeatedStringExtension;
import static protobuf_unittest.UnittestProto.repeatedStringPieceExtension;
-import static protobuf_unittest.UnittestProto.repeatedCordExtension;
-
-import static protobuf_unittest.UnittestProto.OptionalGroup_extension;
-import static protobuf_unittest.UnittestProto.RepeatedGroup_extension;
-
-import static protobuf_unittest.UnittestProto.packedInt32Extension;
-import static protobuf_unittest.UnittestProto.packedInt64Extension;
-import static protobuf_unittest.UnittestProto.packedUint32Extension;
-import static protobuf_unittest.UnittestProto.packedUint64Extension;
-import static protobuf_unittest.UnittestProto.packedSint32Extension;
-import static protobuf_unittest.UnittestProto.packedSint64Extension;
-import static protobuf_unittest.UnittestProto.packedFixed32Extension;
-import static protobuf_unittest.UnittestProto.packedFixed64Extension;
-import static protobuf_unittest.UnittestProto.packedSfixed32Extension;
-import static protobuf_unittest.UnittestProto.packedSfixed64Extension;
-import static protobuf_unittest.UnittestProto.packedFloatExtension;
-import static protobuf_unittest.UnittestProto.packedDoubleExtension;
-import static protobuf_unittest.UnittestProto.packedBoolExtension;
-import static protobuf_unittest.UnittestProto.packedEnumExtension;
-
-import static com.google.protobuf.UnittestLite.defaultInt32ExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultInt64ExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultUint32ExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultUint64ExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultSint32ExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultSint64ExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultFixed32ExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultFixed64ExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultSfixed32ExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultSfixed64ExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultFloatExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultDoubleExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultBoolExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultStringExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultBytesExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultNestedEnumExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultForeignEnumExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultImportEnumExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultStringPieceExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultCordExtensionLite;
-
-import static com.google.protobuf.UnittestLite.oneofUint32ExtensionLite;
-import static com.google.protobuf.UnittestLite.oneofNestedMessageExtensionLite;
-import static com.google.protobuf.UnittestLite.oneofStringExtensionLite;
-import static com.google.protobuf.UnittestLite.oneofBytesExtensionLite;
-
-import static com.google.protobuf.UnittestLite.optionalInt32ExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalInt64ExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalUint32ExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalUint64ExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalSint32ExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalSint64ExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalFixed32ExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalFixed64ExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalSfixed32ExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalSfixed64ExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalFloatExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalDoubleExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalBoolExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalStringExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalBytesExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalGroupExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalNestedMessageExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalForeignEnumExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalForeignMessageExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalImportEnumExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalImportMessageExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalNestedEnumExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalPublicImportMessageExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalLazyMessageExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalStringPieceExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalCordExtensionLite;
-
-import static com.google.protobuf.UnittestLite.repeatedInt32ExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedInt64ExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedUint32ExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedUint64ExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedSint32ExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedSint64ExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedFixed32ExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedFixed64ExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedSfixed32ExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedSfixed64ExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedFloatExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedDoubleExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedBoolExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedStringExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedBytesExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedGroupExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedNestedMessageExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedForeignMessageExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedImportMessageExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedLazyMessageExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedNestedEnumExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedForeignEnumExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedImportEnumExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedStringPieceExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedCordExtensionLite;
-
-import static com.google.protobuf.UnittestLite.OptionalGroup_extension_lite;
-import static com.google.protobuf.UnittestLite.RepeatedGroup_extension_lite;
-
-import static com.google.protobuf.UnittestLite.packedInt32ExtensionLite;
-import static com.google.protobuf.UnittestLite.packedInt64ExtensionLite;
-import static com.google.protobuf.UnittestLite.packedUint32ExtensionLite;
-import static com.google.protobuf.UnittestLite.packedUint64ExtensionLite;
-import static com.google.protobuf.UnittestLite.packedSint32ExtensionLite;
-import static com.google.protobuf.UnittestLite.packedSint64ExtensionLite;
-import static com.google.protobuf.UnittestLite.packedFixed32ExtensionLite;
-import static com.google.protobuf.UnittestLite.packedFixed64ExtensionLite;
-import static com.google.protobuf.UnittestLite.packedSfixed32ExtensionLite;
-import static com.google.protobuf.UnittestLite.packedSfixed64ExtensionLite;
-import static com.google.protobuf.UnittestLite.packedFloatExtensionLite;
-import static com.google.protobuf.UnittestLite.packedDoubleExtensionLite;
-import static com.google.protobuf.UnittestLite.packedBoolExtensionLite;
-import static com.google.protobuf.UnittestLite.packedEnumExtensionLite;
+import static protobuf_unittest.UnittestProto.repeatedUint32Extension;
+import static protobuf_unittest.UnittestProto.repeatedUint64Extension;
+import com.google.protobuf.UnittestImportLite.ImportEnumLite;
+import com.google.protobuf.UnittestLite.ForeignEnumLite;
+import com.google.protobuf.UnittestLite.TestAllExtensionsLiteOrBuilder;
+import com.google.protobuf.UnittestLite.TestAllTypesLite;
+import com.google.protobuf.UnittestLite.TestPackedExtensionsLite;
+import com.google.protobuf.test.UnittestImport.ImportEnum;
+import com.google.protobuf.test.UnittestImport.ImportMessage;
+import com.google.protobuf.test.UnittestImportPublic.PublicImportMessage;
+import protobuf_unittest.UnittestProto;
+import protobuf_unittest.UnittestProto.ForeignEnum;
+import protobuf_unittest.UnittestProto.ForeignMessage;
import protobuf_unittest.UnittestProto.TestAllExtensions;
import protobuf_unittest.UnittestProto.TestAllExtensionsOrBuilder;
import protobuf_unittest.UnittestProto.TestAllTypes;
@@ -237,21 +232,6 @@ import protobuf_unittest.UnittestProto.TestOneof2;
import protobuf_unittest.UnittestProto.TestPackedExtensions;
import protobuf_unittest.UnittestProto.TestPackedTypes;
import protobuf_unittest.UnittestProto.TestUnpackedTypes;
-import protobuf_unittest.UnittestProto.ForeignMessage;
-import protobuf_unittest.UnittestProto.ForeignEnum;
-import com.google.protobuf.test.UnittestImport.ImportEnum;
-import com.google.protobuf.test.UnittestImport.ImportMessage;
-import com.google.protobuf.test.UnittestImportPublic.PublicImportMessage;
-
-import com.google.protobuf.UnittestLite.TestAllTypesLite;
-import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
-import com.google.protobuf.UnittestLite.TestAllExtensionsLiteOrBuilder;
-import com.google.protobuf.UnittestLite.TestPackedExtensionsLite;
-import com.google.protobuf.UnittestLite.ForeignMessageLite;
-import com.google.protobuf.UnittestLite.ForeignEnumLite;
-import com.google.protobuf.UnittestImportLite.ImportEnumLite;
-import com.google.protobuf.UnittestImportLite.ImportMessageLite;
-import com.google.protobuf.UnittestImportPublicLite.PublicImportMessageLite;
import junit.framework.Assert;
@@ -300,16 +280,6 @@ public final class TestUtil {
}
/**
- * Get a {@code TestAllTypesLite.Builder} with all fields set as they would be by
- * {@link #setAllFields(TestAllTypesLite.Builder)}.
- */
- public static TestAllTypesLite.Builder getAllLiteSetBuilder() {
- TestAllTypesLite.Builder builder = TestAllTypesLite.newBuilder();
- setAllFields(builder);
- return builder;
- }
-
- /**
* Get a {@code TestAllExtensions} with all fields set as they would be by
* {@link #setAllExtensions(TestAllExtensions.Builder)}.
*/
@@ -319,12 +289,6 @@ public final class TestUtil {
return builder.build();
}
- public static TestAllExtensionsLite getAllLiteExtensionsSet() {
- TestAllExtensionsLite.Builder builder = TestAllExtensionsLite.newBuilder();
- setAllExtensions(builder);
- return builder.build();
- }
-
public static TestPackedTypes getPackedSet() {
TestPackedTypes.Builder builder = TestPackedTypes.newBuilder();
setPackedFields(builder);
@@ -343,157 +307,6 @@ public final class TestUtil {
return builder.build();
}
- public static TestPackedExtensionsLite getLitePackedExtensionsSet() {
- TestPackedExtensionsLite.Builder builder =
- TestPackedExtensionsLite.newBuilder();
- setPackedExtensions(builder);
- return builder.build();
- }
-
- /**
- * Set every field of {@code builder} to the values expected by
- * {@code assertAllFieldsSet()}.
- */
- public static void setAllFields(TestAllTypesLite.Builder builder) {
- builder.setOptionalInt32 (101);
- builder.setOptionalInt64 (102);
- builder.setOptionalUint32 (103);
- builder.setOptionalUint64 (104);
- builder.setOptionalSint32 (105);
- builder.setOptionalSint64 (106);
- builder.setOptionalFixed32 (107);
- builder.setOptionalFixed64 (108);
- builder.setOptionalSfixed32(109);
- builder.setOptionalSfixed64(110);
- builder.setOptionalFloat (111);
- builder.setOptionalDouble (112);
- builder.setOptionalBool (true);
- builder.setOptionalString ("115");
- builder.setOptionalBytes (toBytes("116"));
-
- builder.setOptionalGroup(
- TestAllTypesLite.OptionalGroup.newBuilder().setA(117).build());
- builder.setOptionalNestedMessage(
- TestAllTypesLite.NestedMessage.newBuilder().setBb(118).build());
- builder.setOptionalForeignMessage(
- ForeignMessageLite.newBuilder().setC(119).build());
- builder.setOptionalImportMessage(
- ImportMessageLite.newBuilder().setD(120).build());
- builder.setOptionalPublicImportMessage(
- PublicImportMessageLite.newBuilder().setE(126).build());
- builder.setOptionalLazyMessage(
- TestAllTypesLite.NestedMessage.newBuilder().setBb(127).build());
-
- builder.setOptionalNestedEnum (TestAllTypesLite.NestedEnum.BAZ);
- builder.setOptionalForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAZ);
- builder.setOptionalImportEnum (ImportEnumLite.IMPORT_LITE_BAZ);
-
- builder.setOptionalStringPiece("124");
- builder.setOptionalCord("125");
-
- // -----------------------------------------------------------------
-
- builder.addRepeatedInt32 (201);
- builder.addRepeatedInt64 (202);
- builder.addRepeatedUint32 (203);
- builder.addRepeatedUint64 (204);
- builder.addRepeatedSint32 (205);
- builder.addRepeatedSint64 (206);
- builder.addRepeatedFixed32 (207);
- builder.addRepeatedFixed64 (208);
- builder.addRepeatedSfixed32(209);
- builder.addRepeatedSfixed64(210);
- builder.addRepeatedFloat (211);
- builder.addRepeatedDouble (212);
- builder.addRepeatedBool (true);
- builder.addRepeatedString ("215");
- builder.addRepeatedBytes (toBytes("216"));
-
- builder.addRepeatedGroup(
- TestAllTypesLite.RepeatedGroup.newBuilder().setA(217).build());
- builder.addRepeatedNestedMessage(
- TestAllTypesLite.NestedMessage.newBuilder().setBb(218).build());
- builder.addRepeatedForeignMessage(
- ForeignMessageLite.newBuilder().setC(219).build());
- builder.addRepeatedImportMessage(
- ImportMessageLite.newBuilder().setD(220).build());
- builder.addRepeatedLazyMessage(
- TestAllTypesLite.NestedMessage.newBuilder().setBb(227).build());
-
- builder.addRepeatedNestedEnum (TestAllTypesLite.NestedEnum.BAR);
- builder.addRepeatedForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR);
- builder.addRepeatedImportEnum (ImportEnumLite.IMPORT_LITE_BAR);
-
- builder.addRepeatedStringPiece("224");
- builder.addRepeatedCord("225");
-
- // Add a second one of each field.
- builder.addRepeatedInt32 (301);
- builder.addRepeatedInt64 (302);
- builder.addRepeatedUint32 (303);
- builder.addRepeatedUint64 (304);
- builder.addRepeatedSint32 (305);
- builder.addRepeatedSint64 (306);
- builder.addRepeatedFixed32 (307);
- builder.addRepeatedFixed64 (308);
- builder.addRepeatedSfixed32(309);
- builder.addRepeatedSfixed64(310);
- builder.addRepeatedFloat (311);
- builder.addRepeatedDouble (312);
- builder.addRepeatedBool (false);
- builder.addRepeatedString ("315");
- builder.addRepeatedBytes (toBytes("316"));
-
- builder.addRepeatedGroup(
- TestAllTypesLite.RepeatedGroup.newBuilder().setA(317).build());
- builder.addRepeatedNestedMessage(
- TestAllTypesLite.NestedMessage.newBuilder().setBb(318).build());
- builder.addRepeatedForeignMessage(
- ForeignMessageLite.newBuilder().setC(319).build());
- builder.addRepeatedImportMessage(
- ImportMessageLite.newBuilder().setD(320).build());
- builder.addRepeatedLazyMessage(
- TestAllTypesLite.NestedMessage.newBuilder().setBb(327).build());
-
- builder.addRepeatedNestedEnum (TestAllTypesLite.NestedEnum.BAZ);
- builder.addRepeatedForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAZ);
- builder.addRepeatedImportEnum (ImportEnumLite.IMPORT_LITE_BAZ);
-
- builder.addRepeatedStringPiece("324");
- builder.addRepeatedCord("325");
-
- // -----------------------------------------------------------------
-
- builder.setDefaultInt32 (401);
- builder.setDefaultInt64 (402);
- builder.setDefaultUint32 (403);
- builder.setDefaultUint64 (404);
- builder.setDefaultSint32 (405);
- builder.setDefaultSint64 (406);
- builder.setDefaultFixed32 (407);
- builder.setDefaultFixed64 (408);
- builder.setDefaultSfixed32(409);
- builder.setDefaultSfixed64(410);
- builder.setDefaultFloat (411);
- builder.setDefaultDouble (412);
- builder.setDefaultBool (false);
- builder.setDefaultString ("415");
- builder.setDefaultBytes (toBytes("416"));
-
- builder.setDefaultNestedEnum (TestAllTypesLite.NestedEnum.FOO);
- builder.setDefaultForeignEnum(ForeignEnumLite.FOREIGN_LITE_FOO);
- builder.setDefaultImportEnum (ImportEnumLite.IMPORT_LITE_FOO);
-
- builder.setDefaultStringPiece("424");
- builder.setDefaultCord("425");
-
- builder.setOneofUint32(601);
- builder.setOneofNestedMessage(
- TestAllTypesLite.NestedMessage.newBuilder().setBb(602).build());
- builder.setOneofString("603");
- builder.setOneofBytes(toBytes("604"));
- }
-
/**
* Set every field of {@code message} to the values expected by
* {@code assertAllFieldsSet()}.
@@ -1383,23 +1196,13 @@ public final class TestUtil {
return registry.getUnmodifiable();
}
- public static ExtensionRegistryLite getExtensionRegistryLite() {
- ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance();
- registerAllExtensionsLite(registry);
- return registry.getUnmodifiable();
- }
-
/**
* Register all of {@code TestAllExtensions}'s extensions with the
* given {@link ExtensionRegistry}.
*/
public static void registerAllExtensions(ExtensionRegistry registry) {
UnittestProto.registerAllExtensions(registry);
- registerAllExtensionsLite(registry);
- }
-
- public static void registerAllExtensionsLite(ExtensionRegistryLite registry) {
- UnittestLite.registerAllExtensions(registry);
+ TestUtilLite.registerAllExtensionsLite(registry);
}
/**
@@ -2193,195 +1996,6 @@ public final class TestUtil {
// Lite extensions
/**
- * Set every field of {@code message} to the values expected by
- * {@code assertAllExtensionsSet()}.
- */
- public static void setAllExtensions(TestAllExtensionsLite.Builder message) {
- message.setExtension(optionalInt32ExtensionLite , 101);
- message.setExtension(optionalInt64ExtensionLite , 102L);
- message.setExtension(optionalUint32ExtensionLite , 103);
- message.setExtension(optionalUint64ExtensionLite , 104L);
- message.setExtension(optionalSint32ExtensionLite , 105);
- message.setExtension(optionalSint64ExtensionLite , 106L);
- message.setExtension(optionalFixed32ExtensionLite , 107);
- message.setExtension(optionalFixed64ExtensionLite , 108L);
- message.setExtension(optionalSfixed32ExtensionLite, 109);
- message.setExtension(optionalSfixed64ExtensionLite, 110L);
- message.setExtension(optionalFloatExtensionLite , 111F);
- message.setExtension(optionalDoubleExtensionLite , 112D);
- message.setExtension(optionalBoolExtensionLite , true);
- message.setExtension(optionalStringExtensionLite , "115");
- message.setExtension(optionalBytesExtensionLite , toBytes("116"));
-
- message.setExtension(optionalGroupExtensionLite,
- OptionalGroup_extension_lite.newBuilder().setA(117).build());
- message.setExtension(optionalNestedMessageExtensionLite,
- TestAllTypesLite.NestedMessage.newBuilder().setBb(118).build());
- message.setExtension(optionalForeignMessageExtensionLite,
- ForeignMessageLite.newBuilder().setC(119).build());
- message.setExtension(optionalImportMessageExtensionLite,
- ImportMessageLite.newBuilder().setD(120).build());
- message.setExtension(optionalPublicImportMessageExtensionLite,
- PublicImportMessageLite.newBuilder().setE(126).build());
- message.setExtension(optionalLazyMessageExtensionLite,
- TestAllTypesLite.NestedMessage.newBuilder().setBb(127).build());
-
- message.setExtension(optionalNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAZ);
- message.setExtension(optionalForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAZ);
- message.setExtension(optionalImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_BAZ);
-
- message.setExtension(optionalStringPieceExtensionLite, "124");
- message.setExtension(optionalCordExtensionLite, "125");
-
- // -----------------------------------------------------------------
-
- message.addExtension(repeatedInt32ExtensionLite , 201);
- message.addExtension(repeatedInt64ExtensionLite , 202L);
- message.addExtension(repeatedUint32ExtensionLite , 203);
- message.addExtension(repeatedUint64ExtensionLite , 204L);
- message.addExtension(repeatedSint32ExtensionLite , 205);
- message.addExtension(repeatedSint64ExtensionLite , 206L);
- message.addExtension(repeatedFixed32ExtensionLite , 207);
- message.addExtension(repeatedFixed64ExtensionLite , 208L);
- message.addExtension(repeatedSfixed32ExtensionLite, 209);
- message.addExtension(repeatedSfixed64ExtensionLite, 210L);
- message.addExtension(repeatedFloatExtensionLite , 211F);
- message.addExtension(repeatedDoubleExtensionLite , 212D);
- message.addExtension(repeatedBoolExtensionLite , true);
- message.addExtension(repeatedStringExtensionLite , "215");
- message.addExtension(repeatedBytesExtensionLite , toBytes("216"));
-
- message.addExtension(repeatedGroupExtensionLite,
- RepeatedGroup_extension_lite.newBuilder().setA(217).build());
- message.addExtension(repeatedNestedMessageExtensionLite,
- TestAllTypesLite.NestedMessage.newBuilder().setBb(218).build());
- message.addExtension(repeatedForeignMessageExtensionLite,
- ForeignMessageLite.newBuilder().setC(219).build());
- message.addExtension(repeatedImportMessageExtensionLite,
- ImportMessageLite.newBuilder().setD(220).build());
- message.addExtension(repeatedLazyMessageExtensionLite,
- TestAllTypesLite.NestedMessage.newBuilder().setBb(227).build());
-
- message.addExtension(repeatedNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAR);
- message.addExtension(repeatedForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAR);
- message.addExtension(repeatedImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_BAR);
-
- message.addExtension(repeatedStringPieceExtensionLite, "224");
- message.addExtension(repeatedCordExtensionLite, "225");
-
- // Add a second one of each field.
- message.addExtension(repeatedInt32ExtensionLite , 301);
- message.addExtension(repeatedInt64ExtensionLite , 302L);
- message.addExtension(repeatedUint32ExtensionLite , 303);
- message.addExtension(repeatedUint64ExtensionLite , 304L);
- message.addExtension(repeatedSint32ExtensionLite , 305);
- message.addExtension(repeatedSint64ExtensionLite , 306L);
- message.addExtension(repeatedFixed32ExtensionLite , 307);
- message.addExtension(repeatedFixed64ExtensionLite , 308L);
- message.addExtension(repeatedSfixed32ExtensionLite, 309);
- message.addExtension(repeatedSfixed64ExtensionLite, 310L);
- message.addExtension(repeatedFloatExtensionLite , 311F);
- message.addExtension(repeatedDoubleExtensionLite , 312D);
- message.addExtension(repeatedBoolExtensionLite , false);
- message.addExtension(repeatedStringExtensionLite , "315");
- message.addExtension(repeatedBytesExtensionLite , toBytes("316"));
-
- message.addExtension(repeatedGroupExtensionLite,
- RepeatedGroup_extension_lite.newBuilder().setA(317).build());
- message.addExtension(repeatedNestedMessageExtensionLite,
- TestAllTypesLite.NestedMessage.newBuilder().setBb(318).build());
- message.addExtension(repeatedForeignMessageExtensionLite,
- ForeignMessageLite.newBuilder().setC(319).build());
- message.addExtension(repeatedImportMessageExtensionLite,
- ImportMessageLite.newBuilder().setD(320).build());
- message.addExtension(repeatedLazyMessageExtensionLite,
- TestAllTypesLite.NestedMessage.newBuilder().setBb(327).build());
-
- message.addExtension(repeatedNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAZ);
- message.addExtension(repeatedForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAZ);
- message.addExtension(repeatedImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_BAZ);
-
- message.addExtension(repeatedStringPieceExtensionLite, "324");
- message.addExtension(repeatedCordExtensionLite, "325");
-
- // -----------------------------------------------------------------
-
- message.setExtension(defaultInt32ExtensionLite , 401);
- message.setExtension(defaultInt64ExtensionLite , 402L);
- message.setExtension(defaultUint32ExtensionLite , 403);
- message.setExtension(defaultUint64ExtensionLite , 404L);
- message.setExtension(defaultSint32ExtensionLite , 405);
- message.setExtension(defaultSint64ExtensionLite , 406L);
- message.setExtension(defaultFixed32ExtensionLite , 407);
- message.setExtension(defaultFixed64ExtensionLite , 408L);
- message.setExtension(defaultSfixed32ExtensionLite, 409);
- message.setExtension(defaultSfixed64ExtensionLite, 410L);
- message.setExtension(defaultFloatExtensionLite , 411F);
- message.setExtension(defaultDoubleExtensionLite , 412D);
- message.setExtension(defaultBoolExtensionLite , false);
- message.setExtension(defaultStringExtensionLite , "415");
- message.setExtension(defaultBytesExtensionLite , toBytes("416"));
-
- message.setExtension(defaultNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.FOO);
- message.setExtension(defaultForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_FOO);
- message.setExtension(defaultImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_FOO);
-
- message.setExtension(defaultStringPieceExtensionLite, "424");
- message.setExtension(defaultCordExtensionLite, "425");
-
- message.setExtension(oneofUint32ExtensionLite, 601);
- message.setExtension(oneofNestedMessageExtensionLite,
- TestAllTypesLite.NestedMessage.newBuilder().setBb(602).build());
- message.setExtension(oneofStringExtensionLite, "603");
- message.setExtension(oneofBytesExtensionLite, toBytes("604"));
- }
-
- // -------------------------------------------------------------------
-
- /**
- * Modify the repeated extensions of {@code message} to contain the values
- * expected by {@code assertRepeatedExtensionsModified()}.
- */
- public static void modifyRepeatedExtensions(
- TestAllExtensionsLite.Builder message) {
- message.setExtension(repeatedInt32ExtensionLite , 1, 501);
- message.setExtension(repeatedInt64ExtensionLite , 1, 502L);
- message.setExtension(repeatedUint32ExtensionLite , 1, 503);
- message.setExtension(repeatedUint64ExtensionLite , 1, 504L);
- message.setExtension(repeatedSint32ExtensionLite , 1, 505);
- message.setExtension(repeatedSint64ExtensionLite , 1, 506L);
- message.setExtension(repeatedFixed32ExtensionLite , 1, 507);
- message.setExtension(repeatedFixed64ExtensionLite , 1, 508L);
- message.setExtension(repeatedSfixed32ExtensionLite, 1, 509);
- message.setExtension(repeatedSfixed64ExtensionLite, 1, 510L);
- message.setExtension(repeatedFloatExtensionLite , 1, 511F);
- message.setExtension(repeatedDoubleExtensionLite , 1, 512D);
- message.setExtension(repeatedBoolExtensionLite , 1, true);
- message.setExtension(repeatedStringExtensionLite , 1, "515");
- message.setExtension(repeatedBytesExtensionLite , 1, toBytes("516"));
-
- message.setExtension(repeatedGroupExtensionLite, 1,
- RepeatedGroup_extension_lite.newBuilder().setA(517).build());
- message.setExtension(repeatedNestedMessageExtensionLite, 1,
- TestAllTypesLite.NestedMessage.newBuilder().setBb(518).build());
- message.setExtension(repeatedForeignMessageExtensionLite, 1,
- ForeignMessageLite.newBuilder().setC(519).build());
- message.setExtension(repeatedImportMessageExtensionLite, 1,
- ImportMessageLite.newBuilder().setD(520).build());
- message.setExtension(repeatedLazyMessageExtensionLite, 1,
- TestAllTypesLite.NestedMessage.newBuilder().setBb(527).build());
-
- message.setExtension(repeatedNestedEnumExtensionLite , 1, TestAllTypesLite.NestedEnum.FOO);
- message.setExtension(repeatedForeignEnumExtensionLite, 1, ForeignEnumLite.FOREIGN_LITE_FOO);
- message.setExtension(repeatedImportEnumExtensionLite , 1, ImportEnumLite.IMPORT_LITE_FOO);
-
- message.setExtension(repeatedStringPieceExtensionLite, 1, "524");
- message.setExtension(repeatedCordExtensionLite, 1, "525");
- }
-
- // -------------------------------------------------------------------
-
- /**
* Assert (using {@code junit.framework.Assert}} that all extensions of
* {@code message} are set to the values assigned by {@code setAllExtensions}.
*/
@@ -2880,38 +2494,6 @@ public final class TestUtil {
assertEqualsExactType("525", message.getExtension(repeatedCordExtensionLite, 1));
}
- public static void setPackedExtensions(TestPackedExtensionsLite.Builder message) {
- message.addExtension(packedInt32ExtensionLite , 601);
- message.addExtension(packedInt64ExtensionLite , 602L);
- message.addExtension(packedUint32ExtensionLite , 603);
- message.addExtension(packedUint64ExtensionLite , 604L);
- message.addExtension(packedSint32ExtensionLite , 605);
- message.addExtension(packedSint64ExtensionLite , 606L);
- message.addExtension(packedFixed32ExtensionLite , 607);
- message.addExtension(packedFixed64ExtensionLite , 608L);
- message.addExtension(packedSfixed32ExtensionLite, 609);
- message.addExtension(packedSfixed64ExtensionLite, 610L);
- message.addExtension(packedFloatExtensionLite , 611F);
- message.addExtension(packedDoubleExtensionLite , 612D);
- message.addExtension(packedBoolExtensionLite , true);
- message.addExtension(packedEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAR);
- // Add a second one of each field.
- message.addExtension(packedInt32ExtensionLite , 701);
- message.addExtension(packedInt64ExtensionLite , 702L);
- message.addExtension(packedUint32ExtensionLite , 703);
- message.addExtension(packedUint64ExtensionLite , 704L);
- message.addExtension(packedSint32ExtensionLite , 705);
- message.addExtension(packedSint64ExtensionLite , 706L);
- message.addExtension(packedFixed32ExtensionLite , 707);
- message.addExtension(packedFixed64ExtensionLite , 708L);
- message.addExtension(packedSfixed32ExtensionLite, 709);
- message.addExtension(packedSfixed64ExtensionLite, 710L);
- message.addExtension(packedFloatExtensionLite , 711F);
- message.addExtension(packedDoubleExtensionLite , 712D);
- message.addExtension(packedBoolExtensionLite , false);
- message.addExtension(packedEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAZ);
- }
-
public static void assertPackedExtensionsSet(TestPackedExtensionsLite message) {
Assert.assertEquals(2, message.getExtensionCount(packedInt32ExtensionLite ));
Assert.assertEquals(2, message.getExtensionCount(packedInt64ExtensionLite ));
@@ -4263,7 +3845,7 @@ public final class TestUtil {
private int invalidations;
- //@Override (Java 1.6 override semantics, but we must support 1.5)
+ @Override
public void markDirty() {
invalidations++;
}
diff --git a/java/core/src/test/java/com/google/protobuf/TestUtilLite.java b/java/core/src/test/java/com/google/protobuf/TestUtilLite.java
new file mode 100644
index 00000000..8f33fa14
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/TestUtilLite.java
@@ -0,0 +1,559 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import static com.google.protobuf.UnittestLite.OptionalGroup_extension_lite;
+import static com.google.protobuf.UnittestLite.RepeatedGroup_extension_lite;
+import static com.google.protobuf.UnittestLite.defaultBoolExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultBytesExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultCordExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultDoubleExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultFixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultFixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultFloatExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultForeignEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultImportEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultInt32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultInt64ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultNestedEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultSfixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultSfixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultSint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultSint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultStringExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultStringPieceExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultUint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.oneofBytesExtensionLite;
+import static com.google.protobuf.UnittestLite.oneofNestedMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.oneofStringExtensionLite;
+import static com.google.protobuf.UnittestLite.oneofUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalBoolExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalBytesExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalCordExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalDoubleExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalFixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalFixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalFloatExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalForeignEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalForeignMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalGroupExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalImportEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalImportMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalInt32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalInt64ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalLazyMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalNestedEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalNestedMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalPublicImportMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalSfixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalSfixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalSint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalSint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalStringExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalStringPieceExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalUint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedBoolExtensionLite;
+import static com.google.protobuf.UnittestLite.packedDoubleExtensionLite;
+import static com.google.protobuf.UnittestLite.packedEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.packedFixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedFixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedFloatExtensionLite;
+import static com.google.protobuf.UnittestLite.packedInt32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedInt64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedSfixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedSfixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedSint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedSint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedUint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedBoolExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedBytesExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedCordExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedDoubleExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedFixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedFixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedFloatExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedForeignEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedForeignMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedGroupExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedImportEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedImportMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedInt32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedInt64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedLazyMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedNestedEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedNestedMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedSfixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedSfixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedSint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedSint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedStringExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedStringPieceExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedUint64ExtensionLite;
+
+import com.google.protobuf.UnittestImportLite.ImportEnumLite;
+import com.google.protobuf.UnittestImportLite.ImportMessageLite;
+import com.google.protobuf.UnittestImportPublicLite.PublicImportMessageLite;
+import com.google.protobuf.UnittestLite.ForeignEnumLite;
+import com.google.protobuf.UnittestLite.ForeignMessageLite;
+import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
+import com.google.protobuf.UnittestLite.TestAllTypesLite;
+import com.google.protobuf.UnittestLite.TestPackedExtensionsLite;
+
+/**
+ * Contains methods for setting fields of {@code TestAllTypesLite}, {@code TestAllExtensionsLite},
+ * and {@code TestPackedExtensionsLite}. This is analogous to the functionality in TestUtil.java but
+ * does not depend on the presence of any non-lite protos.
+ *
+ * <p>This code is not to be used outside of {@code com.google.protobuf} and
+ * subpackages.
+ */
+public final class TestUtilLite {
+ private TestUtilLite() {}
+
+ /** Helper to convert a String to ByteString. */
+ static ByteString toBytes(String str) {
+ return ByteString.copyFrom(str.getBytes(Internal.UTF_8));
+ }
+
+ /**
+ * Get a {@code TestAllTypesLite.Builder} with all fields set as they would be by
+ * {@link #setAllFields(TestAllTypesLite.Builder)}.
+ */
+ public static TestAllTypesLite.Builder getAllLiteSetBuilder() {
+ TestAllTypesLite.Builder builder = TestAllTypesLite.newBuilder();
+ setAllFields(builder);
+ return builder;
+ }
+
+ /**
+ * Get a {@code TestAllExtensionsLite} with all fields set as they would be by
+ * {@link #setAllExtensions(TestAllExtensionsLite.Builder)}.
+ */
+ public static TestAllExtensionsLite getAllLiteExtensionsSet() {
+ TestAllExtensionsLite.Builder builder = TestAllExtensionsLite.newBuilder();
+ setAllExtensions(builder);
+ return builder.build();
+ }
+
+ public static TestPackedExtensionsLite getLitePackedExtensionsSet() {
+ TestPackedExtensionsLite.Builder builder = TestPackedExtensionsLite.newBuilder();
+ setPackedExtensions(builder);
+ return builder.build();
+ }
+
+ /**
+ * Set every field of {@code builder} to the values expected by
+ * {@code assertAllFieldsSet()}.
+ */
+ public static void setAllFields(TestAllTypesLite.Builder builder) {
+ builder.setOptionalInt32 (101);
+ builder.setOptionalInt64 (102);
+ builder.setOptionalUint32 (103);
+ builder.setOptionalUint64 (104);
+ builder.setOptionalSint32 (105);
+ builder.setOptionalSint64 (106);
+ builder.setOptionalFixed32 (107);
+ builder.setOptionalFixed64 (108);
+ builder.setOptionalSfixed32(109);
+ builder.setOptionalSfixed64(110);
+ builder.setOptionalFloat (111);
+ builder.setOptionalDouble (112);
+ builder.setOptionalBool (true);
+ builder.setOptionalString ("115");
+ builder.setOptionalBytes (toBytes("116"));
+
+ builder.setOptionalGroup(
+ TestAllTypesLite.OptionalGroup.newBuilder().setA(117).build());
+ builder.setOptionalNestedMessage(
+ TestAllTypesLite.NestedMessage.newBuilder().setBb(118).build());
+ builder.setOptionalForeignMessage(
+ ForeignMessageLite.newBuilder().setC(119).build());
+ builder.setOptionalImportMessage(
+ ImportMessageLite.newBuilder().setD(120).build());
+ builder.setOptionalPublicImportMessage(
+ PublicImportMessageLite.newBuilder().setE(126).build());
+ builder.setOptionalLazyMessage(
+ TestAllTypesLite.NestedMessage.newBuilder().setBb(127).build());
+
+ builder.setOptionalNestedEnum (TestAllTypesLite.NestedEnum.BAZ);
+ builder.setOptionalForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAZ);
+ builder.setOptionalImportEnum (ImportEnumLite.IMPORT_LITE_BAZ);
+
+ builder.setOptionalStringPiece("124");
+ builder.setOptionalCord("125");
+
+ // -----------------------------------------------------------------
+
+ builder.addRepeatedInt32 (201);
+ builder.addRepeatedInt64 (202);
+ builder.addRepeatedUint32 (203);
+ builder.addRepeatedUint64 (204);
+ builder.addRepeatedSint32 (205);
+ builder.addRepeatedSint64 (206);
+ builder.addRepeatedFixed32 (207);
+ builder.addRepeatedFixed64 (208);
+ builder.addRepeatedSfixed32(209);
+ builder.addRepeatedSfixed64(210);
+ builder.addRepeatedFloat (211);
+ builder.addRepeatedDouble (212);
+ builder.addRepeatedBool (true);
+ builder.addRepeatedString ("215");
+ builder.addRepeatedBytes (toBytes("216"));
+
+ builder.addRepeatedGroup(
+ TestAllTypesLite.RepeatedGroup.newBuilder().setA(217).build());
+ builder.addRepeatedNestedMessage(
+ TestAllTypesLite.NestedMessage.newBuilder().setBb(218).build());
+ builder.addRepeatedForeignMessage(
+ ForeignMessageLite.newBuilder().setC(219).build());
+ builder.addRepeatedImportMessage(
+ ImportMessageLite.newBuilder().setD(220).build());
+ builder.addRepeatedLazyMessage(
+ TestAllTypesLite.NestedMessage.newBuilder().setBb(227).build());
+
+ builder.addRepeatedNestedEnum (TestAllTypesLite.NestedEnum.BAR);
+ builder.addRepeatedForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR);
+ builder.addRepeatedImportEnum (ImportEnumLite.IMPORT_LITE_BAR);
+
+ builder.addRepeatedStringPiece("224");
+ builder.addRepeatedCord("225");
+
+ // Add a second one of each field.
+ builder.addRepeatedInt32 (301);
+ builder.addRepeatedInt64 (302);
+ builder.addRepeatedUint32 (303);
+ builder.addRepeatedUint64 (304);
+ builder.addRepeatedSint32 (305);
+ builder.addRepeatedSint64 (306);
+ builder.addRepeatedFixed32 (307);
+ builder.addRepeatedFixed64 (308);
+ builder.addRepeatedSfixed32(309);
+ builder.addRepeatedSfixed64(310);
+ builder.addRepeatedFloat (311);
+ builder.addRepeatedDouble (312);
+ builder.addRepeatedBool (false);
+ builder.addRepeatedString ("315");
+ builder.addRepeatedBytes (toBytes("316"));
+
+ builder.addRepeatedGroup(
+ TestAllTypesLite.RepeatedGroup.newBuilder().setA(317).build());
+ builder.addRepeatedNestedMessage(
+ TestAllTypesLite.NestedMessage.newBuilder().setBb(318).build());
+ builder.addRepeatedForeignMessage(
+ ForeignMessageLite.newBuilder().setC(319).build());
+ builder.addRepeatedImportMessage(
+ ImportMessageLite.newBuilder().setD(320).build());
+ builder.addRepeatedLazyMessage(
+ TestAllTypesLite.NestedMessage.newBuilder().setBb(327).build());
+
+ builder.addRepeatedNestedEnum (TestAllTypesLite.NestedEnum.BAZ);
+ builder.addRepeatedForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAZ);
+ builder.addRepeatedImportEnum (ImportEnumLite.IMPORT_LITE_BAZ);
+
+ builder.addRepeatedStringPiece("324");
+ builder.addRepeatedCord("325");
+
+ // -----------------------------------------------------------------
+
+ builder.setDefaultInt32 (401);
+ builder.setDefaultInt64 (402);
+ builder.setDefaultUint32 (403);
+ builder.setDefaultUint64 (404);
+ builder.setDefaultSint32 (405);
+ builder.setDefaultSint64 (406);
+ builder.setDefaultFixed32 (407);
+ builder.setDefaultFixed64 (408);
+ builder.setDefaultSfixed32(409);
+ builder.setDefaultSfixed64(410);
+ builder.setDefaultFloat (411);
+ builder.setDefaultDouble (412);
+ builder.setDefaultBool (false);
+ builder.setDefaultString ("415");
+ builder.setDefaultBytes (toBytes("416"));
+
+ builder.setDefaultNestedEnum (TestAllTypesLite.NestedEnum.FOO);
+ builder.setDefaultForeignEnum(ForeignEnumLite.FOREIGN_LITE_FOO);
+ builder.setDefaultImportEnum (ImportEnumLite.IMPORT_LITE_FOO);
+
+ builder.setDefaultStringPiece("424");
+ builder.setDefaultCord("425");
+
+ builder.setOneofUint32(601);
+ builder.setOneofNestedMessage(
+ TestAllTypesLite.NestedMessage.newBuilder().setBb(602).build());
+ builder.setOneofString("603");
+ builder.setOneofBytes(toBytes("604"));
+ }
+
+ /**
+ * Get an unmodifiable {@link ExtensionRegistryLite} containing all the
+ * extensions of {@code TestAllExtensionsLite}.
+ */
+ public static ExtensionRegistryLite getExtensionRegistryLite() {
+ ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance();
+ registerAllExtensionsLite(registry);
+ return registry.getUnmodifiable();
+ }
+
+ /**
+ * Register all of {@code TestAllExtensionsLite}'s extensions with the
+ * given {@link ExtensionRegistryLite}.
+ */
+ public static void registerAllExtensionsLite(ExtensionRegistryLite registry) {
+ UnittestLite.registerAllExtensions(registry);
+ }
+
+ // ===================================================================
+ // Lite extensions
+
+ /**
+ * Set every field of {@code message} to the values expected by
+ * {@code assertAllExtensionsSet()}.
+ */
+ public static void setAllExtensions(TestAllExtensionsLite.Builder message) {
+ message.setExtension(optionalInt32ExtensionLite , 101);
+ message.setExtension(optionalInt64ExtensionLite , 102L);
+ message.setExtension(optionalUint32ExtensionLite , 103);
+ message.setExtension(optionalUint64ExtensionLite , 104L);
+ message.setExtension(optionalSint32ExtensionLite , 105);
+ message.setExtension(optionalSint64ExtensionLite , 106L);
+ message.setExtension(optionalFixed32ExtensionLite , 107);
+ message.setExtension(optionalFixed64ExtensionLite , 108L);
+ message.setExtension(optionalSfixed32ExtensionLite, 109);
+ message.setExtension(optionalSfixed64ExtensionLite, 110L);
+ message.setExtension(optionalFloatExtensionLite , 111F);
+ message.setExtension(optionalDoubleExtensionLite , 112D);
+ message.setExtension(optionalBoolExtensionLite , true);
+ message.setExtension(optionalStringExtensionLite , "115");
+ message.setExtension(optionalBytesExtensionLite , toBytes("116"));
+
+ message.setExtension(optionalGroupExtensionLite,
+ OptionalGroup_extension_lite.newBuilder().setA(117).build());
+ message.setExtension(optionalNestedMessageExtensionLite,
+ TestAllTypesLite.NestedMessage.newBuilder().setBb(118).build());
+ message.setExtension(optionalForeignMessageExtensionLite,
+ ForeignMessageLite.newBuilder().setC(119).build());
+ message.setExtension(optionalImportMessageExtensionLite,
+ ImportMessageLite.newBuilder().setD(120).build());
+ message.setExtension(optionalPublicImportMessageExtensionLite,
+ PublicImportMessageLite.newBuilder().setE(126).build());
+ message.setExtension(optionalLazyMessageExtensionLite,
+ TestAllTypesLite.NestedMessage.newBuilder().setBb(127).build());
+
+ message.setExtension(optionalNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAZ);
+ message.setExtension(optionalForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAZ);
+ message.setExtension(optionalImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_BAZ);
+
+ message.setExtension(optionalStringPieceExtensionLite, "124");
+ message.setExtension(optionalCordExtensionLite, "125");
+
+ // -----------------------------------------------------------------
+
+ message.addExtension(repeatedInt32ExtensionLite , 201);
+ message.addExtension(repeatedInt64ExtensionLite , 202L);
+ message.addExtension(repeatedUint32ExtensionLite , 203);
+ message.addExtension(repeatedUint64ExtensionLite , 204L);
+ message.addExtension(repeatedSint32ExtensionLite , 205);
+ message.addExtension(repeatedSint64ExtensionLite , 206L);
+ message.addExtension(repeatedFixed32ExtensionLite , 207);
+ message.addExtension(repeatedFixed64ExtensionLite , 208L);
+ message.addExtension(repeatedSfixed32ExtensionLite, 209);
+ message.addExtension(repeatedSfixed64ExtensionLite, 210L);
+ message.addExtension(repeatedFloatExtensionLite , 211F);
+ message.addExtension(repeatedDoubleExtensionLite , 212D);
+ message.addExtension(repeatedBoolExtensionLite , true);
+ message.addExtension(repeatedStringExtensionLite , "215");
+ message.addExtension(repeatedBytesExtensionLite , toBytes("216"));
+
+ message.addExtension(repeatedGroupExtensionLite,
+ RepeatedGroup_extension_lite.newBuilder().setA(217).build());
+ message.addExtension(repeatedNestedMessageExtensionLite,
+ TestAllTypesLite.NestedMessage.newBuilder().setBb(218).build());
+ message.addExtension(repeatedForeignMessageExtensionLite,
+ ForeignMessageLite.newBuilder().setC(219).build());
+ message.addExtension(repeatedImportMessageExtensionLite,
+ ImportMessageLite.newBuilder().setD(220).build());
+ message.addExtension(repeatedLazyMessageExtensionLite,
+ TestAllTypesLite.NestedMessage.newBuilder().setBb(227).build());
+
+ message.addExtension(repeatedNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAR);
+ message.addExtension(repeatedForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAR);
+ message.addExtension(repeatedImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_BAR);
+
+ message.addExtension(repeatedStringPieceExtensionLite, "224");
+ message.addExtension(repeatedCordExtensionLite, "225");
+
+ // Add a second one of each field.
+ message.addExtension(repeatedInt32ExtensionLite , 301);
+ message.addExtension(repeatedInt64ExtensionLite , 302L);
+ message.addExtension(repeatedUint32ExtensionLite , 303);
+ message.addExtension(repeatedUint64ExtensionLite , 304L);
+ message.addExtension(repeatedSint32ExtensionLite , 305);
+ message.addExtension(repeatedSint64ExtensionLite , 306L);
+ message.addExtension(repeatedFixed32ExtensionLite , 307);
+ message.addExtension(repeatedFixed64ExtensionLite , 308L);
+ message.addExtension(repeatedSfixed32ExtensionLite, 309);
+ message.addExtension(repeatedSfixed64ExtensionLite, 310L);
+ message.addExtension(repeatedFloatExtensionLite , 311F);
+ message.addExtension(repeatedDoubleExtensionLite , 312D);
+ message.addExtension(repeatedBoolExtensionLite , false);
+ message.addExtension(repeatedStringExtensionLite , "315");
+ message.addExtension(repeatedBytesExtensionLite , toBytes("316"));
+
+ message.addExtension(repeatedGroupExtensionLite,
+ RepeatedGroup_extension_lite.newBuilder().setA(317).build());
+ message.addExtension(repeatedNestedMessageExtensionLite,
+ TestAllTypesLite.NestedMessage.newBuilder().setBb(318).build());
+ message.addExtension(repeatedForeignMessageExtensionLite,
+ ForeignMessageLite.newBuilder().setC(319).build());
+ message.addExtension(repeatedImportMessageExtensionLite,
+ ImportMessageLite.newBuilder().setD(320).build());
+ message.addExtension(repeatedLazyMessageExtensionLite,
+ TestAllTypesLite.NestedMessage.newBuilder().setBb(327).build());
+
+ message.addExtension(repeatedNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAZ);
+ message.addExtension(repeatedForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAZ);
+ message.addExtension(repeatedImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_BAZ);
+
+ message.addExtension(repeatedStringPieceExtensionLite, "324");
+ message.addExtension(repeatedCordExtensionLite, "325");
+
+ // -----------------------------------------------------------------
+
+ message.setExtension(defaultInt32ExtensionLite , 401);
+ message.setExtension(defaultInt64ExtensionLite , 402L);
+ message.setExtension(defaultUint32ExtensionLite , 403);
+ message.setExtension(defaultUint64ExtensionLite , 404L);
+ message.setExtension(defaultSint32ExtensionLite , 405);
+ message.setExtension(defaultSint64ExtensionLite , 406L);
+ message.setExtension(defaultFixed32ExtensionLite , 407);
+ message.setExtension(defaultFixed64ExtensionLite , 408L);
+ message.setExtension(defaultSfixed32ExtensionLite, 409);
+ message.setExtension(defaultSfixed64ExtensionLite, 410L);
+ message.setExtension(defaultFloatExtensionLite , 411F);
+ message.setExtension(defaultDoubleExtensionLite , 412D);
+ message.setExtension(defaultBoolExtensionLite , false);
+ message.setExtension(defaultStringExtensionLite , "415");
+ message.setExtension(defaultBytesExtensionLite , toBytes("416"));
+
+ message.setExtension(defaultNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.FOO);
+ message.setExtension(defaultForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_FOO);
+ message.setExtension(defaultImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_FOO);
+
+ message.setExtension(defaultStringPieceExtensionLite, "424");
+ message.setExtension(defaultCordExtensionLite, "425");
+
+ message.setExtension(oneofUint32ExtensionLite, 601);
+ message.setExtension(oneofNestedMessageExtensionLite,
+ TestAllTypesLite.NestedMessage.newBuilder().setBb(602).build());
+ message.setExtension(oneofStringExtensionLite, "603");
+ message.setExtension(oneofBytesExtensionLite, toBytes("604"));
+ }
+
+ // -------------------------------------------------------------------
+
+ /**
+ * Modify the repeated extensions of {@code message} to contain the values
+ * expected by {@code assertRepeatedExtensionsModified()}.
+ */
+ public static void modifyRepeatedExtensions(
+ TestAllExtensionsLite.Builder message) {
+ message.setExtension(repeatedInt32ExtensionLite , 1, 501);
+ message.setExtension(repeatedInt64ExtensionLite , 1, 502L);
+ message.setExtension(repeatedUint32ExtensionLite , 1, 503);
+ message.setExtension(repeatedUint64ExtensionLite , 1, 504L);
+ message.setExtension(repeatedSint32ExtensionLite , 1, 505);
+ message.setExtension(repeatedSint64ExtensionLite , 1, 506L);
+ message.setExtension(repeatedFixed32ExtensionLite , 1, 507);
+ message.setExtension(repeatedFixed64ExtensionLite , 1, 508L);
+ message.setExtension(repeatedSfixed32ExtensionLite, 1, 509);
+ message.setExtension(repeatedSfixed64ExtensionLite, 1, 510L);
+ message.setExtension(repeatedFloatExtensionLite , 1, 511F);
+ message.setExtension(repeatedDoubleExtensionLite , 1, 512D);
+ message.setExtension(repeatedBoolExtensionLite , 1, true);
+ message.setExtension(repeatedStringExtensionLite , 1, "515");
+ message.setExtension(repeatedBytesExtensionLite , 1, toBytes("516"));
+
+ message.setExtension(repeatedGroupExtensionLite, 1,
+ RepeatedGroup_extension_lite.newBuilder().setA(517).build());
+ message.setExtension(repeatedNestedMessageExtensionLite, 1,
+ TestAllTypesLite.NestedMessage.newBuilder().setBb(518).build());
+ message.setExtension(repeatedForeignMessageExtensionLite, 1,
+ ForeignMessageLite.newBuilder().setC(519).build());
+ message.setExtension(repeatedImportMessageExtensionLite, 1,
+ ImportMessageLite.newBuilder().setD(520).build());
+ message.setExtension(repeatedLazyMessageExtensionLite, 1,
+ TestAllTypesLite.NestedMessage.newBuilder().setBb(527).build());
+
+ message.setExtension(repeatedNestedEnumExtensionLite , 1, TestAllTypesLite.NestedEnum.FOO);
+ message.setExtension(repeatedForeignEnumExtensionLite, 1, ForeignEnumLite.FOREIGN_LITE_FOO);
+ message.setExtension(repeatedImportEnumExtensionLite , 1, ImportEnumLite.IMPORT_LITE_FOO);
+
+ message.setExtension(repeatedStringPieceExtensionLite, 1, "524");
+ message.setExtension(repeatedCordExtensionLite, 1, "525");
+ }
+
+ public static void setPackedExtensions(TestPackedExtensionsLite.Builder message) {
+ message.addExtension(packedInt32ExtensionLite , 601);
+ message.addExtension(packedInt64ExtensionLite , 602L);
+ message.addExtension(packedUint32ExtensionLite , 603);
+ message.addExtension(packedUint64ExtensionLite , 604L);
+ message.addExtension(packedSint32ExtensionLite , 605);
+ message.addExtension(packedSint64ExtensionLite , 606L);
+ message.addExtension(packedFixed32ExtensionLite , 607);
+ message.addExtension(packedFixed64ExtensionLite , 608L);
+ message.addExtension(packedSfixed32ExtensionLite, 609);
+ message.addExtension(packedSfixed64ExtensionLite, 610L);
+ message.addExtension(packedFloatExtensionLite , 611F);
+ message.addExtension(packedDoubleExtensionLite , 612D);
+ message.addExtension(packedBoolExtensionLite , true);
+ message.addExtension(packedEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAR);
+ // Add a second one of each field.
+ message.addExtension(packedInt32ExtensionLite , 701);
+ message.addExtension(packedInt64ExtensionLite , 702L);
+ message.addExtension(packedUint32ExtensionLite , 703);
+ message.addExtension(packedUint64ExtensionLite , 704L);
+ message.addExtension(packedSint32ExtensionLite , 705);
+ message.addExtension(packedSint64ExtensionLite , 706L);
+ message.addExtension(packedFixed32ExtensionLite , 707);
+ message.addExtension(packedFixed64ExtensionLite , 708L);
+ message.addExtension(packedSfixed32ExtensionLite, 709);
+ message.addExtension(packedSfixed64ExtensionLite, 710L);
+ message.addExtension(packedFloatExtensionLite , 711F);
+ message.addExtension(packedDoubleExtensionLite , 712D);
+ message.addExtension(packedBoolExtensionLite , false);
+ message.addExtension(packedEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAZ);
+ }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/TextFormatParseInfoTreeTest.java b/java/core/src/test/java/com/google/protobuf/TextFormatParseInfoTreeTest.java
new file mode 100644
index 00000000..e338af21
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/TextFormatParseInfoTreeTest.java
@@ -0,0 +1,182 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.Descriptor;
+import com.google.protobuf.Descriptors.FieldDescriptor;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+
+import junit.framework.TestCase;
+
+/**
+ * Test @{link TextFormatParseInfoTree}.
+ */
+public class TextFormatParseInfoTreeTest extends TestCase {
+
+ private static final Descriptor DESCRIPTOR = TestAllTypes.getDescriptor();
+ private static final FieldDescriptor OPTIONAL_INT32 =
+ DESCRIPTOR.findFieldByName("optional_int32");
+ private static final FieldDescriptor OPTIONAL_BOOLEAN =
+ DESCRIPTOR.findFieldByName("optional_boolean");
+ private static final FieldDescriptor REPEATED_INT32 =
+ DESCRIPTOR.findFieldByName("repeated_int32");
+ private static final FieldDescriptor OPTIONAL_NESTED_MESSAGE =
+ DESCRIPTOR.findFieldByName("optional_nested_message");
+ private static final FieldDescriptor REPEATED_NESTED_MESSAGE =
+ DESCRIPTOR.findFieldByName("repeated_nested_message");
+ private static final FieldDescriptor FIELD_BB =
+ TestAllTypes.NestedMessage.getDescriptor().findFieldByName("bb");
+
+ private static final TextFormatParseLocation LOC0 = TextFormatParseLocation.create(1, 2);
+ private static final TextFormatParseLocation LOC1 = TextFormatParseLocation.create(2, 3);
+
+ private TextFormatParseInfoTree.Builder rootBuilder;
+
+ @Override
+ public void setUp() {
+ rootBuilder = TextFormatParseInfoTree.builder();
+ }
+
+ public void testBuildEmptyParseTree() {
+ TextFormatParseInfoTree tree = rootBuilder.build();
+ assertTrue(tree.getLocations(null).isEmpty());
+ }
+
+ public void testGetLocationReturnsSingleLocation() {
+ rootBuilder.setLocation(OPTIONAL_INT32, LOC0);
+ TextFormatParseInfoTree root = rootBuilder.build();
+ assertEquals(LOC0, root.getLocation(OPTIONAL_INT32, 0));
+ assertEquals(1, root.getLocations(OPTIONAL_INT32).size());
+ }
+
+ public void testGetLocationsReturnsNoParseLocationsForUnknownField() {
+ assertTrue(rootBuilder.build().getLocations(OPTIONAL_INT32).isEmpty());
+ rootBuilder.setLocation(OPTIONAL_BOOLEAN, LOC0);
+ TextFormatParseInfoTree root = rootBuilder.build();
+ assertTrue(root.getLocations(OPTIONAL_INT32).isEmpty());
+ assertEquals(LOC0, root.getLocations(OPTIONAL_BOOLEAN).get(0));
+ }
+
+ public void testGetLocationThrowsIllegalArgumentExceptionForUnknownField() {
+ rootBuilder.setLocation(REPEATED_INT32, LOC0);
+ TextFormatParseInfoTree root = rootBuilder.build();
+ try {
+ root.getNestedTree(OPTIONAL_INT32, 0);
+ fail("Did not detect unknown field");
+ } catch (IllegalArgumentException expected) {
+ // pass
+ }
+ }
+
+ public void testGetLocationThrowsIllegalArgumentExceptionForInvalidIndex() {
+ TextFormatParseInfoTree root = rootBuilder.setLocation(OPTIONAL_INT32, LOC0).build();
+ try {
+ root.getLocation(OPTIONAL_INT32, 1);
+ fail("Invalid index not detected");
+ } catch (IllegalArgumentException expected) {
+ // pass
+ }
+ try {
+ root.getLocation(OPTIONAL_INT32, -1);
+ fail("Negative index not detected");
+ } catch (IllegalArgumentException expected) {
+ // pass
+ }
+ }
+
+ public void testGetLocationsReturnsMultipleLocations() {
+ rootBuilder.setLocation(REPEATED_INT32, LOC0);
+ rootBuilder.setLocation(REPEATED_INT32, LOC1);
+ TextFormatParseInfoTree root = rootBuilder.build();
+ assertEquals(LOC0, root.getLocation(REPEATED_INT32, 0));
+ assertEquals(LOC1, root.getLocation(REPEATED_INT32, 1));
+ assertEquals(2, root.getLocations(REPEATED_INT32).size());
+ }
+
+ public void testGetNestedTreeThrowsIllegalArgumentExceptionForUnknownField() {
+ rootBuilder.setLocation(REPEATED_INT32, LOC0);
+ TextFormatParseInfoTree root = rootBuilder.build();
+ try {
+ root.getNestedTree(OPTIONAL_NESTED_MESSAGE, 0);
+ fail("Did not detect unknown field");
+ } catch (IllegalArgumentException expected) {
+ // pass
+ }
+ }
+
+ public void testGetNestedTreesReturnsNoParseInfoTreesForUnknownField() {
+ rootBuilder.setLocation(REPEATED_INT32, LOC0);
+ TextFormatParseInfoTree root = rootBuilder.build();
+ assertTrue(root.getNestedTrees(OPTIONAL_NESTED_MESSAGE).isEmpty());
+ }
+
+ public void testGetNestedTreeThrowsIllegalArgumentExceptionForInvalidIndex() {
+ rootBuilder.setLocation(REPEATED_INT32, LOC0);
+ rootBuilder.getBuilderForSubMessageField(OPTIONAL_NESTED_MESSAGE);
+ TextFormatParseInfoTree root = rootBuilder.build();
+ try {
+ root.getNestedTree(OPTIONAL_NESTED_MESSAGE, 1);
+ fail("Submessage index that is too large not detected");
+ } catch (IllegalArgumentException expected) {
+ // pass
+ }
+ try {
+ rootBuilder.build().getNestedTree(OPTIONAL_NESTED_MESSAGE, -1);
+ fail("Invalid submessage index (-1) not detected");
+ } catch (IllegalArgumentException expected) {
+ // pass
+ }
+ }
+
+ public void testGetNestedTreesReturnsSingleTree() {
+ rootBuilder.getBuilderForSubMessageField(OPTIONAL_NESTED_MESSAGE);
+ TextFormatParseInfoTree root = rootBuilder.build();
+ assertEquals(1, root.getNestedTrees(OPTIONAL_NESTED_MESSAGE).size());
+ TextFormatParseInfoTree subtree = root.getNestedTrees(OPTIONAL_NESTED_MESSAGE).get(0);
+ assertNotNull(subtree);
+ }
+
+ public void testGetNestedTreesReturnsMultipleTrees() {
+ TextFormatParseInfoTree.Builder subtree1Builder =
+ rootBuilder.getBuilderForSubMessageField(REPEATED_NESTED_MESSAGE);
+ subtree1Builder.getBuilderForSubMessageField(FIELD_BB);
+ subtree1Builder.getBuilderForSubMessageField(FIELD_BB);
+ TextFormatParseInfoTree.Builder subtree2Builder =
+ rootBuilder.getBuilderForSubMessageField(REPEATED_NESTED_MESSAGE);
+ subtree2Builder.getBuilderForSubMessageField(FIELD_BB);
+ TextFormatParseInfoTree root = rootBuilder.build();
+ assertEquals(2, root.getNestedTrees(REPEATED_NESTED_MESSAGE).size());
+ assertEquals(
+ 2, root.getNestedTrees(REPEATED_NESTED_MESSAGE).get(0).getNestedTrees(FIELD_BB).size());
+ assertEquals(
+ 1, root.getNestedTrees(REPEATED_NESTED_MESSAGE).get(1).getNestedTrees(FIELD_BB).size());
+ }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/TextFormatParseLocationTest.java b/java/core/src/test/java/com/google/protobuf/TextFormatParseLocationTest.java
new file mode 100644
index 00000000..c42bfa6e
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/TextFormatParseLocationTest.java
@@ -0,0 +1,86 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import junit.framework.TestCase;
+
+/**
+ * Test @{link TextFormatParseLocation}.
+ */
+public class TextFormatParseLocationTest extends TestCase {
+
+ public void testCreateEmpty() {
+ TextFormatParseLocation location = TextFormatParseLocation.create(-1, -1);
+ assertEquals(TextFormatParseLocation.EMPTY, location);
+ }
+
+ public void testCreate() {
+ TextFormatParseLocation location = TextFormatParseLocation.create(2, 1);
+ assertEquals(2, location.getLine());
+ assertEquals(1, location.getColumn());
+ }
+
+ public void testCreateThrowsIllegalArgumentExceptionForInvalidIndex() {
+ try {
+ TextFormatParseLocation.create(-1, 0);
+ fail("Should throw IllegalArgumentException if line is less than 0");
+ } catch (IllegalArgumentException unused) {
+ // pass
+ }
+ try {
+ TextFormatParseLocation.create(0, -1);
+ fail("Should throw, column < 0");
+ } catch (IllegalArgumentException unused) {
+ // pass
+ }
+ }
+
+ public void testHashCode() {
+ TextFormatParseLocation loc0 = TextFormatParseLocation.create(2, 1);
+ TextFormatParseLocation loc1 = TextFormatParseLocation.create(2, 1);
+
+ assertEquals(loc0.hashCode(), loc1.hashCode());
+ assertEquals(
+ TextFormatParseLocation.EMPTY.hashCode(), TextFormatParseLocation.EMPTY.hashCode());
+ }
+
+ public void testEquals() {
+ TextFormatParseLocation loc0 = TextFormatParseLocation.create(2, 1);
+ TextFormatParseLocation loc1 = TextFormatParseLocation.create(1, 2);
+ TextFormatParseLocation loc2 = TextFormatParseLocation.create(2, 2);
+ TextFormatParseLocation loc3 = TextFormatParseLocation.create(2, 1);
+
+ assertEquals(loc0, loc3);
+ assertNotSame(loc0, loc1);
+ assertNotSame(loc0, loc2);
+ assertNotSame(loc1, loc2);
+ }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/TextFormatTest.java b/java/core/src/test/java/com/google/protobuf/TextFormatTest.java
index 1df4fad7..63c17cd0 100644
--- a/java/core/src/test/java/com/google/protobuf/TextFormatTest.java
+++ b/java/core/src/test/java/com/google/protobuf/TextFormatTest.java
@@ -30,6 +30,7 @@
package com.google.protobuf;
+import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.TextFormat.Parser.SingularOverwritePolicy;
import protobuf_unittest.UnittestMset.TestMessageSetExtension1;
@@ -45,6 +46,7 @@ import proto2_wireformat_unittest.UnittestMsetWireFormat.TestMessageSet;
import junit.framework.TestCase;
import java.io.StringReader;
+import java.util.List;
/**
* Test case for {@link TextFormat}.
@@ -568,6 +570,16 @@ public class TextFormatTest extends TestCase {
assertEquals(kEscapeTestString,
TextFormat.unescapeText(kEscapeTestStringEscaped));
+ // Invariant
+ assertEquals("hello",
+ TextFormat.escapeBytes(bytes("hello")));
+ assertEquals("hello",
+ TextFormat.escapeText("hello"));
+ assertEquals(bytes("hello"),
+ TextFormat.unescapeBytes("hello"));
+ assertEquals("hello",
+ TextFormat.unescapeText("hello"));
+
// Unicode handling.
assertEquals("\\341\\210\\264", TextFormat.escapeText("\u1234"));
assertEquals("\\341\\210\\264",
@@ -763,11 +775,14 @@ public class TextFormatTest extends TestCase {
public void testParseBoolean() throws Exception {
String goodText =
"repeated_bool: t repeated_bool : 0\n" +
- "repeated_bool :f repeated_bool:1";
+ "repeated_bool :f repeated_bool:1\n" +
+ "repeated_bool: False repeated_bool: True";
String goodTextCanonical =
"repeated_bool: true\n" +
"repeated_bool: false\n" +
"repeated_bool: false\n" +
+ "repeated_bool: true\n" +
+ "repeated_bool: false\n" +
"repeated_bool: true\n";
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
TextFormat.merge(goodText, builder);
@@ -811,7 +826,6 @@ public class TextFormatTest extends TestCase {
private void assertPrintFieldValue(String expect, Object value,
String fieldName) throws Exception {
- TestAllTypes.Builder builder = TestAllTypes.newBuilder();
StringBuilder sb = new StringBuilder();
TextFormat.printFieldValue(
TestAllTypes.getDescriptor().findFieldByName(fieldName),
@@ -1018,4 +1032,98 @@ public class TextFormatTest extends TestCase {
assertFalse(oneof.hasFooString());
assertTrue(oneof.hasFooInt());
}
+
+ // =======================================================================
+ // test location information
+
+ public void testParseInfoTreeBuilding() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+
+ Descriptor descriptor = TestAllTypes.getDescriptor();
+ TextFormatParseInfoTree.Builder treeBuilder = TextFormatParseInfoTree.builder();
+ // Set to allow unknown fields
+ TextFormat.Parser parser =
+ TextFormat.Parser.newBuilder()
+ .setParseInfoTreeBuilder(treeBuilder)
+ .build();
+
+ final String stringData =
+ "optional_int32: 1\n"
+ + "optional_int64: 2\n"
+ + " optional_double: 2.4\n"
+ + "repeated_int32: 5\n"
+ + "repeated_int32: 10\n"
+ + "optional_nested_message <\n"
+ + " bb: 78\n"
+ + ">\n"
+ + "repeated_nested_message <\n"
+ + " bb: 79\n"
+ + ">\n"
+ + "repeated_nested_message <\n"
+ + " bb: 80\n"
+ + ">";
+
+ parser.merge(stringData, builder);
+ TextFormatParseInfoTree tree = treeBuilder.build();
+
+ // Verify that the tree has the correct positions.
+ assertLocation(tree, descriptor, "optional_int32", 0, 0, 0);
+ assertLocation(tree, descriptor, "optional_int64", 0, 1, 0);
+ assertLocation(tree, descriptor, "optional_double", 0, 2, 2);
+
+ assertLocation(tree, descriptor, "repeated_int32", 0, 3, 0);
+ assertLocation(tree, descriptor, "repeated_int32", 1, 4, 0);
+
+ assertLocation(tree, descriptor, "optional_nested_message", 0, 5, 0);
+ assertLocation(tree, descriptor, "repeated_nested_message", 0, 8, 0);
+ assertLocation(tree, descriptor, "repeated_nested_message", 1, 11, 0);
+
+ // Check for fields not set. For an invalid field, the location returned should be -1, -1.
+ assertLocation(tree, descriptor, "repeated_int64", 0, -1, -1);
+ assertLocation(tree, descriptor, "repeated_int32", 6, -1, -1);
+
+ // Verify inside the nested message.
+ FieldDescriptor nestedField = descriptor.findFieldByName("optional_nested_message");
+
+ TextFormatParseInfoTree nestedTree = tree.getNestedTrees(nestedField).get(0);
+ assertLocation(nestedTree, nestedField.getMessageType(), "bb", 0, 6, 2);
+
+ // Verify inside another nested message.
+ nestedField = descriptor.findFieldByName("repeated_nested_message");
+ nestedTree = tree.getNestedTrees(nestedField).get(0);
+ assertLocation(nestedTree, nestedField.getMessageType(), "bb", 0, 9, 2);
+
+ nestedTree = tree.getNestedTrees(nestedField).get(1);
+ assertLocation(nestedTree, nestedField.getMessageType(), "bb", 0, 12, 2);
+
+ // Verify a NULL tree for an unknown nested field.
+ try {
+ tree.getNestedTree(nestedField, 2);
+ fail("unknown nested field should throw");
+ } catch (IllegalArgumentException unused) {
+ // pass
+ }
+ }
+
+ private void assertLocation(
+ TextFormatParseInfoTree tree,
+ final Descriptor descriptor,
+ final String fieldName,
+ int index,
+ int line,
+ int column) {
+ List<TextFormatParseLocation> locs = tree.getLocations(descriptor.findFieldByName(fieldName));
+ if (index < locs.size()) {
+ TextFormatParseLocation location = locs.get(index);
+ TextFormatParseLocation expected = TextFormatParseLocation.create(line, column);
+ assertEquals(expected, location);
+ } else if (line != -1 && column != -1) {
+ fail(
+ String.format(
+ "Tree/descriptor/fieldname did not contain index %d, line %d column %d expected",
+ index,
+ line,
+ column));
+ }
+ }
}
diff --git a/java/core/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java b/java/core/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java
index dc987379..573cd665 100644
--- a/java/core/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java
+++ b/java/core/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java
@@ -47,46 +47,6 @@ import java.io.IOException;
* @author dweis@google.com (Daniel Weis)
*/
public class UnknownFieldSetLiteTest extends TestCase {
-
- public void testNoDataIsDefaultInstance() {
- assertSame(
- UnknownFieldSetLite.getDefaultInstance(),
- 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();
diff --git a/java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java b/java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
index 8c9dcafe..32380f70 100644
--- a/java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
+++ b/java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
@@ -50,6 +50,7 @@ import java.util.Map;
* @author kenton@google.com (Kenton Varda)
*/
public class UnknownFieldSetTest extends TestCase {
+ @Override
public void setUp() throws Exception {
descriptor = TestAllTypes.getDescriptor();
allFields = TestUtil.getAllSet();
diff --git a/java/core/src/test/java/com/google/protobuf/WireFormatTest.java b/java/core/src/test/java/com/google/protobuf/WireFormatTest.java
index 0175005d..e66b371c 100644
--- a/java/core/src/test/java/com/google/protobuf/WireFormatTest.java
+++ b/java/core/src/test/java/com/google/protobuf/WireFormatTest.java
@@ -30,12 +30,11 @@
package com.google.protobuf;
-import junit.framework.TestCase;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.util.List;
-
+import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
+import com.google.protobuf.UnittestLite.TestPackedExtensionsLite;
+import protobuf_unittest.UnittestMset.RawMessageSet;
+import protobuf_unittest.UnittestMset.TestMessageSetExtension1;
+import protobuf_unittest.UnittestMset.TestMessageSetExtension2;
import protobuf_unittest.UnittestProto;
import protobuf_unittest.UnittestProto.TestAllExtensions;
import protobuf_unittest.UnittestProto.TestAllTypes;
@@ -44,12 +43,13 @@ import protobuf_unittest.UnittestProto.TestOneof2;
import protobuf_unittest.UnittestProto.TestOneofBackwardsCompatible;
import protobuf_unittest.UnittestProto.TestPackedExtensions;
import protobuf_unittest.UnittestProto.TestPackedTypes;
-import protobuf_unittest.UnittestMset.RawMessageSet;
-import protobuf_unittest.UnittestMset.TestMessageSetExtension1;
-import protobuf_unittest.UnittestMset.TestMessageSetExtension2;
import proto2_wireformat_unittest.UnittestMsetWireFormat.TestMessageSet;
-import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
-import com.google.protobuf.UnittestLite.TestPackedExtensionsLite;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.util.List;
/**
* Tests related to parsing and serialization.
@@ -132,7 +132,7 @@ public class WireFormatTest extends TestCase {
// so if we serialize a TestAllExtensions then parse it as TestAllTypes
// it should work.
- TestAllExtensionsLite message = TestUtil.getAllLiteExtensionsSet();
+ TestAllExtensionsLite message = TestUtilLite.getAllLiteExtensionsSet();
ByteString rawBytes = message.toByteString();
assertEquals(rawBytes.size(), message.getSerializedSize());
@@ -144,7 +144,7 @@ public class WireFormatTest extends TestCase {
public void testSerializePackedExtensionsLite() throws Exception {
// TestPackedTypes and TestPackedExtensions should have compatible wire
// formats; check that they serialize to the same string.
- TestPackedExtensionsLite message = TestUtil.getLitePackedExtensionsSet();
+ TestPackedExtensionsLite message = TestUtilLite.getLitePackedExtensionsSet();
ByteString rawBytes = message.toByteString();
TestPackedTypes message2 = TestUtil.getPackedSet();
@@ -190,7 +190,7 @@ public class WireFormatTest extends TestCase {
TestAllTypes message = TestUtil.getAllSet();
ByteString rawBytes = message.toByteString();
- ExtensionRegistryLite registry_lite = TestUtil.getExtensionRegistryLite();
+ ExtensionRegistryLite registry_lite = TestUtilLite.getExtensionRegistryLite();
TestAllExtensionsLite message2 =
TestAllExtensionsLite.parseFrom(rawBytes, registry_lite);
@@ -208,10 +208,10 @@ public class WireFormatTest extends TestCase {
public void testParsePackedExtensionsLite() throws Exception {
// Ensure that packed extensions can be properly parsed.
- TestPackedExtensionsLite message = TestUtil.getLitePackedExtensionsSet();
+ TestPackedExtensionsLite message = TestUtilLite.getLitePackedExtensionsSet();
ByteString rawBytes = message.toByteString();
- ExtensionRegistryLite registry = TestUtil.getExtensionRegistryLite();
+ ExtensionRegistryLite registry = TestUtilLite.getExtensionRegistryLite();
TestPackedExtensionsLite message2 =
TestPackedExtensionsLite.parseFrom(rawBytes, registry);
diff --git a/java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto b/java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto
index 86837250..6eef42c5 100644
--- a/java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto
+++ b/java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto
@@ -34,11 +34,15 @@ syntax = "proto2";
package protobuf_unittest.lite_equals_and_hash;
-// This proto definition is used to test that java_generate_equals_and_hash
-// works correctly with the LITE_RUNTIME.
-option java_generate_equals_and_hash = true;
option optimize_for = LITE_RUNTIME;
+message TestOneofEquals {
+ oneof oneof_field {
+ string name = 1;
+ int32 value = 2;
+ }
+}
+
message Foo {
optional int32 value = 1;
repeated Bar bar = 2;
@@ -70,3 +74,8 @@ extend Foo {
}
}
+message TestRecursiveOneof {
+ oneof Foo {
+ TestRecursiveOneof r = 1;
+ }
+}
diff --git a/java/lite/generate-sources-build.xml b/java/lite/generate-sources-build.xml
new file mode 100644
index 00000000..89c21c13
--- /dev/null
+++ b/java/lite/generate-sources-build.xml
@@ -0,0 +1,20 @@
+<project name="generate-sources">
+ <echo message="Running protoc ..."/>
+ <mkdir dir="${generated.sources.lite.dir}"/>
+ <exec executable="${protoc}">
+ <arg value="--java_out=lite:${generated.sources.lite.dir}"/>
+ <arg value="--proto_path=${protobuf.source.dir}"/>
+ <arg value="${protobuf.source.dir}/google/protobuf/any.proto"/>
+ <arg value="${protobuf.source.dir}/google/protobuf/api.proto"/>
+ <arg value="${protobuf.source.dir}/google/protobuf/descriptor.proto"/>
+ <arg value="${protobuf.source.dir}/google/protobuf/duration.proto"/>
+ <arg value="${protobuf.source.dir}/google/protobuf/empty.proto"/>
+ <arg value="${protobuf.source.dir}/google/protobuf/field_mask.proto"/>
+ <arg value="${protobuf.source.dir}/google/protobuf/source_context.proto"/>
+ <arg value="${protobuf.source.dir}/google/protobuf/struct.proto"/>
+ <arg value="${protobuf.source.dir}/google/protobuf/timestamp.proto"/>
+ <arg value="${protobuf.source.dir}/google/protobuf/type.proto"/>
+ <arg value="${protobuf.source.dir}/google/protobuf/wrappers.proto"/>
+ <arg value="${protobuf.source.dir}/google/protobuf/compiler/plugin.proto"/>
+ </exec>
+</project>
diff --git a/java/lite/generate-test-sources-build.xml b/java/lite/generate-test-sources-build.xml
new file mode 100644
index 00000000..cdd1ee89
--- /dev/null
+++ b/java/lite/generate-test-sources-build.xml
@@ -0,0 +1,43 @@
+<project name="generate-test-sources">
+ <mkdir dir="${generated.testsources.lite.dir}"/>
+ <exec executable="${protoc}">
+ <arg value="--java_out=lite:${generated.testsources.lite.dir}"/>
+ <arg value="--proto_path=${protobuf.source.dir}"/>
+ <arg value="--proto_path=${test.proto.dir}"/>
+ <arg value="${protobuf.source.dir}/google/protobuf/unittest.proto"/>
+ <arg value="${protobuf.source.dir}/google/protobuf/unittest_import.proto"/>
+ <arg value="${protobuf.source.dir}/google/protobuf/unittest_import_public.proto"/>
+ <arg value="${protobuf.source.dir}/google/protobuf/unittest_mset.proto"/>
+ <arg value="${protobuf.source.dir}/google/protobuf/unittest_mset_wire_format.proto"/>
+ <arg value="${protobuf.source.dir}/google/protobuf/unittest_optimize_for.proto"/>
+ <arg value="${protobuf.source.dir}/google/protobuf/unittest_custom_options.proto"/>
+ <arg value="${protobuf.source.dir}/google/protobuf/unittest_lite.proto"/>
+ <arg value="${protobuf.source.dir}/google/protobuf/unittest_import_lite.proto"/>
+ <arg value="${protobuf.source.dir}/google/protobuf/unittest_import_public_lite.proto"/>
+ <arg value="${protobuf.source.dir}/google/protobuf/unittest_lite_imports_nonlite.proto"/>
+ <arg value="${protobuf.source.dir}/google/protobuf/unittest_enormous_descriptor.proto"/>
+ <arg value="${protobuf.source.dir}/google/protobuf/unittest_no_generic_services.proto"/>
+ <arg value="${protobuf.source.dir}/google/protobuf/unittest_well_known_types.proto"/>
+ <arg value="${test.proto.dir}/com/google/protobuf/lazy_fields_lite.proto"/>
+ <arg value="${test.proto.dir}/com/google/protobuf/lite_equals_and_hash.proto"/>
+ <arg value="${test.proto.dir}/com/google/protobuf/multiple_files_test.proto"/>
+ <arg value="${test.proto.dir}/com/google/protobuf/nested_builders_test.proto"/>
+ <arg value="${test.proto.dir}/com/google/protobuf/nested_extension.proto"/>
+ <arg value="${test.proto.dir}/com/google/protobuf/nested_extension_lite.proto"/>
+ <arg value="${test.proto.dir}/com/google/protobuf/non_nested_extension.proto"/>
+ <arg value="${test.proto.dir}/com/google/protobuf/non_nested_extension_lite.proto"/>
+ <arg value="${test.proto.dir}/com/google/protobuf/outer_class_name_test.proto"/>
+ <arg value="${test.proto.dir}/com/google/protobuf/outer_class_name_test2.proto"/>
+ <arg value="${test.proto.dir}/com/google/protobuf/outer_class_name_test3.proto"/>
+ <arg value="${test.proto.dir}/com/google/protobuf/test_bad_identifiers.proto"/>
+ <arg value="${test.proto.dir}/com/google/protobuf/test_check_utf8.proto"/>
+ <arg value="${test.proto.dir}/com/google/protobuf/test_check_utf8_size.proto"/>
+ <arg value="${test.proto.dir}/com/google/protobuf/test_custom_options.proto"/>
+ <arg value="${test.proto.dir}/com/google/protobuf/any_test.proto"/>
+ <arg value="${test.proto.dir}/com/google/protobuf/field_presence_test.proto"/>
+ <arg value="${test.proto.dir}/com/google/protobuf/map_for_proto2_lite_test.proto"/>
+ <arg value="${test.proto.dir}/com/google/protobuf/map_for_proto2_test.proto"/>
+ <arg value="${test.proto.dir}/com/google/protobuf/map_test.proto"/>
+ <arg value="${test.proto.dir}/com/google/protobuf/map_initialization_order_test.proto"/>
+ </exec>
+</project>
diff --git a/java/lite/pom.xml b/java/lite/pom.xml
index 70c7d047..23cb4f78 100644
--- a/java/lite/pom.xml
+++ b/java/lite/pom.xml
@@ -50,7 +50,7 @@
<phase>generate-sources</phase>
<configuration>
<target>
- <ant antfile="${core.root}/generate-sources-build.xml"/>
+ <ant antfile="generate-sources-build.xml"/>
</target>
</configuration>
<goals>
@@ -64,7 +64,7 @@
<phase>generate-test-sources</phase>
<configuration>
<target>
- <ant antfile="${core.root}/generate-test-sources-build.xml"/>
+ <ant antfile="generate-test-sources-build.xml"/>
</target>
</configuration>
<goals>
@@ -78,8 +78,8 @@
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
- <generatedSourcesDirectory>${generated.sources.dir}</generatedSourcesDirectory>
- <generatedTestSourcesDirectory>${generated.testsources.dir}</generatedTestSourcesDirectory>
+ <generatedSourcesDirectory>${generated.sources.lite.dir}</generatedSourcesDirectory>
+ <generatedTestSourcesDirectory>${generated.testsources.lite.dir}</generatedTestSourcesDirectory>
<includes>
<include>**/AbstractMessageLite.java</include>
<include>**/AbstractParser.java</include>
diff --git a/java/pom.xml b/java/pom.xml
index d5719edf..e8dc5ded 100644
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -33,6 +33,8 @@
<test.proto.dir>src/test/proto</test.proto.dir>
<generated.sources.dir>${project.build.directory}/generated-sources</generated.sources.dir>
<generated.testsources.dir>${project.build.directory}/generated-test-sources</generated.testsources.dir>
+ <generated.sources.lite.dir>${project.build.directory}/generated-sources-lite</generated.sources.lite.dir>
+ <generated.testsources.lite.dir>${project.build.directory}/generated-test-sources-lite</generated.testsources.lite.dir>
</properties>
<licenses>
@@ -64,7 +66,7 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
- <version>4.4</version>
+ <version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
diff --git a/java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java b/java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java
index dc2f4b84..668d65ab 100644
--- a/java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java
+++ b/java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java
@@ -60,10 +60,9 @@ import java.util.logging.Logger;
* FieldMask in a message tree.
*/
class FieldMaskTree {
- private static final Logger logger =
- Logger.getLogger(FieldMaskTree.class.getName());
-
- private static final String FIELD_PATH_SEPARATOR_REGEX = "\\.";
+ private static final Logger logger = Logger.getLogger(FieldMaskTree.class.getName());
+
+ private static final String FIELD_PATH_SEPARATOR_REGEX = "\\.";
private static class Node {
public TreeMap<String, Node> children = new TreeMap<String, Node>();
@@ -73,12 +72,12 @@ class FieldMaskTree {
/** Creates an empty FieldMaskTree. */
public FieldMaskTree() {}
-
+
/** Creates a FieldMaskTree for a given FieldMask. */
public FieldMaskTree(FieldMask mask) {
mergeFromFieldMask(mask);
}
-
+
@Override
public String toString() {
return FieldMaskUtil.toString(toFieldMask());
@@ -121,7 +120,7 @@ class FieldMaskTree {
node.children.clear();
return this;
}
-
+
/**
* Merges all field paths in a FieldMask into this tree.
*/
@@ -149,8 +148,7 @@ class FieldMaskTree {
return;
}
for (Entry<String, Node> entry : node.children.entrySet()) {
- String childPath = path.isEmpty()
- ? entry.getKey() : path + "." + entry.getKey();
+ String childPath = path.isEmpty() ? entry.getKey() : path + "." + entry.getKey();
getFieldPaths(entry.getValue(), childPath, paths);
}
}
@@ -193,11 +191,10 @@ class FieldMaskTree {
* Merges all fields specified by this FieldMaskTree from {@code source} to
* {@code destination}.
*/
- public void merge(Message source, Message.Builder destination,
- FieldMaskUtil.MergeOptions options) {
+ public void merge(
+ Message source, Message.Builder destination, FieldMaskUtil.MergeOptions options) {
if (source.getDescriptorForType() != destination.getDescriptorForType()) {
- throw new IllegalArgumentException(
- "Cannot merge messages of different types.");
+ throw new IllegalArgumentException("Cannot merge messages of different types.");
}
if (root.children.isEmpty()) {
return;
@@ -208,30 +205,41 @@ class FieldMaskTree {
/** Merges all fields specified by a sub-tree from {@code source} to
* {@code destination}.
*/
- private void merge(Node node, String path, Message source,
- Message.Builder destination, FieldMaskUtil.MergeOptions options) {
+ private void merge(
+ Node node,
+ String path,
+ Message source,
+ Message.Builder destination,
+ FieldMaskUtil.MergeOptions options) {
assert source.getDescriptorForType() == destination.getDescriptorForType();
-
+
Descriptor descriptor = source.getDescriptorForType();
for (Entry<String, Node> entry : node.children.entrySet()) {
- FieldDescriptor field =
- descriptor.findFieldByName(entry.getKey());
+ FieldDescriptor field = descriptor.findFieldByName(entry.getKey());
if (field == null) {
- logger.warning("Cannot find field \"" + entry.getKey()
- + "\" in message type " + descriptor.getFullName());
+ logger.warning(
+ "Cannot find field \""
+ + entry.getKey()
+ + "\" in message type "
+ + descriptor.getFullName());
continue;
}
if (!entry.getValue().children.isEmpty()) {
- if (field.isRepeated()
- || field.getJavaType() != FieldDescriptor.JavaType.MESSAGE) {
- logger.warning("Field \"" + field.getFullName() + "\" is not a "
- + "singluar message field and cannot have sub-fields.");
+ if (field.isRepeated() || field.getJavaType() != FieldDescriptor.JavaType.MESSAGE) {
+ logger.warning(
+ "Field \""
+ + field.getFullName()
+ + "\" is not a "
+ + "singluar message field and cannot have sub-fields.");
continue;
}
- String childPath = path.isEmpty()
- ? entry.getKey() : path + "." + entry.getKey();
- merge(entry.getValue(), childPath, (Message) source.getField(field),
- destination.getFieldBuilder(field), options);
+ String childPath = path.isEmpty() ? entry.getKey() : path + "." + entry.getKey();
+ merge(
+ entry.getValue(),
+ childPath,
+ (Message) source.getField(field),
+ destination.getFieldBuilder(field),
+ options);
continue;
}
if (field.isRepeated()) {
@@ -245,13 +253,22 @@ class FieldMaskTree {
} else {
if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
if (options.replaceMessageFields()) {
- destination.setField(field, source.getField(field));
+ if (!source.hasField(field)) {
+ destination.clearField(field);
+ } else {
+ destination.setField(field, source.getField(field));
+ }
} else {
- destination.getFieldBuilder(field).mergeFrom(
- (Message) source.getField(field));
+ if (source.hasField(field)) {
+ destination.getFieldBuilder(field).mergeFrom((Message) source.getField(field));
+ }
}
} else {
- destination.setField(field, source.getField(field));
+ if (source.hasField(field) || !options.replacePrimitiveFields()) {
+ destination.setField(field, source.getField(field));
+ } else {
+ destination.clearField(field);
+ }
}
}
}
diff --git a/java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java b/java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java
index 0b3060a7..96961521 100644
--- a/java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java
+++ b/java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java
@@ -211,14 +211,19 @@ public class FieldMaskUtil {
public static FieldMask normalize(FieldMask mask) {
return new FieldMaskTree(mask).toFieldMask();
}
-
+
/**
- * Creates an union of two FieldMasks.
+ * Creates a union of two or more FieldMasks.
*/
- public static FieldMask union(FieldMask mask1, FieldMask mask2) {
- return new FieldMaskTree(mask1).mergeFromFieldMask(mask2).toFieldMask();
+ public static FieldMask union(
+ FieldMask firstMask, FieldMask secondMask, FieldMask... otherMasks) {
+ FieldMaskTree maskTree = new FieldMaskTree(firstMask).mergeFromFieldMask(secondMask);
+ for (FieldMask mask : otherMasks) {
+ maskTree.mergeFromFieldMask(mask);
+ }
+ return maskTree.toFieldMask();
}
-
+
/**
* Calculates the intersection of two FieldMasks.
*/
@@ -237,6 +242,9 @@ public class FieldMaskUtil {
public static final class MergeOptions {
private boolean replaceMessageFields = false;
private boolean replaceRepeatedFields = false;
+ // TODO(b/28277137): change the default behavior to always replace primitive fields after
+ // fixing all failing TAP tests.
+ private boolean replacePrimitiveFields = false;
/**
* Whether to replace message fields (i.e., discard existing content in
@@ -257,7 +265,23 @@ public class FieldMaskUtil {
public boolean replaceRepeatedFields() {
return replaceRepeatedFields;
}
-
+
+ /**
+ * Whether to replace primitive (non-repeated and non-message) fields in
+ * destination message fields with the source primitive fields (i.e., if the
+ * field is set in the source, the value is copied to the
+ * destination; if the field is unset in the source, the field is cleared
+ * from the destination) when merging.
+ *
+ * <p>Default behavior is to always set the value of the source primitive
+ * field to the destination primitive field, and if the source field is
+ * unset, the default value of the source field is copied to the
+ * destination.
+ */
+ public boolean replacePrimitiveFields() {
+ return replacePrimitiveFields;
+ }
+
public void setReplaceMessageFields(boolean value) {
replaceMessageFields = value;
}
@@ -265,10 +289,15 @@ public class FieldMaskUtil {
public void setReplaceRepeatedFields(boolean value) {
replaceRepeatedFields = value;
}
+
+ public void setReplacePrimitiveFields(boolean value) {
+ replacePrimitiveFields = value;
+ }
}
-
+
/**
- * Merges fields specified by a FieldMask from one message to another.
+ * Merges fields specified by a FieldMask from one message to another with the
+ * specified merge options.
*/
public static void merge(FieldMask mask, Message source,
Message.Builder destination, MergeOptions options) {
diff --git a/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java b/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
index d13ff0ed..76f3437a 100644
--- a/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
+++ b/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
@@ -32,6 +32,7 @@ package com.google.protobuf.util;
import com.google.common.io.BaseEncoding;
import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonNull;
@@ -433,7 +434,7 @@ public class JsonFormat {
private final Gson gson;
private static class GsonHolder {
- private static final Gson DEFAULT_GSON = new Gson();
+ private static final Gson DEFAULT_GSON = new GsonBuilder().disableHtmlEscaping().create();
}
PrinterImpl(
@@ -951,16 +952,15 @@ public class JsonFormat {
}
}
- private static final String TYPE_URL_PREFIX = "type.googleapis.com";
-
+
private static String getTypeName(String typeUrl)
throws InvalidProtocolBufferException {
String[] parts = typeUrl.split("/");
- if (parts.length != 2 || !parts[0].equals(TYPE_URL_PREFIX)) {
+ if (parts.length == 1) {
throw new InvalidProtocolBufferException(
"Invalid type url found: " + typeUrl);
}
- return parts[1];
+ return parts[parts.length - 1];
}
private static class ParserImpl {
@@ -1066,6 +1066,15 @@ public class JsonFormat {
parser.mergeStruct(json, builder);
}
});
+ // Special-case ListValue.
+ parsers.put(ListValue.getDescriptor().getFullName(),
+ new WellKnownTypeParser() {
+ @Override
+ public void merge(ParserImpl parser, JsonElement json,
+ Message.Builder builder) throws InvalidProtocolBufferException {
+ parser.mergeListValue(json, builder);
+ }
+ });
// Special-case Value.
parsers.put(Value.getDescriptor().getFullName(),
new WellKnownTypeParser() {
@@ -1213,6 +1222,16 @@ public class JsonFormat {
}
mergeMapField(field, json, builder);
}
+
+ private void mergeListValue(JsonElement json, Message.Builder builder)
+ throws InvalidProtocolBufferException {
+ Descriptor descriptor = builder.getDescriptorForType();
+ FieldDescriptor field = descriptor.findFieldByName("values");
+ if (field == null) {
+ throw new InvalidProtocolBufferException("Invalid ListValue type.");
+ }
+ mergeRepeatedField(field, json, builder);
+ }
private void mergeValue(JsonElement json, Message.Builder builder)
throws InvalidProtocolBufferException {
@@ -1237,9 +1256,7 @@ public class JsonFormat {
} else if (json instanceof JsonArray) {
FieldDescriptor field = type.findFieldByName("list_value");
Message.Builder listBuilder = builder.newBuilderForField(field);
- FieldDescriptor listField =
- listBuilder.getDescriptorForType().findFieldByName("values");
- mergeRepeatedField(listField, json, listBuilder);
+ merge(json, listBuilder);
builder.setField(field, listBuilder.build());
} else {
throw new IllegalStateException("Unexpected json data: " + json);
diff --git a/java/util/src/test/java/com/google/protobuf/util/FieldMaskTreeTest.java b/java/util/src/test/java/com/google/protobuf/util/FieldMaskTreeTest.java
index 3391f239..3ee0fc6e 100644
--- a/java/util/src/test/java/com/google/protobuf/util/FieldMaskTreeTest.java
+++ b/java/util/src/test/java/com/google/protobuf/util/FieldMaskTreeTest.java
@@ -61,19 +61,16 @@ public class FieldMaskTreeTest extends TestCase {
tree.addFieldPath("bar");
assertEquals("bar,foo", tree.toString());
}
-
+
public void testMergeFromFieldMask() throws Exception {
- FieldMaskTree tree = new FieldMaskTree(
- FieldMaskUtil.fromString("foo,bar.baz,bar.quz"));
+ FieldMaskTree tree = new FieldMaskTree(FieldMaskUtil.fromString("foo,bar.baz,bar.quz"));
assertEquals("bar.baz,bar.quz,foo", tree.toString());
- tree.mergeFromFieldMask(
- FieldMaskUtil.fromString("foo.bar,bar"));
+ tree.mergeFromFieldMask(FieldMaskUtil.fromString("foo.bar,bar"));
assertEquals("bar,foo", tree.toString());
}
-
+
public void testIntersectFieldPath() throws Exception {
- FieldMaskTree tree = new FieldMaskTree(
- FieldMaskUtil.fromString("foo,bar.baz,bar.quz"));
+ FieldMaskTree tree = new FieldMaskTree(FieldMaskUtil.fromString("foo,bar.baz,bar.quz"));
FieldMaskTree result = new FieldMaskTree();
// Empty path.
tree.intersectFieldPath("", result);
@@ -96,16 +93,18 @@ public class FieldMaskTreeTest extends TestCase {
}
public void testMerge() throws Exception {
- TestAllTypes value = TestAllTypes.newBuilder()
- .setOptionalInt32(1234)
- .setOptionalNestedMessage(NestedMessage.newBuilder().setBb(5678))
- .addRepeatedInt32(4321)
- .addRepeatedNestedMessage(NestedMessage.newBuilder().setBb(8765))
- .build();
- NestedTestAllTypes source = NestedTestAllTypes.newBuilder()
- .setPayload(value)
- .setChild(NestedTestAllTypes.newBuilder().setPayload(value))
- .build();
+ TestAllTypes value =
+ TestAllTypes.newBuilder()
+ .setOptionalInt32(1234)
+ .setOptionalNestedMessage(NestedMessage.newBuilder().setBb(5678))
+ .addRepeatedInt32(4321)
+ .addRepeatedNestedMessage(NestedMessage.newBuilder().setBb(8765))
+ .build();
+ NestedTestAllTypes source =
+ NestedTestAllTypes.newBuilder()
+ .setPayload(value)
+ .setChild(NestedTestAllTypes.newBuilder().setPayload(value))
+ .build();
// Now we have a message source with the following structure:
// [root] -+- payload -+- optional_int32
// | +- optional_nested_message
@@ -116,114 +115,147 @@ public class FieldMaskTreeTest extends TestCase {
// +- optional_nested_message
// +- repeated_int32
// +- repeated_nested_message
-
+
FieldMaskUtil.MergeOptions options = new FieldMaskUtil.MergeOptions();
-
+
// Test merging each individual field.
NestedTestAllTypes.Builder builder = NestedTestAllTypes.newBuilder();
- new FieldMaskTree().addFieldPath("payload.optional_int32")
- .merge(source, builder, options);
+ new FieldMaskTree().addFieldPath("payload.optional_int32").merge(source, builder, options);
NestedTestAllTypes.Builder expected = NestedTestAllTypes.newBuilder();
expected.getPayloadBuilder().setOptionalInt32(1234);
assertEquals(expected.build(), builder.build());
builder = NestedTestAllTypes.newBuilder();
- new FieldMaskTree().addFieldPath("payload.optional_nested_message")
+ new FieldMaskTree()
+ .addFieldPath("payload.optional_nested_message")
.merge(source, builder, options);
expected = NestedTestAllTypes.newBuilder();
- expected.getPayloadBuilder().setOptionalNestedMessage(
- NestedMessage.newBuilder().setBb(5678));
+ expected.getPayloadBuilder().setOptionalNestedMessage(NestedMessage.newBuilder().setBb(5678));
assertEquals(expected.build(), builder.build());
-
builder = NestedTestAllTypes.newBuilder();
- new FieldMaskTree().addFieldPath("payload.repeated_int32")
- .merge(source, builder, options);
+ new FieldMaskTree().addFieldPath("payload.repeated_int32").merge(source, builder, options);
expected = NestedTestAllTypes.newBuilder();
expected.getPayloadBuilder().addRepeatedInt32(4321);
assertEquals(expected.build(), builder.build());
builder = NestedTestAllTypes.newBuilder();
- new FieldMaskTree().addFieldPath("payload.repeated_nested_message")
+ new FieldMaskTree()
+ .addFieldPath("payload.repeated_nested_message")
.merge(source, builder, options);
expected = NestedTestAllTypes.newBuilder();
- expected.getPayloadBuilder().addRepeatedNestedMessage(
- NestedMessage.newBuilder().setBb(8765));
+ expected.getPayloadBuilder().addRepeatedNestedMessage(NestedMessage.newBuilder().setBb(8765));
assertEquals(expected.build(), builder.build());
builder = NestedTestAllTypes.newBuilder();
- new FieldMaskTree().addFieldPath("child.payload.optional_int32")
+ new FieldMaskTree()
+ .addFieldPath("child.payload.optional_int32")
.merge(source, builder, options);
expected = NestedTestAllTypes.newBuilder();
expected.getChildBuilder().getPayloadBuilder().setOptionalInt32(1234);
assertEquals(expected.build(), builder.build());
builder = NestedTestAllTypes.newBuilder();
- new FieldMaskTree().addFieldPath("child.payload.optional_nested_message")
+ new FieldMaskTree()
+ .addFieldPath("child.payload.optional_nested_message")
.merge(source, builder, options);
expected = NestedTestAllTypes.newBuilder();
- expected.getChildBuilder().getPayloadBuilder().setOptionalNestedMessage(
- NestedMessage.newBuilder().setBb(5678));
+ expected
+ .getChildBuilder()
+ .getPayloadBuilder()
+ .setOptionalNestedMessage(NestedMessage.newBuilder().setBb(5678));
assertEquals(expected.build(), builder.build());
-
builder = NestedTestAllTypes.newBuilder();
- new FieldMaskTree().addFieldPath("child.payload.repeated_int32")
+ new FieldMaskTree()
+ .addFieldPath("child.payload.repeated_int32")
.merge(source, builder, options);
expected = NestedTestAllTypes.newBuilder();
expected.getChildBuilder().getPayloadBuilder().addRepeatedInt32(4321);
assertEquals(expected.build(), builder.build());
-
builder = NestedTestAllTypes.newBuilder();
- new FieldMaskTree().addFieldPath("child.payload.repeated_nested_message")
+ new FieldMaskTree()
+ .addFieldPath("child.payload.repeated_nested_message")
.merge(source, builder, options);
expected = NestedTestAllTypes.newBuilder();
- expected.getChildBuilder().getPayloadBuilder().addRepeatedNestedMessage(
- NestedMessage.newBuilder().setBb(8765));
+ expected
+ .getChildBuilder()
+ .getPayloadBuilder()
+ .addRepeatedNestedMessage(NestedMessage.newBuilder().setBb(8765));
assertEquals(expected.build(), builder.build());
-
+
// Test merging all fields.
builder = NestedTestAllTypes.newBuilder();
- new FieldMaskTree().addFieldPath("child").addFieldPath("payload")
- .merge(source, builder, options);
+ new FieldMaskTree()
+ .addFieldPath("child")
+ .addFieldPath("payload")
+ .merge(source, builder, options);
assertEquals(source, builder.build());
-
+
// Test repeated options.
builder = NestedTestAllTypes.newBuilder();
builder.getPayloadBuilder().addRepeatedInt32(1000);
- new FieldMaskTree().addFieldPath("payload.repeated_int32")
- .merge(source, builder, options);
+ new FieldMaskTree().addFieldPath("payload.repeated_int32").merge(source, builder, options);
// Default behavior is to append repeated fields.
assertEquals(2, builder.getPayload().getRepeatedInt32Count());
assertEquals(1000, builder.getPayload().getRepeatedInt32(0));
assertEquals(4321, builder.getPayload().getRepeatedInt32(1));
// Change to replace repeated fields.
options.setReplaceRepeatedFields(true);
- new FieldMaskTree().addFieldPath("payload.repeated_int32")
- .merge(source, builder, options);
+ new FieldMaskTree().addFieldPath("payload.repeated_int32").merge(source, builder, options);
assertEquals(1, builder.getPayload().getRepeatedInt32Count());
assertEquals(4321, builder.getPayload().getRepeatedInt32(0));
-
+
// Test message options.
builder = NestedTestAllTypes.newBuilder();
builder.getPayloadBuilder().setOptionalInt32(1000);
builder.getPayloadBuilder().setOptionalUint32(2000);
- new FieldMaskTree().addFieldPath("payload")
- .merge(source, builder, options);
+ new FieldMaskTree().addFieldPath("payload").merge(source, builder, options);
// Default behavior is to merge message fields.
assertEquals(1234, builder.getPayload().getOptionalInt32());
assertEquals(2000, builder.getPayload().getOptionalUint32());
-
+
+ // Test merging unset message fields.
+ NestedTestAllTypes clearedSource = source.toBuilder().clearPayload().build();
+ builder = NestedTestAllTypes.newBuilder();
+ new FieldMaskTree().addFieldPath("payload").merge(clearedSource, builder, options);
+ assertEquals(false, builder.hasPayload());
+
// Change to replace message fields.
options.setReplaceMessageFields(true);
builder = NestedTestAllTypes.newBuilder();
builder.getPayloadBuilder().setOptionalInt32(1000);
builder.getPayloadBuilder().setOptionalUint32(2000);
- new FieldMaskTree().addFieldPath("payload")
- .merge(source, builder, options);
+ new FieldMaskTree().addFieldPath("payload").merge(source, builder, options);
assertEquals(1234, builder.getPayload().getOptionalInt32());
assertEquals(0, builder.getPayload().getOptionalUint32());
+
+ // Test merging unset message fields.
+ builder = NestedTestAllTypes.newBuilder();
+ builder.getPayloadBuilder().setOptionalInt32(1000);
+ builder.getPayloadBuilder().setOptionalUint32(2000);
+ new FieldMaskTree().addFieldPath("payload").merge(clearedSource, builder, options);
+ assertEquals(false, builder.hasPayload());
+
+ // Test merging unset primitive fields.
+ builder = source.toBuilder();
+ builder.getPayloadBuilder().clearOptionalInt32();
+ NestedTestAllTypes sourceWithPayloadInt32Unset = builder.build();
+ builder = source.toBuilder();
+ new FieldMaskTree()
+ .addFieldPath("payload.optional_int32")
+ .merge(sourceWithPayloadInt32Unset, builder, options);
+ assertEquals(true, builder.getPayload().hasOptionalInt32());
+ assertEquals(0, builder.getPayload().getOptionalInt32());
+
+ // Change to clear unset primitive fields.
+ options.setReplacePrimitiveFields(true);
+ builder = source.toBuilder();
+ new FieldMaskTree()
+ .addFieldPath("payload.optional_int32")
+ .merge(sourceWithPayloadInt32Unset, builder, options);
+ assertEquals(true, builder.hasPayload());
+ assertEquals(false, builder.getPayload().hasOptionalInt32());
}
}
-
diff --git a/java/util/src/test/java/com/google/protobuf/util/FieldMaskUtilTest.java b/java/util/src/test/java/com/google/protobuf/util/FieldMaskUtilTest.java
index a312fc33..194f7b9c 100644
--- a/java/util/src/test/java/com/google/protobuf/util/FieldMaskUtilTest.java
+++ b/java/util/src/test/java/com/google/protobuf/util/FieldMaskUtilTest.java
@@ -152,6 +152,15 @@ public class FieldMaskUtilTest extends TestCase {
FieldMask result = FieldMaskUtil.union(mask1, mask2);
assertEquals("bar,foo", FieldMaskUtil.toString(result));
}
+
+ public void testUnion_usingVarArgs() throws Exception {
+ FieldMask mask1 = FieldMaskUtil.fromString("foo");
+ FieldMask mask2 = FieldMaskUtil.fromString("foo.bar,bar.quz");
+ FieldMask mask3 = FieldMaskUtil.fromString("bar.quz");
+ FieldMask mask4 = FieldMaskUtil.fromString("bar");
+ FieldMask result = FieldMaskUtil.union(mask1, mask2, mask3, mask4);
+ assertEquals("bar,foo", FieldMaskUtil.toString(result));
+ }
public void testIntersection() throws Exception {
// Only test a simple case here and expect
diff --git a/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java b/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java
index c0eb0330..d95b626c 100644
--- a/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java
+++ b/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java
@@ -122,11 +122,11 @@ public class JsonFormatTest extends TestCase {
builder.addRepeatedNestedEnum(NestedEnum.BAZ);
builder.addRepeatedNestedMessageBuilder().setValue(200);
}
-
+
private void assertRoundTripEquals(Message message) throws Exception {
assertRoundTripEquals(message, TypeRegistry.getEmptyTypeRegistry());
}
-
+
private void assertRoundTripEquals(Message message, TypeRegistry registry) throws Exception {
JsonFormat.Printer printer = JsonFormat.printer().usingTypeRegistry(registry);
JsonFormat.Parser parser = JsonFormat.parser().usingTypeRegistry(registry);
@@ -135,68 +135,68 @@ public class JsonFormatTest extends TestCase {
Message parsedMessage = builder.build();
assertEquals(message.toString(), parsedMessage.toString());
}
-
+
private String toJsonString(Message message) throws IOException {
return JsonFormat.printer().print(message);
}
-
+
private void mergeFromJson(String json, Message.Builder builder) throws IOException {
JsonFormat.parser().merge(json, builder);
}
-
+
public void testAllFields() throws Exception {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
setAllFields(builder);
TestAllTypes message = builder.build();
-
- assertEquals(
+
+ assertEquals(
"{\n"
- + " \"optionalInt32\": 1234,\n"
- + " \"optionalInt64\": \"1234567890123456789\",\n"
- + " \"optionalUint32\": 5678,\n"
- + " \"optionalUint64\": \"2345678901234567890\",\n"
- + " \"optionalSint32\": 9012,\n"
- + " \"optionalSint64\": \"3456789012345678901\",\n"
- + " \"optionalFixed32\": 3456,\n"
- + " \"optionalFixed64\": \"4567890123456789012\",\n"
- + " \"optionalSfixed32\": 7890,\n"
- + " \"optionalSfixed64\": \"5678901234567890123\",\n"
- + " \"optionalFloat\": 1.5,\n"
- + " \"optionalDouble\": 1.25,\n"
- + " \"optionalBool\": true,\n"
- + " \"optionalString\": \"Hello world!\",\n"
- + " \"optionalBytes\": \"AAEC\",\n"
- + " \"optionalNestedMessage\": {\n"
- + " \"value\": 100\n"
- + " },\n"
- + " \"optionalNestedEnum\": \"BAR\",\n"
- + " \"repeatedInt32\": [1234, 234],\n"
- + " \"repeatedInt64\": [\"1234567890123456789\", \"234567890123456789\"],\n"
- + " \"repeatedUint32\": [5678, 678],\n"
- + " \"repeatedUint64\": [\"2345678901234567890\", \"345678901234567890\"],\n"
- + " \"repeatedSint32\": [9012, 10],\n"
- + " \"repeatedSint64\": [\"3456789012345678901\", \"456789012345678901\"],\n"
- + " \"repeatedFixed32\": [3456, 456],\n"
- + " \"repeatedFixed64\": [\"4567890123456789012\", \"567890123456789012\"],\n"
- + " \"repeatedSfixed32\": [7890, 890],\n"
- + " \"repeatedSfixed64\": [\"5678901234567890123\", \"678901234567890123\"],\n"
- + " \"repeatedFloat\": [1.5, 11.5],\n"
- + " \"repeatedDouble\": [1.25, 11.25],\n"
- + " \"repeatedBool\": [true, true],\n"
- + " \"repeatedString\": [\"Hello world!\", \"ello world!\"],\n"
- + " \"repeatedBytes\": [\"AAEC\", \"AQI=\"],\n"
- + " \"repeatedNestedMessage\": [{\n"
- + " \"value\": 100\n"
- + " }, {\n"
- + " \"value\": 200\n"
- + " }],\n"
- + " \"repeatedNestedEnum\": [\"BAR\", \"BAZ\"]\n"
- + "}",
+ + " \"optionalInt32\": 1234,\n"
+ + " \"optionalInt64\": \"1234567890123456789\",\n"
+ + " \"optionalUint32\": 5678,\n"
+ + " \"optionalUint64\": \"2345678901234567890\",\n"
+ + " \"optionalSint32\": 9012,\n"
+ + " \"optionalSint64\": \"3456789012345678901\",\n"
+ + " \"optionalFixed32\": 3456,\n"
+ + " \"optionalFixed64\": \"4567890123456789012\",\n"
+ + " \"optionalSfixed32\": 7890,\n"
+ + " \"optionalSfixed64\": \"5678901234567890123\",\n"
+ + " \"optionalFloat\": 1.5,\n"
+ + " \"optionalDouble\": 1.25,\n"
+ + " \"optionalBool\": true,\n"
+ + " \"optionalString\": \"Hello world!\",\n"
+ + " \"optionalBytes\": \"AAEC\",\n"
+ + " \"optionalNestedMessage\": {\n"
+ + " \"value\": 100\n"
+ + " },\n"
+ + " \"optionalNestedEnum\": \"BAR\",\n"
+ + " \"repeatedInt32\": [1234, 234],\n"
+ + " \"repeatedInt64\": [\"1234567890123456789\", \"234567890123456789\"],\n"
+ + " \"repeatedUint32\": [5678, 678],\n"
+ + " \"repeatedUint64\": [\"2345678901234567890\", \"345678901234567890\"],\n"
+ + " \"repeatedSint32\": [9012, 10],\n"
+ + " \"repeatedSint64\": [\"3456789012345678901\", \"456789012345678901\"],\n"
+ + " \"repeatedFixed32\": [3456, 456],\n"
+ + " \"repeatedFixed64\": [\"4567890123456789012\", \"567890123456789012\"],\n"
+ + " \"repeatedSfixed32\": [7890, 890],\n"
+ + " \"repeatedSfixed64\": [\"5678901234567890123\", \"678901234567890123\"],\n"
+ + " \"repeatedFloat\": [1.5, 11.5],\n"
+ + " \"repeatedDouble\": [1.25, 11.25],\n"
+ + " \"repeatedBool\": [true, true],\n"
+ + " \"repeatedString\": [\"Hello world!\", \"ello world!\"],\n"
+ + " \"repeatedBytes\": [\"AAEC\", \"AQI=\"],\n"
+ + " \"repeatedNestedMessage\": [{\n"
+ + " \"value\": 100\n"
+ + " }, {\n"
+ + " \"value\": 200\n"
+ + " }],\n"
+ + " \"repeatedNestedEnum\": [\"BAR\", \"BAZ\"]\n"
+ + "}",
toJsonString(message));
-
+
assertRoundTripEquals(message);
}
-
+
public void testUnknownEnumValues() throws Exception {
TestAllTypes message = TestAllTypes.newBuilder()
.setOptionalNestedEnumValue(12345)
@@ -209,21 +209,22 @@ public class JsonFormatTest extends TestCase {
+ " \"repeatedNestedEnum\": [12345, \"FOO\"]\n"
+ "}", toJsonString(message));
assertRoundTripEquals(message);
-
+
TestMap.Builder mapBuilder = TestMap.newBuilder();
mapBuilder.getMutableInt32ToEnumMapValue().put(1, 0);
mapBuilder.getMutableInt32ToEnumMapValue().put(2, 12345);
TestMap mapMessage = mapBuilder.build();
assertEquals(
- "{\n"
- + " \"int32ToEnumMap\": {\n"
- + " \"1\": \"FOO\",\n"
- + " \"2\": 12345\n"
- + " }\n"
- + "}", toJsonString(mapMessage));
+ "{\n"
+ + " \"int32ToEnumMap\": {\n"
+ + " \"1\": \"FOO\",\n"
+ + " \"2\": 12345\n"
+ + " }\n"
+ + "}",
+ toJsonString(mapMessage));
assertRoundTripEquals(mapMessage);
}
-
+
public void testSpecialFloatValues() throws Exception {
TestAllTypes message = TestAllTypes.newBuilder()
.addRepeatedFloat(Float.NaN)
@@ -238,10 +239,10 @@ public class JsonFormatTest extends TestCase {
+ " \"repeatedFloat\": [\"NaN\", \"Infinity\", \"-Infinity\"],\n"
+ " \"repeatedDouble\": [\"NaN\", \"Infinity\", \"-Infinity\"]\n"
+ "}", toJsonString(message));
-
+
assertRoundTripEquals(message);
}
-
+
public void testParserAcceptStringForNumbericField() throws Exception {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
mergeFromJson(
@@ -265,7 +266,7 @@ public class JsonFormatTest extends TestCase {
assertEquals(1.25, message.getOptionalDouble());
assertEquals(true, message.getOptionalBool());
}
-
+
public void testParserAcceptFloatingPointValueForIntegerField() throws Exception {
// Test that numeric values like "1.000", "1e5" will also be accepted.
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
@@ -287,14 +288,14 @@ public class JsonFormatTest extends TestCase {
assertEquals(expectedValues[i], builder.getRepeatedInt64(i));
assertEquals(expectedValues[i], builder.getRepeatedUint64(i));
}
-
+
// Non-integers will still be rejected.
assertRejects("optionalInt32", "1.5");
assertRejects("optionalUint32", "1.5");
assertRejects("optionalInt64", "1.5");
assertRejects("optionalUint64", "1.5");
}
-
+
private void assertRejects(String name, String value) {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
try {
@@ -312,7 +313,7 @@ public class JsonFormatTest extends TestCase {
// Expected.
}
}
-
+
private void assertAccepts(String name, String value) throws IOException {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
// Both numeric form and string form are accepted.
@@ -320,17 +321,17 @@ public class JsonFormatTest extends TestCase {
builder.clear();
mergeFromJson("{\"" + name + "\":\"" + value + "\"}", builder);
}
-
+
public void testParserRejectOutOfRangeNumericValues() throws Exception {
assertAccepts("optionalInt32", String.valueOf(Integer.MAX_VALUE));
assertAccepts("optionalInt32", String.valueOf(Integer.MIN_VALUE));
assertRejects("optionalInt32", String.valueOf(Integer.MAX_VALUE + 1L));
assertRejects("optionalInt32", String.valueOf(Integer.MIN_VALUE - 1L));
-
+
assertAccepts("optionalUint32", String.valueOf(Integer.MAX_VALUE + 1L));
assertRejects("optionalUint32", "123456789012345");
assertRejects("optionalUint32", "-1");
-
+
BigInteger one = new BigInteger("1");
BigInteger maxLong = new BigInteger(String.valueOf(Long.MAX_VALUE));
BigInteger minLong = new BigInteger(String.valueOf(Long.MIN_VALUE));
@@ -351,7 +352,7 @@ public class JsonFormatTest extends TestCase {
assertAccepts("optionalFloat", String.valueOf(-Float.MAX_VALUE));
assertRejects("optionalFloat", String.valueOf(Double.MAX_VALUE));
assertRejects("optionalFloat", String.valueOf(-Double.MAX_VALUE));
-
+
BigDecimal moreThanOne = new BigDecimal("1.000001");
BigDecimal maxDouble = new BigDecimal(Double.MAX_VALUE);
BigDecimal minDouble = new BigDecimal(-Double.MAX_VALUE);
@@ -360,7 +361,7 @@ public class JsonFormatTest extends TestCase {
assertRejects("optionalDouble", maxDouble.multiply(moreThanOne).toString());
assertRejects("optionalDouble", minDouble.multiply(moreThanOne).toString());
}
-
+
public void testParserAcceptNull() throws Exception {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
mergeFromJson(
@@ -402,7 +403,7 @@ public class JsonFormatTest extends TestCase {
+ "}", builder);
TestAllTypes message = builder.build();
assertEquals(TestAllTypes.getDefaultInstance(), message);
-
+
// Repeated field elements cannot be null.
try {
builder = TestAllTypes.newBuilder();
@@ -414,7 +415,7 @@ public class JsonFormatTest extends TestCase {
} catch (InvalidProtocolBufferException e) {
// Exception expected.
}
-
+
try {
builder = TestAllTypes.newBuilder();
mergeFromJson(
@@ -426,14 +427,14 @@ public class JsonFormatTest extends TestCase {
// Exception expected.
}
}
-
+
public void testParserRejectDuplicatedFields() throws Exception {
// TODO(xiaofeng): The parser we are currently using (GSON) will accept and keep the last
// one if multiple entries have the same name. This is not the desired behavior but it can
// only be fixed by using our own parser. Here we only test the cases where the names are
// different but still referring to the same field.
-
- // Duplicated optional fields.
+
+ // Duplicated optional fields.
try {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
mergeFromJson(
@@ -445,7 +446,7 @@ public class JsonFormatTest extends TestCase {
} catch (InvalidProtocolBufferException e) {
// Exception expected.
}
-
+
// Duplicated repeated fields.
try {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
@@ -458,7 +459,7 @@ public class JsonFormatTest extends TestCase {
} catch (InvalidProtocolBufferException e) {
// Exception expected.
}
-
+
// Duplicated oneof fields.
try {
TestOneof.Builder builder = TestOneof.newBuilder();
@@ -472,7 +473,7 @@ public class JsonFormatTest extends TestCase {
// Exception expected.
}
}
-
+
public void testMapFields() throws Exception {
TestMap.Builder builder = TestMap.newBuilder();
builder.getMutableInt32ToInt32Map().put(1, 10);
@@ -507,7 +508,7 @@ public class JsonFormatTest extends TestCase {
8, NestedMessage.newBuilder().setValue(1234).build());
builder.getMutableInt32ToEnumMap().put(9, NestedEnum.BAR);
TestMap message = builder.build();
-
+
assertEquals(
"{\n"
+ " \"int32ToInt32Map\": {\n"
@@ -598,13 +599,13 @@ public class JsonFormatTest extends TestCase {
+ " }\n"
+ "}", toJsonString(message));
assertRoundTripEquals(message);
-
+
// Test multiple entries.
builder = TestMap.newBuilder();
builder.getMutableInt32ToInt32Map().put(1, 2);
builder.getMutableInt32ToInt32Map().put(3, 4);
message = builder.build();
-
+
assertEquals(
"{\n"
+ " \"int32ToInt32Map\": {\n"
@@ -614,7 +615,7 @@ public class JsonFormatTest extends TestCase {
+ "}", toJsonString(message));
assertRoundTripEquals(message);
}
-
+
public void testMapNullValueIsRejected() throws Exception {
try {
TestMap.Builder builder = TestMap.newBuilder();
@@ -627,7 +628,7 @@ public class JsonFormatTest extends TestCase {
} catch (InvalidProtocolBufferException e) {
// Exception expected.
}
-
+
try {
TestMap.Builder builder = TestMap.newBuilder();
mergeFromJson(
@@ -640,7 +641,7 @@ public class JsonFormatTest extends TestCase {
// Exception expected.
}
}
-
+
public void testParserAcceptNonQuotedObjectKey() throws Exception {
TestMap.Builder builder = TestMap.newBuilder();
mergeFromJson(
@@ -652,7 +653,7 @@ public class JsonFormatTest extends TestCase {
assertEquals(2, message.getInt32ToInt32Map().get(1).intValue());
assertEquals(3, message.getStringToInt32Map().get("hello").intValue());
}
-
+
public void testWrappers() throws Exception {
TestWrappers.Builder builder = TestWrappers.newBuilder();
builder.getBoolValueBuilder().setValue(false);
@@ -665,7 +666,7 @@ public class JsonFormatTest extends TestCase {
builder.getStringValueBuilder().setValue("");
builder.getBytesValueBuilder().setValue(ByteString.EMPTY);
TestWrappers message = builder.build();
-
+
assertEquals(
"{\n"
+ " \"int32Value\": 0,\n"
@@ -691,7 +692,7 @@ public class JsonFormatTest extends TestCase {
builder.getStringValueBuilder().setValue("7");
builder.getBytesValueBuilder().setValue(ByteString.copyFrom(new byte[]{8}));
message = builder.build();
-
+
assertEquals(
"{\n"
+ " \"int32Value\": 1,\n"
@@ -706,43 +707,43 @@ public class JsonFormatTest extends TestCase {
+ "}", toJsonString(message));
assertRoundTripEquals(message);
}
-
+
public void testTimestamp() throws Exception {
TestTimestamp message = TestTimestamp.newBuilder()
.setTimestampValue(TimeUtil.parseTimestamp("1970-01-01T00:00:00Z"))
.build();
-
+
assertEquals(
"{\n"
+ " \"timestampValue\": \"1970-01-01T00:00:00Z\"\n"
+ "}", toJsonString(message));
assertRoundTripEquals(message);
}
-
+
public void testDuration() throws Exception {
TestDuration message = TestDuration.newBuilder()
.setDurationValue(TimeUtil.parseDuration("12345s"))
.build();
-
+
assertEquals(
"{\n"
+ " \"durationValue\": \"12345s\"\n"
+ "}", toJsonString(message));
assertRoundTripEquals(message);
}
-
+
public void testFieldMask() throws Exception {
TestFieldMask message = TestFieldMask.newBuilder()
.setFieldMaskValue(FieldMaskUtil.fromString("foo.bar,baz"))
.build();
-
+
assertEquals(
"{\n"
+ " \"fieldMaskValue\": \"foo.bar,baz\"\n"
+ "}", toJsonString(message));
assertRoundTripEquals(message);
}
-
+
public void testStruct() throws Exception {
// Build a struct with all possible values.
TestStruct.Builder builder = TestStruct.newBuilder();
@@ -764,7 +765,7 @@ public class JsonFormatTest extends TestCase {
structBuilder.getMutableFields().put(
"list_value", Value.newBuilder().setListValue(listBuilder.build()).build());
TestStruct message = builder.build();
-
+
assertEquals(
"{\n"
+ " \"structValue\": {\n"
@@ -778,7 +779,7 @@ public class JsonFormatTest extends TestCase {
+ " }\n"
+ "}", toJsonString(message));
assertRoundTripEquals(message);
-
+
builder = TestStruct.newBuilder();
builder.setValue(Value.newBuilder().setNullValueValue(0).build());
message = builder.build();
@@ -787,12 +788,23 @@ public class JsonFormatTest extends TestCase {
+ " \"value\": null\n"
+ "}", toJsonString(message));
assertRoundTripEquals(message);
+
+ builder = TestStruct.newBuilder();
+ listBuilder = builder.getListValueBuilder();
+ listBuilder.addValues(Value.newBuilder().setNumberValue(31831.125).build());
+ listBuilder.addValues(Value.newBuilder().setNullValueValue(0).build());
+ message = builder.build();
+ assertEquals(
+ "{\n"
+ + " \"listValue\": [31831.125, null]\n"
+ + "}", toJsonString(message));
+ assertRoundTripEquals(message);
}
-
+
public void testAnyFields() throws Exception {
TestAllTypes content = TestAllTypes.newBuilder().setOptionalInt32(1234).build();
TestAny message = TestAny.newBuilder().setAnyValue(Any.pack(content)).build();
-
+
// A TypeRegistry must be provided in order to convert Any types.
try {
toJsonString(message);
@@ -800,11 +812,11 @@ public class JsonFormatTest extends TestCase {
} catch (IOException e) {
// Expected.
}
-
+
JsonFormat.TypeRegistry registry = JsonFormat.TypeRegistry.newBuilder()
.add(TestAllTypes.getDescriptor()).build();
JsonFormat.Printer printer = JsonFormat.printer().usingTypeRegistry(registry);
-
+
assertEquals(
"{\n"
+ " \"anyValue\": {\n"
@@ -813,8 +825,8 @@ public class JsonFormatTest extends TestCase {
+ " }\n"
+ "}" , printer.print(message));
assertRoundTripEquals(message, registry);
-
-
+
+
// Well-known types have a special formatting when embedded in Any.
//
// 1. Any in Any.
@@ -828,7 +840,7 @@ public class JsonFormatTest extends TestCase {
+ " }\n"
+ "}", printer.print(anyMessage));
assertRoundTripEquals(anyMessage, registry);
-
+
// 2. Wrappers in Any.
anyMessage = Any.pack(Int32Value.newBuilder().setValue(12345).build());
assertEquals(
@@ -894,7 +906,7 @@ public class JsonFormatTest extends TestCase {
+ " \"value\": \"AQI=\"\n"
+ "}", printer.print(anyMessage));
assertRoundTripEquals(anyMessage, registry);
-
+
// 3. Timestamp in Any.
anyMessage = Any.pack(TimeUtil.parseTimestamp("1969-12-31T23:59:59Z"));
assertEquals(
@@ -903,7 +915,7 @@ public class JsonFormatTest extends TestCase {
+ " \"value\": \"1969-12-31T23:59:59Z\"\n"
+ "}", printer.print(anyMessage));
assertRoundTripEquals(anyMessage, registry);
-
+
// 4. Duration in Any
anyMessage = Any.pack(TimeUtil.parseDuration("12345.10s"));
assertEquals(
@@ -945,7 +957,7 @@ public class JsonFormatTest extends TestCase {
+ "}", printer.print(anyMessage));
assertRoundTripEquals(anyMessage, registry);
}
-
+
public void testParserMissingTypeUrl() throws Exception {
try {
Any.Builder builder = Any.newBuilder();
@@ -958,7 +970,7 @@ public class JsonFormatTest extends TestCase {
// Expected.
}
}
-
+
public void testParserUnexpectedTypeUrl() throws Exception {
try {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
@@ -970,9 +982,9 @@ public class JsonFormatTest extends TestCase {
fail("Exception is expected.");
} catch (IOException e) {
// Expected.
- }
+ }
}
-
+
public void testParserRejectTrailingComma() throws Exception {
try {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
@@ -1000,13 +1012,13 @@ public class JsonFormatTest extends TestCase {
// // Expected.
// }
}
-
+
public void testParserRejectInvalidBase64() throws Exception {
assertRejects("optionalBytes", "!@#$");
// We use standard BASE64 with paddings.
assertRejects("optionalBytes", "AQI");
}
-
+
public void testParserRejectInvalidEnumValue() throws Exception {
try {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
@@ -1017,7 +1029,7 @@ public class JsonFormatTest extends TestCase {
fail("Exception is expected.");
} catch (InvalidProtocolBufferException e) {
// Expected.
- }
+ }
}
public void testCustomJsonName() throws Exception {
@@ -1026,6 +1038,12 @@ public class JsonFormatTest extends TestCase {
assertRoundTripEquals(message);
}
+ public void testDefaultGsonDoesNotHtmlEscape() throws Exception {
+ TestAllTypes message = TestAllTypes.newBuilder().setOptionalString("=").build();
+ assertEquals(
+ "{\n" + " \"optionalString\": \"=\"" + "\n}", JsonFormat.printer().print(message));
+ }
+
public void testIncludingDefaultValueFields() throws Exception {
TestAllTypes message = TestAllTypes.getDefaultInstance();
assertEquals("{\n}", JsonFormat.printer().print(message));
diff --git a/java/util/src/test/proto/com/google/protobuf/util/json_test.proto b/java/util/src/test/proto/com/google/protobuf/util/json_test.proto
index 509c1d69..686edc42 100644
--- a/java/util/src/test/proto/com/google/protobuf/util/json_test.proto
+++ b/java/util/src/test/proto/com/google/protobuf/util/json_test.proto
@@ -28,6 +28,36 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
syntax = "proto3";
package json_test;
@@ -159,6 +189,7 @@ message TestFieldMask {
message TestStruct {
google.protobuf.Struct struct_value = 1;
google.protobuf.Value value = 2;
+ google.protobuf.ListValue list_value = 3;
}
message TestAny {