aboutsummaryrefslogtreecommitdiff
path: root/java/core
diff options
context:
space:
mode:
Diffstat (limited to 'java/core')
-rw-r--r--java/core/generate-test-sources-build.xml5
-rw-r--r--java/core/pom.xml5
-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.java103
-rw-r--r--java/core/src/main/java/com/google/protobuf/AbstractParser.java26
-rw-r--r--java/core/src/main/java/com/google/protobuf/Android.java57
-rw-r--r--java/core/src/main/java/com/google/protobuf/BooleanArrayList.java28
-rw-r--r--java/core/src/main/java/com/google/protobuf/ByteString.java10
-rw-r--r--java/core/src/main/java/com/google/protobuf/CodedInputStream.java1260
-rw-r--r--java/core/src/main/java/com/google/protobuf/CodedOutputStream.java100
-rw-r--r--java/core/src/main/java/com/google/protobuf/Descriptors.java7
-rw-r--r--java/core/src/main/java/com/google/protobuf/DiscardUnknownFieldsParser.java71
-rw-r--r--java/core/src/main/java/com/google/protobuf/DoubleArrayList.java28
-rw-r--r--java/core/src/main/java/com/google/protobuf/DynamicMessage.java35
-rw-r--r--java/core/src/main/java/com/google/protobuf/Extension.java7
-rw-r--r--java/core/src/main/java/com/google/protobuf/ExtensionRegistryFactory.java5
-rw-r--r--java/core/src/main/java/com/google/protobuf/FieldSet.java12
-rw-r--r--java/core/src/main/java/com/google/protobuf/FloatArrayList.java28
-rw-r--r--java/core/src/main/java/com/google/protobuf/GeneratedMessage.java4
-rw-r--r--java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java387
-rw-r--r--java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java105
-rw-r--r--java/core/src/main/java/com/google/protobuf/IntArrayList.java28
-rw-r--r--java/core/src/main/java/com/google/protobuf/Internal.java20
-rw-r--r--java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java4
-rw-r--r--java/core/src/main/java/com/google/protobuf/IterableByteBufferInputStream.java150
-rw-r--r--java/core/src/main/java/com/google/protobuf/LazyFieldLite.java1
-rw-r--r--java/core/src/main/java/com/google/protobuf/LongArrayList.java28
-rw-r--r--java/core/src/main/java/com/google/protobuf/MapEntry.java26
-rw-r--r--java/core/src/main/java/com/google/protobuf/MapEntryLite.java5
-rw-r--r--java/core/src/main/java/com/google/protobuf/MapField.java9
-rw-r--r--java/core/src/main/java/com/google/protobuf/MapFieldLite.java14
-rw-r--r--java/core/src/main/java/com/google/protobuf/Message.java2
-rw-r--r--java/core/src/main/java/com/google/protobuf/MessageLiteToString.java96
-rw-r--r--java/core/src/main/java/com/google/protobuf/MessageReflection.java24
-rw-r--r--java/core/src/main/java/com/google/protobuf/Parser.java13
-rw-r--r--java/core/src/main/java/com/google/protobuf/PrimitiveNonBoxingCollection.java34
-rw-r--r--java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilderV3.java18
-rw-r--r--java/core/src/main/java/com/google/protobuf/SingleFieldBuilderV3.java12
-rw-r--r--java/core/src/main/java/com/google/protobuf/SmallSortedMap.java4
-rw-r--r--java/core/src/main/java/com/google/protobuf/TextFormat.java319
-rw-r--r--java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java2
-rw-r--r--java/core/src/main/java/com/google/protobuf/UnknownFieldSetLite.java27
-rw-r--r--java/core/src/main/java/com/google/protobuf/UnsafeUtil.java485
-rw-r--r--java/core/src/main/java/com/google/protobuf/Utf8.java513
-rw-r--r--java/core/src/main/java/com/google/protobuf/WireFormat.java6
-rw-r--r--java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java12
-rw-r--r--java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java15
-rw-r--r--java/core/src/test/java/com/google/protobuf/CheckUtf8Test.java43
-rw-r--r--java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java169
-rw-r--r--java/core/src/test/java/com/google/protobuf/DecodeUtf8Test.java325
-rw-r--r--java/core/src/test/java/com/google/protobuf/DeprecatedFieldTest.java20
-rw-r--r--java/core/src/test/java/com/google/protobuf/DiscardUnknownFieldsTest.java157
-rw-r--r--java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java15
-rw-r--r--java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java42
-rw-r--r--java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java15
-rw-r--r--java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java157
-rw-r--r--java/core/src/test/java/com/google/protobuf/IntArrayListTest.java15
-rw-r--r--java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java9
-rw-r--r--java/core/src/test/java/com/google/protobuf/LazyFieldTest.java2
-rw-r--r--java/core/src/test/java/com/google/protobuf/LazyStringArrayListTest.java1
-rw-r--r--java/core/src/test/java/com/google/protobuf/LiteTest.java1742
-rw-r--r--java/core/src/test/java/com/google/protobuf/LongArrayListTest.java15
-rw-r--r--java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java8
-rw-r--r--java/core/src/test/java/com/google/protobuf/MapForProto2Test.java27
-rw-r--r--java/core/src/test/java/com/google/protobuf/MapTest.java89
-rw-r--r--java/core/src/test/java/com/google/protobuf/MessageTest.java20
-rw-r--r--java/core/src/test/java/com/google/protobuf/ParserTest.java95
-rw-r--r--java/core/src/test/java/com/google/protobuf/TestBadIdentifiers.java26
-rw-r--r--java/core/src/test/java/com/google/protobuf/TestBadIdentifiersLite.java83
-rw-r--r--java/core/src/test/java/com/google/protobuf/TestUtil.java11
-rw-r--r--java/core/src/test/java/com/google/protobuf/TextFormatTest.java235
-rw-r--r--java/core/src/test/java/com/google/protobuf/UnknownEnumValueTest.java14
-rw-r--r--java/core/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java268
-rw-r--r--java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java204
-rw-r--r--java/core/src/test/java/com/google/protobuf/WireFormatTest.java91
-rw-r--r--java/core/src/test/proto/com/google/protobuf/deprecated_file.proto38
-rw-r--r--java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto8
-rw-r--r--java/core/src/test/proto/com/google/protobuf/map_lite_test.proto111
-rw-r--r--java/core/src/test/proto/com/google/protobuf/test_bad_identifiers.proto17
79 files changed, 6059 insertions, 2211 deletions
diff --git a/java/core/generate-test-sources-build.xml b/java/core/generate-test-sources-build.xml
index ab415db6..1d11f131 100644
--- a/java/core/generate-test-sources-build.xml
+++ b/java/core/generate-test-sources-build.xml
@@ -5,6 +5,7 @@
<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_proto3.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"/>
@@ -18,6 +19,7 @@
<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/deprecated_file.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"/>
@@ -37,7 +39,8 @@
<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_lite_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> \ No newline at end of file
+</project>
diff --git a/java/core/pom.xml b/java/core/pom.xml
index 07bcfa46..5b0b9520 100644
--- a/java/core/pom.xml
+++ b/java/core/pom.xml
@@ -6,7 +6,7 @@
<parent>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-parent</artifactId>
- <version>3.2.0</version>
+ <version>3.5.2</version>
</parent>
<artifactId>protobuf-java</artifactId>
@@ -22,14 +22,17 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
+ <scope>test</scope>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
+ <scope>test</scope>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymockclassextension</artifactId>
+ <scope>test</scope>
</dependency>
</dependencies>
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 37180da8..fc3c2a5d 100644
--- a/java/core/src/main/java/com/google/protobuf/AbstractMessage.java
+++ b/java/core/src/main/java/com/google/protobuf/AbstractMessage.java
@@ -32,9 +32,9 @@ package com.google.protobuf;
import com.google.protobuf.Descriptors.EnumValueDescriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
+import com.google.protobuf.Descriptors.FileDescriptor.Syntax;
import com.google.protobuf.Descriptors.OneofDescriptor;
import com.google.protobuf.Internal.EnumLite;
-
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
@@ -125,6 +125,16 @@ public abstract class AbstractMessage
protected int memoizedSize = -1;
@Override
+ int getMemoizedSerializedSize() {
+ return memoizedSize;
+ }
+
+ @Override
+ void setMemoizedSerializedSize(int size) {
+ memoizedSize = size;
+ }
+
+ @Override
public int getSerializedSize() {
int size = memoizedSize;
if (size != -1) {
@@ -163,7 +173,7 @@ public abstract class AbstractMessage
}
return hash;
}
-
+
private static ByteString toByteString(Object value) {
if (value instanceof byte[]) {
return ByteString.copyFrom((byte[]) value);
@@ -171,7 +181,7 @@ public abstract class AbstractMessage
return (ByteString) value;
}
}
-
+
/**
* Compares two bytes fields. The parameters must be either a byte array or a
* ByteString object. They can be of different type though.
@@ -182,7 +192,7 @@ public abstract class AbstractMessage
}
return toByteString(a).equals(toByteString(b));
}
-
+
/**
* Converts a list of MapEntry messages into a Map used for equals() and
* hashCode().
@@ -213,7 +223,7 @@ public abstract class AbstractMessage
}
return result;
}
-
+
/**
* Compares two map fields. The parameters must be a list of MapEntry
* messages.
@@ -224,13 +234,13 @@ public abstract class AbstractMessage
Map mb = convertMapEntryListToMap((List) b);
return MapFieldLite.equals(ma, mb);
}
-
+
/**
* Compares two set of fields.
* This method is used to implement {@link AbstractMessage#equals(Object)}
* and {@link AbstractMutableMessage#equals(Object)}. It takes special care
* of bytes fields because immutable messages and mutable messages use
- * different Java type to reprensent a bytes field and this method should be
+ * different Java type to represent a bytes field and this method should be
* able to compare immutable messages, mutable messages and also an immutable
* message to a mutable message.
*/
@@ -276,7 +286,7 @@ public abstract class AbstractMessage
}
return true;
}
-
+
/**
* Calculates the hash code of a map field. {@code value} must be a list of
* MapEntry messages.
@@ -328,7 +338,8 @@ public abstract class AbstractMessage
extends AbstractMessageLite.Builder
implements Message.Builder {
// The compiler produces an error if this is not declared explicitly.
- // Method isn't abstract to bypass Java 1.6 compiler issue http://bugs.java.com/view_bug.do?bug_id=6908259
+ // Method isn't abstract to bypass Java 1.6 compiler issue:
+ // http://bugs.java.com/view_bug.do?bug_id=6908259
@Override
public BuilderType clone() {
throw new UnsupportedOperationException("clone() should be implemented in subclasses.");
@@ -371,7 +382,7 @@ public abstract class AbstractMessage
public String getInitializationErrorString() {
return MessageReflection.delimitWithCommas(findInitializationErrors());
}
-
+
@Override
protected BuilderType internalMergeFrom(AbstractMessageLite other) {
return mergeFrom((Message) other);
@@ -379,6 +390,10 @@ public abstract class AbstractMessage
@Override
public BuilderType mergeFrom(final Message other) {
+ return mergeFrom(other, other.getAllFields());
+ }
+
+ BuilderType mergeFrom(final Message other, Map<FieldDescriptor, Object> allFields) {
if (other.getDescriptorForType() != getDescriptorForType()) {
throw new IllegalArgumentException(
"mergeFrom(Message) can only merge messages of the same type.");
@@ -393,8 +408,7 @@ public abstract class AbstractMessage
// TODO(kenton): Provide a function somewhere called makeDeepCopy()
// which allows people to make secure deep copies of messages.
- for (final Map.Entry<FieldDescriptor, Object> entry :
- other.getAllFields().entrySet()) {
+ for (final Map.Entry<FieldDescriptor, Object> entry : allFields.entrySet()) {
final FieldDescriptor field = entry.getKey();
if (field.isRepeated()) {
for (final Object element : (List)entry.getValue()) {
@@ -432,8 +446,12 @@ public abstract class AbstractMessage
final CodedInputStream input,
final ExtensionRegistryLite extensionRegistry)
throws IOException {
+ boolean discardUnknown =
+ getDescriptorForType().getFile().getSyntax() == Syntax.PROTO3
+ ? input.shouldDiscardUnknownFieldsProto3()
+ : input.shouldDiscardUnknownFields();
final UnknownFieldSet.Builder unknownFields =
- UnknownFieldSet.newBuilder(getUnknownFields());
+ discardUnknown ? null : UnknownFieldSet.newBuilder(getUnknownFields());
while (true) {
final int tag = input.readTag();
if (tag == 0) {
@@ -451,7 +469,9 @@ public abstract class AbstractMessage
break;
}
}
- setUnknownFields(unknownFields.build());
+ if (unknownFields != null) {
+ setUnknownFields(unknownFields.build());
+ }
return (BuilderType) this;
}
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 4f691dfd..b22bbaab 100644
--- a/java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java
+++ b/java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java
@@ -30,11 +30,15 @@
package com.google.protobuf;
+import static com.google.protobuf.Internal.checkNotNull;
+
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.List;
/**
* A partial implementation of the {@link MessageLite} interface which
@@ -95,6 +99,16 @@ public abstract class AbstractMessageLite<
codedOutput.flush();
}
+ // We'd like these to be abstract but some folks are extending this class directly. They shouldn't
+ // be doing that and they should feel bad.
+ int getMemoizedSerializedSize() {
+ throw new UnsupportedOperationException();
+ }
+
+ void setMemoizedSerializedSize(int size) {
+ throw new UnsupportedOperationException();
+ }
+
/**
* Package private helper method for AbstractParser to create
@@ -116,8 +130,13 @@ public abstract class AbstractMessageLite<
}
}
- protected static <T> void addAll(final Iterable<T> values,
- final Collection<? super T> list) {
+ // For binary compatibility
+ @Deprecated
+ protected static <T> void addAll(final Iterable<T> values, final Collection<? super T> list) {
+ Builder.addAll(values, (List) list);
+ }
+
+ protected static <T> void addAll(final Iterable<T> values, final List<? super T> list) {
Builder.addAll(values, list);
}
@@ -332,6 +351,25 @@ public abstract class AbstractMessageLite<
+ " threw an IOException (should never happen).";
}
+ // We check nulls as we iterate to avoid iterating over values twice.
+ private static <T> void addAllCheckingNulls(Iterable<T> values, List<? super T> list) {
+ if (list instanceof ArrayList && values instanceof Collection) {
+ ((ArrayList<T>) list).ensureCapacity(list.size() + ((Collection<T>) values).size());
+ }
+ int begin = list.size();
+ for (T value : values) {
+ if (value == null) {
+ // encountered a null value so we must undo our modifications prior to throwing
+ String message = "Element at index " + (list.size() - begin) + " is null.";
+ for (int i = list.size() - 1; i >= begin; i--) {
+ list.remove(i);
+ }
+ throw new NullPointerException(message);
+ }
+ list.add(value);
+ }
+ }
+
/**
* Construct an UninitializedMessageException reporting missing fields in
* the given message.
@@ -341,41 +379,50 @@ public abstract class AbstractMessageLite<
return new UninitializedMessageException(message);
}
+ // For binary compatibility.
+ @Deprecated
+ protected static <T> void addAll(final Iterable<T> values, final Collection<? super T> list) {
+ addAll(values, (List<T>) list);
+ }
+
/**
- * Adds the {@code values} to the {@code list}. This is a helper method
- * used by generated code. Users should ignore it.
+ * Adds the {@code values} to the {@code list}. This is a helper method used by generated code.
+ * Users should ignore it.
*
- * @throws NullPointerException if {@code values} or any of the elements of
- * {@code values} is null. When that happens, some elements of
- * {@code values} may have already been added to the result {@code list}.
+ * @throws NullPointerException if {@code values} or any of the elements of {@code values} is
+ * null.
*/
- protected static <T> void addAll(final Iterable<T> values,
- final Collection<? super T> list) {
- if (values == null) {
- throw new NullPointerException();
- }
+ protected static <T> void addAll(final Iterable<T> values, final List<? super T> list) {
+ checkNotNull(values);
if (values instanceof LazyStringList) {
// For StringOrByteStringLists, check the underlying elements to avoid
// forcing conversions of ByteStrings to Strings.
- checkForNullValues(((LazyStringList) values).getUnderlyingElements());
- list.addAll((Collection<T>) values);
- } else if (values instanceof Collection) {
- checkForNullValues(values);
- list.addAll((Collection<T>) values);
- } else {
- for (final T value : values) {
+ // TODO(dweis): Could we just prohibit nulls in all protobuf lists and get rid of this? Is
+ // if even possible to hit this condition as all protobuf methods check for null first,
+ // right?
+ List<?> lazyValues = ((LazyStringList) values).getUnderlyingElements();
+ LazyStringList lazyList = (LazyStringList) list;
+ int begin = list.size();
+ for (Object value : lazyValues) {
if (value == null) {
- throw new NullPointerException();
+ // encountered a null value so we must undo our modifications prior to throwing
+ String message = "Element at index " + (lazyList.size() - begin) + " is null.";
+ for (int i = lazyList.size() - 1; i >= begin; i--) {
+ lazyList.remove(i);
+ }
+ throw new NullPointerException(message);
+ }
+ if (value instanceof ByteString) {
+ lazyList.add((ByteString) value);
+ } else {
+ lazyList.add((String) value);
}
- list.add(value);
}
- }
- }
-
- private static void checkForNullValues(final Iterable<?> values) {
- for (final Object value : values) {
- if (value == null) {
- throw new NullPointerException();
+ } else {
+ if (values instanceof PrimitiveNonBoxingCollection) {
+ list.addAll((Collection<T>) values);
+ } else {
+ addAllCheckingNulls(values, list);
}
}
}
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 7ff73ba4..ba570e3d 100644
--- a/java/core/src/main/java/com/google/protobuf/AbstractParser.java
+++ b/java/core/src/main/java/com/google/protobuf/AbstractParser.java
@@ -31,9 +31,9 @@
package com.google.protobuf;
import com.google.protobuf.AbstractMessageLite.Builder.LimitedInputStream;
-
import java.io.IOException;
import java.io.InputStream;
+import java.nio.ByteBuffer;
/**
* A partial implementation of the {@link Parser} interface which implements
@@ -131,6 +131,30 @@ public abstract class AbstractParser<MessageType extends MessageLite>
}
@Override
+ public MessageType parseFrom(ByteBuffer data, ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
+ MessageType message;
+ try {
+ CodedInputStream input = CodedInputStream.newInstance(data);
+ message = parsePartialFrom(input, extensionRegistry);
+ try {
+ input.checkLastTagWas(0);
+ } catch (InvalidProtocolBufferException e) {
+ throw e.setUnfinishedMessage(message);
+ }
+ } catch (InvalidProtocolBufferException e) {
+ throw e;
+ }
+
+ return checkMessageInitialized(message);
+ }
+
+ @Override
+ public MessageType parseFrom(ByteBuffer data) throws InvalidProtocolBufferException {
+ return parseFrom(data, EMPTY_REGISTRY);
+ }
+
+ @Override
public MessageType parsePartialFrom(
byte[] data, int off, int len, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
diff --git a/java/core/src/main/java/com/google/protobuf/Android.java b/java/core/src/main/java/com/google/protobuf/Android.java
new file mode 100644
index 00000000..cad54783
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/Android.java
@@ -0,0 +1,57 @@
+// 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;
+
+final class Android {
+
+ private static final Class<?> MEMORY_CLASS = getClassForName("libcore.io.Memory");
+ private static final boolean IS_ROBOLECTRIC =
+ getClassForName("org.robolectric.Robolectric") != null;
+
+ /** Returns {@code true} if running on an Android device. */
+ static boolean isOnAndroidDevice() {
+ return MEMORY_CLASS != null && !IS_ROBOLECTRIC;
+ }
+
+ /** Returns the memory class or {@code null} if not on Android device. */
+ static Class<?> getMemoryClass() {
+ return MEMORY_CLASS;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T> Class<T> getClassForName(String name) {
+ try {
+ return (Class<T>) Class.forName(name);
+ } catch (Throwable e) {
+ return null;
+ }
+ }
+}
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 0d9f87ba..4d7a9727 100644
--- a/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java
@@ -30,8 +30,9 @@
package com.google.protobuf;
-import com.google.protobuf.Internal.BooleanList;
+import static com.google.protobuf.Internal.checkNotNull;
+import com.google.protobuf.Internal.BooleanList;
import java.util.Arrays;
import java.util.Collection;
import java.util.RandomAccess;
@@ -41,9 +42,8 @@ import java.util.RandomAccess;
*
* @author dweis@google.com (Daniel Weis)
*/
-final class BooleanArrayList
- extends AbstractProtobufList<Boolean>
- implements BooleanList, RandomAccess {
+final class BooleanArrayList extends AbstractProtobufList<Boolean>
+ implements BooleanList, RandomAccess, PrimitiveNonBoxingCollection {
private static final BooleanArrayList EMPTY_LIST = new BooleanArrayList();
static {
@@ -82,6 +82,18 @@ final class BooleanArrayList
}
@Override
+ protected void removeRange(int fromIndex, int toIndex) {
+ ensureIsMutable();
+ if (toIndex < fromIndex) {
+ throw new IndexOutOfBoundsException("toIndex < fromIndex");
+ }
+
+ System.arraycopy(array, toIndex, array, fromIndex, size - toIndex);
+ size -= (toIndex - fromIndex);
+ modCount++;
+ }
+
+ @Override
public boolean equals(Object o) {
if (this == o) {
return true;
@@ -198,9 +210,7 @@ final class BooleanArrayList
public boolean addAll(Collection<? extends Boolean> collection) {
ensureIsMutable();
- if (collection == null) {
- throw new NullPointerException();
- }
+ checkNotNull(collection);
// We specialize when adding another BooleanArrayList to avoid boxing elements.
if (!(collection instanceof BooleanArrayList)) {
@@ -248,7 +258,9 @@ final class BooleanArrayList
ensureIsMutable();
ensureIndexInRange(index);
boolean value = array[index];
- System.arraycopy(array, index + 1, array, index, size - index);
+ if (index < size - 1) {
+ System.arraycopy(array, index + 1, array, index, size - index);
+ }
size--;
modCount++;
return value;
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 99a31209..d67bb54a 100644
--- a/java/core/src/main/java/com/google/protobuf/ByteString.java
+++ b/java/core/src/main/java/com/google/protobuf/ByteString.java
@@ -124,14 +124,8 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
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();
+ byteArrayCopier =
+ Android.isOnAndroidDevice() ? new SystemByteArrayCopier() : new ArraysByteArrayCopier();
}
/**
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 14169dc4..1297462e 100644
--- a/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
+++ b/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
@@ -34,8 +34,8 @@ import static com.google.protobuf.Internal.EMPTY_BYTE_ARRAY;
import static com.google.protobuf.Internal.EMPTY_BYTE_BUFFER;
import static com.google.protobuf.Internal.UTF_8;
import static com.google.protobuf.Internal.checkNotNull;
-import static com.google.protobuf.WireFormat.FIXED_32_SIZE;
-import static com.google.protobuf.WireFormat.FIXED_64_SIZE;
+import static com.google.protobuf.WireFormat.FIXED32_SIZE;
+import static com.google.protobuf.WireFormat.FIXED64_SIZE;
import static com.google.protobuf.WireFormat.MAX_VARINT_SIZE;
import java.io.ByteArrayOutputStream;
@@ -44,6 +44,7 @@ import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Iterator;
import java.util.List;
/**
@@ -63,6 +64,12 @@ public abstract class CodedInputStream {
// Integer.MAX_VALUE == 0x7FFFFFF == INT_MAX from limits.h
private static final int DEFAULT_SIZE_LIMIT = Integer.MAX_VALUE;
+ /**
+ * Whether to enable our custom UTF-8 decode codepath which does not use {@link StringCoding}.
+ * Currently disabled.
+ */
+ private static final boolean ENABLE_CUSTOM_UTF8_DECODE = false;
+
/** Visible for subclasses. See setRecursionLimit() */
int recursionDepth;
@@ -85,6 +92,43 @@ public abstract class CodedInputStream {
return new StreamDecoder(input, bufferSize);
}
+ /** Create a new CodedInputStream wrapping the given {@code Iterable <ByteBuffer>}. */
+ public static CodedInputStream newInstance(final Iterable<ByteBuffer> input) {
+ if (!UnsafeDirectNioDecoder.isSupported()) {
+ return newInstance(new IterableByteBufferInputStream(input));
+ }
+ return newInstance(input, false);
+ }
+
+ /** Create a new CodedInputStream wrapping the given {@code Iterable <ByteBuffer>}. */
+ static CodedInputStream newInstance(
+ final Iterable<ByteBuffer> bufs, final boolean bufferIsImmutable) {
+ // flag is to check the type of input's ByteBuffers.
+ // flag equals 1: all ByteBuffers have array.
+ // flag equals 2: all ByteBuffers are direct ByteBuffers.
+ // flag equals 3: some ByteBuffers are direct and some have array.
+ // flag greater than 3: other cases.
+ int flag = 0;
+ // Total size of the input
+ int totalSize = 0;
+ for (ByteBuffer buf : bufs) {
+ totalSize += buf.remaining();
+ if (buf.hasArray()) {
+ flag |= 1;
+ } else if (buf.isDirect()) {
+ flag |= 2;
+ } else {
+ flag |= 4;
+ }
+ }
+ if (flag == 2) {
+ return new IterableDirectByteBufferDecoder(bufs, totalSize, bufferIsImmutable);
+ } else {
+ // TODO(yilunchong): add another decoders to deal case 1 and 3.
+ return newInstance(new IterableByteBufferInputStream(bufs));
+ }
+ }
+
/** Create a new CodedInputStream wrapping the given byte array. */
public static CodedInputStream newInstance(final byte[] buf) {
return newInstance(buf, 0, buf.length);
@@ -354,9 +398,9 @@ public abstract class CodedInputStream {
*
* <p>Set the maximum message size. In order to prevent malicious messages from exhausting memory
* or causing integer overflows, {@code CodedInputStream} limits how large a message may be. The
- * default limit is 64MB. You should set this limit as small as you can without harming your app's
- * functionality. Note that size limits only apply when reading from an {@code InputStream}, not
- * when constructed around a raw byte array (nor with {@link ByteString#newCodedInput}).
+ * default limit is {@code Integer.MAX_INT}. You should set this limit as small as you can without
+ * harming your app's functionality. Note that size limits only apply when reading from an {@code
+ * InputStream}, not when constructed around a raw byte array.
*
* <p>If you want to read several messages from a single CodedInputStream, you could call {@link
* #resetSizeCounter()} after each one to avoid hitting the size limit.
@@ -372,6 +416,63 @@ public abstract class CodedInputStream {
return oldLimit;
}
+
+ private boolean explicitDiscardUnknownFields = false;
+
+ private static volatile boolean proto3DiscardUnknownFieldsDefault = false;
+
+ static void setProto3DiscardUnknownsByDefaultForTest() {
+ proto3DiscardUnknownFieldsDefault = true;
+ }
+
+ static void setProto3KeepUnknownsByDefaultForTest() {
+ proto3DiscardUnknownFieldsDefault = false;
+ }
+
+ static boolean getProto3DiscardUnknownFieldsDefault() {
+ return proto3DiscardUnknownFieldsDefault;
+ }
+
+ /**
+ * Sets this {@code CodedInputStream} to discard unknown fields. Only applies to full runtime
+ * messages; lite messages will always preserve unknowns.
+ *
+ * <p>Note calling this function alone will have NO immediate effect on the underlying input data.
+ * The unknown fields will be discarded during parsing. This affects both Proto2 and Proto3 full
+ * runtime.
+ */
+ final void discardUnknownFields() {
+ explicitDiscardUnknownFields = true;
+ }
+
+ /**
+ * Reverts the unknown fields preservation behavior for Proto2 and Proto3 full runtime to their
+ * default.
+ */
+ final void unsetDiscardUnknownFields() {
+ explicitDiscardUnknownFields = false;
+ }
+
+ /**
+ * Whether unknown fields in this input stream should be discarded during parsing into full
+ * runtime messages.
+ */
+ final boolean shouldDiscardUnknownFields() {
+ return explicitDiscardUnknownFields;
+ }
+
+ /**
+ * Whether unknown fields in this input stream should be discarded during parsing for proto3 full
+ * runtime messages.
+ *
+ * <p>This function was temporarily introduced before proto3 unknown fields behavior is changed.
+ * TODO(liujisi): remove this and related code in GeneratedMessage after proto3 unknown
+ * fields migration is done.
+ */
+ final boolean shouldDiscardUnknownFieldsProto3() {
+ return explicitDiscardUnknownFields ? true : proto3DiscardUnknownFieldsDefault;
+ }
+
/**
* Resets the current size counter to zero (see {@link #setSizeLimit(int)}). Only valid for {@link
* InputStream}-backed streams.
@@ -572,7 +673,7 @@ public abstract class CodedInputStream {
skipRawVarint();
return true;
case WireFormat.WIRETYPE_FIXED64:
- skipRawBytes(FIXED_64_SIZE);
+ skipRawBytes(FIXED64_SIZE);
return true;
case WireFormat.WIRETYPE_LENGTH_DELIMITED:
skipRawBytes(readRawVarint32());
@@ -585,7 +686,7 @@ public abstract class CodedInputStream {
case WireFormat.WIRETYPE_END_GROUP:
return false;
case WireFormat.WIRETYPE_FIXED32:
- skipRawBytes(FIXED_32_SIZE);
+ skipRawBytes(FIXED32_SIZE);
return true;
default:
throw InvalidProtocolBufferException.invalidWireType();
@@ -730,13 +831,19 @@ public abstract class CodedInputStream {
public String readStringRequireUtf8() throws IOException {
final int size = readRawVarint32();
if (size > 0 && size <= (limit - pos)) {
- // TODO(martinrb): We could save a pass by validating while decoding.
- if (!Utf8.isValidUtf8(buffer, pos, pos + size)) {
- throw InvalidProtocolBufferException.invalidUtf8();
+ if (ENABLE_CUSTOM_UTF8_DECODE) {
+ String result = Utf8.decodeUtf8(buffer, pos, size);
+ pos += size;
+ return result;
+ } else {
+ // TODO(martinrb): We could save a pass by validating while decoding.
+ if (!Utf8.isValidUtf8(buffer, pos, pos + size)) {
+ throw InvalidProtocolBufferException.invalidUtf8();
+ }
+ final int tempPos = pos;
+ pos += size;
+ return new String(buffer, tempPos, size, UTF_8);
}
- final int tempPos = pos;
- pos += size;
- return new String(buffer, tempPos, size, UTF_8);
}
if (size == 0) {
@@ -1064,12 +1171,12 @@ public abstract class CodedInputStream {
public int readRawLittleEndian32() throws IOException {
int tempPos = pos;
- if (limit - tempPos < FIXED_32_SIZE) {
+ if (limit - tempPos < FIXED32_SIZE) {
throw InvalidProtocolBufferException.truncatedMessage();
}
final byte[] buffer = this.buffer;
- pos = tempPos + FIXED_32_SIZE;
+ pos = tempPos + FIXED32_SIZE;
return (((buffer[tempPos] & 0xff))
| ((buffer[tempPos + 1] & 0xff) << 8)
| ((buffer[tempPos + 2] & 0xff) << 16)
@@ -1080,12 +1187,12 @@ public abstract class CodedInputStream {
public long readRawLittleEndian64() throws IOException {
int tempPos = pos;
- if (limit - tempPos < FIXED_64_SIZE) {
+ if (limit - tempPos < FIXED64_SIZE) {
throw InvalidProtocolBufferException.truncatedMessage();
}
final byte[] buffer = this.buffer;
- pos = tempPos + FIXED_64_SIZE;
+ pos = tempPos + FIXED64_SIZE;
return (((buffer[tempPos] & 0xffL))
| ((buffer[tempPos + 1] & 0xffL) << 8)
| ((buffer[tempPos + 2] & 0xffL) << 16)
@@ -1290,7 +1397,7 @@ public abstract class CodedInputStream {
skipRawVarint();
return true;
case WireFormat.WIRETYPE_FIXED64:
- skipRawBytes(FIXED_64_SIZE);
+ skipRawBytes(FIXED64_SIZE);
return true;
case WireFormat.WIRETYPE_LENGTH_DELIMITED:
skipRawBytes(readRawVarint32());
@@ -1303,7 +1410,7 @@ public abstract class CodedInputStream {
case WireFormat.WIRETYPE_END_GROUP:
return false;
case WireFormat.WIRETYPE_FIXED32:
- skipRawBytes(FIXED_32_SIZE);
+ skipRawBytes(FIXED32_SIZE);
return true;
default:
throw InvalidProtocolBufferException.invalidWireType();
@@ -1429,7 +1536,11 @@ public abstract class CodedInputStream {
final int size = readRawVarint32();
if (size > 0 && size <= remaining()) {
// TODO(nathanmittler): Is there a way to avoid this copy?
- byte[] bytes = copyToArray(pos, pos + size);
+ // TODO(anuraaga): It might be possible to share the optimized loop with
+ // readStringRequireUtf8 by implementing Java replacement logic there.
+ // The same as readBytes' logic
+ byte[] bytes = new byte[size];
+ UnsafeUtil.copyMemory(pos, bytes, 0, size);
String result = new String(bytes, UTF_8);
pos += size;
return result;
@@ -1447,17 +1558,26 @@ public abstract class CodedInputStream {
@Override
public String readStringRequireUtf8() throws IOException {
final int size = readRawVarint32();
- if (size >= 0 && size <= remaining()) {
- // TODO(nathanmittler): Is there a way to avoid this copy?
- byte[] bytes = copyToArray(pos, pos + size);
- // TODO(martinrb): We could save a pass by validating while decoding.
- if (!Utf8.isValidUtf8(bytes)) {
- throw InvalidProtocolBufferException.invalidUtf8();
- }
+ if (size > 0 && size <= remaining()) {
+ if (ENABLE_CUSTOM_UTF8_DECODE) {
+ final int bufferPos = bufferPos(pos);
+ String result = Utf8.decodeUtf8(buffer, bufferPos, size);
+ pos += size;
+ return result;
+ } else {
+ // TODO(nathanmittler): Is there a way to avoid this copy?
+ // The same as readBytes' logic
+ byte[] bytes = new byte[size];
+ UnsafeUtil.copyMemory(pos, bytes, 0, size);
+ // TODO(martinrb): We could save a pass by validating while decoding.
+ if (!Utf8.isValidUtf8(bytes)) {
+ throw InvalidProtocolBufferException.invalidUtf8();
+ }
- String result = new String(bytes, UTF_8);
- pos += size;
- return result;
+ String result = new String(bytes, UTF_8);
+ pos += size;
+ return result;
+ }
}
if (size == 0) {
@@ -1545,14 +1665,17 @@ public abstract class CodedInputStream {
public ByteString readBytes() throws IOException {
final int size = readRawVarint32();
if (size > 0 && size <= remaining()) {
- ByteBuffer result;
if (immutable && enableAliasing) {
- result = slice(pos, pos + size);
+ final ByteBuffer result = slice(pos, pos + size);
+ pos += size;
+ return ByteString.wrap(result);
} else {
- result = copy(pos, pos + size);
+ // Use UnsafeUtil to copy the memory to bytes instead of using ByteBuffer ways.
+ byte[] bytes = new byte[size];
+ UnsafeUtil.copyMemory(pos, bytes, 0, size);
+ pos += size;
+ return ByteString.wrap(bytes);
}
- pos += size;
- return ByteString.wrap(result);
}
if (size == 0) {
@@ -1573,18 +1696,21 @@ public abstract class CodedInputStream {
public ByteBuffer readByteBuffer() throws IOException {
final int size = readRawVarint32();
if (size > 0 && size <= remaining()) {
- ByteBuffer result;
// "Immutable" implies that buffer is backing a ByteString.
// Disallow slicing in this case to prevent the caller from modifying the contents
// of the ByteString.
if (!immutable && enableAliasing) {
- result = slice(pos, pos + size);
+ final ByteBuffer result = slice(pos, pos + size);
+ pos += size;
+ return result;
} else {
- result = copy(pos, pos + size);
+ // The same as readBytes' logic
+ byte[] bytes = new byte[size];
+ UnsafeUtil.copyMemory(pos, bytes, 0, size);
+ pos += size;
+ return ByteBuffer.wrap(bytes);
}
- pos += size;
// TODO(nathanmittler): Investigate making the ByteBuffer be made read-only
- return result;
}
if (size == 0) {
@@ -1785,11 +1911,11 @@ public abstract class CodedInputStream {
public int readRawLittleEndian32() throws IOException {
long tempPos = pos;
- if (limit - tempPos < FIXED_32_SIZE) {
+ if (limit - tempPos < FIXED32_SIZE) {
throw InvalidProtocolBufferException.truncatedMessage();
}
- pos = tempPos + FIXED_32_SIZE;
+ pos = tempPos + FIXED32_SIZE;
return (((UnsafeUtil.getByte(tempPos) & 0xff))
| ((UnsafeUtil.getByte(tempPos + 1) & 0xff) << 8)
| ((UnsafeUtil.getByte(tempPos + 2) & 0xff) << 16)
@@ -1800,11 +1926,11 @@ public abstract class CodedInputStream {
public long readRawLittleEndian64() throws IOException {
long tempPos = pos;
- if (limit - tempPos < FIXED_64_SIZE) {
+ if (limit - tempPos < FIXED64_SIZE) {
throw InvalidProtocolBufferException.truncatedMessage();
}
- pos = tempPos + FIXED_64_SIZE;
+ pos = tempPos + FIXED64_SIZE;
return (((UnsafeUtil.getByte(tempPos) & 0xffL))
| ((UnsafeUtil.getByte(tempPos + 1) & 0xffL) << 8)
| ((UnsafeUtil.getByte(tempPos + 2) & 0xffL) << 16)
@@ -1943,27 +2069,6 @@ public abstract class CodedInputStream {
buffer.limit(prevLimit);
}
}
-
- private ByteBuffer copy(long begin, long end) throws IOException {
- return ByteBuffer.wrap(copyToArray(begin, end));
- }
-
- private byte[] copyToArray(long begin, long end) throws IOException {
- int prevPos = buffer.position();
- int prevLimit = buffer.limit();
- try {
- buffer.position(bufferPos(begin));
- buffer.limit(bufferPos(end));
- byte[] bytes = new byte[(int) (end - begin)];
- buffer.get(bytes);
- return bytes;
- } catch (IllegalArgumentException e) {
- throw InvalidProtocolBufferException.truncatedMessage();
- } finally {
- buffer.position(prevPos);
- buffer.limit(prevLimit);
- }
- }
}
/**
@@ -2034,7 +2139,7 @@ public abstract class CodedInputStream {
skipRawVarint();
return true;
case WireFormat.WIRETYPE_FIXED64:
- skipRawBytes(FIXED_64_SIZE);
+ skipRawBytes(FIXED64_SIZE);
return true;
case WireFormat.WIRETYPE_LENGTH_DELIMITED:
skipRawBytes(readRawVarint32());
@@ -2047,7 +2152,7 @@ public abstract class CodedInputStream {
case WireFormat.WIRETYPE_END_GROUP:
return false;
case WireFormat.WIRETYPE_FIXED32:
- skipRawBytes(FIXED_32_SIZE);
+ skipRawBytes(FIXED32_SIZE);
return true;
default:
throw InvalidProtocolBufferException.invalidWireType();
@@ -2240,11 +2345,15 @@ public abstract class CodedInputStream {
bytes = readRawBytesSlowPath(size);
tempPos = 0;
}
- // TODO(martinrb): We could save a pass by validating while decoding.
- if (!Utf8.isValidUtf8(bytes, tempPos, tempPos + size)) {
- throw InvalidProtocolBufferException.invalidUtf8();
+ if (ENABLE_CUSTOM_UTF8_DECODE) {
+ return Utf8.decodeUtf8(bytes, tempPos, size);
+ } else {
+ // TODO(martinrb): We could save a pass by validating while decoding.
+ if (!Utf8.isValidUtf8(bytes, tempPos, tempPos + size)) {
+ throw InvalidProtocolBufferException.invalidUtf8();
+ }
+ return new String(bytes, tempPos, size, UTF_8);
}
- return new String(bytes, tempPos, size, UTF_8);
}
@Override
@@ -2332,8 +2441,7 @@ public abstract class CodedInputStream {
if (size == 0) {
return ByteString.EMPTY;
}
- // Slow path: Build a byte array first then copy it.
- return ByteString.wrap(readRawBytesSlowPath(size));
+ return readBytesSlowPath(size);
}
@Override
@@ -2558,13 +2666,13 @@ public abstract class CodedInputStream {
public int readRawLittleEndian32() throws IOException {
int tempPos = pos;
- if (bufferSize - tempPos < FIXED_32_SIZE) {
- refillBuffer(FIXED_32_SIZE);
+ if (bufferSize - tempPos < FIXED32_SIZE) {
+ refillBuffer(FIXED32_SIZE);
tempPos = pos;
}
final byte[] buffer = this.buffer;
- pos = tempPos + FIXED_32_SIZE;
+ pos = tempPos + FIXED32_SIZE;
return (((buffer[tempPos] & 0xff))
| ((buffer[tempPos + 1] & 0xff) << 8)
| ((buffer[tempPos + 2] & 0xff) << 16)
@@ -2575,13 +2683,13 @@ public abstract class CodedInputStream {
public long readRawLittleEndian64() throws IOException {
int tempPos = pos;
- if (bufferSize - tempPos < FIXED_64_SIZE) {
- refillBuffer(FIXED_64_SIZE);
+ if (bufferSize - tempPos < FIXED64_SIZE) {
+ refillBuffer(FIXED64_SIZE);
tempPos = pos;
}
final byte[] buffer = this.buffer;
- pos = tempPos + FIXED_64_SIZE;
+ pos = tempPos + FIXED64_SIZE;
return (((buffer[tempPos] & 0xffL))
| ((buffer[tempPos + 1] & 0xffL) << 8)
| ((buffer[tempPos + 2] & 0xffL) << 16)
@@ -2675,7 +2783,13 @@ public abstract class CodedInputStream {
*/
private void refillBuffer(int n) throws IOException {
if (!tryRefillBuffer(n)) {
- throw InvalidProtocolBufferException.truncatedMessage();
+ // We have to distinguish the exception between sizeLimitExceeded and truncatedMessage. So
+ // we just throw an sizeLimitExceeded exception here if it exceeds the sizeLimit
+ if (n > sizeLimit - totalBytesRetired - pos) {
+ throw InvalidProtocolBufferException.sizeLimitExceeded();
+ } else {
+ throw InvalidProtocolBufferException.truncatedMessage();
+ }
}
}
@@ -2684,8 +2798,8 @@ public abstract class CodedInputStream {
* buffer. Caller must ensure that the requested space is not yet available, and that the
* requested space is less than BUFFER_SIZE.
*
- * @return {@code true} if the bytes could be made available; {@code false} if the end of the
- * stream or the current limit was reached.
+ * @return {@code true} If the bytes could be made available; {@code false} 1. Current at the
+ * end of the stream 2. The current limit was reached 3. The total size limit was reached
*/
private boolean tryRefillBuffer(int n) throws IOException {
if (pos + n <= bufferSize) {
@@ -2693,6 +2807,14 @@ public abstract class CodedInputStream {
"refillBuffer() called when " + n + " bytes were already available in buffer");
}
+ // Check whether the size of total message needs to read is bigger than the size limit.
+ // We shouldn't throw an exception here as isAtEnd() function needs to get this function's
+ // return as the result.
+ if (n > sizeLimit - totalBytesRetired - pos) {
+ return false;
+ }
+
+ // Shouldn't throw the exception here either.
if (totalBytesRetired + pos + n > currentLimit) {
// Oops, we hit a limit.
return false;
@@ -2712,7 +2834,16 @@ public abstract class CodedInputStream {
pos = 0;
}
- int bytesRead = input.read(buffer, bufferSize, buffer.length - bufferSize);
+ // Here we should refill the buffer as many bytes as possible.
+ int bytesRead =
+ input.read(
+ buffer,
+ bufferSize,
+ Math.min(
+ // the size of allocated but unused bytes in the buffer
+ buffer.length - bufferSize,
+ // do not exceed the total bytes limit
+ sizeLimit - totalBytesRetired - bufferSize));
if (bytesRead == 0 || bytesRead < -1 || bytesRead > buffer.length) {
throw new IllegalStateException(
"InputStream#read(byte[]) returned invalid result: "
@@ -2721,10 +2852,6 @@ public abstract class CodedInputStream {
}
if (bytesRead > 0) {
bufferSize += bytesRead;
- // Integer-overflow-conscious check against sizeLimit
- if (totalBytesRetired + n - sizeLimit > 0) {
- throw InvalidProtocolBufferException.sizeLimitExceeded();
- }
recomputeBufferSizeAfterLimit();
return (bufferSize >= n) ? true : tryRefillBuffer(n);
}
@@ -2756,6 +2883,49 @@ public abstract class CodedInputStream {
* (bufferSize - pos) && size > 0)
*/
private byte[] readRawBytesSlowPath(final int size) throws IOException {
+ // Attempt to read the data in one byte array when it's safe to do.
+ byte[] result = readRawBytesSlowPathOneChunk(size);
+ if (result != null) {
+ return result;
+ }
+
+ final int originalBufferPos = pos;
+ final int bufferedBytes = bufferSize - pos;
+
+ // Mark the current buffer consumed.
+ totalBytesRetired += bufferSize;
+ pos = 0;
+ bufferSize = 0;
+
+ // Determine the number of bytes we need to read from the input stream.
+ int sizeLeft = size - bufferedBytes;
+
+ // The size is very large. For security reasons we read them in small
+ // chunks.
+ List<byte[]> chunks = readRawBytesSlowPathRemainingChunks(sizeLeft);
+
+ // OK, got everything. Now concatenate it all into one buffer.
+ final byte[] bytes = new byte[size];
+
+ // Start by copying the leftover bytes from this.buffer.
+ System.arraycopy(buffer, originalBufferPos, bytes, 0, bufferedBytes);
+
+ // And now all the chunks.
+ int tempPos = bufferedBytes;
+ for (final byte[] chunk : chunks) {
+ System.arraycopy(chunk, 0, bytes, tempPos, chunk.length);
+ tempPos += chunk.length;
+ }
+
+ // Done.
+ return bytes;
+ }
+
+ /**
+ * Attempts to read the data in one byte array when it's safe to do. Returns null if the size to
+ * read is too large and needs to be allocated in smaller chunks for security reasons.
+ */
+ private byte[] readRawBytesSlowPathOneChunk(final int size) throws IOException {
if (size == 0) {
return Internal.EMPTY_BYTE_ARRAY;
}
@@ -2776,14 +2946,7 @@ public abstract class CodedInputStream {
throw InvalidProtocolBufferException.truncatedMessage();
}
- final int originalBufferPos = pos;
final int bufferedBytes = bufferSize - pos;
-
- // Mark the current buffer consumed.
- totalBytesRetired += bufferSize;
- pos = 0;
- bufferSize = 0;
-
// Determine the number of bytes we need to read from the input stream.
int sizeLeft = size - bufferedBytes;
// TODO(nathanmittler): Consider using a value larger than DEFAULT_BUFFER_SIZE.
@@ -2793,7 +2956,10 @@ public abstract class CodedInputStream {
final byte[] bytes = new byte[size];
// Copy all of the buffered bytes to the result buffer.
- System.arraycopy(buffer, originalBufferPos, bytes, 0, bufferedBytes);
+ System.arraycopy(buffer, pos, bytes, 0, bufferedBytes);
+ totalBytesRetired += bufferSize;
+ pos = 0;
+ bufferSize = 0;
// Fill the remaining bytes from the input stream.
int tempPos = bufferedBytes;
@@ -2809,6 +2975,11 @@ public abstract class CodedInputStream {
return bytes;
}
+ return null;
+ }
+
+ /** Reads the remaining data in small chunks from the input stream. */
+ private List<byte[]> readRawBytesSlowPathRemainingChunks(int sizeLeft) throws IOException {
// The size is very large. For security reasons, we can't allocate the
// entire byte array yet. The size comes directly from the input, so a
// maliciously-crafted message could provide a bogus very large size in
@@ -2834,21 +3005,41 @@ public abstract class CodedInputStream {
chunks.add(chunk);
}
- // OK, got everything. Now concatenate it all into one buffer.
- final byte[] bytes = new byte[size];
-
- // Start by copying the leftover bytes from this.buffer.
- System.arraycopy(buffer, originalBufferPos, bytes, 0, bufferedBytes);
+ return chunks;
+ }
- // And now all the chunks.
- int tempPos = bufferedBytes;
- for (final byte[] chunk : chunks) {
- System.arraycopy(chunk, 0, bytes, tempPos, chunk.length);
- tempPos += chunk.length;
+ /**
+ * Like readBytes, but caller must have already checked the fast path: (size <= (bufferSize -
+ * pos) && size > 0 || size == 0)
+ */
+ private ByteString readBytesSlowPath(final int size) throws IOException {
+ final byte[] result = readRawBytesSlowPathOneChunk(size);
+ if (result != null) {
+ return ByteString.wrap(result);
}
- // Done.
- return bytes;
+ final int originalBufferPos = pos;
+ final int bufferedBytes = bufferSize - pos;
+
+ // Mark the current buffer consumed.
+ totalBytesRetired += bufferSize;
+ pos = 0;
+ bufferSize = 0;
+
+ // Determine the number of bytes we need to read from the input stream.
+ int sizeLeft = size - bufferedBytes;
+
+ // The size is very large. For security reasons we read them in small
+ // chunks.
+ List<byte[]> chunks = readRawBytesSlowPathRemainingChunks(sizeLeft);
+
+ // Wrap the byte arrays into a single ByteString.
+ List<ByteString> byteStrings = new ArrayList<ByteString>(1 + chunks.size());
+ byteStrings.add(ByteString.copyFrom(buffer, originalBufferPos, bufferedBytes));
+ for (byte[] chunk : chunks) {
+ byteStrings.add(ByteString.wrap(chunk));
+ }
+ return ByteString.copyFrom(byteStrings);
}
@Override
@@ -2893,4 +3084,859 @@ public abstract class CodedInputStream {
pos = size - tempPos;
}
}
+
+ /**
+ * Implementation of {@link CodedInputStream} that uses an {@link Iterable <ByteBuffer>} as the
+ * data source. Requires the use of {@code sun.misc.Unsafe} to perform fast reads on the buffer.
+ */
+ private static final class IterableDirectByteBufferDecoder extends CodedInputStream {
+ /** The object that need to decode. */
+ private Iterable<ByteBuffer> input;
+ /** The {@link Iterator} with type {@link ByteBuffer} of {@code input} */
+ private Iterator<ByteBuffer> iterator;
+ /** The current ByteBuffer; */
+ private ByteBuffer currentByteBuffer;
+ /**
+ * If {@code true}, indicates that all the buffer are backing a {@link ByteString} and are
+ * therefore considered to be an immutable input source.
+ */
+ private boolean immutable;
+ /**
+ * If {@code true}, indicates that calls to read {@link ByteString} or {@code byte[]}
+ * <strong>may</strong> return slices of the underlying buffer, rather than copies.
+ */
+ private boolean enableAliasing;
+ /** The global total message length limit */
+ private int totalBufferSize;
+ /** The amount of available data in the input beyond {@link #currentLimit}. */
+ private int bufferSizeAfterCurrentLimit;
+ /** The absolute position of the end of the current message. */
+ private int currentLimit = Integer.MAX_VALUE;
+ /** The last tag that was read from this stream. */
+ private int lastTag;
+ /** Total Bytes have been Read from the {@link Iterable} {@link ByteBuffer} */
+ private int totalBytesRead;
+ /** The start position offset of the whole message, used as to reset the totalBytesRead */
+ private int startOffset;
+ /** The current position for current ByteBuffer */
+ private long currentByteBufferPos;
+
+ private long currentByteBufferStartPos;
+ /**
+ * If the current ByteBuffer is unsafe-direct based, currentAddress is the start address of this
+ * ByteBuffer; otherwise should be zero.
+ */
+ private long currentAddress;
+ /** The limit position for current ByteBuffer */
+ private long currentByteBufferLimit;
+
+ /**
+ * The constructor of {@code Iterable<ByteBuffer>} decoder.
+ *
+ * @param inputBufs The input data.
+ * @param size The total size of the input data.
+ * @param immutableFlag whether the input data is immutable.
+ */
+ private IterableDirectByteBufferDecoder(
+ Iterable<ByteBuffer> inputBufs, int size, boolean immutableFlag) {
+ totalBufferSize = size;
+ input = inputBufs;
+ iterator = input.iterator();
+ immutable = immutableFlag;
+ startOffset = totalBytesRead = 0;
+ if (size == 0) {
+ currentByteBuffer = EMPTY_BYTE_BUFFER;
+ currentByteBufferPos = 0;
+ currentByteBufferStartPos = 0;
+ currentByteBufferLimit = 0;
+ currentAddress = 0;
+ } else {
+ tryGetNextByteBuffer();
+ }
+ }
+
+ /** To get the next ByteBuffer from {@code input}, and then update the parameters */
+ private void getNextByteBuffer() throws InvalidProtocolBufferException {
+ if (!iterator.hasNext()) {
+ throw InvalidProtocolBufferException.truncatedMessage();
+ }
+ tryGetNextByteBuffer();
+ }
+
+ private void tryGetNextByteBuffer() {
+ currentByteBuffer = iterator.next();
+ totalBytesRead += (int) (currentByteBufferPos - currentByteBufferStartPos);
+ currentByteBufferPos = currentByteBuffer.position();
+ currentByteBufferStartPos = currentByteBufferPos;
+ currentByteBufferLimit = currentByteBuffer.limit();
+ currentAddress = UnsafeUtil.addressOffset(currentByteBuffer);
+ currentByteBufferPos += currentAddress;
+ currentByteBufferStartPos += currentAddress;
+ currentByteBufferLimit += currentAddress;
+ }
+
+ @Override
+ public int readTag() throws IOException {
+ if (isAtEnd()) {
+ lastTag = 0;
+ return 0;
+ }
+
+ lastTag = readRawVarint32();
+ if (WireFormat.getTagFieldNumber(lastTag) == 0) {
+ // If we actually read zero (or any tag number corresponding to field
+ // number zero), that's not a valid tag.
+ throw InvalidProtocolBufferException.invalidTag();
+ }
+ return lastTag;
+ }
+
+ @Override
+ public void checkLastTagWas(final int value) throws InvalidProtocolBufferException {
+ if (lastTag != value) {
+ throw InvalidProtocolBufferException.invalidEndTag();
+ }
+ }
+
+ @Override
+ public int getLastTag() {
+ return lastTag;
+ }
+
+ @Override
+ public boolean skipField(final int tag) throws IOException {
+ switch (WireFormat.getTagWireType(tag)) {
+ case WireFormat.WIRETYPE_VARINT:
+ skipRawVarint();
+ return true;
+ case WireFormat.WIRETYPE_FIXED64:
+ skipRawBytes(FIXED64_SIZE);
+ return true;
+ case WireFormat.WIRETYPE_LENGTH_DELIMITED:
+ skipRawBytes(readRawVarint32());
+ return true;
+ case WireFormat.WIRETYPE_START_GROUP:
+ skipMessage();
+ checkLastTagWas(
+ WireFormat.makeTag(WireFormat.getTagFieldNumber(tag), WireFormat.WIRETYPE_END_GROUP));
+ return true;
+ case WireFormat.WIRETYPE_END_GROUP:
+ return false;
+ case WireFormat.WIRETYPE_FIXED32:
+ skipRawBytes(FIXED32_SIZE);
+ return true;
+ default:
+ throw InvalidProtocolBufferException.invalidWireType();
+ }
+ }
+
+ @Override
+ public boolean skipField(final int tag, final CodedOutputStream output) throws IOException {
+ switch (WireFormat.getTagWireType(tag)) {
+ case WireFormat.WIRETYPE_VARINT:
+ {
+ long value = readInt64();
+ output.writeRawVarint32(tag);
+ output.writeUInt64NoTag(value);
+ return true;
+ }
+ case WireFormat.WIRETYPE_FIXED64:
+ {
+ long value = readRawLittleEndian64();
+ output.writeRawVarint32(tag);
+ output.writeFixed64NoTag(value);
+ return true;
+ }
+ case WireFormat.WIRETYPE_LENGTH_DELIMITED:
+ {
+ ByteString value = readBytes();
+ output.writeRawVarint32(tag);
+ output.writeBytesNoTag(value);
+ return true;
+ }
+ case WireFormat.WIRETYPE_START_GROUP:
+ {
+ output.writeRawVarint32(tag);
+ skipMessage(output);
+ int endtag =
+ WireFormat.makeTag(
+ WireFormat.getTagFieldNumber(tag), WireFormat.WIRETYPE_END_GROUP);
+ checkLastTagWas(endtag);
+ output.writeRawVarint32(endtag);
+ return true;
+ }
+ case WireFormat.WIRETYPE_END_GROUP:
+ {
+ return false;
+ }
+ case WireFormat.WIRETYPE_FIXED32:
+ {
+ int value = readRawLittleEndian32();
+ output.writeRawVarint32(tag);
+ output.writeFixed32NoTag(value);
+ return true;
+ }
+ default:
+ throw InvalidProtocolBufferException.invalidWireType();
+ }
+ }
+
+ @Override
+ public void skipMessage() throws IOException {
+ while (true) {
+ final int tag = readTag();
+ if (tag == 0 || !skipField(tag)) {
+ return;
+ }
+ }
+ }
+
+ @Override
+ public void skipMessage(CodedOutputStream output) throws IOException {
+ while (true) {
+ final int tag = readTag();
+ if (tag == 0 || !skipField(tag, output)) {
+ return;
+ }
+ }
+ }
+
+ // -----------------------------------------------------------------
+
+ @Override
+ public double readDouble() throws IOException {
+ return Double.longBitsToDouble(readRawLittleEndian64());
+ }
+
+ @Override
+ public float readFloat() throws IOException {
+ return Float.intBitsToFloat(readRawLittleEndian32());
+ }
+
+ @Override
+ public long readUInt64() throws IOException {
+ return readRawVarint64();
+ }
+
+ @Override
+ public long readInt64() throws IOException {
+ return readRawVarint64();
+ }
+
+ @Override
+ public int readInt32() throws IOException {
+ return readRawVarint32();
+ }
+
+ @Override
+ public long readFixed64() throws IOException {
+ return readRawLittleEndian64();
+ }
+
+ @Override
+ public int readFixed32() throws IOException {
+ return readRawLittleEndian32();
+ }
+
+ @Override
+ public boolean readBool() throws IOException {
+ return readRawVarint64() != 0;
+ }
+
+ @Override
+ public String readString() throws IOException {
+ final int size = readRawVarint32();
+ if (size > 0 && size <= currentByteBufferLimit - currentByteBufferPos) {
+ byte[] bytes = new byte[size];
+ UnsafeUtil.copyMemory(currentByteBufferPos, bytes, 0, size);
+ String result = new String(bytes, UTF_8);
+ currentByteBufferPos += size;
+ return result;
+ } else if (size > 0 && size <= remaining()) {
+ // TODO(yilunchong): To use an underlying bytes[] instead of allocating a new bytes[]
+ byte[] bytes = new byte[size];
+ readRawBytesTo(bytes, 0, size);
+ String result = new String(bytes, UTF_8);
+ return result;
+ }
+
+ if (size == 0) {
+ return "";
+ }
+ if (size < 0) {
+ throw InvalidProtocolBufferException.negativeSize();
+ }
+ throw InvalidProtocolBufferException.truncatedMessage();
+ }
+
+ @Override
+ public String readStringRequireUtf8() throws IOException {
+ final int size = readRawVarint32();
+ if (size > 0 && size <= currentByteBufferLimit - currentByteBufferPos) {
+ if (ENABLE_CUSTOM_UTF8_DECODE) {
+ final int bufferPos = (int) (currentByteBufferPos - currentByteBufferStartPos);
+ String result = Utf8.decodeUtf8(currentByteBuffer, bufferPos, size);
+ currentByteBufferPos += size;
+ return result;
+ } else {
+ byte[] bytes = new byte[size];
+ UnsafeUtil.copyMemory(currentByteBufferPos, bytes, 0, size);
+ if (!Utf8.isValidUtf8(bytes)) {
+ throw InvalidProtocolBufferException.invalidUtf8();
+ }
+ String result = new String(bytes, UTF_8);
+ currentByteBufferPos += size;
+ return result;
+ }
+ }
+ if (size >= 0 && size <= remaining()) {
+ byte[] bytes = new byte[size];
+ readRawBytesTo(bytes, 0, size);
+ if (ENABLE_CUSTOM_UTF8_DECODE) {
+ return Utf8.decodeUtf8(bytes, 0, size);
+ } else {
+ if (!Utf8.isValidUtf8(bytes)) {
+ throw InvalidProtocolBufferException.invalidUtf8();
+ }
+ String result = new String(bytes, UTF_8);
+ return result;
+ }
+ }
+
+ if (size == 0) {
+ return "";
+ }
+ if (size <= 0) {
+ throw InvalidProtocolBufferException.negativeSize();
+ }
+ throw InvalidProtocolBufferException.truncatedMessage();
+ }
+
+ @Override
+ public void readGroup(
+ final int fieldNumber,
+ final MessageLite.Builder builder,
+ final ExtensionRegistryLite extensionRegistry)
+ throws IOException {
+ if (recursionDepth >= recursionLimit) {
+ throw InvalidProtocolBufferException.recursionLimitExceeded();
+ }
+ ++recursionDepth;
+ builder.mergeFrom(this, extensionRegistry);
+ checkLastTagWas(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
+ --recursionDepth;
+ }
+
+
+ @Override
+ public <T extends MessageLite> T readGroup(
+ final int fieldNumber,
+ final Parser<T> parser,
+ final ExtensionRegistryLite extensionRegistry)
+ throws IOException {
+ if (recursionDepth >= recursionLimit) {
+ throw InvalidProtocolBufferException.recursionLimitExceeded();
+ }
+ ++recursionDepth;
+ T result = parser.parsePartialFrom(this, extensionRegistry);
+ checkLastTagWas(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
+ --recursionDepth;
+ return result;
+ }
+
+ @Deprecated
+ @Override
+ public void readUnknownGroup(final int fieldNumber, final MessageLite.Builder builder)
+ throws IOException {
+ readGroup(fieldNumber, builder, ExtensionRegistryLite.getEmptyRegistry());
+ }
+
+ @Override
+ public void readMessage(
+ final MessageLite.Builder builder, final ExtensionRegistryLite extensionRegistry)
+ throws IOException {
+ final int length = readRawVarint32();
+ if (recursionDepth >= recursionLimit) {
+ throw InvalidProtocolBufferException.recursionLimitExceeded();
+ }
+ final int oldLimit = pushLimit(length);
+ ++recursionDepth;
+ builder.mergeFrom(this, extensionRegistry);
+ checkLastTagWas(0);
+ --recursionDepth;
+ popLimit(oldLimit);
+ }
+
+
+ @Override
+ public <T extends MessageLite> T readMessage(
+ final Parser<T> parser, final ExtensionRegistryLite extensionRegistry) throws IOException {
+ int length = readRawVarint32();
+ if (recursionDepth >= recursionLimit) {
+ throw InvalidProtocolBufferException.recursionLimitExceeded();
+ }
+ final int oldLimit = pushLimit(length);
+ ++recursionDepth;
+ T result = parser.parsePartialFrom(this, extensionRegistry);
+ checkLastTagWas(0);
+ --recursionDepth;
+ popLimit(oldLimit);
+ return result;
+ }
+
+ @Override
+ public ByteString readBytes() throws IOException {
+ final int size = readRawVarint32();
+ if (size > 0 && size <= currentByteBufferLimit - currentByteBufferPos) {
+ if (immutable && enableAliasing) {
+ final int idx = (int) (currentByteBufferPos - currentAddress);
+ final ByteString result = ByteString.wrap(slice(idx, idx + size));
+ currentByteBufferPos += size;
+ return result;
+ } else {
+ byte[] bytes;
+ bytes = new byte[size];
+ UnsafeUtil.copyMemory(currentByteBufferPos, bytes, 0, size);
+ currentByteBufferPos += size;
+ return ByteString.wrap(bytes);
+ }
+ } else if (size > 0 && size <= remaining()) {
+ byte[] temp = new byte[size];
+ readRawBytesTo(temp, 0, size);
+ return ByteString.wrap(temp);
+ }
+
+ if (size == 0) {
+ return ByteString.EMPTY;
+ }
+ if (size < 0) {
+ throw InvalidProtocolBufferException.negativeSize();
+ }
+ throw InvalidProtocolBufferException.truncatedMessage();
+ }
+
+ @Override
+ public byte[] readByteArray() throws IOException {
+ return readRawBytes(readRawVarint32());
+ }
+
+ @Override
+ public ByteBuffer readByteBuffer() throws IOException {
+ final int size = readRawVarint32();
+ if (size > 0 && size <= currentRemaining()) {
+ if (!immutable && enableAliasing) {
+ currentByteBufferPos += size;
+ return slice(
+ (int) (currentByteBufferPos - currentAddress - size),
+ (int) (currentByteBufferPos - currentAddress));
+ } else {
+ byte[] bytes = new byte[size];
+ UnsafeUtil.copyMemory(currentByteBufferPos, bytes, 0, size);
+ currentByteBufferPos += size;
+ return ByteBuffer.wrap(bytes);
+ }
+ } else if (size > 0 && size <= remaining()) {
+ byte[] temp = new byte[size];
+ readRawBytesTo(temp, 0, size);
+ return ByteBuffer.wrap(temp);
+ }
+
+ if (size == 0) {
+ return EMPTY_BYTE_BUFFER;
+ }
+ if (size < 0) {
+ throw InvalidProtocolBufferException.negativeSize();
+ }
+ throw InvalidProtocolBufferException.truncatedMessage();
+ }
+
+ @Override
+ public int readUInt32() throws IOException {
+ return readRawVarint32();
+ }
+
+ @Override
+ public int readEnum() throws IOException {
+ return readRawVarint32();
+ }
+
+ @Override
+ public int readSFixed32() throws IOException {
+ return readRawLittleEndian32();
+ }
+
+ @Override
+ public long readSFixed64() throws IOException {
+ return readRawLittleEndian64();
+ }
+
+ @Override
+ public int readSInt32() throws IOException {
+ return decodeZigZag32(readRawVarint32());
+ }
+
+ @Override
+ public long readSInt64() throws IOException {
+ return decodeZigZag64(readRawVarint64());
+ }
+
+ @Override
+ public int readRawVarint32() throws IOException {
+ fastpath:
+ {
+ long tempPos = currentByteBufferPos;
+
+ if (currentByteBufferLimit == currentByteBufferPos) {
+ break fastpath;
+ }
+
+ int x;
+ if ((x = UnsafeUtil.getByte(tempPos++)) >= 0) {
+ currentByteBufferPos++;
+ return x;
+ } else if (currentByteBufferLimit - currentByteBufferPos < 10) {
+ break fastpath;
+ } else if ((x ^= (UnsafeUtil.getByte(tempPos++) << 7)) < 0) {
+ x ^= (~0 << 7);
+ } else if ((x ^= (UnsafeUtil.getByte(tempPos++) << 14)) >= 0) {
+ x ^= (~0 << 7) ^ (~0 << 14);
+ } else if ((x ^= (UnsafeUtil.getByte(tempPos++) << 21)) < 0) {
+ x ^= (~0 << 7) ^ (~0 << 14) ^ (~0 << 21);
+ } else {
+ int y = UnsafeUtil.getByte(tempPos++);
+ x ^= y << 28;
+ x ^= (~0 << 7) ^ (~0 << 14) ^ (~0 << 21) ^ (~0 << 28);
+ if (y < 0
+ && UnsafeUtil.getByte(tempPos++) < 0
+ && UnsafeUtil.getByte(tempPos++) < 0
+ && UnsafeUtil.getByte(tempPos++) < 0
+ && UnsafeUtil.getByte(tempPos++) < 0
+ && UnsafeUtil.getByte(tempPos++) < 0) {
+ break fastpath; // Will throw malformedVarint()
+ }
+ }
+ currentByteBufferPos = tempPos;
+ return x;
+ }
+ return (int) readRawVarint64SlowPath();
+ }
+
+ @Override
+ public long readRawVarint64() throws IOException {
+ fastpath:
+ {
+ long tempPos = currentByteBufferPos;
+
+ if (currentByteBufferLimit == currentByteBufferPos) {
+ break fastpath;
+ }
+
+ long x;
+ int y;
+ if ((y = UnsafeUtil.getByte(tempPos++)) >= 0) {
+ currentByteBufferPos++;
+ return y;
+ } else if (currentByteBufferLimit - currentByteBufferPos < 10) {
+ break fastpath;
+ } else if ((y ^= (UnsafeUtil.getByte(tempPos++) << 7)) < 0) {
+ x = y ^ (~0 << 7);
+ } else if ((y ^= (UnsafeUtil.getByte(tempPos++) << 14)) >= 0) {
+ x = y ^ ((~0 << 7) ^ (~0 << 14));
+ } else if ((y ^= (UnsafeUtil.getByte(tempPos++) << 21)) < 0) {
+ x = y ^ ((~0 << 7) ^ (~0 << 14) ^ (~0 << 21));
+ } else if ((x = y ^ ((long) UnsafeUtil.getByte(tempPos++) << 28)) >= 0L) {
+ x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28);
+ } else if ((x ^= ((long) UnsafeUtil.getByte(tempPos++) << 35)) < 0L) {
+ x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35);
+ } else if ((x ^= ((long) UnsafeUtil.getByte(tempPos++) << 42)) >= 0L) {
+ x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35) ^ (~0L << 42);
+ } else if ((x ^= ((long) UnsafeUtil.getByte(tempPos++) << 49)) < 0L) {
+ x ^=
+ (~0L << 7)
+ ^ (~0L << 14)
+ ^ (~0L << 21)
+ ^ (~0L << 28)
+ ^ (~0L << 35)
+ ^ (~0L << 42)
+ ^ (~0L << 49);
+ } else {
+ x ^= ((long) UnsafeUtil.getByte(tempPos++) << 56);
+ x ^=
+ (~0L << 7)
+ ^ (~0L << 14)
+ ^ (~0L << 21)
+ ^ (~0L << 28)
+ ^ (~0L << 35)
+ ^ (~0L << 42)
+ ^ (~0L << 49)
+ ^ (~0L << 56);
+ if (x < 0L) {
+ if (UnsafeUtil.getByte(tempPos++) < 0L) {
+ break fastpath; // Will throw malformedVarint()
+ }
+ }
+ }
+ currentByteBufferPos = tempPos;
+ return x;
+ }
+ return readRawVarint64SlowPath();
+ }
+
+ @Override
+ long readRawVarint64SlowPath() throws IOException {
+ long result = 0;
+ for (int shift = 0; shift < 64; shift += 7) {
+ final byte b = readRawByte();
+ result |= (long) (b & 0x7F) << shift;
+ if ((b & 0x80) == 0) {
+ return result;
+ }
+ }
+ throw InvalidProtocolBufferException.malformedVarint();
+ }
+
+ @Override
+ public int readRawLittleEndian32() throws IOException {
+ if (currentRemaining() >= FIXED32_SIZE) {
+ long tempPos = currentByteBufferPos;
+ currentByteBufferPos += FIXED32_SIZE;
+ return (((UnsafeUtil.getByte(tempPos) & 0xff))
+ | ((UnsafeUtil.getByte(tempPos + 1) & 0xff) << 8)
+ | ((UnsafeUtil.getByte(tempPos + 2) & 0xff) << 16)
+ | ((UnsafeUtil.getByte(tempPos + 3) & 0xff) << 24));
+ }
+ return ((readRawByte() & 0xff)
+ | ((readRawByte() & 0xff) << 8)
+ | ((readRawByte() & 0xff) << 16)
+ | ((readRawByte() & 0xff) << 24));
+ }
+
+ @Override
+ public long readRawLittleEndian64() throws IOException {
+ if (currentRemaining() >= FIXED64_SIZE) {
+ long tempPos = currentByteBufferPos;
+ currentByteBufferPos += FIXED64_SIZE;
+ return (((UnsafeUtil.getByte(tempPos) & 0xffL))
+ | ((UnsafeUtil.getByte(tempPos + 1) & 0xffL) << 8)
+ | ((UnsafeUtil.getByte(tempPos + 2) & 0xffL) << 16)
+ | ((UnsafeUtil.getByte(tempPos + 3) & 0xffL) << 24)
+ | ((UnsafeUtil.getByte(tempPos + 4) & 0xffL) << 32)
+ | ((UnsafeUtil.getByte(tempPos + 5) & 0xffL) << 40)
+ | ((UnsafeUtil.getByte(tempPos + 6) & 0xffL) << 48)
+ | ((UnsafeUtil.getByte(tempPos + 7) & 0xffL) << 56));
+ }
+ return ((readRawByte() & 0xffL)
+ | ((readRawByte() & 0xffL) << 8)
+ | ((readRawByte() & 0xffL) << 16)
+ | ((readRawByte() & 0xffL) << 24)
+ | ((readRawByte() & 0xffL) << 32)
+ | ((readRawByte() & 0xffL) << 40)
+ | ((readRawByte() & 0xffL) << 48)
+ | ((readRawByte() & 0xffL) << 56));
+ }
+
+ @Override
+ public void enableAliasing(boolean enabled) {
+ this.enableAliasing = enabled;
+ }
+
+ @Override
+ public void resetSizeCounter() {
+ startOffset = (int) (totalBytesRead + currentByteBufferPos - currentByteBufferStartPos);
+ }
+
+ @Override
+ public int pushLimit(int byteLimit) throws InvalidProtocolBufferException {
+ if (byteLimit < 0) {
+ throw InvalidProtocolBufferException.negativeSize();
+ }
+ byteLimit += getTotalBytesRead();
+ final int oldLimit = currentLimit;
+ if (byteLimit > oldLimit) {
+ throw InvalidProtocolBufferException.truncatedMessage();
+ }
+ currentLimit = byteLimit;
+
+ recomputeBufferSizeAfterLimit();
+
+ return oldLimit;
+ }
+
+ private void recomputeBufferSizeAfterLimit() {
+ totalBufferSize += bufferSizeAfterCurrentLimit;
+ final int bufferEnd = totalBufferSize - startOffset;
+ if (bufferEnd > currentLimit) {
+ // Limit is in current buffer.
+ bufferSizeAfterCurrentLimit = bufferEnd - currentLimit;
+ totalBufferSize -= bufferSizeAfterCurrentLimit;
+ } else {
+ bufferSizeAfterCurrentLimit = 0;
+ }
+ }
+
+ @Override
+ public void popLimit(final int oldLimit) {
+ currentLimit = oldLimit;
+ recomputeBufferSizeAfterLimit();
+ }
+
+ @Override
+ public int getBytesUntilLimit() {
+ if (currentLimit == Integer.MAX_VALUE) {
+ return -1;
+ }
+
+ return currentLimit - getTotalBytesRead();
+ }
+
+ @Override
+ public boolean isAtEnd() throws IOException {
+ return totalBytesRead + currentByteBufferPos - currentByteBufferStartPos == totalBufferSize;
+ }
+
+ @Override
+ public int getTotalBytesRead() {
+ return (int)
+ (totalBytesRead - startOffset + currentByteBufferPos - currentByteBufferStartPos);
+ }
+
+ @Override
+ public byte readRawByte() throws IOException {
+ if (currentRemaining() == 0) {
+ getNextByteBuffer();
+ }
+ return UnsafeUtil.getByte(currentByteBufferPos++);
+ }
+
+ @Override
+ public byte[] readRawBytes(final int length) throws IOException {
+ if (length >= 0 && length <= currentRemaining()) {
+ byte[] bytes = new byte[length];
+ UnsafeUtil.copyMemory(currentByteBufferPos, bytes, 0, length);
+ currentByteBufferPos += length;
+ return bytes;
+ }
+ if (length >= 0 && length <= remaining()) {
+ byte[] bytes = new byte[length];
+ readRawBytesTo(bytes, 0, length);
+ return bytes;
+ }
+
+ if (length <= 0) {
+ if (length == 0) {
+ return EMPTY_BYTE_ARRAY;
+ } else {
+ throw InvalidProtocolBufferException.negativeSize();
+ }
+ }
+
+ throw InvalidProtocolBufferException.truncatedMessage();
+ }
+
+ /**
+ * Try to get raw bytes from {@code input} with the size of {@code length} and copy to {@code
+ * bytes} array. If the size is bigger than the number of remaining bytes in the input, then
+ * throw {@code truncatedMessage} exception.
+ *
+ * @param bytes
+ * @param offset
+ * @param length
+ * @throws IOException
+ */
+ private void readRawBytesTo(byte[] bytes, int offset, final int length) throws IOException {
+ if (length >= 0 && length <= remaining()) {
+ int l = length;
+ while (l > 0) {
+ if (currentRemaining() == 0) {
+ getNextByteBuffer();
+ }
+ int bytesToCopy = Math.min(l, (int) currentRemaining());
+ UnsafeUtil.copyMemory(currentByteBufferPos, bytes, length - l + offset, bytesToCopy);
+ l -= bytesToCopy;
+ currentByteBufferPos += bytesToCopy;
+ }
+ return;
+ }
+
+ if (length <= 0) {
+ if (length == 0) {
+ return;
+ } else {
+ throw InvalidProtocolBufferException.negativeSize();
+ }
+ }
+ throw InvalidProtocolBufferException.truncatedMessage();
+ }
+
+ @Override
+ public void skipRawBytes(final int length) throws IOException {
+ if (length >= 0
+ && length
+ <= (totalBufferSize
+ - totalBytesRead
+ - currentByteBufferPos
+ + currentByteBufferStartPos)) {
+ // We have all the bytes we need already.
+ int l = length;
+ while (l > 0) {
+ if (currentRemaining() == 0) {
+ getNextByteBuffer();
+ }
+ int rl = Math.min(l, (int) currentRemaining());
+ l -= rl;
+ currentByteBufferPos += rl;
+ }
+ return;
+ }
+
+ if (length < 0) {
+ throw InvalidProtocolBufferException.negativeSize();
+ }
+ throw InvalidProtocolBufferException.truncatedMessage();
+ }
+
+ // TODO: optimize to fastpath
+ private void skipRawVarint() throws IOException {
+ for (int i = 0; i < MAX_VARINT_SIZE; i++) {
+ if (readRawByte() >= 0) {
+ return;
+ }
+ }
+ throw InvalidProtocolBufferException.malformedVarint();
+ }
+
+ /**
+ * Try to get the number of remaining bytes in {@code input}.
+ *
+ * @return the number of remaining bytes in {@code input}.
+ */
+ private int remaining() {
+ return (int)
+ (totalBufferSize - totalBytesRead - currentByteBufferPos + currentByteBufferStartPos);
+ }
+
+ /**
+ * Try to get the number of remaining bytes in {@code currentByteBuffer}.
+ *
+ * @return the number of remaining bytes in {@code currentByteBuffer}
+ */
+ private long currentRemaining() {
+ return (currentByteBufferLimit - currentByteBufferPos);
+ }
+
+ private ByteBuffer slice(int begin, int end) throws IOException {
+ int prevPos = currentByteBuffer.position();
+ int prevLimit = currentByteBuffer.limit();
+ try {
+ currentByteBuffer.position(begin);
+ currentByteBuffer.limit(end);
+ return currentByteBuffer.slice();
+ } catch (IllegalArgumentException e) {
+ throw InvalidProtocolBufferException.truncatedMessage();
+ } finally {
+ currentByteBuffer.position(prevPos);
+ currentByteBuffer.limit(prevLimit);
+ }
+ }
+ }
}
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 3e32c2c5..7b1ac651 100644
--- a/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
+++ b/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
@@ -30,8 +30,8 @@
package com.google.protobuf;
-import static com.google.protobuf.WireFormat.FIXED_32_SIZE;
-import static com.google.protobuf.WireFormat.FIXED_64_SIZE;
+import static com.google.protobuf.WireFormat.FIXED32_SIZE;
+import static com.google.protobuf.WireFormat.FIXED64_SIZE;
import static com.google.protobuf.WireFormat.MAX_VARINT_SIZE;
import static java.lang.Math.max;
@@ -59,13 +59,12 @@ import java.util.logging.Logger;
public abstract class CodedOutputStream extends ByteOutput {
private static final Logger logger = Logger.getLogger(CodedOutputStream.class.getName());
private static final boolean HAS_UNSAFE_ARRAY_OPERATIONS = UnsafeUtil.hasUnsafeArrayOperations();
- private static final long ARRAY_BASE_OFFSET = UnsafeUtil.getArrayBaseOffset();
/**
* @deprecated Use {@link #computeFixed32SizeNoTag(int)} instead.
*/
@Deprecated
- public static final int LITTLE_ENDIAN_32_SIZE = FIXED_32_SIZE;
+ public static final int LITTLE_ENDIAN_32_SIZE = FIXED32_SIZE;
/**
* The buffer size used in {@link #newInstance(OutputStream)}.
@@ -184,7 +183,7 @@ public abstract class CodedOutputStream extends ByteOutput {
* maps are sorted on the lexicographical order of the UTF8 encoded keys.
* </ul>
*/
- void useDeterministicSerialization() {
+ public void useDeterministicSerialization() {
serializationDeterministic = true;
}
@@ -378,6 +377,7 @@ public abstract class CodedOutputStream extends ByteOutput {
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.
@@ -482,6 +482,7 @@ public abstract class CodedOutputStream extends ByteOutput {
// Abstract to avoid overhead of additional virtual method calls.
public abstract void writeMessageNoTag(final MessageLite value) throws IOException;
+
//=================================================================
@ExperimentalApi
@@ -667,6 +668,7 @@ public abstract class CodedOutputStream extends ByteOutput {
return computeTagSize(fieldNumber) + computeMessageSizeNoTag(value);
}
+
/**
* Compute the number of bytes that would be needed to encode a
* MessageSet extension to the stream. For historical reasons,
@@ -755,7 +757,7 @@ public abstract class CodedOutputStream extends ByteOutput {
* {@code fixed32} field.
*/
public static int computeFixed32SizeNoTag(@SuppressWarnings("unused") final int unused) {
- return FIXED_32_SIZE;
+ return FIXED32_SIZE;
}
/**
@@ -763,7 +765,7 @@ public abstract class CodedOutputStream extends ByteOutput {
* {@code sfixed32} field.
*/
public static int computeSFixed32SizeNoTag(@SuppressWarnings("unused") final int unused) {
- return FIXED_32_SIZE;
+ return FIXED32_SIZE;
}
/**
@@ -813,7 +815,7 @@ public abstract class CodedOutputStream extends ByteOutput {
* {@code fixed64} field.
*/
public static int computeFixed64SizeNoTag(@SuppressWarnings("unused") final long unused) {
- return FIXED_64_SIZE;
+ return FIXED64_SIZE;
}
/**
@@ -821,7 +823,7 @@ public abstract class CodedOutputStream extends ByteOutput {
* {@code sfixed64} field.
*/
public static int computeSFixed64SizeNoTag(@SuppressWarnings("unused") final long unused) {
- return FIXED_64_SIZE;
+ return FIXED64_SIZE;
}
/**
@@ -829,7 +831,7 @@ public abstract class CodedOutputStream extends ByteOutput {
* {@code float} field, including tag.
*/
public static int computeFloatSizeNoTag(@SuppressWarnings("unused") final float unused) {
- return FIXED_32_SIZE;
+ return FIXED32_SIZE;
}
/**
@@ -837,7 +839,7 @@ public abstract class CodedOutputStream extends ByteOutput {
* {@code double} field, including tag.
*/
public static int computeDoubleSizeNoTag(@SuppressWarnings("unused") final double unused) {
- return FIXED_64_SIZE;
+ return FIXED64_SIZE;
}
/**
@@ -914,6 +916,7 @@ public abstract class CodedOutputStream extends ByteOutput {
return computeLengthDelimitedFieldSize(value.getSerializedSize());
}
+
static int computeLengthDelimitedFieldSize(int fieldLength) {
return computeUInt32SizeNoTag(fieldLength) + fieldLength;
}
@@ -1050,6 +1053,7 @@ public abstract class CodedOutputStream extends ByteOutput {
writeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP);
}
+
/**
* Write a {@code group} field to the stream.
*
@@ -1060,6 +1064,7 @@ public abstract class CodedOutputStream extends ByteOutput {
value.writeTo(this);
}
+
/**
* Compute the number of bytes that would be needed to encode a
* {@code group} field, including tag.
@@ -1071,6 +1076,7 @@ public abstract class CodedOutputStream extends ByteOutput {
return computeTagSize(fieldNumber) * 2 + computeGroupSizeNoTag(value);
}
+
/**
* Compute the number of bytes that would be needed to encode a
* {@code group} field.
@@ -1080,6 +1086,7 @@ public abstract class CodedOutputStream extends ByteOutput {
return value.getSerializedSize();
}
+
/**
* Encode and write a varint. {@code value} is treated as
* unsigned, so it won't be sign-extended if negative.
@@ -1274,6 +1281,7 @@ public abstract class CodedOutputStream extends ByteOutput {
writeMessageNoTag(value);
}
+
@Override
public final void writeMessageSetExtension(final int fieldNumber, final MessageLite value)
throws IOException {
@@ -1298,6 +1306,7 @@ public abstract class CodedOutputStream extends ByteOutput {
value.writeTo(this);
}
+
@Override
public final void write(byte value) throws IOException {
try {
@@ -1321,15 +1330,12 @@ public abstract class CodedOutputStream extends ByteOutput {
@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) {
- UnsafeUtil.putByte(buffer, pos++, (byte) value);
- position++;
+ UnsafeUtil.putByte(buffer, position++, (byte) value);
return;
} else {
- UnsafeUtil.putByte(buffer, pos++, (byte) ((value & 0x7F) | 0x80));
- position++;
+ UnsafeUtil.putByte(buffer, position++, (byte) ((value & 0x7F) | 0x80));
value >>>= 7;
}
}
@@ -1367,15 +1373,12 @@ public abstract class CodedOutputStream extends ByteOutput {
@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) {
- UnsafeUtil.putByte(buffer, pos++, (byte) value);
- position++;
+ UnsafeUtil.putByte(buffer, position++, (byte) value);
return;
} else {
- UnsafeUtil.putByte(buffer, pos++, (byte) (((int) value & 0x7F) | 0x80));
- position++;
+ UnsafeUtil.putByte(buffer, position++, (byte) (((int) value & 0x7F) | 0x80));
value >>>= 7;
}
}
@@ -1615,6 +1618,7 @@ public abstract class CodedOutputStream extends ByteOutput {
writeMessageNoTag(value);
}
+
@Override
public void writeMessageSetExtension(final int fieldNumber, final MessageLite value)
throws IOException {
@@ -1639,6 +1643,7 @@ public abstract class CodedOutputStream extends ByteOutput {
value.writeTo(this);
}
+
@Override
public void write(byte value) throws IOException {
try {
@@ -1935,6 +1940,7 @@ public abstract class CodedOutputStream extends ByteOutput {
writeMessageNoTag(value);
}
+
@Override
public void writeMessageSetExtension(int fieldNumber, MessageLite value) throws IOException {
writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
@@ -1957,6 +1963,7 @@ public abstract class CodedOutputStream extends ByteOutput {
value.writeTo(this);
}
+
@Override
public void write(byte value) throws IOException {
if (position >= limit) {
@@ -2030,7 +2037,7 @@ public abstract class CodedOutputStream extends ByteOutput {
@Override
public void writeFixed32NoTag(int value) throws IOException {
buffer.putInt(bufferPos(position), value);
- position += FIXED_32_SIZE;
+ position += FIXED32_SIZE;
}
@Override
@@ -2064,7 +2071,7 @@ public abstract class CodedOutputStream extends ByteOutput {
@Override
public void writeFixed64NoTag(long value) throws IOException {
buffer.putLong(bufferPos(position), value);
- position += FIXED_64_SIZE;
+ position += FIXED64_SIZE;
}
@Override
@@ -2081,8 +2088,7 @@ public abstract class CodedOutputStream extends ByteOutput {
String.format("Pos: %d, limit: %d, len: %d", position, limit, length));
}
- UnsafeUtil.copyMemory(
- value, UnsafeUtil.getArrayBaseOffset() + offset, null, position, length);
+ UnsafeUtil.copyMemory(value, offset, position, length);
position += length;
}
@@ -2249,19 +2255,17 @@ public abstract class CodedOutputStream extends ByteOutput {
*/
final void bufferUInt32NoTag(int value) {
if (HAS_UNSAFE_ARRAY_OPERATIONS) {
- final long originalPos = ARRAY_BASE_OFFSET + position;
- long pos = originalPos;
+ final long originalPos = position;
while (true) {
if ((value & ~0x7F) == 0) {
- UnsafeUtil.putByte(buffer, pos++, (byte) value);
+ UnsafeUtil.putByte(buffer, position++, (byte) value);
break;
} else {
- UnsafeUtil.putByte(buffer, pos++, (byte) ((value & 0x7F) | 0x80));
+ UnsafeUtil.putByte(buffer, position++, (byte) ((value & 0x7F) | 0x80));
value >>>= 7;
}
}
- int delta = (int) (pos - originalPos);
- position += delta;
+ int delta = (int) (position - originalPos);
totalBytesWritten += delta;
} else {
while (true) {
@@ -2284,19 +2288,17 @@ public abstract class CodedOutputStream extends ByteOutput {
*/
final void bufferUInt64NoTag(long value) {
if (HAS_UNSAFE_ARRAY_OPERATIONS) {
- final long originalPos = ARRAY_BASE_OFFSET + position;
- long pos = originalPos;
+ final long originalPos = position;
while (true) {
if ((value & ~0x7FL) == 0) {
- UnsafeUtil.putByte(buffer, pos++, (byte) value);
+ UnsafeUtil.putByte(buffer, position++, (byte) value);
break;
} else {
- UnsafeUtil.putByte(buffer, pos++, (byte) (((int) value & 0x7F) | 0x80));
+ UnsafeUtil.putByte(buffer, position++, (byte) (((int) value & 0x7F) | 0x80));
value >>>= 7;
}
}
- int delta = (int) (pos - originalPos);
- position += delta;
+ int delta = (int) (position - originalPos);
totalBytesWritten += delta;
} else {
while (true) {
@@ -2322,7 +2324,7 @@ public abstract class CodedOutputStream extends ByteOutput {
buffer[position++] = (byte) ((value >> 8) & 0xFF);
buffer[position++] = (byte) ((value >> 16) & 0xFF);
buffer[position++] = (byte) ((value >> 24) & 0xFF);
- totalBytesWritten += FIXED_32_SIZE;
+ totalBytesWritten += FIXED32_SIZE;
}
/**
@@ -2338,7 +2340,7 @@ public abstract class CodedOutputStream extends ByteOutput {
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;
+ totalBytesWritten += FIXED64_SIZE;
}
}
@@ -2379,7 +2381,7 @@ public abstract class CodedOutputStream extends ByteOutput {
@Override
public void writeFixed32(final int fieldNumber, final int value) throws IOException {
- flushIfNotAvailable(MAX_VARINT_SIZE + FIXED_32_SIZE);
+ flushIfNotAvailable(MAX_VARINT_SIZE + FIXED32_SIZE);
bufferTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
bufferFixed32NoTag(value);
}
@@ -2393,7 +2395,7 @@ public abstract class CodedOutputStream extends ByteOutput {
@Override
public void writeFixed64(final int fieldNumber, final long value) throws IOException {
- flushIfNotAvailable(MAX_VARINT_SIZE + FIXED_64_SIZE);
+ flushIfNotAvailable(MAX_VARINT_SIZE + FIXED64_SIZE);
bufferTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
bufferFixed64NoTag(value);
}
@@ -2468,6 +2470,7 @@ public abstract class CodedOutputStream extends ByteOutput {
writeMessageNoTag(value);
}
+
@Override
public void writeMessageSetExtension(final int fieldNumber, final MessageLite value)
throws IOException {
@@ -2492,6 +2495,7 @@ public abstract class CodedOutputStream extends ByteOutput {
value.writeTo(this);
}
+
@Override
public void write(byte value) throws IOException {
if (position == limit) {
@@ -2519,7 +2523,7 @@ public abstract class CodedOutputStream extends ByteOutput {
@Override
public void writeFixed32NoTag(final int value) throws IOException {
- flushIfNotAvailable(FIXED_32_SIZE);
+ flushIfNotAvailable(FIXED32_SIZE);
bufferFixed32NoTag(value);
}
@@ -2531,7 +2535,7 @@ public abstract class CodedOutputStream extends ByteOutput {
@Override
public void writeFixed64NoTag(final long value) throws IOException {
- flushIfNotAvailable(FIXED_64_SIZE);
+ flushIfNotAvailable(FIXED64_SIZE);
bufferFixed64NoTag(value);
}
@@ -2682,7 +2686,7 @@ public abstract class CodedOutputStream extends ByteOutput {
@Override
public void writeFixed32(final int fieldNumber, final int value) throws IOException {
- flushIfNotAvailable(MAX_VARINT_SIZE + FIXED_32_SIZE);
+ flushIfNotAvailable(MAX_VARINT_SIZE + FIXED32_SIZE);
bufferTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
bufferFixed32NoTag(value);
}
@@ -2696,7 +2700,7 @@ public abstract class CodedOutputStream extends ByteOutput {
@Override
public void writeFixed64(final int fieldNumber, final long value) throws IOException {
- flushIfNotAvailable(MAX_VARINT_SIZE + FIXED_64_SIZE);
+ flushIfNotAvailable(MAX_VARINT_SIZE + FIXED64_SIZE);
bufferTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
bufferFixed64NoTag(value);
}
@@ -2771,6 +2775,7 @@ public abstract class CodedOutputStream extends ByteOutput {
writeMessageNoTag(value);
}
+
@Override
public void writeMessageSetExtension(final int fieldNumber, final MessageLite value)
throws IOException {
@@ -2795,6 +2800,7 @@ public abstract class CodedOutputStream extends ByteOutput {
value.writeTo(this);
}
+
@Override
public void write(byte value) throws IOException {
if (position == limit) {
@@ -2822,7 +2828,7 @@ public abstract class CodedOutputStream extends ByteOutput {
@Override
public void writeFixed32NoTag(final int value) throws IOException {
- flushIfNotAvailable(FIXED_32_SIZE);
+ flushIfNotAvailable(FIXED32_SIZE);
bufferFixed32NoTag(value);
}
@@ -2834,7 +2840,7 @@ public abstract class CodedOutputStream extends ByteOutput {
@Override
public void writeFixed64NoTag(final long value) throws IOException {
- flushIfNotAvailable(FIXED_64_SIZE);
+ flushIfNotAvailable(FIXED64_SIZE);
bufferFixed64NoTag(value);
}
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 38346f15..75b16fe3 100644
--- a/java/core/src/main/java/com/google/protobuf/Descriptors.java
+++ b/java/core/src/main/java/com/google/protobuf/Descriptors.java
@@ -30,9 +30,10 @@
package com.google.protobuf;
+import static com.google.protobuf.Internal.checkNotNull;
+
import com.google.protobuf.DescriptorProtos.*;
import com.google.protobuf.Descriptors.FileDescriptor.Syntax;
-
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
@@ -682,9 +683,7 @@ public final class Descriptors {
/** Determines if the given field name is reserved. */
public boolean isReservedName(final String name) {
- if (name == null) {
- throw new NullPointerException();
- }
+ checkNotNull(name);
for (final String reservedName : proto.getReservedNameList()) {
if (reservedName.equals(name)) {
return true;
diff --git a/java/core/src/main/java/com/google/protobuf/DiscardUnknownFieldsParser.java b/java/core/src/main/java/com/google/protobuf/DiscardUnknownFieldsParser.java
new file mode 100644
index 00000000..7ae94349
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/DiscardUnknownFieldsParser.java
@@ -0,0 +1,71 @@
+// 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;
+
+/**
+ * Parsers to discard unknown fields during parsing.
+ */
+public final class DiscardUnknownFieldsParser {
+
+ /**
+ * Warps a given {@link Parser} into a new {@link Parser} that discards unknown fields during
+ * parsing.
+ *
+ * <p>Usage example:
+ * <pre>{@code
+ * private final static Parser<Foo> FOO_PARSER = DiscardUnknownFieldsParser.wrap(Foo.parser());
+ * Foo parseFooDiscardUnknown(ByteBuffer input) throws IOException {
+ * return FOO_PARSER.parseFrom(input);
+ * }
+ * }</pre>
+ *
+ * <p>Like all other implementations of {@code Parser}, this parser is stateless and thread-safe.
+ *
+ * @param parser The delegated parser that parses messages.
+ * @return a {@link Parser} that will discard unknown fields during parsing.
+ */
+ public static final <T extends Message> Parser<T> wrap(final Parser<T> parser) {
+ return new AbstractParser<T>() {
+ @Override
+ public T parsePartialFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
+ try {
+ input.discardUnknownFields();
+ return parser.parsePartialFrom(input, extensionRegistry);
+ } finally {
+ input.unsetDiscardUnknownFields();
+ }
+ }
+ };
+ }
+
+ private DiscardUnknownFieldsParser() {}
+}
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 6177f3ca..5b28b4a8 100644
--- a/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java
@@ -30,8 +30,9 @@
package com.google.protobuf;
-import com.google.protobuf.Internal.DoubleList;
+import static com.google.protobuf.Internal.checkNotNull;
+import com.google.protobuf.Internal.DoubleList;
import java.util.Arrays;
import java.util.Collection;
import java.util.RandomAccess;
@@ -41,9 +42,8 @@ import java.util.RandomAccess;
*
* @author dweis@google.com (Daniel Weis)
*/
-final class DoubleArrayList
- extends AbstractProtobufList<Double>
- implements DoubleList, RandomAccess {
+final class DoubleArrayList extends AbstractProtobufList<Double>
+ implements DoubleList, RandomAccess, PrimitiveNonBoxingCollection {
private static final DoubleArrayList EMPTY_LIST = new DoubleArrayList();
static {
@@ -82,6 +82,18 @@ final class DoubleArrayList
}
@Override
+ protected void removeRange(int fromIndex, int toIndex) {
+ ensureIsMutable();
+ if (toIndex < fromIndex) {
+ throw new IndexOutOfBoundsException("toIndex < fromIndex");
+ }
+
+ System.arraycopy(array, toIndex, array, fromIndex, size - toIndex);
+ size -= (toIndex - fromIndex);
+ modCount++;
+ }
+
+ @Override
public boolean equals(Object o) {
if (this == o) {
return true;
@@ -199,9 +211,7 @@ final class DoubleArrayList
public boolean addAll(Collection<? extends Double> collection) {
ensureIsMutable();
- if (collection == null) {
- throw new NullPointerException();
- }
+ checkNotNull(collection);
// We specialize when adding another DoubleArrayList to avoid boxing elements.
if (!(collection instanceof DoubleArrayList)) {
@@ -249,7 +259,9 @@ final class DoubleArrayList
ensureIsMutable();
ensureIndexInRange(index);
double value = array[index];
- System.arraycopy(array, index + 1, array, index, size - index);
+ if (index < size - 1) {
+ System.arraycopy(array, index + 1, array, index, size - index);
+ }
size--;
modCount++;
return value;
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 e6358c3b..a6a774b7 100644
--- a/java/core/src/main/java/com/google/protobuf/DynamicMessage.java
+++ b/java/core/src/main/java/com/google/protobuf/DynamicMessage.java
@@ -30,11 +30,12 @@
package com.google.protobuf;
+import static com.google.protobuf.Internal.checkNotNull;
+
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.EnumValueDescriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.Descriptors.OneofDescriptor;
-
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
@@ -338,6 +339,20 @@ public final class DynamicMessage extends AbstractMessage {
this.fields = FieldSet.newFieldSet();
this.unknownFields = UnknownFieldSet.getDefaultInstance();
this.oneofCases = new FieldDescriptor[type.toProto().getOneofDeclCount()];
+ // A MapEntry has all of its fields present at all times.
+ if (type.getOptions().getMapEntry()) {
+ populateMapEntry();
+ }
+ }
+
+ private void populateMapEntry() {
+ for (FieldDescriptor field : type.getFields()) {
+ if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+ fields.setField(field, getDefaultInstance(field.getMessageType()));
+ } else {
+ fields.setField(field, field.getDefaultValue());
+ }
+ }
}
// ---------------------------------------------------------------
@@ -350,6 +365,10 @@ public final class DynamicMessage extends AbstractMessage {
} else {
fields.clear();
}
+ // A MapEntry has all of its fields present at all times.
+ if (type.getOptions().getMapEntry()) {
+ populateMapEntry();
+ }
unknownFields = UnknownFieldSet.getDefaultInstance();
return this;
}
@@ -589,9 +608,8 @@ public final class DynamicMessage extends AbstractMessage {
@Override
public Builder setUnknownFields(UnknownFieldSet unknownFields) {
- if (getDescriptorForType().getFile().getSyntax()
- == Descriptors.FileDescriptor.Syntax.PROTO3) {
- // Proto3 discards unknown fields.
+ if (getDescriptorForType().getFile().getSyntax() == Descriptors.FileDescriptor.Syntax.PROTO3
+ && CodedInputStream.getProto3DiscardUnknownFieldsDefault()) {
return this;
}
this.unknownFields = unknownFields;
@@ -600,9 +618,8 @@ public final class DynamicMessage extends AbstractMessage {
@Override
public Builder mergeUnknownFields(UnknownFieldSet unknownFields) {
- if (getDescriptorForType().getFile().getSyntax()
- == Descriptors.FileDescriptor.Syntax.PROTO3) {
- // Proto3 discards unknown fields.
+ if (getDescriptorForType().getFile().getSyntax() == Descriptors.FileDescriptor.Syntax.PROTO3
+ && CodedInputStream.getProto3DiscardUnknownFieldsDefault()) {
return this;
}
this.unknownFields =
@@ -631,9 +648,7 @@ public final class DynamicMessage extends AbstractMessage {
/** Verifies that the value is EnumValueDescriptor and matches Enum Type. */
private void ensureSingularEnumValueDescriptor(
FieldDescriptor field, Object value) {
- if (value == null) {
- throw new NullPointerException();
- }
+ checkNotNull(value);
if (!(value instanceof EnumValueDescriptor)) {
throw new IllegalArgumentException(
"DynamicMessage should use EnumValueDescriptor to set Enum Value.");
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 08ec5b45..5df12e64 100644
--- a/java/core/src/main/java/com/google/protobuf/Extension.java
+++ b/java/core/src/main/java/com/google/protobuf/Extension.java
@@ -58,10 +58,7 @@ public abstract class Extension<ContainingType extends MessageLite, Type>
PROTO1,
}
- protected ExtensionType getExtensionType() {
- // TODO(liujisi): make this abstract after we fix proto1.
- return ExtensionType.IMMUTABLE;
- }
+ protected abstract ExtensionType getExtensionType();
/**
* Type of a message extension.
@@ -70,7 +67,7 @@ public abstract class Extension<ContainingType extends MessageLite, Type>
PROTO1,
PROTO2,
}
-
+
/**
* If the extension is a message extension (i.e., getLiteType() == MESSAGE),
* returns the type of the message, otherwise undefined.
diff --git a/java/core/src/main/java/com/google/protobuf/ExtensionRegistryFactory.java b/java/core/src/main/java/com/google/protobuf/ExtensionRegistryFactory.java
index 23174e24..89f7ab9b 100644
--- a/java/core/src/main/java/com/google/protobuf/ExtensionRegistryFactory.java
+++ b/java/core/src/main/java/com/google/protobuf/ExtensionRegistryFactory.java
@@ -34,7 +34,7 @@ import static com.google.protobuf.ExtensionRegistryLite.EMPTY_REGISTRY_LITE;
/**
* A factory object to create instances of {@link ExtensionRegistryLite}.
- *
+ *
* <p>
* This factory detects (via reflection) if the full (non-Lite) protocol buffer libraries
* are available, and if so, the instances returned are actually {@link ExtensionRegistry}.
@@ -82,6 +82,7 @@ final class ExtensionRegistryFactory {
return EMPTY_REGISTRY_LITE;
}
+
static boolean isFullRegistry(ExtensionRegistryLite registry) {
return EXTENSION_REGISTRY_CLASS != null
&& EXTENSION_REGISTRY_CLASS.isAssignableFrom(registry.getClass());
@@ -90,6 +91,6 @@ final class ExtensionRegistryFactory {
private static final ExtensionRegistryLite invokeSubclassFactory(String methodName)
throws Exception {
return (ExtensionRegistryLite) EXTENSION_REGISTRY_CLASS
- .getMethod(methodName).invoke(null);
+ .getDeclaredMethod(methodName).invoke(null);
}
}
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 a828f30e..c09daa32 100644
--- a/java/core/src/main/java/com/google/protobuf/FieldSet.java
+++ b/java/core/src/main/java/com/google/protobuf/FieldSet.java
@@ -30,8 +30,9 @@
package com.google.protobuf;
-import com.google.protobuf.LazyField.LazyIterator;
+import static com.google.protobuf.Internal.checkNotNull;
+import com.google.protobuf.LazyField.LazyIterator;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
@@ -101,6 +102,11 @@ final class FieldSet<FieldDescriptorType extends
@SuppressWarnings("rawtypes")
private static final FieldSet DEFAULT_INSTANCE = new FieldSet(true);
+ /** Returns {@code true} if empty, {@code false} otherwise. */
+ boolean isEmpty() {
+ return fields.isEmpty();
+ }
+
/** Make this FieldSet immutable from this point forward. */
@SuppressWarnings("unchecked")
public void makeImmutable() {
@@ -385,9 +391,7 @@ final class FieldSet<FieldDescriptorType extends
*/
private static void verifyType(final WireFormat.FieldType type,
final Object value) {
- if (value == null) {
- throw new NullPointerException();
- }
+ checkNotNull(value);
boolean isValid = false;
switch (type.getJavaType()) {
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 90d6154b..7c080af3 100644
--- a/java/core/src/main/java/com/google/protobuf/FloatArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/FloatArrayList.java
@@ -30,8 +30,9 @@
package com.google.protobuf;
-import com.google.protobuf.Internal.FloatList;
+import static com.google.protobuf.Internal.checkNotNull;
+import com.google.protobuf.Internal.FloatList;
import java.util.Arrays;
import java.util.Collection;
import java.util.RandomAccess;
@@ -41,9 +42,8 @@ import java.util.RandomAccess;
*
* @author dweis@google.com (Daniel Weis)
*/
-final class FloatArrayList
- extends AbstractProtobufList<Float>
- implements FloatList, RandomAccess {
+final class FloatArrayList extends AbstractProtobufList<Float>
+ implements FloatList, RandomAccess, PrimitiveNonBoxingCollection {
private static final FloatArrayList EMPTY_LIST = new FloatArrayList();
static {
@@ -82,6 +82,18 @@ final class FloatArrayList
}
@Override
+ protected void removeRange(int fromIndex, int toIndex) {
+ ensureIsMutable();
+ if (toIndex < fromIndex) {
+ throw new IndexOutOfBoundsException("toIndex < fromIndex");
+ }
+
+ System.arraycopy(array, toIndex, array, fromIndex, size - toIndex);
+ size -= (toIndex - fromIndex);
+ modCount++;
+ }
+
+ @Override
public boolean equals(Object o) {
if (this == o) {
return true;
@@ -198,9 +210,7 @@ final class FloatArrayList
public boolean addAll(Collection<? extends Float> collection) {
ensureIsMutable();
- if (collection == null) {
- throw new NullPointerException();
- }
+ checkNotNull(collection);
// We specialize when adding another FloatArrayList to avoid boxing elements.
if (!(collection instanceof FloatArrayList)) {
@@ -248,7 +258,9 @@ final class FloatArrayList
ensureIsMutable();
ensureIndexInRange(index);
float value = array[index];
- System.arraycopy(array, index + 1, array, index, size - index);
+ if (index < size - 1) {
+ System.arraycopy(array, index + 1, array, index, size - index);
+ }
size--;
modCount++;
return value;
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 cea05794..60179e37 100644
--- a/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java
+++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java
@@ -854,6 +854,7 @@ public abstract class GeneratedMessage extends AbstractMessage
/** Check if a singular extension is present. */
@Override
+ @SuppressWarnings("unchecked")
public final <Type> boolean hasExtension(final ExtensionLite<MessageType, Type> extensionLite) {
Extension<MessageType, Type> extension = checkNotLite(extensionLite);
@@ -863,6 +864,7 @@ public abstract class GeneratedMessage extends AbstractMessage
/** Get the number of elements in a repeated extension. */
@Override
+ @SuppressWarnings("unchecked")
public final <Type> int getExtensionCount(
final ExtensionLite<MessageType, List<Type>> extensionLite) {
Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
@@ -2555,6 +2557,7 @@ public abstract class GeneratedMessage extends AbstractMessage
}
@Override
+ @SuppressWarnings("unchecked")
public Object get(GeneratedMessage message) {
List result = new ArrayList();
for (int i = 0; i < getRepeatedCount(message); i++) {
@@ -2564,6 +2567,7 @@ public abstract class GeneratedMessage extends AbstractMessage
}
@Override
+ @SuppressWarnings("unchecked")
public Object get(Builder builder) {
List result = new ArrayList();
for (int i = 0; i < getRepeatedCount(builder); i++) {
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 f885b01e..df01547e 100644
--- a/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
+++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
@@ -31,9 +31,9 @@
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.EnumLiteMap;
import com.google.protobuf.Internal.FloatList;
import com.google.protobuf.Internal.IntList;
import com.google.protobuf.Internal.LongList;
@@ -45,11 +45,13 @@ import java.io.ObjectStreamException;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
/**
* Lite version of {@link GeneratedMessage}.
@@ -60,6 +62,12 @@ public abstract class GeneratedMessageLite<
MessageType extends GeneratedMessageLite<MessageType, BuilderType>,
BuilderType extends GeneratedMessageLite.Builder<MessageType, BuilderType>>
extends AbstractMessageLite<MessageType, BuilderType> {
+ // BEGIN REGULAR
+ static final boolean ENABLE_EXPERIMENTAL_RUNTIME_AT_BUILD_TIME = false;
+ // END REGULAR
+ // BEGIN EXPERIMENTAL
+ // static final boolean ENABLE_EXPERIMENTAL_RUNTIME_AT_BUILD_TIME = true;
+ // END EXPERIMENTAL
/** For use by generated code only. Lazily initialized to reduce allocations. */
protected UnknownFieldSetLite unknownFields = UnknownFieldSetLite.getDefaultInstance();
@@ -105,14 +113,22 @@ public abstract class GeneratedMessageLite<
@SuppressWarnings("unchecked") // Guaranteed by runtime
@Override
public int hashCode() {
- if (memoizedHashCode == 0) {
- HashCodeVisitor visitor = new HashCodeVisitor();
- visit(visitor, (MessageType) this);
- memoizedHashCode = visitor.hashCode;
- }
+ if (memoizedHashCode != 0) {
+ return memoizedHashCode;
+ }
+ // BEGIN EXPERIMENTAL
+ // memoizedHashCode = Protobuf.getInstance().schemaFor(this).hashCode(this);
+ // return memoizedHashCode;
+ // END EXPERIMENTAL
+ // BEGIN REGULAR
+ HashCodeVisitor visitor = new HashCodeVisitor();
+ visit(visitor, (MessageType) this);
+ memoizedHashCode = visitor.hashCode;
return memoizedHashCode;
+ // END REGULAR
}
+ // BEGIN REGULAR
@SuppressWarnings("unchecked") // Guaranteed by runtime
int hashCode(HashCodeVisitor visitor) {
if (memoizedHashCode == 0) {
@@ -124,6 +140,7 @@ public abstract class GeneratedMessageLite<
}
return memoizedHashCode;
}
+ // END REGULAR
@SuppressWarnings("unchecked") // Guaranteed by isInstance + runtime
@Override
@@ -136,17 +153,22 @@ public abstract class GeneratedMessageLite<
return false;
}
+ // BEGIN EXPERIMENTAL
+ // return Protobuf.getInstance().schemaFor(this).equals(this, (MessageType) other);
+ // END EXPERIMENTAL
+ // BEGIN REGULAR
+
try {
visit(EqualsVisitor.INSTANCE, (MessageType) other);
- } catch (NotEqualsException e) {
+ } catch (EqualsVisitor.NotEqualsException e) {
return false;
}
return true;
+ // END REGULAR
}
- /**
- * Same as {@link #equals(Object)} but throws {@code NotEqualsException}.
- */
+ // BEGIN REGULAR
+ /** Same as {@link #equals(Object)} but throws {@code NotEqualsException}. */
@SuppressWarnings("unchecked") // Guaranteed by isInstance + runtime
boolean equals(EqualsVisitor visitor, MessageLite other) {
if (this == other) {
@@ -160,14 +182,13 @@ public abstract class GeneratedMessageLite<
visit(visitor, (MessageType) other);
return true;
}
+ // END REGULAR
// The general strategy for unknown fields is to use an UnknownFieldSetLite that is treated as
// mutable during the parsing constructor and immutable after. This allows us to avoid
// any unnecessary intermediary allocations while reducing the generated code size.
- /**
- * Lazily initializes unknown fields.
- */
+ /** Lazily initializes unknown fields. */
private final void ensureUnknownFieldsInitialized() {
if (unknownFields == UnknownFieldSetLite.getDefaultInstance()) {
unknownFields = UnknownFieldSetLite.newInstance();
@@ -209,17 +230,36 @@ public abstract class GeneratedMessageLite<
* Called by subclasses to complete parsing. For use by generated code only.
*/
protected void makeImmutable() {
+ // BEGIN REGULAR
dynamicMethod(MethodToInvoke.MAKE_IMMUTABLE);
-
unknownFields.makeImmutable();
+ // END REGULAR
+ // BEGIN EXPERIMENTAL
+ // Protobuf.getInstance().schemaFor(this).makeImmutable(this);
+ // END EXPERIMENTAL
+ }
+
+ protected final <
+ MessageType extends GeneratedMessageLite<MessageType, BuilderType>,
+ BuilderType extends GeneratedMessageLite.Builder<MessageType, BuilderType>>
+ BuilderType createBuilder() {
+ return (BuilderType) dynamicMethod(MethodToInvoke.NEW_BUILDER);
+ }
+
+ protected final <
+ MessageType extends GeneratedMessageLite<MessageType, BuilderType>,
+ BuilderType extends GeneratedMessageLite.Builder<MessageType, BuilderType>>
+ BuilderType createBuilder(MessageType prototype) {
+ return ((BuilderType) createBuilder()).mergeFrom(prototype);
}
@Override
public final boolean isInitialized() {
- return dynamicMethod(MethodToInvoke.IS_INITIALIZED, Boolean.TRUE) != null;
+ return isInitialized((MessageType) this, Boolean.TRUE);
}
@Override
+ @SuppressWarnings("unchecked")
public final BuilderType toBuilder() {
BuilderType builder = (BuilderType) dynamicMethod(MethodToInvoke.NEW_BUILDER);
builder.mergeFrom((MessageType) this);
@@ -233,11 +273,15 @@ public abstract class GeneratedMessageLite<
* For use by generated code only.
*/
public static enum MethodToInvoke {
- // Rely on/modify instance state
+ // BEGIN REGULAR
IS_INITIALIZED,
VISIT,
MERGE_FROM_STREAM,
MAKE_IMMUTABLE,
+ // END REGULAR
+ // Rely on/modify instance state
+ GET_MEMOIZED_IS_INITIALIZED,
+ SET_MEMOIZED_IS_INITIALIZED,
// Rely on static state
NEW_MUTABLE_INSTANCE,
@@ -251,25 +295,30 @@ public abstract class GeneratedMessageLite<
* Theses different kinds of operations are required to implement message-level operations for
* builders in the runtime. This method bundles those operations to reduce the generated methods
* count.
+ *
* <ul>
- * <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 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 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.
+ * <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 that has not yet been
+ * made immutable. See {@code MAKE_IMMUTABLE}.
+ * <li>{@code IS_INITIALIZED} returns {@code null} for false and the default instance for true.
+ * It doesn't use or modify any memoized value.
+ * <li>{@code GET_MEMOIZED_IS_INITIALIZED} returns the memoized {@code isInitialized} byte
+ * value.
+ * <li>{@code SET_MEMOIZED_IS_INITIALIZED} sets the memoized {@code isInitilaized} byte value to
+ * 1 if the first parameter is not null, or to 0 if the first parameter is null.
+ * <li>{@code NEW_BUILDER} returns a {@code BuilderType} 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
* away entirely on Android.
- * <p>
- * For use by generated code only.
+ *
+ * <p>For use by generated code only.
*/
protected abstract Object dynamicMethod(MethodToInvoke method, Object arg0, Object arg1);
@@ -287,14 +336,27 @@ public abstract class GeneratedMessageLite<
return dynamicMethod(method, null, null);
}
+ // BEGIN REGULAR
void visit(Visitor visitor, MessageType other) {
dynamicMethod(MethodToInvoke.VISIT, visitor, other);
unknownFields = visitor.visitUnknownFields(unknownFields, other.unknownFields);
}
+ // END REGULAR
+
+ @Override
+ int getMemoizedSerializedSize() {
+ return memoizedSerializedSize;
+ }
+
+ @Override
+ void setMemoizedSerializedSize(int size) {
+ memoizedSerializedSize = size;
+ }
+
+
/**
- * Merge some unknown fields into the {@link UnknownFieldSetLite} for this
- * message.
+ * Merge some unknown fields into the {@link UnknownFieldSetLite} for this message.
*
* <p>For use by generated code only.
*/
@@ -327,7 +389,7 @@ public abstract class GeneratedMessageLite<
if (isBuilt) {
MessageType newInstance =
(MessageType) instance.dynamicMethod(MethodToInvoke.NEW_MUTABLE_INSTANCE);
- newInstance.visit(MergeFromVisitor.INSTANCE, instance);
+ mergeFromInstance(newInstance, instance);
instance = newInstance;
isBuilt = false;
}
@@ -382,23 +444,60 @@ public abstract class GeneratedMessageLite<
/** All subclasses implement this. */
public BuilderType mergeFrom(MessageType message) {
copyOnWrite();
- instance.visit(MergeFromVisitor.INSTANCE, message);
+ mergeFromInstance(instance, message);
return (BuilderType) this;
}
+ private void mergeFromInstance(MessageType dest, MessageType src) {
+ // BEGIN EXPERIMENTAL
+ // Protobuf.getInstance().schemaFor(dest).mergeFrom(dest, src);
+ // END EXPERIMENTAL
+ // BEGIN REGULAR
+ dest.visit(MergeFromVisitor.INSTANCE, src);
+ // END REGULAR
+ }
+
@Override
public MessageType getDefaultInstanceForType() {
return defaultInstance;
}
@Override
+ public BuilderType mergeFrom(byte[] input, int offset, int length)
+ throws InvalidProtocolBufferException {
+ // BEGIN REGULAR
+ return super.mergeFrom(input, offset, length);
+ // END REGULAR
+ // BEGIN EXPERIMENTAL
+ // copyOnWrite();
+ // try {
+ // Protobuf.getInstance().schemaFor(instance).mergeFrom(
+ // instance, input, offset, offset + length, new ArrayDecoders.Registers());
+ // } catch (InvalidProtocolBufferException e) {
+ // throw e;
+ // } catch (IndexOutOfBoundsException e) {
+ // throw InvalidProtocolBufferException.truncatedMessage();
+ // } catch (IOException e) {
+ // throw new RuntimeException("Reading from byte array should not throw IOException.", e);
+ // }
+ // return (BuilderType) this;
+ // END EXPERIMENTAL
+ }
+
+ @Override
public BuilderType mergeFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws IOException {
copyOnWrite();
try {
+ // BEGIN REGULAR
instance.dynamicMethod(MethodToInvoke.MERGE_FROM_STREAM, input, extensionRegistry);
+ // END REGULAR
+ // BEGIN EXPERIMENTAL
+ // Protobuf.getInstance().schemaFor(instance).mergeFrom(
+ // instance, CodedInputStreamReader.forCodedInput(input), extensionRegistry);
+ // END EXPERIMENTAL
} catch (RuntimeException e) {
if (e.getCause() instanceof IOException) {
throw (IOException) e.getCause();
@@ -447,12 +546,10 @@ public abstract class GeneratedMessageLite<
extends GeneratedMessageLite<MessageType, BuilderType>
implements ExtendableMessageOrBuilder<MessageType, BuilderType> {
- /**
- * Represents the set of extensions on this message. For use by generated
- * code only.
- */
- protected FieldSet<ExtensionDescriptor> extensions = FieldSet.newFieldSet();
+ /** Represents the set of extensions on this message. For use by generated code only. */
+ protected FieldSet<ExtensionDescriptor> extensions = FieldSet.emptySet();
+ @SuppressWarnings("unchecked")
protected final void mergeExtensionFields(final MessageType other) {
if (extensions.isImmutable()) {
extensions = extensions.clone();
@@ -460,11 +557,13 @@ public abstract class GeneratedMessageLite<
extensions.mergeFrom(((ExtendableMessage) other).extensions);
}
+ // BEGIN REGULAR
@Override
final void visit(Visitor visitor, MessageType other) {
super.visit(visitor, other);
extensions = visitor.visitExtensions(extensions, other.extensions);
}
+ // END REGULAR
/**
* Parse an unknown field or an extension. For use by generated code only.
@@ -477,7 +576,8 @@ public abstract class GeneratedMessageLite<
MessageType defaultInstance,
CodedInputStream input,
ExtensionRegistryLite extensionRegistry,
- int tag) throws IOException {
+ int tag)
+ throws IOException {
int fieldNumber = WireFormat.getTagFieldNumber(tag);
// TODO(dweis): How much bytecode would be saved by not requiring the generated code to
@@ -517,7 +617,9 @@ public abstract class GeneratedMessageLite<
if (unknown) { // Unknown field or wrong wire type. Skip.
return parseUnknownField(tag, input);
}
-
+
+ ensureExtensionsAreMutable();
+
if (packed) {
int length = input.readRawVarint32();
int limit = input.pushLimit(length);
@@ -732,10 +834,18 @@ public abstract class GeneratedMessageLite<
if (subBuilder == null) {
subBuilder = extension.getMessageDefaultInstance().newBuilderForType();
}
- rawBytes.newCodedInput().readMessage(subBuilder, extensionRegistry);
+ subBuilder.mergeFrom(rawBytes, extensionRegistry);
MessageLite value = subBuilder.build();
- extensions.setField(extension.descriptor, extension.singularToFieldSetType(value));
+ ensureExtensionsAreMutable().setField(
+ extension.descriptor, extension.singularToFieldSetType(value));
+ }
+
+ private FieldSet<ExtensionDescriptor> ensureExtensionsAreMutable() {
+ if (extensions.isImmutable()) {
+ extensions = extensions.clone();
+ }
+ return extensions;
}
private void verifyExtensionContainingType(
@@ -807,10 +917,12 @@ public abstract class GeneratedMessageLite<
@Override
protected final void makeImmutable() {
super.makeImmutable();
-
+ // BEGIN REGULAR
extensions.makeImmutable();
+ // END REGULAR
}
+
/**
* Used by subclasses to serialize extensions. Extension ranges may be
* interleaved with field numbers, but we must write them in canonical
@@ -881,12 +993,6 @@ public abstract class GeneratedMessageLite<
implements ExtendableMessageOrBuilder<MessageType, BuilderType> {
protected ExtendableBuilder(MessageType defaultInstance) {
super(defaultInstance);
-
- // TODO(dweis): This is kind of an unnecessary clone since we construct a
- // new instance in the parent constructor which makes the extensions
- // immutable. This extra allocation shouldn't matter in practice
- // though.
- instance.extensions = instance.extensions.clone();
}
// For immutable message conversion.
@@ -905,6 +1011,15 @@ public abstract class GeneratedMessageLite<
instance.extensions = instance.extensions.clone();
}
+ private FieldSet<ExtensionDescriptor> ensureExtensionsAreMutable() {
+ FieldSet<ExtensionDescriptor> extensions = instance.extensions;
+ if (extensions.isImmutable()) {
+ extensions = extensions.clone();
+ instance.extensions = extensions;
+ }
+ return extensions;
+ }
+
@Override
public final MessageType buildPartial() {
if (isBuilt) {
@@ -963,7 +1078,8 @@ public abstract class GeneratedMessageLite<
verifyExtensionContainingType(extensionLite);
copyOnWrite();
- instance.extensions.setField(extensionLite.descriptor, extensionLite.toFieldSetType(value));
+ ensureExtensionsAreMutable()
+ .setField(extensionLite.descriptor, extensionLite.toFieldSetType(value));
return (BuilderType) this;
}
@@ -976,8 +1092,9 @@ public abstract class GeneratedMessageLite<
verifyExtensionContainingType(extensionLite);
copyOnWrite();
- instance.extensions.setRepeatedField(
- extensionLite.descriptor, index, extensionLite.singularToFieldSetType(value));
+ ensureExtensionsAreMutable()
+ .setRepeatedField(
+ extensionLite.descriptor, index, extensionLite.singularToFieldSetType(value));
return (BuilderType) this;
}
@@ -990,8 +1107,8 @@ public abstract class GeneratedMessageLite<
verifyExtensionContainingType(extensionLite);
copyOnWrite();
- instance.extensions.addRepeatedField(
- extensionLite.descriptor, extensionLite.singularToFieldSetType(value));
+ ensureExtensionsAreMutable()
+ .addRepeatedField(extensionLite.descriptor, extensionLite.singularToFieldSetType(value));
return (BuilderType) this;
}
@@ -1002,7 +1119,7 @@ public abstract class GeneratedMessageLite<
verifyExtensionContainingType(extensionLite);
copyOnWrite();
- instance.extensions.clearField(extensionLite.descriptor);
+ ensureExtensionsAreMutable().clearField(extensionLite.descriptor);
return (BuilderType) this;
}
}
@@ -1152,6 +1269,7 @@ public abstract class GeneratedMessageLite<
}
}
+
/**
* Lite equivalent to {@link GeneratedMessage.GeneratedExtension}.
*
@@ -1392,11 +1510,26 @@ 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);
+ byte memoizedIsInitialized =
+ (Byte) message.dynamicMethod(MethodToInvoke.GET_MEMOIZED_IS_INITIALIZED);
+ if (memoizedIsInitialized == 1) {
+ return true;
+ }
+ if (memoizedIsInitialized == 0) {
+ return false;
+ }
+ // BEGIN EXPERIMENTAL
+ // boolean isInitialized = Protobuf.getInstance().schemaFor(message).isInitialized(message);
+ // END EXPERIMENTAL
+ // BEGIN REGULAR
+ boolean isInitialized =
+ message.dynamicMethod(MethodToInvoke.IS_INITIALIZED, Boolean.FALSE) != null;
+ // END REGULAR
+ if (shouldMemoize) {
+ message.dynamicMethod(
+ MethodToInvoke.SET_MEMOIZED_IS_INITIALIZED, isInitialized ? message : null);
+ }
+ return isInitialized;
}
protected static IntList emptyIntList() {
@@ -1478,6 +1611,11 @@ public abstract class GeneratedMessageLite<
throws InvalidProtocolBufferException {
return GeneratedMessageLite.parsePartialFrom(defaultInstance, input, extensionRegistry);
}
+
+ @Override
+ public T parsePartialFrom(byte[] input) throws InvalidProtocolBufferException {
+ return GeneratedMessageLite.parsePartialFrom(defaultInstance, input);
+ }
}
/**
@@ -1491,8 +1629,21 @@ public abstract class GeneratedMessageLite<
@SuppressWarnings("unchecked") // Guaranteed by protoc
T result = (T) instance.dynamicMethod(MethodToInvoke.NEW_MUTABLE_INSTANCE);
try {
+ // BEGIN REGULAR
result.dynamicMethod(MethodToInvoke.MERGE_FROM_STREAM, input, extensionRegistry);
+ // END REGULAR
+ // BEGIN EXPERIMENTAL
+ // Protobuf.getInstance().schemaFor(result).mergeFrom(
+ // result, CodedInputStreamReader.forCodedInput(input), extensionRegistry);
+ // END EXPERIMENTAL
result.makeImmutable();
+ // BEGIN EXPERIMENTAL
+ // } catch (IOException e) {
+ // if (e.getCause() instanceof InvalidProtocolBufferException) {
+ // throw (InvalidProtocolBufferException) e.getCause();
+ // }
+ // throw new InvalidProtocolBufferException(e.getMessage()).setUnfinishedMessage(result);
+ // END EXPERIMENTAL
} catch (RuntimeException e) {
if (e.getCause() instanceof InvalidProtocolBufferException) {
throw (InvalidProtocolBufferException) e.getCause();
@@ -1502,6 +1653,34 @@ public abstract class GeneratedMessageLite<
return result;
}
+ /** A static helper method for parsing a partial from byte array. */
+ static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom(T instance, byte[] input)
+ throws InvalidProtocolBufferException {
+ // BEGIN REGULAR
+ return parsePartialFrom(instance, input, ExtensionRegistryLite.getEmptyRegistry());
+ // END REGULAR
+ // BEGIN EXPERIMENTAL
+ // @SuppressWarnings("unchecked") // Guaranteed by protoc
+ // T result = (T) instance.dynamicMethod(MethodToInvoke.NEW_MUTABLE_INSTANCE);
+ // try {
+ // Protobuf.getInstance().schemaFor(result).mergeFrom(
+ // result, input, 0, input.length, new ArrayDecoders.Registers());
+ // result.makeImmutable();
+ // if (result.memoizedHashCode != 0) {
+ // throw new RuntimeException();
+ // }
+ // } catch (IOException e) {
+ // if (e.getCause() instanceof InvalidProtocolBufferException) {
+ // throw (InvalidProtocolBufferException) e.getCause();
+ // }
+ // throw new InvalidProtocolBufferException(e.getMessage()).setUnfinishedMessage(result);
+ // } catch (IndexOutOfBoundsException e) {
+ // throw InvalidProtocolBufferException.truncatedMessage().setUnfinishedMessage(result);
+ // }
+ // return result;
+ // END EXPERIMENTAL
+ }
+
protected static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom(
T defaultInstance,
CodedInputStream input)
@@ -1527,6 +1706,20 @@ public abstract class GeneratedMessageLite<
// Validates last tag.
protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
+ T defaultInstance, ByteBuffer data, ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
+ return checkMessageInitialized(
+ parseFrom(defaultInstance, CodedInputStream.newInstance(data), extensionRegistry));
+ }
+
+ // Validates last tag.
+ protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
+ T defaultInstance, ByteBuffer data) throws InvalidProtocolBufferException {
+ return parseFrom(defaultInstance, data, ExtensionRegistryLite.getEmptyRegistry());
+ }
+
+ // Validates last tag.
+ protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
T defaultInstance, ByteString data)
throws InvalidProtocolBufferException {
return checkMessageInitialized(
@@ -1584,8 +1777,7 @@ public abstract class GeneratedMessageLite<
protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
T defaultInstance, byte[] data)
throws InvalidProtocolBufferException {
- return checkMessageInitialized(
- parsePartialFrom(defaultInstance, data, ExtensionRegistryLite.getEmptyRegistry()));
+ return checkMessageInitialized(parsePartialFrom(defaultInstance, data));
}
// Validates last tag.
@@ -1670,6 +1862,7 @@ public abstract class GeneratedMessageLite<
return message;
}
+ // BEGIN REGULAR
/**
* 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
@@ -1693,7 +1886,6 @@ public abstract class GeneratedMessageLite<
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);
@@ -1701,7 +1893,6 @@ public abstract class GeneratedMessageLite<
* Message fields use null sentinals.
*/
<T extends MessageLite> T visitMessage(T mine, T other);
- LazyFieldLite visitLazyMessage(LazyFieldLite mine, LazyFieldLite other);
<T> ProtobufList<T> visitList(ProtobufList<T> mine, ProtobufList<T> other);
BooleanList visitBooleanList(BooleanList mine, BooleanList other);
@@ -1845,14 +2036,6 @@ public abstract class GeneratedMessageLite<
}
@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;
@@ -1883,21 +2066,6 @@ public abstract class GeneratedMessageLite<
}
@Override
- public LazyFieldLite visitLazyMessage(
- LazyFieldLite mine, LazyFieldLite other) {
- if (mine == null && other == null) {
- return null;
- }
- if (mine == null || other == null) {
- throw NOT_EQUALS;
- }
- if (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;
@@ -1977,13 +2145,13 @@ public abstract class GeneratedMessageLite<
/**
* Implements hashCode by accumulating state.
*/
- private static class HashCodeVisitor implements Visitor {
+ 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;
+ int hashCode = 0;
@Override
public boolean visitBoolean(
@@ -2074,12 +2242,6 @@ public abstract class GeneratedMessageLite<
}
@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);
}
@@ -2108,18 +2270,6 @@ public abstract class GeneratedMessageLite<
}
@Override
- public LazyFieldLite visitLazyMessage(LazyFieldLite mine, LazyFieldLite other) {
- final int protoHash;
- if (mine != null) {
- protoHash = mine.hashCode();
- } else {
- protoHash = 37;
- }
- hashCode = (53 * hashCode) + protoHash;
- return mine;
- }
-
- @Override
public <T> ProtobufList<T> visitList(ProtobufList<T> mine, ProtobufList<T> other) {
hashCode = (53 * hashCode) + mine.hashCode();
return mine;
@@ -2262,13 +2412,6 @@ public abstract class GeneratedMessageLite<
}
@Override
- public Object visitOneofLazyMessage(boolean minePresent, Object mine, Object other) {
- LazyFieldLite lazy = minePresent ? (LazyFieldLite) mine : new LazyFieldLite();
- lazy.merge((LazyFieldLite) other);
- return lazy;
- }
-
- @Override
public Object visitOneofMessage(boolean minePresent, Object mine, Object other) {
if (minePresent) {
return visitMessage((MessageLite) mine, (MessageLite) other);
@@ -2292,17 +2435,6 @@ public abstract class GeneratedMessageLite<
}
@Override
- public LazyFieldLite visitLazyMessage(LazyFieldLite mine, LazyFieldLite other) {
- if (other != null) {
- if (mine == null) {
- mine = new LazyFieldLite();
- }
- 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();
@@ -2416,4 +2548,5 @@ public abstract class GeneratedMessageLite<
return mine;
}
}
+ // END REGULAR
}
diff --git a/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java b/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
index 2a5d8b50..4acd8f2f 100644
--- a/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
+++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
@@ -30,6 +30,8 @@
package com.google.protobuf;
+import static com.google.protobuf.Internal.checkNotNull;
+
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.EnumDescriptor;
import com.google.protobuf.Descriptors.EnumValueDescriptor;
@@ -41,13 +43,12 @@ import com.google.protobuf.Descriptors.OneofDescriptor;
// class without breaking binary compatibility with old generated code that still subclasses
// the old GeneratedMessageV3 class. To allow these different GeneratedMessageV3V? classes to
// interoperate (e.g., a GeneratedMessageV3V3 object has a message extension field whose class
-// type is GeneratedMessageV3V4), these classes still share a common parent class AbstarctMessage
+// type is GeneratedMessageV3V4), these classes still share a common parent class AbstractMessage
// and are using the same GeneratedMessage.GeneratedExtension class for extension definitions.
// Since this class becomes GeneratedMessageV3V? in opensource, we have to add an import here
// to be able to use GeneratedMessage.GeneratedExtension. The GeneratedExtension definition in
// this file is also excluded from opensource to avoid conflict.
import com.google.protobuf.GeneratedMessage.GeneratedExtension;
-
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectStreamException;
@@ -277,13 +278,30 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
/**
* Called by subclasses to parse an unknown field.
+ *
* @return {@code true} unless the tag is an end-group tag.
*/
protected boolean parseUnknownField(
CodedInputStream input,
UnknownFieldSet.Builder unknownFields,
ExtensionRegistryLite extensionRegistry,
- int tag) throws IOException {
+ int tag)
+ throws IOException {
+ if (input.shouldDiscardUnknownFields()) {
+ return input.skipField(tag);
+ }
+ return unknownFields.mergeFieldFrom(tag, input);
+ }
+
+ protected boolean parseUnknownFieldProto3(
+ CodedInputStream input,
+ UnknownFieldSet.Builder unknownFields,
+ ExtensionRegistryLite extensionRegistry,
+ int tag)
+ throws IOException {
+ if (input.shouldDiscardUnknownFieldsProto3()) {
+ return input.skipField(tag);
+ }
return unknownFields.mergeFieldFrom(tag, input);
}
@@ -340,6 +358,10 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
throw e.unwrapIOException();
}
}
+
+ protected static boolean canUseUnsafe() {
+ return UnsafeUtil.hasUnsafeArrayOperations() && UnsafeUtil.hasUnsafeByteBufferOperations();
+ }
@Override
public void writeTo(final CodedOutputStream output) throws IOException {
@@ -619,17 +641,25 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
return (BuilderType) this;
}
+ protected BuilderType setUnknownFieldsProto3(final UnknownFieldSet unknownFields) {
+ if (CodedInputStream.getProto3DiscardUnknownFieldsDefault()) {
+ return (BuilderType) this;
+ }
+ this.unknownFields = unknownFields;
+ onChanged();
+ return (BuilderType) this;
+ }
+
@Override
public BuilderType mergeUnknownFields(
final UnknownFieldSet unknownFields) {
- this.unknownFields =
+ return setUnknownFields(
UnknownFieldSet.newBuilder(this.unknownFields)
.mergeFrom(unknownFields)
- .build();
- onChanged();
- return (BuilderType) this;
+ .build());
}
+
@Override
public boolean isInitialized() {
for (final FieldDescriptor field : getDescriptorForType().getFields()) {
@@ -666,18 +696,6 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
}
/**
- * Called by subclasses to parse an unknown field.
- * @return {@code true} unless the tag is an end-group tag.
- */
- protected boolean parseUnknownField(
- final CodedInputStream input,
- final UnknownFieldSet.Builder unknownFields,
- final ExtensionRegistryLite extensionRegistry,
- final int tag) throws IOException {
- return unknownFields.mergeFieldFrom(tag, input);
- }
-
- /**
* Implementation of {@link BuilderParent} for giving to our children. This
* small inner class makes it so we don't publicly expose the BuilderParent
* methods.
@@ -866,6 +884,7 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
/** Check if a singular extension is present. */
@Override
+ @SuppressWarnings("unchecked")
public final <Type> boolean hasExtension(final ExtensionLite<MessageType, Type> extensionLite) {
Extension<MessageType, Type> extension = checkNotLite(extensionLite);
@@ -875,6 +894,7 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
/** Get the number of elements in a repeated extension. */
@Override
+ @SuppressWarnings("unchecked")
public final <Type> int getExtensionCount(
final ExtensionLite<MessageType, List<Type>> extensionLite) {
Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
@@ -985,8 +1005,23 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
ExtensionRegistryLite extensionRegistry,
int tag) throws IOException {
return MessageReflection.mergeFieldFrom(
- input, unknownFields, extensionRegistry, getDescriptorForType(),
- new MessageReflection.ExtensionAdapter(extensions), tag);
+ input, input.shouldDiscardUnknownFields() ? null : unknownFields, extensionRegistry,
+ getDescriptorForType(), new MessageReflection.ExtensionAdapter(extensions), tag);
+ }
+
+ @Override
+ protected boolean parseUnknownFieldProto3(
+ CodedInputStream input,
+ UnknownFieldSet.Builder unknownFields,
+ ExtensionRegistryLite extensionRegistry,
+ int tag) throws IOException {
+ return MessageReflection.mergeFieldFrom(
+ input,
+ input.shouldDiscardUnknownFieldsProto3() ? null : unknownFields,
+ extensionRegistry,
+ getDescriptorForType(),
+ new MessageReflection.ExtensionAdapter(extensions),
+ tag);
}
@@ -1456,21 +1491,6 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
return super.isInitialized() && extensionsAreInitialized();
}
- /**
- * Called by subclasses to parse an unknown field or an extension.
- * @return {@code true} unless the tag is an end-group tag.
- */
- @Override
- protected boolean parseUnknownField(
- final CodedInputStream input,
- final UnknownFieldSet.Builder unknownFields,
- final ExtensionRegistryLite extensionRegistry,
- final int tag) throws IOException {
- return MessageReflection.mergeFieldFrom(
- input, unknownFields, extensionRegistry, getDescriptorForType(),
- new MessageReflection.BuilderAdapter(this), tag);
- }
-
// ---------------------------------------------------------------
// Reflection
@@ -2219,6 +2239,7 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
}
@Override
+ @SuppressWarnings("unchecked")
public Object get(GeneratedMessageV3 message) {
List result = new ArrayList();
for (int i = 0; i < getRepeatedCount(message); i++) {
@@ -2228,6 +2249,7 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
}
@Override
+ @SuppressWarnings("unchecked")
public Object get(Builder builder) {
List result = new ArrayList();
for (int i = 0; i < getRepeatedCount(builder); i++) {
@@ -2273,7 +2295,7 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
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, coerceType((Message) value));
@@ -2674,7 +2696,7 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
return (Extension<MessageType, T>) extension;
}
-
+
protected static int computeStringSize(final int fieldNumber, final Object value) {
if (value instanceof String) {
return CodedOutputStream.computeStringSize(fieldNumber, (String) value);
@@ -2682,7 +2704,7 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
return CodedOutputStream.computeBytesSize(fieldNumber, (ByteString) value);
}
}
-
+
protected static int computeStringSizeNoTag(final Object value) {
if (value instanceof String) {
return CodedOutputStream.computeStringSizeNoTag((String) value);
@@ -2690,7 +2712,7 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
return CodedOutputStream.computeBytesSizeNoTag((ByteString) value);
}
}
-
+
protected static void writeString(
CodedOutputStream output, final int fieldNumber, final Object value) throws IOException {
if (value instanceof String) {
@@ -2699,7 +2721,7 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
output.writeBytes(fieldNumber, (ByteString) value);
}
}
-
+
protected static void writeStringNoTag(
CodedOutputStream output, final Object value) throws IOException {
if (value instanceof String) {
@@ -2836,3 +2858,4 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
}
}
}
+
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 2f526e3f..aacd71e1 100644
--- a/java/core/src/main/java/com/google/protobuf/IntArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/IntArrayList.java
@@ -30,8 +30,9 @@
package com.google.protobuf;
-import com.google.protobuf.Internal.IntList;
+import static com.google.protobuf.Internal.checkNotNull;
+import com.google.protobuf.Internal.IntList;
import java.util.Arrays;
import java.util.Collection;
import java.util.RandomAccess;
@@ -41,9 +42,8 @@ import java.util.RandomAccess;
*
* @author dweis@google.com (Daniel Weis)
*/
-final class IntArrayList
- extends AbstractProtobufList<Integer>
- implements IntList, RandomAccess {
+final class IntArrayList extends AbstractProtobufList<Integer>
+ implements IntList, RandomAccess, PrimitiveNonBoxingCollection {
private static final IntArrayList EMPTY_LIST = new IntArrayList();
static {
@@ -82,6 +82,18 @@ final class IntArrayList
}
@Override
+ protected void removeRange(int fromIndex, int toIndex) {
+ ensureIsMutable();
+ if (toIndex < fromIndex) {
+ throw new IndexOutOfBoundsException("toIndex < fromIndex");
+ }
+
+ System.arraycopy(array, toIndex, array, fromIndex, size - toIndex);
+ size -= (toIndex - fromIndex);
+ modCount++;
+ }
+
+ @Override
public boolean equals(Object o) {
if (this == o) {
return true;
@@ -198,9 +210,7 @@ final class IntArrayList
public boolean addAll(Collection<? extends Integer> collection) {
ensureIsMutable();
- if (collection == null) {
- throw new NullPointerException();
- }
+ checkNotNull(collection);
// We specialize when adding another IntArrayList to avoid boxing elements.
if (!(collection instanceof IntArrayList)) {
@@ -248,7 +258,9 @@ final class IntArrayList
ensureIsMutable();
ensureIndexInRange(index);
int value = array[index];
- System.arraycopy(array, index + 1, array, index, size - index);
+ if (index < size - 1) {
+ System.arraycopy(array, index + 1, array, index, size - index);
+ }
size--;
modCount++;
return value;
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 c234559c..848cad03 100644
--- a/java/core/src/main/java/com/google/protobuf/Internal.java
+++ b/java/core/src/main/java/com/google/protobuf/Internal.java
@@ -62,6 +62,16 @@ public final class Internal {
/**
* Throws an appropriate {@link NullPointerException} if the given objects is {@code null}.
*/
+ static <T> T checkNotNull(T obj) {
+ if (obj == null) {
+ throw new NullPointerException();
+ }
+ return obj;
+ }
+
+ /**
+ * Throws an appropriate {@link NullPointerException} if the given objects is {@code null}.
+ */
static <T> T checkNotNull(T obj, String message) {
if (obj == null) {
throw new NullPointerException(message);
@@ -404,9 +414,8 @@ public final class Internal {
}
}
- /**
- * An empty byte array constant used in generated code.
- */
+
+ /** An empty byte array constant used in generated code. */
public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
/**
@@ -420,6 +429,11 @@ public final class Internal {
CodedInputStream.newInstance(EMPTY_BYTE_ARRAY);
+ /** Helper method to merge two MessageLite instances. */
+ static Object mergeMessage(Object destination, Object source) {
+ return ((MessageLite) destination).toBuilder().mergeFrom((MessageLite) source).buildPartial();
+ }
+
/**
* Provides an immutable view of {@code List<T>} around a {@code List<F>}.
*
diff --git a/java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java b/java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java
index 55e33d21..510c6aac 100644
--- a/java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java
+++ b/java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java
@@ -50,6 +50,10 @@ public class InvalidProtocolBufferException extends IOException {
super(e.getMessage(), e);
}
+ public InvalidProtocolBufferException(final String description, IOException e) {
+ super(description, e);
+ }
+
/**
* Attaches an unfinished message to the exception to support best-effort
* parsing in {@code Parser} interface.
diff --git a/java/core/src/main/java/com/google/protobuf/IterableByteBufferInputStream.java b/java/core/src/main/java/com/google/protobuf/IterableByteBufferInputStream.java
new file mode 100644
index 00000000..713e8064
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/IterableByteBufferInputStream.java
@@ -0,0 +1,150 @@
+// 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.Internal.EMPTY_BYTE_BUFFER;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.Iterator;
+
+class IterableByteBufferInputStream extends InputStream {
+ /** The {@link Iterator} with type {@link ByteBuffer} of {@code input} */
+ private Iterator<ByteBuffer> iterator;
+ /** The current ByteBuffer; */
+ private ByteBuffer currentByteBuffer;
+ /** The number of ByteBuffers in the input data. */
+ private int dataSize;
+ /**
+ * Current {@code ByteBuffer}'s index
+ *
+ * <p>If index equals dataSize, then all the data in the InputStream has been consumed
+ */
+ private int currentIndex;
+ /** The current position for current ByteBuffer */
+ private int currentByteBufferPos;
+ /** Whether current ByteBuffer has an array */
+ private boolean hasArray;
+ /**
+ * If the current ByteBuffer is unsafe-direct based, currentArray is null; otherwise should be the
+ * array inside ByteBuffer.
+ */
+ private byte[] currentArray;
+ /** Current ByteBuffer's array offset */
+ private int currentArrayOffset;
+ /**
+ * If the current ByteBuffer is unsafe-direct based, currentAddress is the start address of this
+ * ByteBuffer; otherwise should be zero.
+ */
+ private long currentAddress;
+
+ IterableByteBufferInputStream(Iterable<ByteBuffer> data) {
+ iterator = data.iterator();
+ dataSize = 0;
+ for (ByteBuffer unused : data) {
+ dataSize++;
+ }
+ currentIndex = -1;
+
+ if (!getNextByteBuffer()) {
+ currentByteBuffer = EMPTY_BYTE_BUFFER;
+ currentIndex = 0;
+ currentByteBufferPos = 0;
+ currentAddress = 0;
+ }
+ }
+
+ private boolean getNextByteBuffer() {
+ currentIndex++;
+ if (!iterator.hasNext()) {
+ return false;
+ }
+ currentByteBuffer = iterator.next();
+ currentByteBufferPos = currentByteBuffer.position();
+ if (currentByteBuffer.hasArray()) {
+ hasArray = true;
+ currentArray = currentByteBuffer.array();
+ currentArrayOffset = currentByteBuffer.arrayOffset();
+ } else {
+ hasArray = false;
+ currentAddress = UnsafeUtil.addressOffset(currentByteBuffer);
+ currentArray = null;
+ }
+ return true;
+ }
+
+ private void updateCurrentByteBufferPos(int numberOfBytesRead) {
+ currentByteBufferPos += numberOfBytesRead;
+ if (currentByteBufferPos == currentByteBuffer.limit()) {
+ getNextByteBuffer();
+ }
+ }
+
+ @Override
+ public int read() throws IOException {
+ if (currentIndex == dataSize) {
+ return -1;
+ }
+ if (hasArray) {
+ int result = currentArray[currentByteBufferPos + currentArrayOffset] & 0xFF;
+ updateCurrentByteBufferPos(1);
+ return result;
+ } else {
+ int result = UnsafeUtil.getByte(currentByteBufferPos + currentAddress) & 0xFF;
+ updateCurrentByteBufferPos(1);
+ return result;
+ }
+ }
+
+ @Override
+ public int read(byte[] output, int offset, int length) throws IOException {
+ if (currentIndex == dataSize) {
+ return -1;
+ }
+ int remaining = currentByteBuffer.limit() - currentByteBufferPos;
+ if (length > remaining) {
+ length = remaining;
+ }
+ if (hasArray) {
+ System.arraycopy(
+ currentArray, currentByteBufferPos + currentArrayOffset, output, offset, length);
+ updateCurrentByteBufferPos(length);
+ } else {
+ int prevPos = currentByteBuffer.position();
+ currentByteBuffer.position(currentByteBufferPos);
+ currentByteBuffer.get(output, offset, length);
+ currentByteBuffer.position(prevPos);
+ updateCurrentByteBufferPos(length);
+ }
+ return length;
+ }
+}
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 4b0ba0fd..49ecfc0b 100644
--- a/java/core/src/main/java/com/google/protobuf/LazyFieldLite.java
+++ b/java/core/src/main/java/com/google/protobuf/LazyFieldLite.java
@@ -394,6 +394,7 @@ public class LazyFieldLite {
}
}
+
/**
* Might lazily parse the bytes that were previously passed in. Is thread-safe.
*/
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 5a772e3a..95945cb7 100644
--- a/java/core/src/main/java/com/google/protobuf/LongArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/LongArrayList.java
@@ -30,8 +30,9 @@
package com.google.protobuf;
-import com.google.protobuf.Internal.LongList;
+import static com.google.protobuf.Internal.checkNotNull;
+import com.google.protobuf.Internal.LongList;
import java.util.Arrays;
import java.util.Collection;
import java.util.RandomAccess;
@@ -41,9 +42,8 @@ import java.util.RandomAccess;
*
* @author dweis@google.com (Daniel Weis)
*/
-final class LongArrayList
- extends AbstractProtobufList<Long>
- implements LongList, RandomAccess {
+final class LongArrayList extends AbstractProtobufList<Long>
+ implements LongList, RandomAccess, PrimitiveNonBoxingCollection {
private static final LongArrayList EMPTY_LIST = new LongArrayList();
static {
@@ -82,6 +82,18 @@ final class LongArrayList
}
@Override
+ protected void removeRange(int fromIndex, int toIndex) {
+ ensureIsMutable();
+ if (toIndex < fromIndex) {
+ throw new IndexOutOfBoundsException("toIndex < fromIndex");
+ }
+
+ System.arraycopy(array, toIndex, array, fromIndex, size - toIndex);
+ size -= (toIndex - fromIndex);
+ modCount++;
+ }
+
+ @Override
public boolean equals(Object o) {
if (this == o) {
return true;
@@ -198,9 +210,7 @@ final class LongArrayList
public boolean addAll(Collection<? extends Long> collection) {
ensureIsMutable();
- if (collection == null) {
- throw new NullPointerException();
- }
+ checkNotNull(collection);
// We specialize when adding another LongArrayList to avoid boxing elements.
if (!(collection instanceof LongArrayList)) {
@@ -248,7 +258,9 @@ final class LongArrayList
ensureIsMutable();
ensureIndexInRange(index);
long value = array[index];
- System.arraycopy(array, index + 1, array, index, size - index);
+ if (index < size - 1) {
+ System.arraycopy(array, index + 1, array, index, size - index);
+ }
size--;
modCount++;
return value;
diff --git a/java/core/src/main/java/com/google/protobuf/MapEntry.java b/java/core/src/main/java/com/google/protobuf/MapEntry.java
index 179c3348..0849b821 100644
--- a/java/core/src/main/java/com/google/protobuf/MapEntry.java
+++ b/java/core/src/main/java/com/google/protobuf/MapEntry.java
@@ -33,7 +33,6 @@ package com.google.protobuf;
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.EnumValueDescriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
-
import java.io.IOException;
import java.util.Collections;
import java.util.Map;
@@ -89,6 +88,7 @@ public final class MapEntry<K, V> extends AbstractMessage {
}
/** Create a MapEntry with the provided key and value. */
+ @SuppressWarnings("unchecked")
private MapEntry(Metadata metadata, K key, V value) {
this.key = key;
this.value = value;
@@ -170,7 +170,7 @@ public final class MapEntry<K, V> extends AbstractMessage {
@Override
public Builder<K, V> toBuilder() {
- return new Builder<K, V>(metadata, key, value);
+ return new Builder<K, V>(metadata, key, value, true, true);
}
@Override
@@ -246,15 +246,19 @@ public final class MapEntry<K, V> extends AbstractMessage {
private final Metadata<K, V> metadata;
private K key;
private V value;
+ private boolean hasKey;
+ private boolean hasValue;
private Builder(Metadata<K, V> metadata) {
- this(metadata, metadata.defaultKey, metadata.defaultValue);
+ this(metadata, metadata.defaultKey, metadata.defaultValue, false, false);
}
- private Builder(Metadata<K, V> metadata, K key, V value) {
+ private Builder(Metadata<K, V> metadata, K key, V value, boolean hasKey, boolean hasValue) {
this.metadata = metadata;
this.key = key;
this.value = value;
+ this.hasKey = hasKey;
+ this.hasValue = hasValue;
}
public K getKey() {
@@ -267,21 +271,25 @@ public final class MapEntry<K, V> extends AbstractMessage {
public Builder<K, V> setKey(K key) {
this.key = key;
+ this.hasKey = true;
return this;
}
public Builder<K, V> clearKey() {
this.key = metadata.defaultKey;
+ this.hasKey = false;
return this;
}
public Builder<K, V> setValue(V value) {
this.value = value;
+ this.hasValue = true;
return this;
}
public Builder<K, V> clearValue() {
this.value = metadata.defaultValue;
+ this.hasValue = false;
return this;
}
@@ -403,7 +411,7 @@ public final class MapEntry<K, V> extends AbstractMessage {
@Override
public boolean hasField(FieldDescriptor field) {
checkFieldDescriptor(field);
- return true;
+ return field.getNumber() == 1 ? hasKey : hasValue;
}
@Override
@@ -435,8 +443,9 @@ public final class MapEntry<K, V> extends AbstractMessage {
}
@Override
+ @SuppressWarnings("unchecked")
public Builder<K, V> clone() {
- return new Builder(metadata, key, value);
+ return new Builder(metadata, key, value, hasKey, hasValue);
}
}
@@ -446,4 +455,9 @@ public final class MapEntry<K, V> extends AbstractMessage {
}
return true;
}
+
+ /** Returns the metadata only for experimental runtime. */
+ final Metadata<K, V> getMetadata() {
+ return metadata;
+ }
}
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 22aef8f9..dcb5dfad 100644
--- a/java/core/src/main/java/com/google/protobuf/MapEntryLite.java
+++ b/java/core/src/main/java/com/google/protobuf/MapEntryLite.java
@@ -223,4 +223,9 @@ public class MapEntryLite<K, V> {
input.popLimit(oldLimit);
map.put(key, value);
}
+
+ /** For experimental runtime internal use only. */
+ Metadata<K, V> getMetadata() {
+ return metadata;
+ }
}
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 a6109f98..ad8ceb02 100644
--- a/java/core/src/main/java/com/google/protobuf/MapField.java
+++ b/java/core/src/main/java/com/google/protobuf/MapField.java
@@ -30,6 +30,8 @@
package com.google.protobuf;
+import static com.google.protobuf.Internal.checkNotNull;
+
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -100,6 +102,7 @@ public class MapField<K, V> implements MutabilityOracle {
}
@Override
+ @SuppressWarnings("unchecked")
public void convertMessageToKeyAndValue(Message message, Map<K, V> map) {
MapEntry<K, V> entry = (MapEntry<K, V>) message;
map.put(entry.getKey(), entry.getValue());
@@ -328,6 +331,8 @@ public class MapField<K, V> implements MutabilityOracle {
@Override
public V put(K key, V value) {
mutabilityOracle.ensureMutable();
+ checkNotNull(key);
+ checkNotNull(value);
return delegate.put(key, value);
}
@@ -340,6 +345,10 @@ public class MapField<K, V> implements MutabilityOracle {
@Override
public void putAll(Map<? extends K, ? extends V> m) {
mutabilityOracle.ensureMutable();
+ for (K key : m.keySet()) {
+ checkNotNull(key);
+ checkNotNull(m.get(key));
+ }
delegate.putAll(m);
}
diff --git a/java/core/src/main/java/com/google/protobuf/MapFieldLite.java b/java/core/src/main/java/com/google/protobuf/MapFieldLite.java
index 42640279..a8b3dd88 100644
--- a/java/core/src/main/java/com/google/protobuf/MapFieldLite.java
+++ b/java/core/src/main/java/com/google/protobuf/MapFieldLite.java
@@ -30,8 +30,9 @@
package com.google.protobuf;
-import com.google.protobuf.Internal.EnumLite;
+import static com.google.protobuf.Internal.checkNotNull;
+import com.google.protobuf.Internal.EnumLite;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
@@ -88,6 +89,9 @@ public final class MapFieldLite<K, V> extends LinkedHashMap<K, V> {
@Override public V put(K key, V value) {
ensureMutable();
+ checkNotNull(key);
+
+ checkNotNull(value);
return super.put(key, value);
}
@@ -97,6 +101,7 @@ public final class MapFieldLite<K, V> extends LinkedHashMap<K, V> {
@Override public void putAll(Map<? extends K, ? extends V> m) {
ensureMutable();
+ checkForNullKeysAndValues(m);
super.putAll(m);
}
@@ -105,6 +110,13 @@ public final class MapFieldLite<K, V> extends LinkedHashMap<K, V> {
return super.remove(key);
}
+ private static void checkForNullKeysAndValues(Map<?, ?> m) {
+ for (Object key : m.keySet()) {
+ checkNotNull(key);
+ checkNotNull(m.get(key));
+ }
+ }
+
private static boolean equals(Object a, Object b) {
if (a instanceof byte[] && b instanceof byte[]) {
return Arrays.equals((byte[]) a, (byte[]) b);
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 94590fb9..0770d417 100644
--- a/java/core/src/main/java/com/google/protobuf/Message.java
+++ b/java/core/src/main/java/com/google/protobuf/Message.java
@@ -125,7 +125,7 @@ public interface Message extends MessageLite, MessageOrBuilder {
* 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.
+ * with the elements in this message.<br>
* * 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.
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 23373ef4..8e265935 100644
--- a/java/core/src/main/java/com/google/protobuf/MessageLiteToString.java
+++ b/java/core/src/main/java/com/google/protobuf/MessageLiteToString.java
@@ -31,6 +31,7 @@
package com.google.protobuf;
import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@@ -38,20 +39,18 @@ 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.
+/** Helps generate {@link String} representations of {@link MessageLite} protos. */
final class MessageLiteToString {
private static final String LIST_SUFFIX = "List";
private static final String BUILDER_LIST_SUFFIX = "OrBuilderList";
+ private static final String MAP_SUFFIX = "Map";
private static final String BYTES_SUFFIX = "Bytes";
-
+
/**
- * Returns a {@link String} representation of the {@link MessageLite} object. The first line of
+ * 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
+ * the object instance. This acts as an indicator that this should not be relied on for
* comparisons.
*
* <p>For use by generated code only.
@@ -71,8 +70,9 @@ final class MessageLiteToString {
*/
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.
+ // Build a map of method name to method. We're looking for methods like getFoo(), hasFoo(),
+ // getFooList() and getFooMap() 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>();
@@ -89,12 +89,16 @@ final class MessageLiteToString {
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());
+ if (suffix.endsWith(LIST_SUFFIX)
+ && !suffix.endsWith(BUILDER_LIST_SUFFIX)
+ // Sometimes people have fields named 'list' that aren't repeated.
+ && !suffix.equals(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);
+ // only works if the method names have not been proguarded out or renamed.
+ Method listMethod = nameToNoArgMethod.get(getter);
if (listMethod != null && listMethod.getReturnType().equals(List.class)) {
printField(
buffer,
@@ -104,6 +108,30 @@ final class MessageLiteToString {
continue;
}
}
+ if (suffix.endsWith(MAP_SUFFIX)
+ // Sometimes people have fields named 'map' that aren't maps.
+ && !suffix.equals(MAP_SUFFIX)) {
+ String camelCase =
+ suffix.substring(0, 1).toLowerCase()
+ + suffix.substring(1, suffix.length() - MAP_SUFFIX.length());
+ // Try to reflectively get the value and toString() the field as if it were a map. This only
+ // works if the method names have not been proguarded out or renamed.
+ Method mapMethod = nameToNoArgMethod.get(getter);
+ if (mapMethod != null
+ && mapMethod.getReturnType().equals(Map.class)
+ // Skip the deprecated getter method with no prefix "Map" when the field name ends with
+ // "map".
+ && !mapMethod.isAnnotationPresent(Deprecated.class)
+ // Skip the internal mutable getter method.
+ && Modifier.isPublic(mapMethod.getModifiers())) {
+ printField(
+ buffer,
+ indent,
+ camelCaseToSnakeCase(camelCase),
+ GeneratedMessageLite.invokeOrDie(mapMethod, messageLite));
+ continue;
+ }
+ }
Method setter = nameToMethod.get("set" + suffix);
if (setter == null) {
@@ -119,22 +147,19 @@ final class MessageLiteToString {
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.
+ // only works if the method names have not been 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.
+ 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);
+ printField(buffer, indent, camelCaseToSnakeCase(camelCase), value);
}
continue;
}
@@ -153,7 +178,7 @@ final class MessageLiteToString {
((GeneratedMessageLite<?, ?>) messageLite).unknownFields.printWithIndent(buffer, indent);
}
}
-
+
private static boolean isDefaultValue(Object o) {
if (o instanceof Boolean) {
return !((Boolean) o);
@@ -179,7 +204,7 @@ final class MessageLiteToString {
if (o instanceof java.lang.Enum<?>) { // Catches oneof enums.
return ((java.lang.Enum<?>) o).ordinal() == 0;
}
-
+
return false;
}
@@ -201,6 +226,13 @@ final class MessageLiteToString {
}
return;
}
+ if (object instanceof Map<?, ?>) {
+ Map<?, ?> map = (Map<?, ?>) object;
+ for (Map.Entry<?, ?> entry : map.entrySet()) {
+ printField(buffer, indent, name, entry);
+ }
+ return;
+ }
buffer.append('\n');
for (int i = 0; i < indent; i++) {
@@ -220,11 +252,21 @@ final class MessageLiteToString {
buffer.append(' ');
}
buffer.append("}");
+ } else if (object instanceof Map.Entry<?, ?>) {
+ buffer.append(" {");
+ Map.Entry<?, ?> entry = (Map.Entry<?, ?>) object;
+ printField(buffer, indent + 2, "key", entry.getKey());
+ printField(buffer, indent + 2, "value", entry.getValue());
+ 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++) {
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 3d73efb3..69ad7ddf 100644
--- a/java/core/src/main/java/com/google/protobuf/MessageReflection.java
+++ b/java/core/src/main/java/com/google/protobuf/MessageReflection.java
@@ -31,7 +31,6 @@
package com.google.protobuf;
import com.google.protobuf.Descriptors.FieldDescriptor;
-
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -714,12 +713,14 @@ class MessageReflection {
}
/**
- * Parses a single field into MergeTarget. The target can be Message.Builder,
- * FieldSet or MutableMessage.
+ * Parses a single field into MergeTarget. The target can be Message.Builder, FieldSet or
+ * MutableMessage.
*
- * Package-private because it is used by GeneratedMessage.ExtendableMessage.
+ * <p>Package-private because it is used by GeneratedMessage.ExtendableMessage.
*
* @param tag The tag, which should have already been read.
+ * @param unknownFields If not null, unknown fields will be merged to this {@link
+ * UnknownFieldSet}, otherwise unknown fields will be discarded.
* @return {@code true} unless the tag is an end-group tag.
*/
static boolean mergeFieldFrom(
@@ -728,7 +729,8 @@ class MessageReflection {
ExtensionRegistryLite extensionRegistry,
Descriptors.Descriptor type,
MergeTarget target,
- int tag) throws IOException {
+ int tag)
+ throws IOException {
if (type.getOptions().getMessageSetWireFormat() &&
tag == WireFormat.MESSAGE_SET_ITEM_TAG) {
mergeMessageSetExtensionFromCodedStream(
@@ -792,7 +794,11 @@ class MessageReflection {
}
if (unknown) { // Unknown field or wrong wire type. Skip.
- return unknownFields.mergeFieldFrom(tag, input);
+ if (unknownFields != null) {
+ return unknownFields.mergeFieldFrom(tag, input);
+ } else {
+ return input.skipField(tag);
+ }
}
if (packed) {
@@ -844,7 +850,9 @@ class MessageReflection {
// If the number isn't recognized as a valid value for this enum,
// drop it.
if (value == null) {
- unknownFields.mergeVarintField(fieldNumber, rawValue);
+ if (unknownFields != null) {
+ unknownFields.mergeVarintField(fieldNumber, rawValue);
+ }
return true;
}
}
@@ -947,7 +955,7 @@ class MessageReflection {
mergeMessageSetExtensionFromBytes(
rawBytes, extension, extensionRegistry, target);
} else { // We don't know how to parse this. Ignore it.
- if (rawBytes != null) {
+ if (rawBytes != null && unknownFields != null) {
unknownFields.mergeField(typeId, UnknownFieldSet.Field.newBuilder()
.addLengthDelimited(rawBytes).build());
}
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 cfbcb442..e07c6895 100644
--- a/java/core/src/main/java/com/google/protobuf/Parser.java
+++ b/java/core/src/main/java/com/google/protobuf/Parser.java
@@ -31,6 +31,7 @@
package com.google.protobuf;
import java.io.InputStream;
+import java.nio.ByteBuffer;
/**
* Abstract interface for parsing Protocol Messages.
@@ -93,6 +94,18 @@ public interface Parser<MessageType> {
// Convenience methods.
/**
+ * Parses {@code data} as a message of {@code MessageType}. This is just a small wrapper around
+ * {@link #parseFrom(CodedInputStream)}.
+ */
+ public MessageType parseFrom(ByteBuffer data) throws InvalidProtocolBufferException;
+
+ /**
+ * Parses {@code data} as a message of {@code MessageType}. This is just a small wrapper around
+ * {@link #parseFrom(CodedInputStream, ExtensionRegistryLite)}.
+ */
+ public MessageType parseFrom(ByteBuffer data, ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException;
+ /**
* Parses {@code data} as a message of {@code MessageType}.
* This is just a small wrapper around {@link #parseFrom(CodedInputStream)}.
*/
diff --git a/java/core/src/main/java/com/google/protobuf/PrimitiveNonBoxingCollection.java b/java/core/src/main/java/com/google/protobuf/PrimitiveNonBoxingCollection.java
new file mode 100644
index 00000000..79b5769d
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/PrimitiveNonBoxingCollection.java
@@ -0,0 +1,34 @@
+// 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;
+
+/** A marker interface indicating that the collection supports primitives and is non-boxing. */
+interface PrimitiveNonBoxingCollection {}
diff --git a/java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilderV3.java b/java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilderV3.java
index 77b61b5f..30c991d4 100644
--- a/java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilderV3.java
+++ b/java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilderV3.java
@@ -30,6 +30,8 @@
package com.google.protobuf;
+import static com.google.protobuf.Internal.checkNotNull;
+
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Collection;
@@ -290,9 +292,7 @@ public class RepeatedFieldBuilderV3
*/
public RepeatedFieldBuilderV3<MType, BType, IType> setMessage(
int index, MType message) {
- if (message == null) {
- throw new NullPointerException();
- }
+ checkNotNull(message);
ensureMutableMessageList();
messages.set(index, message);
if (builders != null) {
@@ -315,9 +315,7 @@ public class RepeatedFieldBuilderV3
*/
public RepeatedFieldBuilderV3<MType, BType, IType> addMessage(
MType message) {
- if (message == null) {
- throw new NullPointerException();
- }
+ checkNotNull(message);
ensureMutableMessageList();
messages.add(message);
if (builders != null) {
@@ -339,9 +337,7 @@ public class RepeatedFieldBuilderV3
*/
public RepeatedFieldBuilderV3<MType, BType, IType> addMessage(
int index, MType message) {
- if (message == null) {
- throw new NullPointerException();
- }
+ checkNotNull(message);
ensureMutableMessageList();
messages.add(index, message);
if (builders != null) {
@@ -363,9 +359,7 @@ public class RepeatedFieldBuilderV3
public RepeatedFieldBuilderV3<MType, BType, IType> addAllMessages(
Iterable<? extends MType> values) {
for (final MType value : values) {
- if (value == null) {
- throw new NullPointerException();
- }
+ checkNotNull(value);
}
// If we can inspect the size, we can more efficiently add messages.
diff --git a/java/core/src/main/java/com/google/protobuf/SingleFieldBuilderV3.java b/java/core/src/main/java/com/google/protobuf/SingleFieldBuilderV3.java
index fb1f76a7..8ab0f26d 100644
--- a/java/core/src/main/java/com/google/protobuf/SingleFieldBuilderV3.java
+++ b/java/core/src/main/java/com/google/protobuf/SingleFieldBuilderV3.java
@@ -30,6 +30,8 @@
package com.google.protobuf;
+import static com.google.protobuf.Internal.checkNotNull;
+
/**
* {@code SingleFieldBuilderV3} implements a structure that a protocol
* message uses to hold a single field of another protocol message. It supports
@@ -84,10 +86,7 @@ public class SingleFieldBuilderV3
MType message,
AbstractMessage.BuilderParent parent,
boolean isClean) {
- if (message == null) {
- throw new NullPointerException();
- }
- this.message = message;
+ this.message = checkNotNull(message);
this.parent = parent;
this.isClean = isClean;
}
@@ -169,10 +168,7 @@ public class SingleFieldBuilderV3
*/
public SingleFieldBuilderV3<MType, BType, IType> setMessage(
MType message) {
- if (message == null) {
- throw new NullPointerException();
- }
- this.message = message;
+ this.message = checkNotNull(message);
if (builder != null) {
builder.dispose();
builder = null;
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 66033f58..279edc4d 100644
--- a/java/core/src/main/java/com/google/protobuf/SmallSortedMap.java
+++ b/java/core/src/main/java/com/google/protobuf/SmallSortedMap.java
@@ -540,8 +540,8 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> {
@Override
public boolean hasNext() {
- return (pos + 1) < entryList.size() ||
- getOverflowIterator().hasNext();
+ return (pos + 1) < entryList.size()
+ || (!overflowEntries.isEmpty() && getOverflowIterator().hasNext());
}
@Override
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 49708242..25c3474f 100644
--- a/java/core/src/main/java/com/google/protobuf/TextFormat.java
+++ b/java/core/src/main/java/com/google/protobuf/TextFormat.java
@@ -34,7 +34,6 @@ import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.EnumDescriptor;
import com.google.protobuf.Descriptors.EnumValueDescriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
-
import java.io.IOException;
import java.math.BigInteger;
import java.nio.CharBuffer;
@@ -56,14 +55,7 @@ import java.util.regex.Pattern;
public final class TextFormat {
private TextFormat() {}
- private static final Logger logger =
- Logger.getLogger(TextFormat.class.getName());
-
- private static final Printer DEFAULT_PRINTER = new Printer();
- private static final Printer SINGLE_LINE_PRINTER =
- (new Printer()).setSingleLineMode(true);
- private static final Printer UNICODE_PRINTER =
- (new Printer()).setEscapeNonAscii(false);
+ private static final Logger logger = Logger.getLogger(TextFormat.class.getName());
/**
* Outputs a textual representation of the Protocol Message supplied into
@@ -73,14 +65,14 @@ public final class TextFormat {
public static void print(
final MessageOrBuilder message, final Appendable output)
throws IOException {
- DEFAULT_PRINTER.print(message, new TextGenerator(output));
+ Printer.DEFAULT.print(message, multiLineOutput(output));
}
/** Outputs a textual representation of {@code fields} to {@code output}. */
public static void print(final UnknownFieldSet fields,
final Appendable output)
throws IOException {
- DEFAULT_PRINTER.printUnknownFields(fields, new TextGenerator(output));
+ Printer.DEFAULT.printUnknownFields(fields, multiLineOutput(output));
}
/**
@@ -90,7 +82,7 @@ public final class TextFormat {
public static void printUnicode(
final MessageOrBuilder message, final Appendable output)
throws IOException {
- UNICODE_PRINTER.print(message, new TextGenerator(output));
+ Printer.UNICODE.print(message, multiLineOutput(output));
}
/**
@@ -100,7 +92,7 @@ public final class TextFormat {
public static void printUnicode(final UnknownFieldSet fields,
final Appendable output)
throws IOException {
- UNICODE_PRINTER.printUnknownFields(fields, new TextGenerator(output));
+ Printer.UNICODE.printUnknownFields(fields, multiLineOutput(output));
}
/**
@@ -109,10 +101,9 @@ public final class TextFormat {
*/
public static String shortDebugString(final MessageOrBuilder message) {
try {
- final StringBuilder sb = new StringBuilder();
- SINGLE_LINE_PRINTER.print(message, new TextGenerator(sb));
- // Single line mode currently might have an extra space at the end.
- return sb.toString().trim();
+ final StringBuilder text = new StringBuilder();
+ Printer.DEFAULT.print(message, singleLineOutput(text));
+ return text.toString();
} catch (IOException e) {
throw new IllegalStateException(e);
}
@@ -125,11 +116,11 @@ public final class TextFormat {
public static String shortDebugString(final FieldDescriptor field,
final Object value) {
try {
- final StringBuilder sb = new StringBuilder();
- SINGLE_LINE_PRINTER.printField(field, value, new TextGenerator(sb));
- return sb.toString().trim();
+ final StringBuilder text = new StringBuilder();
+ Printer.DEFAULT.printField(field, value, singleLineOutput(text));
+ return text.toString();
} catch (IOException e) {
- throw new IllegalStateException(e);
+ throw new IllegalStateException(e);
}
}
@@ -139,10 +130,9 @@ public final class TextFormat {
*/
public static String shortDebugString(final UnknownFieldSet fields) {
try {
- final StringBuilder sb = new StringBuilder();
- SINGLE_LINE_PRINTER.printUnknownFields(fields, new TextGenerator(sb));
- // Single line mode currently might have an extra space at the end.
- return sb.toString().trim();
+ final StringBuilder text = new StringBuilder();
+ Printer.DEFAULT.printUnknownFields(fields, singleLineOutput(text));
+ return text.toString();
} catch (IOException e) {
throw new IllegalStateException(e);
}
@@ -183,7 +173,7 @@ public final class TextFormat {
public static String printToUnicodeString(final MessageOrBuilder message) {
try {
final StringBuilder text = new StringBuilder();
- UNICODE_PRINTER.print(message, new TextGenerator(text));
+ Printer.UNICODE.print(message, multiLineOutput(text));
return text.toString();
} catch (IOException e) {
throw new IllegalStateException(e);
@@ -197,7 +187,7 @@ public final class TextFormat {
public static String printToUnicodeString(final UnknownFieldSet fields) {
try {
final StringBuilder text = new StringBuilder();
- UNICODE_PRINTER.printUnknownFields(fields, new TextGenerator(text));
+ Printer.UNICODE.printUnknownFields(fields, multiLineOutput(text));
return text.toString();
} catch (IOException e) {
throw new IllegalStateException(e);
@@ -208,7 +198,7 @@ public final class TextFormat {
final Object value,
final Appendable output)
throws IOException {
- DEFAULT_PRINTER.printField(field, value, new TextGenerator(output));
+ Printer.DEFAULT.printField(field, value, multiLineOutput(output));
}
public static String printFieldToString(final FieldDescriptor field,
@@ -223,6 +213,23 @@ public final class TextFormat {
}
/**
+ * Outputs a unicode textual representation of the value of given field value.
+ *
+ * <p>Same as {@code printFieldValue()}, except that non-ASCII characters in string type fields
+ * are not escaped in backslash+octals.
+ *
+ * @param field the descriptor of the field
+ * @param value the value of the field
+ * @param output the output to which to append the formatted value
+ * @throws ClassCastException if the value is not appropriate for the given field descriptor
+ * @throws IOException if there is an exception writing to the output
+ */
+ public static void printUnicodeFieldValue(
+ final FieldDescriptor field, final Object value, final Appendable output) throws IOException {
+ Printer.UNICODE.printFieldValue(field, value, multiLineOutput(output));
+ }
+
+ /**
* Outputs a textual representation of the value of given field value.
*
* @param field the descriptor of the field
@@ -236,7 +243,7 @@ public final class TextFormat {
final Object value,
final Appendable output)
throws IOException {
- DEFAULT_PRINTER.printFieldValue(field, value, new TextGenerator(output));
+ Printer.DEFAULT.printFieldValue(field, value, multiLineOutput(output));
}
/**
@@ -253,7 +260,7 @@ public final class TextFormat {
final Object value,
final Appendable output)
throws IOException {
- printUnknownFieldValue(tag, value, new TextGenerator(output));
+ printUnknownFieldValue(tag, value, multiLineOutput(output));
}
private static void printUnknownFieldValue(final int tag,
@@ -272,12 +279,24 @@ public final class TextFormat {
generator.print(String.format((Locale) null, "0x%016x", (Long) value));
break;
case WireFormat.WIRETYPE_LENGTH_DELIMITED:
- generator.print("\"");
- generator.print(escapeBytes((ByteString) value));
- generator.print("\"");
+ try {
+ // Try to parse and print the field as an embedded message
+ UnknownFieldSet message = UnknownFieldSet.parseFrom((ByteString) value);
+ generator.print("{");
+ generator.eol();
+ generator.indent();
+ Printer.DEFAULT.printUnknownFields(message, generator);
+ generator.outdent();
+ generator.print("}");
+ } catch (InvalidProtocolBufferException e) {
+ // If not parseable as a message, print as a String
+ generator.print("\"");
+ generator.print(escapeBytes((ByteString) value));
+ generator.print("\"");
+ }
break;
case WireFormat.WIRETYPE_START_GROUP:
- DEFAULT_PRINTER.printUnknownFields((UnknownFieldSet) value, generator);
+ Printer.DEFAULT.printUnknownFields((UnknownFieldSet) value, generator);
break;
default:
throw new IllegalArgumentException("Bad tag: " + tag);
@@ -286,24 +305,16 @@ public final class TextFormat {
/** Helper class for converting protobufs to text. */
private static final class Printer {
- /** Whether to omit newlines from the output. */
- boolean singleLineMode = false;
+ // Printer instance which escapes non-ASCII characters.
+ static final Printer DEFAULT = new Printer(true);
+ // Printer instance which emits Unicode (it still escapes newlines and quotes in strings).
+ static final Printer UNICODE = new Printer(false);
/** Whether to escape non ASCII characters with backslash and octal. */
- boolean escapeNonAscii = true;
-
- private Printer() {}
-
- /** Setter of singleLineMode */
- private Printer setSingleLineMode(boolean singleLineMode) {
- this.singleLineMode = singleLineMode;
- return this;
- }
+ private final boolean escapeNonAscii;
- /** Setter of escapeNonAscii */
- private Printer setEscapeNonAscii(boolean escapeNonAscii) {
+ private Printer(boolean escapeNonAscii) {
this.escapeNonAscii = escapeNonAscii;
- return this;
}
private void print(
@@ -355,12 +366,9 @@ public final class TextFormat {
}
if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
- if (singleLineMode) {
- generator.print(" { ");
- } else {
- generator.print(" {\n");
- generator.indent();
- }
+ generator.print(" {");
+ generator.eol();
+ generator.indent();
} else {
generator.print(": ");
}
@@ -368,19 +376,10 @@ public final class TextFormat {
printFieldValue(field, value, generator);
if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
- if (singleLineMode) {
- generator.print("} ");
- } else {
- generator.outdent();
- generator.print("}\n");
- }
- } else {
- if (singleLineMode) {
- generator.print(" ");
- } else {
- generator.print("\n");
- }
+ generator.outdent();
+ generator.print("}");
}
+ generator.eol();
}
private void printFieldValue(final FieldDescriptor field,
@@ -469,19 +468,13 @@ public final class TextFormat {
field.getLengthDelimitedList(), generator);
for (final UnknownFieldSet value : field.getGroupList()) {
generator.print(entry.getKey().toString());
- if (singleLineMode) {
- generator.print(" { ");
- } else {
- generator.print(" {\n");
- generator.indent();
- }
+ generator.print(" {");
+ generator.eol();
+ generator.indent();
printUnknownFields(value, generator);
- if (singleLineMode) {
- generator.print("} ");
- } else {
- generator.outdent();
- generator.print("}\n");
- }
+ generator.outdent();
+ generator.print("}");
+ generator.eol();
}
}
}
@@ -495,7 +488,7 @@ public final class TextFormat {
generator.print(String.valueOf(number));
generator.print(": ");
printUnknownFieldValue(wireType, value, generator);
- generator.print(singleLineMode ? " " : "\n");
+ generator.eol();
}
}
}
@@ -521,16 +514,29 @@ public final class TextFormat {
}
}
- /**
+ private static TextGenerator multiLineOutput(Appendable output) {
+ return new TextGenerator(output, false);
+ }
+
+ private static TextGenerator singleLineOutput(Appendable output) {
+ return new TextGenerator(output, true);
+ }
+
+ /**
* An inner class for writing text to the output stream.
*/
private static final class TextGenerator {
private final Appendable output;
private final StringBuilder indent = new StringBuilder();
- private boolean atStartOfLine = true;
+ private final boolean singleLineMode;
+ // While technically we are "at the start of a line" at the very beginning of the output, all
+ // we would do in response to this is emit the (zero length) indentation, so it has no effect.
+ // Setting it false here does however suppress an unwanted leading space in single-line mode.
+ private boolean atStartOfLine = false;
- private TextGenerator(final Appendable output) {
+ private TextGenerator(final Appendable output, boolean singleLineMode) {
this.output = output;
+ this.singleLineMode = singleLineMode;
}
/**
@@ -552,35 +558,31 @@ public final class TextFormat {
throw new IllegalArgumentException(
" Outdent() without matching Indent().");
}
- indent.delete(length - 2, length);
+ indent.setLength(length - 2);
}
/**
- * Print text to the output stream.
+ * Print text to the output stream. Bare newlines are never expected to be passed to this
+ * method; to indicate the end of a line, call "eol()".
*/
public void print(final CharSequence text) throws IOException {
- final int size = text.length();
- int pos = 0;
-
- for (int i = 0; i < size; i++) {
- if (text.charAt(i) == '\n') {
- write(text.subSequence(pos, i + 1));
- pos = i + 1;
- atStartOfLine = true;
- }
+ if (atStartOfLine) {
+ atStartOfLine = false;
+ output.append(singleLineMode ? " " : indent);
}
- write(text.subSequence(pos, size));
+ output.append(text);
}
- private void write(final CharSequence data) throws IOException {
- if (data.length() == 0) {
- return;
- }
- if (atStartOfLine) {
- atStartOfLine = false;
- output.append(indent);
+ /**
+ * Signifies reaching the "end of the current line" in the output. In single-line mode, this
+ * does not result in a newline being emitted, but ensures that a separating space is written
+ * before the next output.
+ */
+ public void eol() throws IOException {
+ if (!singleLineMode) {
+ output.append("\n");
}
- output.append(data);
+ atStartOfLine = true;
}
}
@@ -985,7 +987,7 @@ public final class TextFormat {
nextToken();
return false;
} else {
- throw parseException("Expected \"true\" or \"false\".");
+ throw parseException("Expected \"true\" or \"false\". Found \"" + currentToken + "\".");
}
}
@@ -1222,6 +1224,22 @@ public final class TextFormat {
}
/**
+ * Parse a text-format message from {@code input}.
+ *
+ * @return the parsed message, guaranteed initialized
+ */
+ public static <T extends Message> T parse(final CharSequence input,
+ final Class<T> protoClass)
+ throws ParseException {
+ Message.Builder builder =
+ Internal.getDefaultInstance(protoClass).newBuilderForType();
+ merge(input, builder);
+ @SuppressWarnings("unchecked")
+ T output = (T) builder.build();
+ return output;
+ }
+
+ /**
* Parse a text-format message from {@code input} and merge the contents
* into {@code builder}. Extensions will be recognized if they are
* registered in {@code extensionRegistry}.
@@ -1246,6 +1264,25 @@ public final class TextFormat {
PARSER.merge(input, extensionRegistry, builder);
}
+ /**
+ * Parse a text-format message from {@code input}. Extensions will be
+ * recognized if they are registered in {@code extensionRegistry}.
+ *
+ * @return the parsed message, guaranteed initialized
+ */
+ public static <T extends Message> T parse(
+ final CharSequence input,
+ final ExtensionRegistry extensionRegistry,
+ final Class<T> protoClass)
+ throws ParseException {
+ Message.Builder builder =
+ Internal.getDefaultInstance(protoClass).newBuilderForType();
+ merge(input, extensionRegistry, builder);
+ @SuppressWarnings("unchecked")
+ T output = (T) builder.build();
+ return output;
+ }
+
/**
* Parser for text-format proto2 instances. This class is thread-safe.
@@ -1274,13 +1311,17 @@ public final class TextFormat {
}
private final boolean allowUnknownFields;
+ private final boolean allowUnknownEnumValues;
private final SingularOverwritePolicy singularOverwritePolicy;
private TextFormatParseInfoTree.Builder parseInfoTreeBuilder;
private Parser(
- boolean allowUnknownFields, SingularOverwritePolicy singularOverwritePolicy,
+ boolean allowUnknownFields,
+ boolean allowUnknownEnumValues,
+ SingularOverwritePolicy singularOverwritePolicy,
TextFormatParseInfoTree.Builder parseInfoTreeBuilder) {
this.allowUnknownFields = allowUnknownFields;
+ this.allowUnknownEnumValues = allowUnknownEnumValues;
this.singularOverwritePolicy = singularOverwritePolicy;
this.parseInfoTreeBuilder = parseInfoTreeBuilder;
}
@@ -1297,6 +1338,7 @@ public final class TextFormat {
*/
public static class Builder {
private boolean allowUnknownFields = false;
+ private boolean allowUnknownEnumValues = false;
private SingularOverwritePolicy singularOverwritePolicy =
SingularOverwritePolicy.ALLOW_SINGULAR_OVERWRITES;
private TextFormatParseInfoTree.Builder parseInfoTreeBuilder = null;
@@ -1318,7 +1360,10 @@ public final class TextFormat {
public Parser build() {
return new Parser(
- allowUnknownFields, singularOverwritePolicy, parseInfoTreeBuilder);
+ allowUnknownFields,
+ allowUnknownEnumValues,
+ singularOverwritePolicy,
+ parseInfoTreeBuilder);
}
}
@@ -1382,7 +1427,7 @@ public final class TextFormat {
return text;
}
- // Check both unknown fields and unknown extensions and log warming messages
+ // Check both unknown fields and unknown extensions and log warning messages
// or throw exceptions according to the flag.
private void checkUnknownFields(final List<String> unknownFields)
throws ParseException {
@@ -1442,7 +1487,7 @@ public final class TextFormat {
/**
* Parse a single field from {@code tokenizer} and merge it into
- * {@code builder}.
+ * {@code target}.
*/
private void mergeField(final Tokenizer tokenizer,
final ExtensionRegistry extensionRegistry,
@@ -1469,9 +1514,15 @@ public final class TextFormat {
extensionRegistry, name.toString());
if (extension == null) {
- unknownFields.add((tokenizer.getPreviousLine() + 1) + ":" +
- (tokenizer.getPreviousColumn() + 1) + ":\t" +
- type.getFullName() + ".[" + name + "]");
+ unknownFields.add(
+ (tokenizer.getPreviousLine() + 1)
+ + ":"
+ + (tokenizer.getPreviousColumn() + 1)
+ + ":\t"
+ + type.getFullName()
+ + ".["
+ + name
+ + "]");
} else {
if (extension.descriptor.getContainingType() != type) {
throw tokenizer.parseExceptionPreviousToken(
@@ -1506,9 +1557,14 @@ public final class TextFormat {
}
if (field == null) {
- unknownFields.add((tokenizer.getPreviousLine() + 1) + ":" +
- (tokenizer.getPreviousColumn() + 1) + ":\t" +
- type.getFullName() + "." + name);
+ unknownFields.add(
+ (tokenizer.getPreviousLine() + 1)
+ + ":"
+ + (tokenizer.getPreviousColumn() + 1)
+ + ":\t"
+ + type.getFullName()
+ + "."
+ + name);
}
}
@@ -1689,17 +1745,40 @@ public final class TextFormat {
final int number = tokenizer.consumeInt32();
value = enumType.findValueByNumber(number);
if (value == null) {
- throw tokenizer.parseExceptionPreviousToken(
- "Enum type \"" + enumType.getFullName()
- + "\" has no value with number " + number + '.');
+ String unknownValueMsg =
+ "Enum type \""
+ + enumType.getFullName()
+ + "\" has no value with number "
+ + number
+ + '.';
+ if (allowUnknownEnumValues) {
+ logger.warning(unknownValueMsg);
+ return;
+ } else {
+ throw tokenizer.parseExceptionPreviousToken(
+ "Enum type \""
+ + enumType.getFullName()
+ + "\" has no value with number "
+ + number
+ + '.');
+ }
}
} else {
final String id = tokenizer.consumeIdentifier();
value = enumType.findValueByName(id);
if (value == null) {
- throw tokenizer.parseExceptionPreviousToken(
- "Enum type \"" + enumType.getFullName()
- + "\" has no value named \"" + id + "\".");
+ String unknownValueMsg =
+ "Enum type \""
+ + enumType.getFullName()
+ + "\" has no value named \""
+ + id
+ + "\".";
+ if (allowUnknownEnumValues) {
+ logger.warning(unknownValueMsg);
+ return;
+ } else {
+ throw tokenizer.parseExceptionPreviousToken(unknownValueMsg);
+ }
}
}
@@ -1712,6 +1791,8 @@ public final class TextFormat {
}
if (field.isRepeated()) {
+ // TODO(b/29122459): If field.isMapField() and FORBID_SINGULAR_OVERWRITES mode,
+ // check for duplicate map keys here.
target.addRepeatedField(field, value);
} else if ((singularOverwritePolicy
== SingularOverwritePolicy.FORBID_SINGULAR_OVERWRITES)
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 2bef27e9..37d64633 100644
--- a/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java
+++ b/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java
@@ -91,7 +91,7 @@ public final class UnknownFieldSet implements MessageLite {
* Construct an {@code UnknownFieldSet} around the given map. The map is
* expected to be immutable.
*/
- private UnknownFieldSet(final Map<Integer, Field> fields,
+ UnknownFieldSet(final Map<Integer, Field> fields,
final Map<Integer, Field> fieldsDescending) {
this.fields = fields;
}
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 d6226fc7..f0b919ad 100644
--- a/java/core/src/main/java/com/google/protobuf/UnknownFieldSetLite.java
+++ b/java/core/src/main/java/com/google/protobuf/UnknownFieldSetLite.java
@@ -81,7 +81,7 @@ public final class UnknownFieldSetLite {
System.arraycopy(second.objects, 0, objects, first.count, second.count);
return new UnknownFieldSetLite(count, tags, objects, true /* isMutable */);
}
-
+
/**
* The number of elements in the set.
*/
@@ -295,14 +295,30 @@ public final class UnknownFieldSetLite {
return true;
}
+ private static int hashCode(int[] tags, int count) {
+ int hashCode = 17;
+ for (int i = 0; i < count; ++i) {
+ hashCode = 31 * hashCode + tags[i];
+ }
+ return hashCode;
+ }
+
+ private static int hashCode(Object[] objects, int count) {
+ int hashCode = 17;
+ for (int i = 0; i < count; ++i) {
+ hashCode = 31 * hashCode + objects[i].hashCode();
+ }
+ return hashCode;
+ }
+
@Override
public int hashCode() {
int hashCode = 17;
-
+
hashCode = 31 * hashCode + count;
- hashCode = 31 * hashCode + Arrays.hashCode(tags);
- hashCode = 31 * hashCode + Arrays.deepHashCode(objects);
-
+ hashCode = 31 * hashCode + hashCode(tags, count);
+ hashCode = 31 * hashCode + hashCode(objects, count);
+
return hashCode;
}
@@ -323,6 +339,7 @@ public final class UnknownFieldSetLite {
// Package private for unsafe experimental runtime.
void storeField(int tag, Object value) {
+ checkMutable();
ensureCapacity();
tags[count] = tag;
diff --git a/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java b/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java
index 5f7bafd6..d84ef3c5 100644
--- a/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java
+++ b/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java
@@ -35,17 +35,41 @@ import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;
-import sun.misc.Unsafe;
+import java.util.logging.Level;
+import java.util.logging.Logger;
/** Utility class for working with unsafe operations. */
-// TODO(nathanmittler): Add support for Android Memory/MemoryBlock
final class UnsafeUtil {
+ private static final Logger logger = Logger.getLogger(UnsafeUtil.class.getName());
private static final sun.misc.Unsafe UNSAFE = getUnsafe();
+ private static final MemoryAccessor MEMORY_ACCESSOR = getMemoryAccessor();
private static final boolean HAS_UNSAFE_BYTEBUFFER_OPERATIONS =
supportsUnsafeByteBufferOperations();
private static final boolean HAS_UNSAFE_ARRAY_OPERATIONS = supportsUnsafeArrayOperations();
- private static final long ARRAY_BASE_OFFSET = byteArrayBaseOffset();
- private static final long BUFFER_ADDRESS_OFFSET = fieldOffset(field(Buffer.class, "address"));
+
+ private static final long BYTE_ARRAY_BASE_OFFSET = arrayBaseOffset(byte[].class);
+ // Micro-optimization: we can assume a scale of 1 and skip the multiply
+ // private static final long BYTE_ARRAY_INDEX_SCALE = 1;
+
+ private static final long BOOLEAN_ARRAY_BASE_OFFSET = arrayBaseOffset(boolean[].class);
+ private static final long BOOLEAN_ARRAY_INDEX_SCALE = arrayIndexScale(boolean[].class);
+
+ private static final long INT_ARRAY_BASE_OFFSET = arrayBaseOffset(int[].class);
+ private static final long INT_ARRAY_INDEX_SCALE = arrayIndexScale(int[].class);
+
+ private static final long LONG_ARRAY_BASE_OFFSET = arrayBaseOffset(long[].class);
+ private static final long LONG_ARRAY_INDEX_SCALE = arrayIndexScale(long[].class);
+
+ private static final long FLOAT_ARRAY_BASE_OFFSET = arrayBaseOffset(float[].class);
+ private static final long FLOAT_ARRAY_INDEX_SCALE = arrayIndexScale(float[].class);
+
+ private static final long DOUBLE_ARRAY_BASE_OFFSET = arrayBaseOffset(double[].class);
+ private static final long DOUBLE_ARRAY_INDEX_SCALE = arrayIndexScale(double[].class);
+
+ private static final long OBJECT_ARRAY_BASE_OFFSET = arrayBaseOffset(Object[].class);
+ private static final long OBJECT_ARRAY_INDEX_SCALE = arrayIndexScale(Object[].class);
+
+ private static final long BUFFER_ADDRESS_OFFSET = fieldOffset(bufferAddressField());
private UnsafeUtil() {}
@@ -57,131 +81,193 @@ final class UnsafeUtil {
return HAS_UNSAFE_BYTEBUFFER_OPERATIONS;
}
- static Object allocateInstance(Class<?> clazz) {
- try {
- return UNSAFE.allocateInstance(clazz);
- } catch (InstantiationException e) {
- throw new RuntimeException(e);
- }
- }
static long objectFieldOffset(Field field) {
- return UNSAFE.objectFieldOffset(field);
+ return MEMORY_ACCESSOR.objectFieldOffset(field);
}
- static long getArrayBaseOffset() {
- return ARRAY_BASE_OFFSET;
+ private static int arrayBaseOffset(Class<?> clazz) {
+ return HAS_UNSAFE_ARRAY_OPERATIONS ? MEMORY_ACCESSOR.arrayBaseOffset(clazz) : -1;
+ }
+
+ private static int arrayIndexScale(Class<?> clazz) {
+ return HAS_UNSAFE_ARRAY_OPERATIONS ? MEMORY_ACCESSOR.arrayIndexScale(clazz) : -1;
}
static byte getByte(Object target, long offset) {
- return UNSAFE.getByte(target, offset);
+ return MEMORY_ACCESSOR.getByte(target, offset);
}
static void putByte(Object target, long offset, byte value) {
- UNSAFE.putByte(target, offset, value);
+ MEMORY_ACCESSOR.putByte(target, offset, value);
}
static int getInt(Object target, long offset) {
- return UNSAFE.getInt(target, offset);
+ return MEMORY_ACCESSOR.getInt(target, offset);
}
static void putInt(Object target, long offset, int value) {
- UNSAFE.putInt(target, offset, value);
+ MEMORY_ACCESSOR.putInt(target, offset, value);
}
static long getLong(Object target, long offset) {
- return UNSAFE.getLong(target, offset);
+ return MEMORY_ACCESSOR.getLong(target, offset);
}
static void putLong(Object target, long offset, long value) {
- UNSAFE.putLong(target, offset, value);
+ MEMORY_ACCESSOR.putLong(target, offset, value);
}
static boolean getBoolean(Object target, long offset) {
- return UNSAFE.getBoolean(target, offset);
+ return MEMORY_ACCESSOR.getBoolean(target, offset);
}
static void putBoolean(Object target, long offset, boolean value) {
- UNSAFE.putBoolean(target, offset, value);
+ MEMORY_ACCESSOR.putBoolean(target, offset, value);
}
static float getFloat(Object target, long offset) {
- return UNSAFE.getFloat(target, offset);
+ return MEMORY_ACCESSOR.getFloat(target, offset);
}
static void putFloat(Object target, long offset, float value) {
- UNSAFE.putFloat(target, offset, value);
+ MEMORY_ACCESSOR.putFloat(target, offset, value);
}
static double getDouble(Object target, long offset) {
- return UNSAFE.getDouble(target, offset);
+ return MEMORY_ACCESSOR.getDouble(target, offset);
}
static void putDouble(Object target, long offset, double value) {
- UNSAFE.putDouble(target, offset, value);
+ MEMORY_ACCESSOR.putDouble(target, offset, value);
}
static Object getObject(Object target, long offset) {
- return UNSAFE.getObject(target, offset);
+ return MEMORY_ACCESSOR.getObject(target, offset);
+ }
+
+ static byte getByte(byte[] target, long index) {
+ return MEMORY_ACCESSOR.getByte(target, BYTE_ARRAY_BASE_OFFSET + index);
+ }
+
+ static void putByte(byte[] target, long index, byte value) {
+ MEMORY_ACCESSOR.putByte(target, BYTE_ARRAY_BASE_OFFSET + index, value);
+ }
+
+ static int getInt(int[] target, long index) {
+ return MEMORY_ACCESSOR.getInt(target, INT_ARRAY_BASE_OFFSET + (index * INT_ARRAY_INDEX_SCALE));
+ }
+
+ static void putInt(int[] target, long index, int value) {
+ MEMORY_ACCESSOR.putInt(target, INT_ARRAY_BASE_OFFSET + (index * INT_ARRAY_INDEX_SCALE), value);
+ }
+
+ static long getLong(long[] target, long index) {
+ return MEMORY_ACCESSOR.getLong(
+ target, LONG_ARRAY_BASE_OFFSET + (index * LONG_ARRAY_INDEX_SCALE));
+ }
+
+ static void putLong(long[] target, long index, long value) {
+ MEMORY_ACCESSOR.putLong(
+ target, LONG_ARRAY_BASE_OFFSET + (index * LONG_ARRAY_INDEX_SCALE), value);
+ }
+
+ static boolean getBoolean(boolean[] target, long index) {
+ return MEMORY_ACCESSOR.getBoolean(
+ target, BOOLEAN_ARRAY_BASE_OFFSET + (index * BOOLEAN_ARRAY_INDEX_SCALE));
}
- static void putObject(Object target, long offset, Object value) {
- UNSAFE.putObject(target, offset, value);
+ static void putBoolean(boolean[] target, long index, boolean value) {
+ MEMORY_ACCESSOR.putBoolean(
+ target, BOOLEAN_ARRAY_BASE_OFFSET + (index * BOOLEAN_ARRAY_INDEX_SCALE), value);
}
- static void copyMemory(
- Object src, long srcOffset, Object target, long targetOffset, long length) {
- UNSAFE.copyMemory(src, srcOffset, target, targetOffset, length);
+ static float getFloat(float[] target, long index) {
+ return MEMORY_ACCESSOR.getFloat(
+ target, FLOAT_ARRAY_BASE_OFFSET + (index * FLOAT_ARRAY_INDEX_SCALE));
+ }
+
+ static void putFloat(float[] target, long index, float value) {
+ MEMORY_ACCESSOR.putFloat(
+ target, FLOAT_ARRAY_BASE_OFFSET + (index * FLOAT_ARRAY_INDEX_SCALE), value);
+ }
+
+ static double getDouble(double[] target, long index) {
+ return MEMORY_ACCESSOR.getDouble(
+ target, DOUBLE_ARRAY_BASE_OFFSET + (index * DOUBLE_ARRAY_INDEX_SCALE));
+ }
+
+ static void putDouble(double[] target, long index, double value) {
+ MEMORY_ACCESSOR.putDouble(
+ target, DOUBLE_ARRAY_BASE_OFFSET + (index * DOUBLE_ARRAY_INDEX_SCALE), value);
+ }
+
+ static Object getObject(Object[] target, long index) {
+ return MEMORY_ACCESSOR.getObject(
+ target, OBJECT_ARRAY_BASE_OFFSET + (index * OBJECT_ARRAY_INDEX_SCALE));
+ }
+
+ static void putObject(Object[] target, long index, Object value) {
+ MEMORY_ACCESSOR.putObject(
+ target, OBJECT_ARRAY_BASE_OFFSET + (index * OBJECT_ARRAY_INDEX_SCALE), value);
+ }
+
+ static void copyMemory(byte[] src, long srcIndex, long targetOffset, long length) {
+ MEMORY_ACCESSOR.copyMemory(src, srcIndex, targetOffset, length);
+ }
+
+ static void copyMemory(long srcOffset, byte[] target, long targetIndex, long length) {
+ MEMORY_ACCESSOR.copyMemory(srcOffset, target, targetIndex, length);
+ }
+
+ static void copyMemory(byte[] src, long srcIndex, byte[] target, long targetIndex, long length) {
+ System.arraycopy(src, (int) srcIndex, target, (int) targetIndex, (int) length);
}
static byte getByte(long address) {
- return UNSAFE.getByte(address);
+ return MEMORY_ACCESSOR.getByte(address);
}
static void putByte(long address, byte value) {
- UNSAFE.putByte(address, value);
+ MEMORY_ACCESSOR.putByte(address, value);
}
static int getInt(long address) {
- return UNSAFE.getInt(address);
+ return MEMORY_ACCESSOR.getInt(address);
}
static void putInt(long address, int value) {
- UNSAFE.putInt(address, value);
+ MEMORY_ACCESSOR.putInt(address, value);
}
static long getLong(long address) {
- return UNSAFE.getLong(address);
+ return MEMORY_ACCESSOR.getLong(address);
}
static void putLong(long address, long value) {
- UNSAFE.putLong(address, value);
- }
-
- static void copyMemory(long srcAddress, long targetAddress, long length) {
- UNSAFE.copyMemory(srcAddress, targetAddress, length);
- }
-
- static void setMemory(long address, long numBytes, byte value) {
- UNSAFE.setMemory(address, numBytes, value);
+ MEMORY_ACCESSOR.putLong(address, value);
}
/**
* Gets the offset of the {@code address} field of the given direct {@link ByteBuffer}.
*/
static long addressOffset(ByteBuffer buffer) {
- return UNSAFE.getLong(buffer, BUFFER_ADDRESS_OFFSET);
+ return MEMORY_ACCESSOR.getLong(buffer, BUFFER_ADDRESS_OFFSET);
+ }
+
+ static Object getStaticObject(Field field) {
+ return MEMORY_ACCESSOR.getStaticObject(field);
}
/**
* Gets the {@code sun.misc.Unsafe} instance, or {@code null} if not available on this platform.
*/
- private static sun.misc.Unsafe getUnsafe() {
+ static sun.misc.Unsafe getUnsafe() {
sun.misc.Unsafe unsafe = null;
try {
unsafe =
AccessController.doPrivileged(
- new PrivilegedExceptionAction<Unsafe>() {
+ new PrivilegedExceptionAction<sun.misc.Unsafe>() {
@Override
public sun.misc.Unsafe run() throws Exception {
Class<sun.misc.Unsafe> k = sun.misc.Unsafe.class;
@@ -204,69 +290,90 @@ final class UnsafeUtil {
return unsafe;
}
+ /** Get a {@link MemoryAccessor} appropriate for the platform, or null if not supported. */
+ private static MemoryAccessor getMemoryAccessor() {
+ if (UNSAFE == null) {
+ return null;
+ }
+ return new JvmMemoryAccessor(UNSAFE);
+ }
+
/** Indicates whether or not unsafe array operations are supported on this platform. */
private static boolean supportsUnsafeArrayOperations() {
- boolean supported = false;
- if (UNSAFE != null) {
- try {
- Class<?> clazz = UNSAFE.getClass();
- clazz.getMethod("objectFieldOffset", Field.class);
- clazz.getMethod("allocateInstance", Class.class);
- clazz.getMethod("arrayBaseOffset", Class.class);
- clazz.getMethod("getByte", Object.class, long.class);
- clazz.getMethod("putByte", Object.class, long.class, byte.class);
- clazz.getMethod("getBoolean", Object.class, long.class);
- clazz.getMethod("putBoolean", Object.class, long.class, boolean.class);
- clazz.getMethod("getInt", Object.class, long.class);
- clazz.getMethod("putInt", Object.class, long.class, int.class);
- clazz.getMethod("getLong", Object.class, long.class);
- clazz.getMethod("putLong", Object.class, long.class, long.class);
- clazz.getMethod("getFloat", Object.class, long.class);
- clazz.getMethod("putFloat", Object.class, long.class, float.class);
- clazz.getMethod("getDouble", Object.class, long.class);
- clazz.getMethod("putDouble", Object.class, long.class, double.class);
- clazz.getMethod("getObject", Object.class, long.class);
- clazz.getMethod("putObject", Object.class, long.class, Object.class);
- clazz.getMethod(
- "copyMemory", Object.class, long.class, Object.class, long.class, long.class);
- supported = true;
- } catch (Throwable e) {
- // Do nothing.
- }
+ if (UNSAFE == null) {
+ return false;
}
- return supported;
+ try {
+ Class<?> clazz = UNSAFE.getClass();
+ clazz.getMethod("objectFieldOffset", Field.class);
+ clazz.getMethod("arrayBaseOffset", Class.class);
+ clazz.getMethod("arrayIndexScale", Class.class);
+ clazz.getMethod("getInt", Object.class, long.class);
+ clazz.getMethod("putInt", Object.class, long.class, int.class);
+ clazz.getMethod("getLong", Object.class, long.class);
+ clazz.getMethod("putLong", Object.class, long.class, long.class);
+ clazz.getMethod("getObject", Object.class, long.class);
+ clazz.getMethod("putObject", Object.class, long.class, Object.class);
+ clazz.getMethod("getByte", Object.class, long.class);
+ clazz.getMethod("putByte", Object.class, long.class, byte.class);
+ clazz.getMethod("getBoolean", Object.class, long.class);
+ clazz.getMethod("putBoolean", Object.class, long.class, boolean.class);
+ clazz.getMethod("getFloat", Object.class, long.class);
+ clazz.getMethod("putFloat", Object.class, long.class, float.class);
+ clazz.getMethod("getDouble", Object.class, long.class);
+ clazz.getMethod("putDouble", Object.class, long.class, double.class);
+
+ return true;
+ } catch (Throwable e) {
+ logger.log(
+ Level.WARNING,
+ "platform method missing - proto runtime falling back to safer methods: " + e);
+ }
+ return false;
}
private static boolean supportsUnsafeByteBufferOperations() {
- boolean supported = false;
- if (UNSAFE != null) {
- try {
- Class<?> clazz = UNSAFE.getClass();
- // Methods for getting direct buffer address.
- clazz.getMethod("objectFieldOffset", Field.class);
- clazz.getMethod("getLong", Object.class, long.class);
-
- clazz.getMethod("getByte", long.class);
- clazz.getMethod("putByte", long.class, byte.class);
- clazz.getMethod("getInt", long.class);
- clazz.getMethod("putInt", long.class, int.class);
- clazz.getMethod("getLong", long.class);
- clazz.getMethod("putLong", long.class, long.class);
- clazz.getMethod("setMemory", long.class, long.class, byte.class);
- clazz.getMethod("copyMemory", long.class, long.class, long.class);
- supported = true;
- } catch (Throwable e) {
- // Do nothing.
+ if (UNSAFE == null) {
+ return false;
+ }
+ try {
+ Class<?> clazz = UNSAFE.getClass();
+ // Methods for getting direct buffer address.
+ clazz.getMethod("objectFieldOffset", Field.class);
+ clazz.getMethod("getLong", Object.class, long.class);
+
+ if (bufferAddressField() == null) {
+ return false;
}
+
+ clazz.getMethod("getByte", long.class);
+ clazz.getMethod("putByte", long.class, byte.class);
+ clazz.getMethod("getInt", long.class);
+ clazz.getMethod("putInt", long.class, int.class);
+ clazz.getMethod("getLong", long.class);
+ clazz.getMethod("putLong", long.class, long.class);
+ clazz.getMethod("copyMemory", long.class, long.class, long.class);
+ clazz.getMethod("copyMemory", Object.class, long.class, Object.class, long.class, long.class);
+ return true;
+ } catch (Throwable e) {
+ logger.log(
+ Level.WARNING,
+ "platform method missing - proto runtime falling back to safer methods: " + e);
}
- return supported;
+ return false;
}
- /**
- * Get the base offset for byte arrays, or {@code -1} if {@code sun.misc.Unsafe} is not available.
- */
- private static int byteArrayBaseOffset() {
- return HAS_UNSAFE_ARRAY_OPERATIONS ? UNSAFE.arrayBaseOffset(byte[].class) : -1;
+
+ /** Finds the address field within a direct {@link Buffer}. */
+ private static Field bufferAddressField() {
+ Field field = field(Buffer.class, "address");
+ return field != null && field.getType() == long.class ? field : null;
+ }
+
+ /** Finds the value field within a {@link String}. */
+ private static Field stringValueField() {
+ Field field = field(String.class, "value");
+ return field != null && field.getType() == char[].class ? field : null;
}
/**
@@ -274,7 +381,7 @@ final class UnsafeUtil {
* available.
*/
private static long fieldOffset(Field field) {
- return field == null || UNSAFE == null ? -1 : UNSAFE.objectFieldOffset(field);
+ return field == null || MEMORY_ACCESSOR == null ? -1 : MEMORY_ACCESSOR.objectFieldOffset(field);
}
/**
@@ -292,4 +399,176 @@ final class UnsafeUtil {
}
return field;
}
+
+ private abstract static class MemoryAccessor {
+
+ sun.misc.Unsafe unsafe;
+
+ MemoryAccessor(sun.misc.Unsafe unsafe) {
+ this.unsafe = unsafe;
+ }
+
+ public final long objectFieldOffset(Field field) {
+ return unsafe.objectFieldOffset(field);
+ }
+
+ public abstract byte getByte(Object target, long offset);
+
+ public abstract void putByte(Object target, long offset, byte value);
+
+ public final int getInt(Object target, long offset) {
+ return unsafe.getInt(target, offset);
+ }
+
+ public final void putInt(Object target, long offset, int value) {
+ unsafe.putInt(target, offset, value);
+ }
+
+ public final long getLong(Object target, long offset) {
+ return unsafe.getLong(target, offset);
+ }
+
+ public final void putLong(Object target, long offset, long value) {
+ unsafe.putLong(target, offset, value);
+ }
+
+ public abstract boolean getBoolean(Object target, long offset);
+
+ public abstract void putBoolean(Object target, long offset, boolean value);
+
+ public abstract float getFloat(Object target, long offset);
+
+ public abstract void putFloat(Object target, long offset, float value);
+
+ public abstract double getDouble(Object target, long offset);
+
+ public abstract void putDouble(Object target, long offset, double value);
+
+ public final Object getObject(Object target, long offset) {
+ return unsafe.getObject(target, offset);
+ }
+
+ public final void putObject(Object target, long offset, Object value) {
+ unsafe.putObject(target, offset, value);
+ }
+
+ public final int arrayBaseOffset(Class<?> clazz) {
+ return unsafe.arrayBaseOffset(clazz);
+ }
+
+ public final int arrayIndexScale(Class<?> clazz) {
+ return unsafe.arrayIndexScale(clazz);
+ }
+
+ public abstract byte getByte(long address);
+
+ public abstract void putByte(long address, byte value);
+
+ public abstract int getInt(long address);
+
+ public abstract void putInt(long address, int value);
+
+ public abstract long getLong(long address);
+
+ public abstract void putLong(long address, long value);
+
+ public abstract Object getStaticObject(Field field);
+
+ public abstract void copyMemory(long srcOffset, byte[] target, long targetIndex, long length);
+
+ public abstract void copyMemory(byte[] src, long srcIndex, long targetOffset, long length);
+ }
+
+ private static final class JvmMemoryAccessor extends MemoryAccessor {
+
+ JvmMemoryAccessor(sun.misc.Unsafe unsafe) {
+ super(unsafe);
+ }
+
+ @Override
+ public byte getByte(long address) {
+ return unsafe.getByte(address);
+ }
+
+ @Override
+ public void putByte(long address, byte value) {
+ unsafe.putByte(address, value);
+ }
+
+ @Override
+ public int getInt(long address) {
+ return unsafe.getInt(address);
+ }
+
+ @Override
+ public void putInt(long address, int value) {
+ unsafe.putInt(address, value);
+ }
+
+ @Override
+ public long getLong(long address) {
+ return unsafe.getLong(address);
+ }
+
+ @Override
+ public void putLong(long address, long value) {
+ unsafe.putLong(address, value);
+ }
+
+ @Override
+ public byte getByte(Object target, long offset) {
+ return unsafe.getByte(target, offset);
+ }
+
+ @Override
+ public void putByte(Object target, long offset, byte value) {
+ unsafe.putByte(target, offset, value);
+ }
+
+ @Override
+ public boolean getBoolean(Object target, long offset) {
+ return unsafe.getBoolean(target, offset);
+ }
+
+ @Override
+ public void putBoolean(Object target, long offset, boolean value) {
+ unsafe.putBoolean(target, offset, value);
+ }
+
+ @Override
+ public float getFloat(Object target, long offset) {
+ return unsafe.getFloat(target, offset);
+ }
+
+ @Override
+ public void putFloat(Object target, long offset, float value) {
+ unsafe.putFloat(target, offset, value);
+ }
+
+ @Override
+ public double getDouble(Object target, long offset) {
+ return unsafe.getDouble(target, offset);
+ }
+
+ @Override
+ public void putDouble(Object target, long offset, double value) {
+ unsafe.putDouble(target, offset, value);
+ }
+
+ @Override
+ public void copyMemory(long srcOffset, byte[] target, long targetIndex, long length) {
+ unsafe.copyMemory(null, srcOffset, target, BYTE_ARRAY_BASE_OFFSET + targetIndex, length);
+ }
+
+ @Override
+ public void copyMemory(byte[] src, long srcIndex, long targetOffset, long length) {
+ unsafe.copyMemory(src, BYTE_ARRAY_BASE_OFFSET + srcIndex, null, targetOffset, length);
+ }
+
+ @Override
+ public Object getStaticObject(Field field) {
+ return getObject(unsafe.staticFieldBase(field), unsafe.staticFieldOffset(field));
+ }
+ }
+
}
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 5b80d405..de75fe6b 100644
--- a/java/core/src/main/java/com/google/protobuf/Utf8.java
+++ b/java/core/src/main/java/com/google/protobuf/Utf8.java
@@ -31,15 +31,18 @@
package com.google.protobuf;
import static com.google.protobuf.UnsafeUtil.addressOffset;
-import static com.google.protobuf.UnsafeUtil.getArrayBaseOffset;
import static com.google.protobuf.UnsafeUtil.hasUnsafeArrayOperations;
import static com.google.protobuf.UnsafeUtil.hasUnsafeByteBufferOperations;
import static java.lang.Character.MAX_SURROGATE;
+import static java.lang.Character.MIN_HIGH_SURROGATE;
+import static java.lang.Character.MIN_LOW_SURROGATE;
+import static java.lang.Character.MIN_SUPPLEMENTARY_CODE_POINT;
import static java.lang.Character.MIN_SURROGATE;
import static java.lang.Character.isSurrogatePair;
import static java.lang.Character.toCodePoint;
import java.nio.ByteBuffer;
+import java.util.Arrays;
/**
* A set of low-level, high-performance static utility methods related
@@ -290,7 +293,7 @@ final class Utf8 {
if (Character.MIN_SURROGATE <= c && c <= Character.MAX_SURROGATE) {
// Check that we have a well-formed surrogate pair.
int cp = Character.codePointAt(sequence, i);
- if (cp < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
+ if (cp < MIN_SUPPLEMENTARY_CODE_POINT) {
throw new UnpairedSurrogateException(i, utf16Length);
}
i++;
@@ -332,6 +335,26 @@ final class Utf8 {
}
/**
+ * Decodes the given UTF-8 portion of the {@link ByteBuffer} into a {@link String}.
+ *
+ * @throws InvalidProtocolBufferException if the input is not valid UTF-8.
+ */
+ static String decodeUtf8(ByteBuffer buffer, int index, int size)
+ throws InvalidProtocolBufferException {
+ return processor.decodeUtf8(buffer, index, size);
+ }
+
+ /**
+ * Decodes the given UTF-8 encoded byte array slice into a {@link String}.
+ *
+ * @throws InvalidProtocolBufferException if the input is not valid UTF-8.
+ */
+ static String decodeUtf8(byte[] bytes, int index, int size)
+ throws InvalidProtocolBufferException {
+ return processor.decodeUtf8(bytes, index, size);
+ }
+
+ /**
* 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)
@@ -611,6 +634,116 @@ final class Utf8 {
}
/**
+ * Decodes the given byte array slice into a {@link String}.
+ *
+ * @throws InvalidProtocolBufferException if the byte array slice is not valid UTF-8.
+ */
+ abstract String decodeUtf8(byte[] bytes, int index, int size)
+ throws InvalidProtocolBufferException;
+
+ /**
+ * Decodes the given portion of the {@link ByteBuffer} into a {@link String}.
+ *
+ * @throws InvalidProtocolBufferException if the portion of the buffer is not valid UTF-8.
+ */
+ final String decodeUtf8(ByteBuffer buffer, int index, int size)
+ throws InvalidProtocolBufferException {
+ if (buffer.hasArray()) {
+ final int offset = buffer.arrayOffset();
+ return decodeUtf8(buffer.array(), offset + index, size);
+ } else if (buffer.isDirect()) {
+ return decodeUtf8Direct(buffer, index, size);
+ }
+ return decodeUtf8Default(buffer, index, size);
+ }
+
+ /**
+ * Decodes direct {@link ByteBuffer} instances into {@link String}.
+ */
+ abstract String decodeUtf8Direct(ByteBuffer buffer, int index, int size)
+ throws InvalidProtocolBufferException;
+
+ /**
+ * Decodes {@link ByteBuffer} instances using the {@link ByteBuffer} API rather than
+ * potentially faster approaches.
+ */
+ final String decodeUtf8Default(ByteBuffer buffer, int index, int size)
+ throws InvalidProtocolBufferException {
+ // Bitwise OR combines the sign bits so any negative value fails the check.
+ if ((index | size | buffer.limit() - index - size) < 0) {
+ throw new ArrayIndexOutOfBoundsException(
+ String.format("buffer limit=%d, index=%d, limit=%d", buffer.limit(), index, size));
+ }
+
+ int offset = index;
+ final int limit = offset + size;
+
+ // The longest possible resulting String is the same as the number of input bytes, when it is
+ // all ASCII. For other cases, this over-allocates and we will truncate in the end.
+ char[] resultArr = new char[size];
+ int resultPos = 0;
+
+ // 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 (offset < limit) {
+ byte b = buffer.get(offset);
+ if (!DecodeUtil.isOneByte(b)) {
+ break;
+ }
+ offset++;
+ DecodeUtil.handleOneByte(b, resultArr, resultPos++);
+ }
+
+ while (offset < limit) {
+ byte byte1 = buffer.get(offset++);
+ if (DecodeUtil.isOneByte(byte1)) {
+ DecodeUtil.handleOneByte(byte1, resultArr, resultPos++);
+ // It's common for there to be multiple ASCII characters in a run mixed in, so add an
+ // extra optimized loop to take care of these runs.
+ while (offset < limit) {
+ byte b = buffer.get(offset);
+ if (!DecodeUtil.isOneByte(b)) {
+ break;
+ }
+ offset++;
+ DecodeUtil.handleOneByte(b, resultArr, resultPos++);
+ }
+ } else if (DecodeUtil.isTwoBytes(byte1)) {
+ if (offset >= limit) {
+ throw InvalidProtocolBufferException.invalidUtf8();
+ }
+ DecodeUtil.handleTwoBytes(
+ byte1, /* byte2 */ buffer.get(offset++), resultArr, resultPos++);
+ } else if (DecodeUtil.isThreeBytes(byte1)) {
+ if (offset >= limit - 1) {
+ throw InvalidProtocolBufferException.invalidUtf8();
+ }
+ DecodeUtil.handleThreeBytes(
+ byte1,
+ /* byte2 */ buffer.get(offset++),
+ /* byte3 */ buffer.get(offset++),
+ resultArr,
+ resultPos++);
+ } else {
+ if (offset >= limit - 2) {
+ throw InvalidProtocolBufferException.invalidUtf8();
+ }
+ DecodeUtil.handleFourBytes(
+ byte1,
+ /* byte2 */ buffer.get(offset++),
+ /* byte3 */ buffer.get(offset++),
+ /* byte4 */ buffer.get(offset++),
+ resultArr,
+ resultPos++);
+ // 4-byte case requires two chars.
+ resultPos++;
+ }
+ }
+
+ return new String(resultArr, 0, resultPos);
+ }
+
+ /**
* 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
@@ -852,6 +985,88 @@ final class Utf8 {
}
@Override
+ String decodeUtf8(byte[] bytes, int index, int size) throws InvalidProtocolBufferException {
+ // Bitwise OR combines the sign bits so any negative value fails the check.
+ if ((index | size | bytes.length - index - size) < 0) {
+ throw new ArrayIndexOutOfBoundsException(
+ String.format("buffer length=%d, index=%d, size=%d", bytes.length, index, size));
+ }
+
+ int offset = index;
+ final int limit = offset + size;
+
+ // The longest possible resulting String is the same as the number of input bytes, when it is
+ // all ASCII. For other cases, this over-allocates and we will truncate in the end.
+ char[] resultArr = new char[size];
+ int resultPos = 0;
+
+ // 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 (offset < limit) {
+ byte b = bytes[offset];
+ if (!DecodeUtil.isOneByte(b)) {
+ break;
+ }
+ offset++;
+ DecodeUtil.handleOneByte(b, resultArr, resultPos++);
+ }
+
+ while (offset < limit) {
+ byte byte1 = bytes[offset++];
+ if (DecodeUtil.isOneByte(byte1)) {
+ DecodeUtil.handleOneByte(byte1, resultArr, resultPos++);
+ // It's common for there to be multiple ASCII characters in a run mixed in, so add an
+ // extra optimized loop to take care of these runs.
+ while (offset < limit) {
+ byte b = bytes[offset];
+ if (!DecodeUtil.isOneByte(b)) {
+ break;
+ }
+ offset++;
+ DecodeUtil.handleOneByte(b, resultArr, resultPos++);
+ }
+ } else if (DecodeUtil.isTwoBytes(byte1)) {
+ if (offset >= limit) {
+ throw InvalidProtocolBufferException.invalidUtf8();
+ }
+ DecodeUtil.handleTwoBytes(byte1, /* byte2 */ bytes[offset++], resultArr, resultPos++);
+ } else if (DecodeUtil.isThreeBytes(byte1)) {
+ if (offset >= limit - 1) {
+ throw InvalidProtocolBufferException.invalidUtf8();
+ }
+ DecodeUtil.handleThreeBytes(
+ byte1,
+ /* byte2 */ bytes[offset++],
+ /* byte3 */ bytes[offset++],
+ resultArr,
+ resultPos++);
+ } else {
+ if (offset >= limit - 2) {
+ throw InvalidProtocolBufferException.invalidUtf8();
+ }
+ DecodeUtil.handleFourBytes(
+ byte1,
+ /* byte2 */ bytes[offset++],
+ /* byte3 */ bytes[offset++],
+ /* byte4 */ bytes[offset++],
+ resultArr,
+ resultPos++);
+ // 4-byte case requires two chars.
+ resultPos++;
+ }
+ }
+
+ return new String(resultArr, 0, resultPos);
+ }
+
+ @Override
+ String decodeUtf8Direct(ByteBuffer buffer, int index, int size)
+ throws InvalidProtocolBufferException {
+ // For safe processing, we have to use the ByteBufferAPI.
+ return decodeUtf8Default(buffer, index, size);
+ }
+
+ @Override
int encodeUtf8(CharSequence in, byte[] out, int offset, int length) {
int utf16Length = in.length();
int j = offset;
@@ -997,12 +1212,13 @@ final class Utf8 {
@Override
int partialIsValidUtf8(int state, byte[] bytes, final int index, final int limit) {
+ // Bitwise OR combines the sign bits so any negative value fails the check.
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 = getArrayBaseOffset() + index;
- final long offsetLimit = getArrayBaseOffset() + limit;
+ long offset = index;
+ final long offsetLimit = limit;
if (state != COMPLETE) {
// The previous decoding operation was incomplete (or malformed).
// We look for a well-formed sequence consisting of bytes from
@@ -1092,6 +1308,7 @@ final class Utf8 {
@Override
int partialIsValidUtf8Direct(
final int state, ByteBuffer buffer, final int index, final int limit) {
+ // Bitwise OR combines the sign bits so any negative value fails the check.
if ((index | limit | buffer.limit() - limit) < 0) {
throw new ArrayIndexOutOfBoundsException(
String.format("buffer limit=%d, index=%d, limit=%d", buffer.limit(), index, limit));
@@ -1186,8 +1403,159 @@ final class Utf8 {
}
@Override
+ String decodeUtf8(byte[] bytes, int index, int size) throws InvalidProtocolBufferException {
+ if ((index | size | bytes.length - index - size) < 0) {
+ throw new ArrayIndexOutOfBoundsException(
+ String.format("buffer length=%d, index=%d, size=%d", bytes.length, index, size));
+ }
+
+ int offset = index;
+ final int limit = offset + size;
+
+ // The longest possible resulting String is the same as the number of input bytes, when it is
+ // all ASCII. For other cases, this over-allocates and we will truncate in the end.
+ char[] resultArr = new char[size];
+ int resultPos = 0;
+
+ // 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 (offset < limit) {
+ byte b = UnsafeUtil.getByte(bytes, offset);
+ if (!DecodeUtil.isOneByte(b)) {
+ break;
+ }
+ offset++;
+ DecodeUtil.handleOneByte(b, resultArr, resultPos++);
+ }
+
+ while (offset < limit) {
+ byte byte1 = UnsafeUtil.getByte(bytes, offset++);
+ if (DecodeUtil.isOneByte(byte1)) {
+ DecodeUtil.handleOneByte(byte1, resultArr, resultPos++);
+ // It's common for there to be multiple ASCII characters in a run mixed in, so add an
+ // extra optimized loop to take care of these runs.
+ while (offset < limit) {
+ byte b = UnsafeUtil.getByte(bytes, offset);
+ if (!DecodeUtil.isOneByte(b)) {
+ break;
+ }
+ offset++;
+ DecodeUtil.handleOneByte(b, resultArr, resultPos++);
+ }
+ } else if (DecodeUtil.isTwoBytes(byte1)) {
+ if (offset >= limit) {
+ throw InvalidProtocolBufferException.invalidUtf8();
+ }
+ DecodeUtil.handleTwoBytes(
+ byte1, /* byte2 */ UnsafeUtil.getByte(bytes, offset++), resultArr, resultPos++);
+ } else if (DecodeUtil.isThreeBytes(byte1)) {
+ if (offset >= limit - 1) {
+ throw InvalidProtocolBufferException.invalidUtf8();
+ }
+ DecodeUtil.handleThreeBytes(
+ byte1,
+ /* byte2 */ UnsafeUtil.getByte(bytes, offset++),
+ /* byte3 */ UnsafeUtil.getByte(bytes, offset++),
+ resultArr,
+ resultPos++);
+ } else {
+ if (offset >= limit - 2) {
+ throw InvalidProtocolBufferException.invalidUtf8();
+ }
+ DecodeUtil.handleFourBytes(
+ byte1,
+ /* byte2 */ UnsafeUtil.getByte(bytes, offset++),
+ /* byte3 */ UnsafeUtil.getByte(bytes, offset++),
+ /* byte4 */ UnsafeUtil.getByte(bytes, offset++),
+ resultArr,
+ resultPos++);
+ // 4-byte case requires two chars.
+ resultPos++;
+ }
+ }
+
+ return new String(resultArr, 0, resultPos);
+ }
+
+ @Override
+ String decodeUtf8Direct(ByteBuffer buffer, int index, int size)
+ throws InvalidProtocolBufferException {
+ // Bitwise OR combines the sign bits so any negative value fails the check.
+ if ((index | size | buffer.limit() - index - size) < 0) {
+ throw new ArrayIndexOutOfBoundsException(
+ String.format("buffer limit=%d, index=%d, limit=%d", buffer.limit(), index, size));
+ }
+ long address = UnsafeUtil.addressOffset(buffer) + index;
+ final long addressLimit = address + size;
+
+ // The longest possible resulting String is the same as the number of input bytes, when it is
+ // all ASCII. For other cases, this over-allocates and we will truncate in the end.
+ char[] resultArr = new char[size];
+ int resultPos = 0;
+
+ // 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 (address < addressLimit) {
+ byte b = UnsafeUtil.getByte(address);
+ if (!DecodeUtil.isOneByte(b)) {
+ break;
+ }
+ address++;
+ DecodeUtil.handleOneByte(b, resultArr, resultPos++);
+ }
+
+ while (address < addressLimit) {
+ byte byte1 = UnsafeUtil.getByte(address++);
+ if (DecodeUtil.isOneByte(byte1)) {
+ DecodeUtil.handleOneByte(byte1, resultArr, resultPos++);
+ // It's common for there to be multiple ASCII characters in a run mixed in, so add an
+ // extra optimized loop to take care of these runs.
+ while (address < addressLimit) {
+ byte b = UnsafeUtil.getByte(address);
+ if (!DecodeUtil.isOneByte(b)) {
+ break;
+ }
+ address++;
+ DecodeUtil.handleOneByte(b, resultArr, resultPos++);
+ }
+ } else if (DecodeUtil.isTwoBytes(byte1)) {
+ if (address >= addressLimit) {
+ throw InvalidProtocolBufferException.invalidUtf8();
+ }
+ DecodeUtil.handleTwoBytes(
+ byte1, /* byte2 */ UnsafeUtil.getByte(address++), resultArr, resultPos++);
+ } else if (DecodeUtil.isThreeBytes(byte1)) {
+ if (address >= addressLimit - 1) {
+ throw InvalidProtocolBufferException.invalidUtf8();
+ }
+ DecodeUtil.handleThreeBytes(
+ byte1,
+ /* byte2 */ UnsafeUtil.getByte(address++),
+ /* byte3 */ UnsafeUtil.getByte(address++),
+ resultArr,
+ resultPos++);
+ } else {
+ if (address >= addressLimit - 2) {
+ throw InvalidProtocolBufferException.invalidUtf8();
+ }
+ DecodeUtil.handleFourBytes(
+ byte1,
+ /* byte2 */ UnsafeUtil.getByte(address++),
+ /* byte3 */ UnsafeUtil.getByte(address++),
+ /* byte4 */ UnsafeUtil.getByte(address++),
+ resultArr,
+ resultPos++);
+ // 4-byte case requires two chars.
+ resultPos++;
+ }
+ }
+
+ return new String(resultArr, 0, resultPos);
+ }
+
+ @Override
int encodeUtf8(final CharSequence in, final byte[] out, final int offset, final int length) {
- long outIx = getArrayBaseOffset() + offset;
+ long outIx = offset;
final long outLimit = outIx + length;
final int inLimit = in.length();
if (inLimit > length || out.length - length < offset) {
@@ -1204,7 +1572,7 @@ final class Utf8 {
}
if (inIx == inLimit) {
// We're done, it was ASCII encoded.
- return (int) (outIx - getArrayBaseOffset());
+ return (int) outIx;
}
for (char c; inIx < inLimit; ++inIx) {
@@ -1243,7 +1611,7 @@ final class Utf8 {
}
// All bytes have been encoded.
- return (int) (outIx - getArrayBaseOffset());
+ return (int) outIx;
}
@Override
@@ -1321,31 +1689,17 @@ final class Utf8 {
*/
private static int unsafeEstimateConsecutiveAscii(
byte[] bytes, long offset, final int maxChars) {
- int remaining = maxChars;
- if (remaining < UNSAFE_COUNT_ASCII_THRESHOLD) {
+ if (maxChars < 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--) {
+ for (int i = 0; i < maxChars; i++) {
if (UnsafeUtil.getByte(bytes, offset++) < 0) {
- return unaligned - j;
+ return i;
}
}
-
- // 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 && (UnsafeUtil.getLong(bytes, offset) & ASCII_MASK_LONG) == 0;
- offset += 8, remaining -= 8) {}
- return maxChars - remaining;
+ return maxChars;
}
/**
@@ -1362,7 +1716,7 @@ final class Utf8 {
// 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;
+ final int unaligned = 8 - ((int) address & 7);
for (int j = unaligned; j > 0; j--) {
if (UnsafeUtil.getByte(address++) < 0) {
return unaligned - j;
@@ -1569,5 +1923,112 @@ final class Utf8 {
}
}
+ /**
+ * Utility methods for decoding bytes into {@link String}. Callers are responsible for extracting
+ * bytes (possibly using Unsafe methods), and checking remaining bytes. All other UTF-8 validity
+ * checks and codepoint conversion happen in this class.
+ */
+ private static class DecodeUtil {
+
+ /**
+ * Returns whether this is a single-byte codepoint (i.e., ASCII) with the form '0XXXXXXX'.
+ */
+ private static boolean isOneByte(byte b) {
+ return b >= 0;
+ }
+
+ /**
+ * Returns whether this is a two-byte codepoint with the form '10XXXXXX'.
+ */
+ private static boolean isTwoBytes(byte b) {
+ return b < (byte) 0xE0;
+ }
+
+ /**
+ * Returns whether this is a three-byte codepoint with the form '110XXXXX'.
+ */
+ private static boolean isThreeBytes(byte b) {
+ return b < (byte) 0xF0;
+ }
+
+ private static void handleOneByte(byte byte1, char[] resultArr, int resultPos) {
+ resultArr[resultPos] = (char) byte1;
+ }
+
+ private static void handleTwoBytes(
+ byte byte1, byte byte2, char[] resultArr, int resultPos)
+ throws InvalidProtocolBufferException {
+ // Simultaneously checks for illegal trailing-byte in leading position (<= '11000000') and
+ // overlong 2-byte, '11000001'.
+ if (byte1 < (byte) 0xC2
+ || isNotTrailingByte(byte2)) {
+ throw InvalidProtocolBufferException.invalidUtf8();
+ }
+ resultArr[resultPos] = (char) (((byte1 & 0x1F) << 6) | trailingByteValue(byte2));
+ }
+
+ private static void handleThreeBytes(
+ byte byte1, byte byte2, byte byte3, char[] resultArr, int resultPos)
+ throws InvalidProtocolBufferException {
+ if (isNotTrailingByte(byte2)
+ // 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)
+ || isNotTrailingByte(byte3)) {
+ throw InvalidProtocolBufferException.invalidUtf8();
+ }
+ resultArr[resultPos] = (char)
+ (((byte1 & 0x0F) << 12) | (trailingByteValue(byte2) << 6) | trailingByteValue(byte3));
+ }
+
+ private static void handleFourBytes(
+ byte byte1, byte byte2, byte byte3, byte byte4, char[] resultArr, int resultPos)
+ throws InvalidProtocolBufferException{
+ if (isNotTrailingByte(byte2)
+ // Check that 1 <= plane <= 16. Tricky optimized form of:
+ // valid 4-byte leading byte?
+ // if (byte1 > (byte) 0xF4 ||
+ // overlong? 4 most significant bits must not all be zero
+ // byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
+ // codepoint larger than the highest code point (U+10FFFF)?
+ // byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
+ || (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0
+ || isNotTrailingByte(byte3)
+ || isNotTrailingByte(byte4)) {
+ throw InvalidProtocolBufferException.invalidUtf8();
+ }
+ int codepoint = ((byte1 & 0x07) << 18)
+ | (trailingByteValue(byte2) << 12)
+ | (trailingByteValue(byte3) << 6)
+ | trailingByteValue(byte4);
+ resultArr[resultPos] = DecodeUtil.highSurrogate(codepoint);
+ resultArr[resultPos + 1] = DecodeUtil.lowSurrogate(codepoint);
+ }
+
+ /**
+ * Returns whether the byte is not a valid continuation of the form '10XXXXXX'.
+ */
+ private static boolean isNotTrailingByte(byte b) {
+ return b > (byte) 0xBF;
+ }
+
+ /**
+ * Returns the actual value of the trailing byte (removes the prefix '10') for composition.
+ */
+ private static int trailingByteValue(byte b) {
+ return b & 0x3F;
+ }
+
+ private static char highSurrogate(int codePoint) {
+ return (char) ((MIN_HIGH_SURROGATE - (MIN_SUPPLEMENTARY_CODE_POINT >>> 10))
+ + (codePoint >>> 10));
+ }
+
+ private static char lowSurrogate(int codePoint) {
+ return (char) (MIN_LOW_SURROGATE + (codePoint & 0x3ff));
+ }
+ }
+
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 0b0cdb7d..8b837ee5 100644
--- a/java/core/src/main/java/com/google/protobuf/WireFormat.java
+++ b/java/core/src/main/java/com/google/protobuf/WireFormat.java
@@ -47,8 +47,10 @@ public final class WireFormat {
// Do not allow instantiation.
private WireFormat() {}
- static final int FIXED_32_SIZE = 4;
- static final int FIXED_64_SIZE = 8;
+ static final int FIXED32_SIZE = 4;
+ static final int FIXED64_SIZE = 8;
+ static final int MAX_VARINT32_SIZE = 5;
+ static final int MAX_VARINT64_SIZE = 10;
static final int MAX_VARINT_SIZE = 10;
public static final int WIRETYPE_VARINT = 0;
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 622e36a4..cb2d34eb 100644
--- a/java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java
+++ b/java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java
@@ -30,6 +30,9 @@
package com.google.protobuf;
+import static com.google.protobuf.TestUtil.TEST_REQUIRED_INITIALIZED;
+import static com.google.protobuf.TestUtil.TEST_REQUIRED_UNINITIALIZED;
+
import com.google.protobuf.Descriptors.FieldDescriptor;
import protobuf_unittest.UnittestOptimizeFor.TestOptimizedForSize;
import protobuf_unittest.UnittestProto;
@@ -346,11 +349,6 @@ public class AbstractMessageTest extends TestCase {
// -----------------------------------------------------------------
// Tests for isInitialized().
- private static final TestRequired TEST_REQUIRED_UNINITIALIZED =
- TestRequired.getDefaultInstance();
- private static final TestRequired TEST_REQUIRED_INITIALIZED =
- TestRequired.newBuilder().setA(1).setB(2).setC(3).build();
-
public void testIsInitialized() throws Exception {
TestRequired.Builder builder = TestRequired.newBuilder();
AbstractMessageWrapper.Builder abstractBuilder =
@@ -380,7 +378,7 @@ public class AbstractMessageTest extends TestCase {
builder.setOptionalMessage(TEST_REQUIRED_UNINITIALIZED);
assertFalse(abstractBuilder.isInitialized());
assertEquals(
- "optional_message.a, optional_message.b, optional_message.c",
+ "optional_message.b, optional_message.c",
abstractBuilder.getInitializationErrorString());
builder.setOptionalMessage(TEST_REQUIRED_INITIALIZED);
@@ -390,7 +388,7 @@ public class AbstractMessageTest extends TestCase {
builder.addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED);
assertFalse(abstractBuilder.isInitialized());
assertEquals(
- "repeated_message[0].a, repeated_message[0].b, repeated_message[0].c",
+ "repeated_message[0].b, repeated_message[0].c",
abstractBuilder.getInitializationErrorString());
builder.setRepeatedMessage(0, TEST_REQUIRED_INITIALIZED);
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 18132e9e..4906763c 100644
--- a/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java
@@ -32,6 +32,7 @@ package com.google.protobuf;
import static java.util.Arrays.asList;
+import com.google.protobuf.Internal.BooleanList;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
@@ -297,6 +298,20 @@ public class BooleanArrayListTest extends TestCase {
}
}
+ public void testRemoveEndOfCapacity() {
+ BooleanList toRemove = BooleanArrayList.emptyList().mutableCopyWithCapacity(1);
+ toRemove.addBoolean(true);
+ toRemove.remove(0);
+ assertEquals(0, toRemove.size());
+ }
+
+ public void testSublistRemoveEndOfCapacity() {
+ BooleanList toRemove = BooleanArrayList.emptyList().mutableCopyWithCapacity(1);
+ toRemove.addBoolean(true);
+ toRemove.subList(0, 1).clear();
+ assertEquals(0, toRemove.size());
+ }
+
private void assertImmutable(BooleanArrayList list) {
try {
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 cc65d19a..50b87ae3 100644
--- a/java/core/src/test/java/com/google/protobuf/CheckUtf8Test.java
+++ b/java/core/src/test/java/com/google/protobuf/CheckUtf8Test.java
@@ -34,7 +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 java.io.ByteArrayInputStream;
import junit.framework.TestCase;
/**
@@ -90,14 +90,9 @@ public class CheckUtf8Test extends TestCase {
}
public void testParseRequiredStringWithBadUtf8() throws Exception {
- ByteString serialized =
- BytesWrapper.newBuilder().setReq(NON_UTF8_BYTE_STRING).build().toByteString();
- try {
- StringWrapper.parser().parseFrom(serialized);
- fail("Expected InvalidProtocolBufferException for non UTF-8 byte string.");
- } catch (InvalidProtocolBufferException exception) {
- assertEquals("Protocol message had invalid UTF-8.", exception.getMessage());
- }
+ byte[] serialized =
+ BytesWrapper.newBuilder().setReq(NON_UTF8_BYTE_STRING).build().toByteArray();
+ assertParseBadUtf8(StringWrapper.getDefaultInstance(), serialized);
}
public void testBuildRequiredStringWithBadUtf8Size() throws Exception {
@@ -128,14 +123,36 @@ public class CheckUtf8Test extends TestCase {
}
public void testParseRequiredStringWithBadUtf8Size() throws Exception {
- ByteString serialized =
- BytesWrapperSize.newBuilder().setReq(NON_UTF8_BYTE_STRING).build().toByteString();
+ byte[] serialized =
+ BytesWrapperSize.newBuilder().setReq(NON_UTF8_BYTE_STRING).build().toByteArray();
+ assertParseBadUtf8(StringWrapperSize.getDefaultInstance(), serialized);
+ }
+
+ private void assertParseBadUtf8(MessageLite defaultInstance, byte[] data) throws Exception {
+ // Check combinations of (parser vs. builder) x (byte[] vs. InputStream)
+ try {
+ defaultInstance.getParserForType().parseFrom(data);
+ fail("Expected InvalidProtocolBufferException for non UTF-8 byte string.");
+ } catch (InvalidProtocolBufferException exception) {
+ assertEquals("Protocol message had invalid UTF-8.", exception.getMessage());
+ }
+ try {
+ defaultInstance.newBuilderForType().mergeFrom(data);
+ fail("Expected InvalidProtocolBufferException for non UTF-8 byte string.");
+ } catch (InvalidProtocolBufferException exception) {
+ assertEquals("Protocol message had invalid UTF-8.", exception.getMessage());
+ }
try {
- StringWrapperSize.parser().parseFrom(serialized);
+ defaultInstance.getParserForType().parseFrom(new ByteArrayInputStream(data));
+ fail("Expected InvalidProtocolBufferException for non UTF-8 byte string.");
+ } catch (InvalidProtocolBufferException exception) {
+ assertEquals("Protocol message had invalid UTF-8.", exception.getMessage());
+ }
+ try {
+ defaultInstance.newBuilderForType().mergeFrom(new ByteArrayInputStream(data));
fail("Expected InvalidProtocolBufferException for non UTF-8 byte string.");
} catch (InvalidProtocolBufferException exception) {
assertEquals("Protocol message had invalid UTF-8.", exception.getMessage());
}
}
-
}
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 e440c7db..5ea6b79c 100644
--- a/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
+++ b/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
@@ -41,6 +41,8 @@ import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
import junit.framework.TestCase;
/**
@@ -49,6 +51,9 @@ import junit.framework.TestCase;
* @author kenton@google.com Kenton Varda
*/
public class CodedInputStreamTest extends TestCase {
+
+ private static final int DEFAULT_BLOCK_SIZE = 4096;
+
private enum InputType {
ARRAY {
@Override
@@ -76,7 +81,43 @@ public class CodedInputStreamTest extends TestCase {
CodedInputStream newDecoder(byte[] data, int blockSize) {
return CodedInputStream.newInstance(new SmallBlockInputStream(data, blockSize));
}
+ },
+ ITER_DIRECT {
+ @Override
+ CodedInputStream newDecoder(byte[] data, int blockSize) {
+ if (blockSize > DEFAULT_BLOCK_SIZE) {
+ blockSize = DEFAULT_BLOCK_SIZE;
+ }
+ ArrayList <ByteBuffer> input = new ArrayList <ByteBuffer>();
+ for (int i = 0; i < data.length; i += blockSize) {
+ int rl = Math.min(blockSize, data.length - i);
+ ByteBuffer rb = ByteBuffer.allocateDirect(rl);
+ rb.put(data, i, rl);
+ rb.flip();
+ input.add(rb);
+ }
+ return CodedInputStream.newInstance(input);
+ }
+ },
+ STREAM_ITER_DIRECT {
+ @Override
+ CodedInputStream newDecoder(byte[] data, int blockSize) {
+ if (blockSize > DEFAULT_BLOCK_SIZE) {
+ blockSize = DEFAULT_BLOCK_SIZE;
+ }
+ ArrayList <ByteBuffer> input = new ArrayList <ByteBuffer>();
+ for (int i = 0; i < data.length; i += blockSize) {
+ int rl = Math.min(blockSize, data.length - i);
+ ByteBuffer rb = ByteBuffer.allocateDirect(rl);
+ rb.put(data, i, rl);
+ rb.flip();
+ input.add(rb);
+ }
+ return CodedInputStream.newInstance(new IterableByteBufferInputStream(input));
+ }
};
+
+
CodedInputStream newDecoder(byte[] data) {
return newDecoder(data, data.length);
@@ -613,6 +654,82 @@ public class CodedInputStreamTest extends TestCase {
checkSizeLimitExceeded(expected);
}
}
+
+ public void testRefillBufferWithCorrectSize() throws Exception {
+ // NOTE: refillBuffer only applies to the stream-backed CIS.
+ byte[] bytes = "123456789".getBytes("UTF-8");
+ ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
+ 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.writeRawVarint32(tag);
+ output.writeRawVarint32(bytes.length);
+ output.writeRawBytes(bytes);
+ output.writeRawByte(4);
+ output.flush();
+
+ // Input is two string with length 9 and one raw byte.
+ byte[] rawInput = rawOutput.toByteArray();
+ for (int inputStreamBufferLength = 8;
+ inputStreamBufferLength <= rawInput.length + 1; inputStreamBufferLength++) {
+ CodedInputStream input = CodedInputStream.newInstance(
+ new ByteArrayInputStream(rawInput), inputStreamBufferLength);
+ input.setSizeLimit(rawInput.length - 1);
+ input.readString();
+ input.readString();
+ try {
+ input.readRawByte(); // Hits limit.
+ fail("Should have thrown an exception!");
+ } catch (InvalidProtocolBufferException expected) {
+ checkSizeLimitExceeded(expected);
+ }
+ }
+ }
+
+ public void testIsAtEnd() throws Exception {
+ CodedInputStream input = CodedInputStream.newInstance(
+ new ByteArrayInputStream(new byte[5]));
+ try {
+ for (int i = 0; i < 5; i++) {
+ assertEquals(false, input.isAtEnd());
+ input.readRawByte();
+ }
+ assertEquals(true, input.isAtEnd());
+ } catch (Exception e) {
+ fail("Catch exception in the testIsAtEnd");
+ }
+ }
+
+ public void testCurrentLimitExceeded() throws Exception {
+ byte[] bytes = "123456789".getBytes("UTF-8");
+ ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
+ 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();
+
+ byte[] rawInput = rawOutput.toByteArray();
+ CodedInputStream input = CodedInputStream.newInstance(
+ new ByteArrayInputStream(rawInput));
+ // The length of the whole rawInput
+ input.setSizeLimit(11);
+ // Some number that is smaller than the rawInput's length
+ // but larger than 2
+ input.pushLimit(5);
+ try {
+ input.readString();
+ fail("Should have thrown an exception");
+ } catch (InvalidProtocolBufferException expected) {
+ assertEquals(expected.getMessage(),
+ InvalidProtocolBufferException.truncatedMessage().getMessage());
+ }
+ }
public void testSizeLimitMultipleMessages() throws Exception {
// NOTE: Size limit only applies to the stream-backed CIS.
@@ -807,6 +924,52 @@ public class CodedInputStreamTest extends TestCase {
}
}
+ public void testReadLargeByteStringFromInputStream() throws Exception {
+ byte[] bytes = new byte[1024 * 1024];
+ for (int i = 0; i < bytes.length; i++) {
+ bytes[i] = (byte) (i & 0xFF);
+ }
+ ByteString.Output rawOutput = ByteString.newOutput();
+ CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
+ output.writeRawVarint32(bytes.length);
+ output.writeRawBytes(bytes);
+ output.flush();
+ byte[] data = rawOutput.toByteString().toByteArray();
+
+ CodedInputStream input = CodedInputStream.newInstance(
+ new ByteArrayInputStream(data) {
+ @Override
+ public synchronized int available() {
+ return 0;
+ }
+ });
+ ByteString result = input.readBytes();
+ assertEquals(ByteString.copyFrom(bytes), result);
+ }
+
+ public void testReadLargeByteArrayFromInputStream() throws Exception {
+ byte[] bytes = new byte[1024 * 1024];
+ for (int i = 0; i < bytes.length; i++) {
+ bytes[i] = (byte) (i & 0xFF);
+ }
+ ByteString.Output rawOutput = ByteString.newOutput();
+ CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
+ output.writeRawVarint32(bytes.length);
+ output.writeRawBytes(bytes);
+ output.flush();
+ byte[] data = rawOutput.toByteString().toByteArray();
+
+ CodedInputStream input = CodedInputStream.newInstance(
+ new ByteArrayInputStream(data) {
+ @Override
+ public synchronized int available() {
+ return 0;
+ }
+ });
+ byte[] result = input.readByteArray();
+ assertTrue(Arrays.equals(bytes, result));
+ }
+
public void testReadByteBuffer() throws Exception {
ByteString.Output rawOutput = ByteString.newOutput();
CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
@@ -871,7 +1034,9 @@ public class CodedInputStreamTest extends TestCase {
byte[] data = byteArrayStream.toByteArray();
for (InputType inputType : InputType.values()) {
- if (inputType == InputType.STREAM) {
+ if (inputType == InputType.STREAM
+ || inputType == InputType.STREAM_ITER_DIRECT
+ || inputType == InputType.ITER_DIRECT) {
// Aliasing doesn't apply to stream-backed CIS.
continue;
}
@@ -896,7 +1061,7 @@ public class CodedInputStreamTest extends TestCase {
assertEquals(inputType.name(), (byte) 89, result.get());
// Enable aliasing
- inputStream = inputType.newDecoder(data);
+ inputStream = inputType.newDecoder(data, data.length);
inputStream.enableAliasing(true);
result = inputStream.readByteBuffer();
assertEquals(inputType.name(), 0, result.capacity());
diff --git a/java/core/src/test/java/com/google/protobuf/DecodeUtf8Test.java b/java/core/src/test/java/com/google/protobuf/DecodeUtf8Test.java
new file mode 100644
index 00000000..359d4d74
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/DecodeUtf8Test.java
@@ -0,0 +1,325 @@
+package com.google.protobuf;
+
+import com.google.protobuf.Utf8.Processor;
+import com.google.protobuf.Utf8.SafeProcessor;
+import com.google.protobuf.Utf8.UnsafeProcessor;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Logger;
+import junit.framework.TestCase;
+
+public class DecodeUtf8Test extends TestCase {
+ private static Logger logger = Logger.getLogger(DecodeUtf8Test.class.getName());
+
+ private static final Processor SAFE_PROCESSOR = new SafeProcessor();
+ private static final Processor UNSAFE_PROCESSOR = new UnsafeProcessor();
+
+ public void testRoundTripAllValidChars() throws Exception {
+ for (int i = Character.MIN_CODE_POINT; i < Character.MAX_CODE_POINT; i++) {
+ if (i < Character.MIN_SURROGATE || i > Character.MAX_SURROGATE) {
+ String str = new String(Character.toChars(i));
+ assertRoundTrips(str);
+ }
+ }
+ }
+
+ // Test all 1, 2, 3 invalid byte combinations. Valid ones would have been covered above.
+
+ public void testOneByte() throws Exception {
+ int valid = 0;
+ for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) {
+ ByteString bs = ByteString.copyFrom(new byte[] { (byte) i });
+ if (!bs.isValidUtf8()) {
+ assertInvalid(bs.toByteArray());
+ } else {
+ valid++;
+ }
+ }
+ assertEquals(IsValidUtf8TestUtil.EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT, valid);
+ }
+
+ public void testTwoBytes() throws Exception {
+ int valid = 0;
+ for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) {
+ for (int j = Byte.MIN_VALUE; j <= Byte.MAX_VALUE; j++) {
+ ByteString bs = ByteString.copyFrom(new byte[]{(byte) i, (byte) j});
+ if (!bs.isValidUtf8()) {
+ assertInvalid(bs.toByteArray());
+ } else {
+ valid++;
+ }
+ }
+ }
+ assertEquals(IsValidUtf8TestUtil.EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT, valid);
+ }
+
+ public void testThreeBytes() throws Exception {
+ // Travis' OOM killer doesn't like this test
+ if (System.getenv("TRAVIS") == null) {
+ int count = 0;
+ int valid = 0;
+ for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) {
+ for (int j = Byte.MIN_VALUE; j <= Byte.MAX_VALUE; j++) {
+ for (int k = Byte.MIN_VALUE; k <= Byte.MAX_VALUE; k++) {
+ byte[] bytes = new byte[]{(byte) i, (byte) j, (byte) k};
+ ByteString bs = ByteString.copyFrom(bytes);
+ if (!bs.isValidUtf8()) {
+ assertInvalid(bytes);
+ } else {
+ valid++;
+ }
+ count++;
+ if (count % 1000000L == 0) {
+ logger.info("Processed " + (count / 1000000L) + " million characters");
+ }
+ }
+ }
+ }
+ assertEquals(IsValidUtf8TestUtil.EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT, valid);
+ }
+ }
+
+ /**
+ * Tests that round tripping of a sample of four byte permutations work.
+ */
+ public void testInvalid_4BytesSamples() throws Exception {
+ // Bad trailing bytes
+ assertInvalid(0xF0, 0xA4, 0xAD, 0x7F);
+ assertInvalid(0xF0, 0xA4, 0xAD, 0xC0);
+
+ // Special cases for byte2
+ assertInvalid(0xF0, 0x8F, 0xAD, 0xA2);
+ assertInvalid(0xF4, 0x90, 0xAD, 0xA2);
+ }
+
+ public void testRealStrings() throws Exception {
+ // English
+ assertRoundTrips("The quick brown fox jumps over the lazy dog");
+ // German
+ assertRoundTrips("Quizdeltagerne spiste jordb\u00e6r med fl\u00f8de, mens cirkusklovnen");
+ // Japanese
+ assertRoundTrips(
+ "\u3044\u308d\u306f\u306b\u307b\u3078\u3068\u3061\u308a\u306c\u308b\u3092");
+ // Hebrew
+ assertRoundTrips(
+ "\u05d3\u05d2 \u05e1\u05e7\u05e8\u05df \u05e9\u05d8 \u05d1\u05d9\u05dd "
+ + "\u05de\u05d0\u05d5\u05db\u05d6\u05d1 \u05d5\u05dc\u05e4\u05ea\u05e2"
+ + " \u05de\u05e6\u05d0 \u05dc\u05d5 \u05d7\u05d1\u05e8\u05d4 "
+ + "\u05d0\u05d9\u05da \u05d4\u05e7\u05dc\u05d9\u05d8\u05d4");
+ // Thai
+ assertRoundTrips(
+ " \u0e08\u0e07\u0e1d\u0e48\u0e32\u0e1f\u0e31\u0e19\u0e1e\u0e31\u0e12"
+ + "\u0e19\u0e32\u0e27\u0e34\u0e0a\u0e32\u0e01\u0e32\u0e23");
+ // Chinese
+ assertRoundTrips(
+ "\u8fd4\u56de\u94fe\u4e2d\u7684\u4e0b\u4e00\u4e2a\u4ee3\u7406\u9879\u9009\u62e9\u5668");
+ // Chinese with 4-byte chars
+ assertRoundTrips("\uD841\uDF0E\uD841\uDF31\uD841\uDF79\uD843\uDC53\uD843\uDC78"
+ + "\uD843\uDC96\uD843\uDCCF\uD843\uDCD5\uD843\uDD15\uD843\uDD7C\uD843\uDD7F"
+ + "\uD843\uDE0E\uD843\uDE0F\uD843\uDE77\uD843\uDE9D\uD843\uDEA2");
+ // Mixed
+ assertRoundTrips(
+ "The quick brown \u3044\u308d\u306f\u306b\u307b\u3078\u8fd4\u56de\u94fe"
+ + "\u4e2d\u7684\u4e0b\u4e00");
+ }
+
+ public void testOverlong() throws Exception {
+ assertInvalid(0xc0, 0xaf);
+ assertInvalid(0xe0, 0x80, 0xaf);
+ assertInvalid(0xf0, 0x80, 0x80, 0xaf);
+
+ // Max overlong
+ assertInvalid(0xc1, 0xbf);
+ assertInvalid(0xe0, 0x9f, 0xbf);
+ assertInvalid(0xf0 ,0x8f, 0xbf, 0xbf);
+
+ // null overlong
+ assertInvalid(0xc0, 0x80);
+ assertInvalid(0xe0, 0x80, 0x80);
+ assertInvalid(0xf0, 0x80, 0x80, 0x80);
+ }
+
+ public void testIllegalCodepoints() throws Exception {
+ // Single surrogate
+ assertInvalid(0xed, 0xa0, 0x80);
+ assertInvalid(0xed, 0xad, 0xbf);
+ assertInvalid(0xed, 0xae, 0x80);
+ assertInvalid(0xed, 0xaf, 0xbf);
+ assertInvalid(0xed, 0xb0, 0x80);
+ assertInvalid(0xed, 0xbe, 0x80);
+ assertInvalid(0xed, 0xbf, 0xbf);
+
+ // Paired surrogates
+ assertInvalid(0xed, 0xa0, 0x80, 0xed, 0xb0, 0x80);
+ assertInvalid(0xed, 0xa0, 0x80, 0xed, 0xbf, 0xbf);
+ assertInvalid(0xed, 0xad, 0xbf, 0xed, 0xb0, 0x80);
+ assertInvalid(0xed, 0xad, 0xbf, 0xed, 0xbf, 0xbf);
+ assertInvalid(0xed, 0xae, 0x80, 0xed, 0xb0, 0x80);
+ assertInvalid(0xed, 0xae, 0x80, 0xed, 0xbf, 0xbf);
+ assertInvalid(0xed, 0xaf, 0xbf, 0xed, 0xb0, 0x80);
+ assertInvalid(0xed, 0xaf, 0xbf, 0xed, 0xbf, 0xbf);
+ }
+
+ public void testBufferSlice() throws Exception {
+ String str = "The quick brown fox jumps over the lazy dog";
+ assertRoundTrips(str, 10, 4);
+ assertRoundTrips(str, str.length(), 0);
+ }
+
+ public void testInvalidBufferSlice() throws Exception {
+ byte[] bytes = "The quick brown fox jumps over the lazy dog".getBytes(Internal.UTF_8);
+ assertInvalidSlice(bytes, bytes.length - 3, 4);
+ assertInvalidSlice(bytes, bytes.length, 1);
+ assertInvalidSlice(bytes, bytes.length + 1, 0);
+ assertInvalidSlice(bytes, 0, bytes.length + 1);
+ }
+
+ private void assertInvalid(int... bytesAsInt) throws Exception {
+ byte[] bytes = new byte[bytesAsInt.length];
+ for (int i = 0; i < bytesAsInt.length; i++) {
+ bytes[i] = (byte) bytesAsInt[i];
+ }
+ assertInvalid(bytes);
+ }
+
+ private void assertInvalid(byte[] bytes) throws Exception {
+ try {
+ UNSAFE_PROCESSOR.decodeUtf8(bytes, 0, bytes.length);
+ fail();
+ } catch (InvalidProtocolBufferException e) {
+ // Expected.
+ }
+ try {
+ SAFE_PROCESSOR.decodeUtf8(bytes, 0, bytes.length);
+ fail();
+ } catch (InvalidProtocolBufferException e) {
+ // Expected.
+ }
+
+ ByteBuffer direct = ByteBuffer.allocateDirect(bytes.length);
+ direct.put(bytes);
+ direct.flip();
+ try {
+ UNSAFE_PROCESSOR.decodeUtf8(direct, 0, bytes.length);
+ fail();
+ } catch (InvalidProtocolBufferException e) {
+ // Expected.
+ }
+ try {
+ SAFE_PROCESSOR.decodeUtf8(direct, 0, bytes.length);
+ fail();
+ } catch (InvalidProtocolBufferException e) {
+ // Expected.
+ }
+
+ ByteBuffer heap = ByteBuffer.allocate(bytes.length);
+ heap.put(bytes);
+ heap.flip();
+ try {
+ UNSAFE_PROCESSOR.decodeUtf8(heap, 0, bytes.length);
+ fail();
+ } catch (InvalidProtocolBufferException e) {
+ // Expected.
+ }
+ try {
+ SAFE_PROCESSOR.decodeUtf8(heap, 0, bytes.length);
+ fail();
+ } catch (InvalidProtocolBufferException e) {
+ // Expected.
+ }
+ }
+
+ private void assertInvalidSlice(byte[] bytes, int index, int size) throws Exception {
+ try {
+ UNSAFE_PROCESSOR.decodeUtf8(bytes, index, size);
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // Expected.
+ }
+ try {
+ SAFE_PROCESSOR.decodeUtf8(bytes, index, size);
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // Expected.
+ }
+
+ ByteBuffer direct = ByteBuffer.allocateDirect(bytes.length);
+ direct.put(bytes);
+ direct.flip();
+ try {
+ UNSAFE_PROCESSOR.decodeUtf8(direct, index, size);
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // Expected.
+ }
+ try {
+ SAFE_PROCESSOR.decodeUtf8(direct, index, size);
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // Expected.
+ }
+
+ ByteBuffer heap = ByteBuffer.allocate(bytes.length);
+ heap.put(bytes);
+ heap.flip();
+ try {
+ UNSAFE_PROCESSOR.decodeUtf8(heap, index, size);
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // Expected.
+ }
+ try {
+ SAFE_PROCESSOR.decodeUtf8(heap, index, size);
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // Expected.
+ }
+ }
+
+ private void assertRoundTrips(String str) throws Exception {
+ assertRoundTrips(str, 0, -1);
+ }
+
+ private void assertRoundTrips(String str, int index, int size) throws Exception {
+ byte[] bytes = str.getBytes(Internal.UTF_8);
+ if (size == -1) {
+ size = bytes.length;
+ }
+ assertDecode(new String(bytes, index, size, Internal.UTF_8),
+ UNSAFE_PROCESSOR.decodeUtf8(bytes, index, size));
+ assertDecode(new String(bytes, index, size, Internal.UTF_8),
+ SAFE_PROCESSOR.decodeUtf8(bytes, index, size));
+
+ ByteBuffer direct = ByteBuffer.allocateDirect(bytes.length);
+ direct.put(bytes);
+ direct.flip();
+ assertDecode(new String(bytes, index, size, Internal.UTF_8),
+ UNSAFE_PROCESSOR.decodeUtf8(direct, index, size));
+ assertDecode(new String(bytes, index, size, Internal.UTF_8),
+ SAFE_PROCESSOR.decodeUtf8(direct, index, size));
+
+ ByteBuffer heap = ByteBuffer.allocate(bytes.length);
+ heap.put(bytes);
+ heap.flip();
+ assertDecode(new String(bytes, index, size, Internal.UTF_8),
+ UNSAFE_PROCESSOR.decodeUtf8(heap, index, size));
+ assertDecode(new String(bytes, index, size, Internal.UTF_8),
+ SAFE_PROCESSOR.decodeUtf8(heap, index, size));
+ }
+
+ private void assertDecode(String expected, String actual) {
+ if (!expected.equals(actual)) {
+ fail("Failure: Expected (" + codepoints(expected) + ") Actual (" + codepoints(actual) + ")");
+ }
+ }
+
+ private List<String> codepoints(String str) {
+ List<String> codepoints = new ArrayList<String>();
+ for (int i = 0; i < str.length(); i++) {
+ codepoints.add(Long.toHexString(str.charAt(i)));
+ }
+ return codepoints;
+ }
+
+}
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 2c272a73..9c0997c4 100644
--- a/java/core/src/test/java/com/google/protobuf/DeprecatedFieldTest.java
+++ b/java/core/src/test/java/com/google/protobuf/DeprecatedFieldTest.java
@@ -37,22 +37,22 @@ import junit.framework.TestCase;
/**
* Test field deprecation
- *
+ *
* @author birdo@google.com (Roberto Scaramuzzi)
*/
public class DeprecatedFieldTest extends TestCase {
private String[] deprecatedGetterNames = {
"hasDeprecatedInt32",
"getDeprecatedInt32"};
-
+
private String[] deprecatedBuilderGetterNames = {
"hasDeprecatedInt32",
"getDeprecatedInt32",
"clearDeprecatedInt32"};
-
+
private String[] deprecatedBuilderSetterNames = {
- "setDeprecatedInt32"};
-
+ "setDeprecatedInt32"};
+
public void testDeprecatedField() throws Exception {
Class<?> deprecatedFields = TestDeprecatedFields.class;
Class<?> deprecatedFieldsBuilder = TestDeprecatedFields.Builder.class;
@@ -72,7 +72,15 @@ public class DeprecatedFieldTest extends TestCase {
isDeprecated(method));
}
}
-
+
+ public void testDeprecatedFieldInOneof() throws Exception {
+ Class<?> oneofCase = TestDeprecatedFields.OneofFieldsCase.class;
+ String name = "DEPRECATED_INT32_IN_ONEOF";
+ java.lang.reflect.Field enumValue = oneofCase.getField(name);
+ assertTrue("Enum value " + name + " should be deprecated.",
+ isDeprecated(enumValue));
+ }
+
private boolean isDeprecated(AnnotatedElement annotated) {
return annotated.isAnnotationPresent(Deprecated.class);
}
diff --git a/java/core/src/test/java/com/google/protobuf/DiscardUnknownFieldsTest.java b/java/core/src/test/java/com/google/protobuf/DiscardUnknownFieldsTest.java
new file mode 100644
index 00000000..0f09a51b
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/DiscardUnknownFieldsTest.java
@@ -0,0 +1,157 @@
+// 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 protobuf_unittest.UnittestProto;
+import proto3_unittest.UnittestProto3;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Unit tests for discard or preserve unknown fields. */
+@RunWith(JUnit4.class)
+public class DiscardUnknownFieldsTest {
+ @Test
+ public void testProto2() throws Exception {
+ testProto2Message(
+ UnittestProto.TestEmptyMessage.getDefaultInstance());
+ testProto2Message(
+ UnittestProto.TestEmptyMessageWithExtensions.getDefaultInstance());
+ testProto2Message(
+ DynamicMessage.getDefaultInstance(UnittestProto.TestEmptyMessage.getDescriptor()));
+ testProto2Message(
+ DynamicMessage.getDefaultInstance(
+ UnittestProto.TestEmptyMessageWithExtensions.getDescriptor()));
+ }
+
+ @Test
+ public void testProto3() throws Exception {
+ testProto3Message(UnittestProto3.TestEmptyMessage.getDefaultInstance());
+ testProto3Message(
+ DynamicMessage.getDefaultInstance(UnittestProto3.TestEmptyMessage.getDescriptor()));
+ }
+
+ private static void testProto2Message(Message message) throws Exception {
+ assertUnknownFieldsDefaultPreserved(message);
+ assertUnknownFieldsExplicitlyDiscarded(message);
+ assertReuseCodedInputStreamPreserve(message);
+ assertUnknownFieldsInUnknownFieldSetArePreserve(message);
+ }
+
+ private static void testProto3Message(Message message) throws Exception {
+ CodedInputStream.setProto3KeepUnknownsByDefaultForTest();
+ assertUnknownFieldsDefaultPreserved(message);
+ assertUnknownFieldsExplicitlyDiscarded(message);
+ assertReuseCodedInputStreamPreserve(message);
+ assertUnknownFieldsInUnknownFieldSetArePreserve(message);
+ CodedInputStream.setProto3DiscardUnknownsByDefaultForTest();
+ assertUnknownFieldsDefaultDiscarded(message);
+ assertUnknownFieldsExplicitlyDiscarded(message);
+ assertUnknownFieldsInUnknownFieldSetAreDiscarded(message);
+ }
+
+ private static void assertReuseCodedInputStreamPreserve(Message message) throws Exception {
+ final int messageSize = payload.size();
+ byte[] copied = new byte[messageSize * 2];
+ payload.copyTo(copied, 0);
+ payload.copyTo(copied, messageSize);
+ CodedInputStream input = CodedInputStream.newInstance(copied);
+ {
+ // Use DiscardUnknownFieldsParser to parse the first payload.
+ int oldLimit = input.pushLimit(messageSize);
+ Message parsed = DiscardUnknownFieldsParser.wrap(message.getParserForType()).parseFrom(input);
+ assertEquals(message.getClass().getName(), 0, parsed.getSerializedSize());
+ input.popLimit(oldLimit);
+ }
+ {
+ // Use the normal parser to parse the remaining payload should have unknown fields preserved.
+ Message parsed = message.getParserForType().parseFrom(input);
+ assertEquals(message.getClass().getName(), payload, parsed.toByteString());
+ }
+ }
+
+ /**
+ * {@link Message.Builder#setUnknownFields(UnknownFieldSet)} and {@link
+ * Message.Builder#mergeUnknownFields(UnknownFieldSet)} should preserve the unknown fields.
+ */
+ private static void assertUnknownFieldsInUnknownFieldSetArePreserve(Message message)
+ throws Exception {
+ UnknownFieldSet unknownFields = UnknownFieldSet.newBuilder().mergeFrom(payload).build();
+ Message built = message.newBuilderForType().setUnknownFields(unknownFields).build();
+ assertEquals(message.getClass().getName(), payload, built.toByteString());
+
+ }
+ /**
+ * {@link Message.Builder#setUnknownFields(UnknownFieldSet)} and {@link
+ * Message.Builder#mergeUnknownFields(UnknownFieldSet)} should discard the unknown fields.
+ */
+ private static void assertUnknownFieldsInUnknownFieldSetAreDiscarded(Message message)
+ throws Exception {
+ UnknownFieldSet unknownFields = UnknownFieldSet.newBuilder().mergeFrom(payload).build();
+ Message built = message.newBuilderForType().setUnknownFields(unknownFields).build();
+ assertEquals(message.getClass().getName(), 0, built.getSerializedSize());
+ }
+
+ private static void assertUnknownFieldsDefaultPreserved(MessageLite message) throws Exception {
+ {
+ MessageLite parsed = message.getParserForType().parseFrom(payload);
+ assertEquals(message.getClass().getName(), payload, parsed.toByteString());
+ }
+
+ {
+ MessageLite parsed = message.newBuilderForType().mergeFrom(payload).build();
+ assertEquals(message.getClass().getName(), payload, parsed.toByteString());
+ }
+ }
+
+ private static void assertUnknownFieldsDefaultDiscarded(MessageLite message) throws Exception {
+ {
+ MessageLite parsed = message.getParserForType().parseFrom(payload);
+ assertEquals(message.getClass().getName(), 0, parsed.getSerializedSize());
+ }
+
+ {
+ MessageLite parsed = message.newBuilderForType().mergeFrom(payload).build();
+ assertEquals(message.getClass().getName(), 0, parsed.getSerializedSize());
+ }
+ }
+
+ private static void assertUnknownFieldsExplicitlyDiscarded(Message message) throws Exception {
+ Message parsed =
+ DiscardUnknownFieldsParser.wrap(message.getParserForType()).parseFrom(payload);
+ assertEquals(message.getClass().getName(), 0, parsed.getSerializedSize());
+ }
+
+ private static final ByteString payload =
+ TestUtilLite.getAllLiteSetBuilder().build().toByteString();
+}
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 d8942792..923d7f43 100644
--- a/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java
@@ -32,6 +32,7 @@ package com.google.protobuf;
import static java.util.Arrays.asList;
+import com.google.protobuf.Internal.DoubleList;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
@@ -297,6 +298,20 @@ public class DoubleArrayListTest extends TestCase {
}
}
+ public void testRemoveEndOfCapacity() {
+ DoubleList toRemove = DoubleArrayList.emptyList().mutableCopyWithCapacity(1);
+ toRemove.addDouble(3);
+ toRemove.remove(0);
+ assertEquals(0, toRemove.size());
+ }
+
+ public void testSublistRemoveEndOfCapacity() {
+ DoubleList toRemove = DoubleArrayList.emptyList().mutableCopyWithCapacity(1);
+ toRemove.addDouble(3);
+ toRemove.subList(0, 1).clear();
+ assertEquals(0, toRemove.size());
+ }
+
private void assertImmutable(DoubleArrayList list) {
if (list.contains(1D)) {
throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
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 4a42c897..42da5bb3 100644
--- a/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java
+++ b/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java
@@ -108,7 +108,7 @@ public class FieldPresenceTest extends TestCase {
assertFalse(TestAllTypes.newBuilder().build().hasOptionalNestedMessage());
assertFalse(TestAllTypes.newBuilder().hasOptionalNestedMessage());
- // oneof fields don't have hasFoo() methods (even for message types).
+ // oneof fields don't have hasFoo() methods for non-message types.
assertHasMethodRemoved(
UnittestProto.TestAllTypes.class,
TestAllTypes.class,
@@ -121,10 +121,8 @@ public class FieldPresenceTest extends TestCase {
UnittestProto.TestAllTypes.class,
TestAllTypes.class,
"OneofBytes");
- assertHasMethodRemoved(
- UnittestProto.TestAllTypes.class,
- TestAllTypes.class,
- "OneofNestedMessage");
+ assertFalse(TestAllTypes.newBuilder().build().hasOneofNestedMessage());
+ assertFalse(TestAllTypes.newBuilder().hasOneofNestedMessage());
assertHasMethodRemoved(
UnittestProto.TestAllTypes.Builder.class,
@@ -138,10 +136,6 @@ public class FieldPresenceTest extends TestCase {
UnittestProto.TestAllTypes.Builder.class,
TestAllTypes.Builder.class,
"OneofBytes");
- assertHasMethodRemoved(
- UnittestProto.TestAllTypes.Builder.class,
- TestAllTypes.Builder.class,
- "OneofNestedMessage");
}
public void testOneofEquals() throws Exception {
@@ -410,34 +404,4 @@ 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();
- builder.setOptionalInt32(1234);
- builder.addRepeatedInt32(5678);
- TestAllTypes message = builder.build();
- ByteString data = message.toByteString();
-
- TestOptionalFieldsOnly optionalOnlyMessage =
- TestOptionalFieldsOnly.parseFrom(data);
- // UnknownFieldSet should be empty.
- assertEquals(
- 0, optionalOnlyMessage.getUnknownFields().toByteString().size());
- assertEquals(1234, optionalOnlyMessage.getOptionalInt32());
- message = TestAllTypes.parseFrom(optionalOnlyMessage.toByteString());
- assertEquals(1234, message.getOptionalInt32());
- // The repeated field is discarded because it's unknown to the optional-only
- // message.
- assertEquals(0, message.getRepeatedInt32Count());
-
- DynamicMessage dynamicOptionalOnlyMessage =
- DynamicMessage.getDefaultInstance(
- TestOptionalFieldsOnly.getDescriptor())
- .getParserForType().parseFrom(data);
- assertEquals(
- 0, dynamicOptionalOnlyMessage.getUnknownFields().toByteString().size());
- assertEquals(optionalOnlyMessage.toByteString(),
- dynamicOptionalOnlyMessage.toByteString());
- }
}
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 aa36be49..903a79db 100644
--- a/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java
@@ -32,6 +32,7 @@ package com.google.protobuf;
import static java.util.Arrays.asList;
+import com.google.protobuf.Internal.FloatList;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
@@ -297,6 +298,20 @@ public class FloatArrayListTest extends TestCase {
}
}
+ public void testRemoveEndOfCapacity() {
+ FloatList toRemove = FloatArrayList.emptyList().mutableCopyWithCapacity(1);
+ toRemove.addFloat(3);
+ toRemove.remove(0);
+ assertEquals(0, toRemove.size());
+ }
+
+ public void testSublistRemoveEndOfCapacity() {
+ FloatList toRemove = FloatArrayList.emptyList().mutableCopyWithCapacity(1);
+ toRemove.addFloat(3);
+ toRemove.subList(0, 1).clear();
+ assertEquals(0, toRemove.size());
+ }
+
private void assertImmutable(FloatArrayList list) {
if (list.contains(1F)) {
throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
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 3eece26a..c9ebe7f5 100644
--- a/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java
+++ b/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java
@@ -32,19 +32,14 @@ package com.google.protobuf;
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
-import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
import com.google.protobuf.test.UnittestImport;
import protobuf_unittest.EnumWithNoOuter;
import protobuf_unittest.MessageWithNoOuter;
import protobuf_unittest.MultipleFilesTestProto;
import protobuf_unittest.NestedExtension.MyNestedExtension;
-import protobuf_unittest.NestedExtensionLite.MyNestedExtensionLite;
import protobuf_unittest.NonNestedExtension;
import protobuf_unittest.NonNestedExtension.MessageToBeExtended;
import protobuf_unittest.NonNestedExtension.MyNonNestedExtension;
-import protobuf_unittest.NonNestedExtensionLite;
-import protobuf_unittest.NonNestedExtensionLite.MessageLiteToBeExtended;
-import protobuf_unittest.NonNestedExtensionLite.MyNonNestedExtensionLite;
import protobuf_unittest.OuterClassNameTest2OuterClass;
import protobuf_unittest.OuterClassNameTest3OuterClass;
import protobuf_unittest.OuterClassNameTestOuterClass;
@@ -712,70 +707,6 @@ public class GeneratedMessageTest extends TestCase {
}
// =================================================================
- // Lite Extensions.
-
- // We test lite extensions directly because they have a separate
- // implementation from full extensions. In contrast, we do not test
- // lite fields directly since they are implemented exactly the same as
- // regular fields.
-
- public void testLiteExtensionMessageOrBuilder() throws Exception {
- TestAllExtensionsLite.Builder builder = TestAllExtensionsLite.newBuilder();
- TestUtilLite.setAllExtensions(builder);
- TestUtil.assertAllExtensionsSet(builder);
-
- TestAllExtensionsLite message = builder.build();
- TestUtil.assertAllExtensionsSet(message);
- }
-
- public void testLiteExtensionRepeatedSetters() throws Exception {
- TestAllExtensionsLite.Builder builder = TestAllExtensionsLite.newBuilder();
- TestUtilLite.setAllExtensions(builder);
- TestUtilLite.modifyRepeatedExtensions(builder);
- TestUtil.assertRepeatedExtensionsModified(builder);
-
- TestAllExtensionsLite message = builder.build();
- TestUtil.assertRepeatedExtensionsModified(message);
- }
-
- public void testLiteExtensionDefaults() throws Exception {
- TestUtil.assertExtensionsClear(TestAllExtensionsLite.getDefaultInstance());
- TestUtil.assertExtensionsClear(TestAllExtensionsLite.newBuilder().build());
- }
-
- public void testClearLiteExtension() throws Exception {
- // clearExtension() is not actually used in TestUtil, so try it manually.
- assertFalse(
- TestAllExtensionsLite.newBuilder()
- .setExtension(UnittestLite.optionalInt32ExtensionLite, 1)
- .clearExtension(UnittestLite.optionalInt32ExtensionLite)
- .hasExtension(UnittestLite.optionalInt32ExtensionLite));
- assertEquals(0,
- TestAllExtensionsLite.newBuilder()
- .addExtension(UnittestLite.repeatedInt32ExtensionLite, 1)
- .clearExtension(UnittestLite.repeatedInt32ExtensionLite)
- .getExtensionCount(UnittestLite.repeatedInt32ExtensionLite));
- }
-
- public void testLiteExtensionCopy() throws Exception {
- TestAllExtensionsLite original = TestUtilLite.getAllLiteExtensionsSet();
- TestAllExtensionsLite copy =
- TestAllExtensionsLite.newBuilder(original).build();
- TestUtil.assertAllExtensionsSet(copy);
- }
-
- public void testLiteExtensionMergeFrom() throws Exception {
- TestAllExtensionsLite original =
- TestAllExtensionsLite.newBuilder()
- .setExtension(UnittestLite.optionalInt32ExtensionLite, 1).build();
- TestAllExtensionsLite merged =
- TestAllExtensionsLite.newBuilder().mergeFrom(original).build();
- assertTrue(merged.hasExtension(UnittestLite.optionalInt32ExtensionLite));
- assertEquals(
- 1, (int) merged.getExtension(UnittestLite.optionalInt32ExtensionLite));
- }
-
- // =================================================================
// multiple_files_test
// Test that custom options of an file level enum are properly initialized.
@@ -923,15 +854,9 @@ public class GeneratedMessageTest extends TestCase {
}
public void testEnumValues() {
- assertEquals(
- TestAllTypes.NestedEnum.BAR.getNumber(),
- TestAllTypes.NestedEnum.BAR_VALUE);
- assertEquals(
- TestAllTypes.NestedEnum.BAZ.getNumber(),
- TestAllTypes.NestedEnum.BAZ_VALUE);
- assertEquals(
- TestAllTypes.NestedEnum.FOO.getNumber(),
- TestAllTypes.NestedEnum.FOO_VALUE);
+ assertEquals(TestAllTypes.NestedEnum.BAR_VALUE, TestAllTypes.NestedEnum.BAR.getNumber());
+ assertEquals(TestAllTypes.NestedEnum.BAZ_VALUE, TestAllTypes.NestedEnum.BAZ.getNumber());
+ assertEquals(TestAllTypes.NestedEnum.FOO_VALUE, TestAllTypes.NestedEnum.FOO.getNumber());
}
public void testNonNestedExtensionInitialization() {
@@ -948,16 +873,6 @@ public class GeneratedMessageTest extends TestCase {
MyNestedExtension.recursiveExtension.getDescriptor().getName());
}
- public void testNonNestedExtensionLiteInitialization() {
- assertTrue(NonNestedExtensionLite.nonNestedExtensionLite
- .getMessageDefaultInstance() instanceof MyNonNestedExtensionLite);
- }
-
- public void testNestedExtensionLiteInitialization() {
- assertTrue(MyNestedExtensionLite.recursiveExtensionLite
- .getMessageDefaultInstance() instanceof MessageLiteToBeExtended);
- }
-
public void testInvalidations() throws Exception {
GeneratedMessage.enableAlwaysUseFieldBuildersForTesting();
TestAllTypes.NestedMessage nestedMessage1 =
@@ -1319,51 +1234,51 @@ public class GeneratedMessageTest extends TestCase {
assertFalse(builder.clearFooInt().hasFooInt());
TestOneof2 message2 = builder.build();
assertFalse(message2.hasFooInt());
- assertEquals(message2.getFooInt(), 0);
+ assertEquals(0, message2.getFooInt());
}
// Enum
{
TestOneof2.Builder builder = TestOneof2.newBuilder();
- assertEquals(builder.getFooEnum(), TestOneof2.NestedEnum.FOO);
+ assertEquals(TestOneof2.NestedEnum.FOO, builder.getFooEnum());
assertTrue(builder.setFooEnum(TestOneof2.NestedEnum.BAR).hasFooEnum());
- assertEquals(builder.getFooEnum(), TestOneof2.NestedEnum.BAR);
+ assertEquals(TestOneof2.NestedEnum.BAR, builder.getFooEnum());
TestOneof2 message = builder.buildPartial();
assertTrue(message.hasFooEnum());
- assertEquals(message.getFooEnum(), TestOneof2.NestedEnum.BAR);
+ assertEquals(TestOneof2.NestedEnum.BAR, message.getFooEnum());
assertFalse(builder.clearFooEnum().hasFooEnum());
TestOneof2 message2 = builder.build();
assertFalse(message2.hasFooEnum());
- assertEquals(message2.getFooEnum(), TestOneof2.NestedEnum.FOO);
+ assertEquals(TestOneof2.NestedEnum.FOO, message2.getFooEnum());
}
// String
{
TestOneof2.Builder builder = TestOneof2.newBuilder();
- assertEquals(builder.getFooString(), "");
+ assertEquals("", builder.getFooString());
builder.setFooString("foo");
assertTrue(builder.hasFooString());
- assertEquals(builder.getFooString(), "foo");
+ assertEquals("foo", builder.getFooString());
TestOneof2 message = builder.buildPartial();
assertTrue(message.hasFooString());
- assertEquals(message.getFooString(), "foo");
+ assertEquals("foo", message.getFooString());
assertEquals(message.getFooStringBytes(), TestUtil.toBytes("foo"));
assertFalse(builder.clearFooString().hasFooString());
TestOneof2 message2 = builder.buildPartial();
assertFalse(message2.hasFooString());
- assertEquals(message2.getFooString(), "");
+ assertEquals("", message2.getFooString());
assertEquals(message2.getFooStringBytes(), TestUtil.toBytes(""));
// Get method should not change the oneof value.
builder.setFooInt(123);
- assertEquals(builder.getFooString(), "");
+ assertEquals("", builder.getFooString());
assertEquals(builder.getFooStringBytes(), TestUtil.toBytes(""));
assertEquals(123, builder.getFooInt());
message = builder.build();
- assertEquals(message.getFooString(), "");
+ assertEquals("", message.getFooString());
assertEquals(message.getFooStringBytes(), TestUtil.toBytes(""));
assertEquals(123, message.getFooInt());
}
@@ -1371,38 +1286,38 @@ public class GeneratedMessageTest extends TestCase {
// Cord
{
TestOneof2.Builder builder = TestOneof2.newBuilder();
- assertEquals(builder.getFooCord(), "");
+ assertEquals("", builder.getFooCord());
builder.setFooCord("foo");
assertTrue(builder.hasFooCord());
- assertEquals(builder.getFooCord(), "foo");
+ assertEquals("foo", builder.getFooCord());
TestOneof2 message = builder.buildPartial();
assertTrue(message.hasFooCord());
- assertEquals(message.getFooCord(), "foo");
+ assertEquals("foo", message.getFooCord());
assertEquals(message.getFooCordBytes(), TestUtil.toBytes("foo"));
assertFalse(builder.clearFooCord().hasFooCord());
TestOneof2 message2 = builder.build();
assertFalse(message2.hasFooCord());
- assertEquals(message2.getFooCord(), "");
+ assertEquals("", message2.getFooCord());
assertEquals(message2.getFooCordBytes(), TestUtil.toBytes(""));
}
// StringPiece
{
TestOneof2.Builder builder = TestOneof2.newBuilder();
- assertEquals(builder.getFooStringPiece(), "");
+ assertEquals("", builder.getFooStringPiece());
builder.setFooStringPiece("foo");
assertTrue(builder.hasFooStringPiece());
- assertEquals(builder.getFooStringPiece(), "foo");
+ assertEquals("foo", builder.getFooStringPiece());
TestOneof2 message = builder.buildPartial();
assertTrue(message.hasFooStringPiece());
- assertEquals(message.getFooStringPiece(), "foo");
+ assertEquals("foo", message.getFooStringPiece());
assertEquals(message.getFooStringPieceBytes(), TestUtil.toBytes("foo"));
assertFalse(builder.clearFooStringPiece().hasFooStringPiece());
TestOneof2 message2 = builder.build();
assertFalse(message2.hasFooStringPiece());
- assertEquals(message2.getFooStringPiece(), "");
+ assertEquals("", message2.getFooStringPiece());
assertEquals(message2.getFooStringPieceBytes(), TestUtil.toBytes(""));
}
@@ -1410,20 +1325,20 @@ public class GeneratedMessageTest extends TestCase {
{
// set
TestOneof2.Builder builder = TestOneof2.newBuilder();
- assertEquals(builder.getFooMessage().getQuxInt(), 0);
+ assertEquals(0, builder.getFooMessage().getQuxInt());
builder.setFooMessage(
TestOneof2.NestedMessage.newBuilder().setQuxInt(234).build());
assertTrue(builder.hasFooMessage());
- assertEquals(builder.getFooMessage().getQuxInt(), 234);
+ assertEquals(234, builder.getFooMessage().getQuxInt());
TestOneof2 message = builder.buildPartial();
assertTrue(message.hasFooMessage());
- assertEquals(message.getFooMessage().getQuxInt(), 234);
+ assertEquals(234, message.getFooMessage().getQuxInt());
// clear
assertFalse(builder.clearFooMessage().hasFooString());
message = builder.build();
assertFalse(message.hasFooMessage());
- assertEquals(message.getFooMessage().getQuxInt(), 0);
+ assertEquals(0, message.getFooMessage().getQuxInt());
// nested builder
builder = TestOneof2.newBuilder();
@@ -1432,10 +1347,10 @@ public class GeneratedMessageTest extends TestCase {
assertFalse(builder.hasFooMessage());
builder.getFooMessageBuilder().setQuxInt(123);
assertTrue(builder.hasFooMessage());
- assertEquals(builder.getFooMessage().getQuxInt(), 123);
+ assertEquals(123, builder.getFooMessage().getQuxInt());
message = builder.build();
assertTrue(message.hasFooMessage());
- assertEquals(message.getFooMessage().getQuxInt(), 123);
+ assertEquals(123, message.getFooMessage().getQuxInt());
}
// LazyMessage is tested in LazyMessageLiteTest.java
@@ -1448,7 +1363,7 @@ public class GeneratedMessageTest extends TestCase {
TestOneof2 message = builder.setFooInt(123).build();
TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build();
assertTrue(message2.hasFooInt());
- assertEquals(message2.getFooInt(), 123);
+ assertEquals(123, message2.getFooInt());
}
// String
@@ -1457,7 +1372,7 @@ public class GeneratedMessageTest extends TestCase {
TestOneof2 message = builder.setFooString("foo").build();
TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build();
assertTrue(message2.hasFooString());
- assertEquals(message2.getFooString(), "foo");
+ assertEquals("foo", message2.getFooString());
}
// Enum
@@ -1466,7 +1381,7 @@ public class GeneratedMessageTest extends TestCase {
TestOneof2 message = builder.setFooEnum(TestOneof2.NestedEnum.BAR).build();
TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build();
assertTrue(message2.hasFooEnum());
- assertEquals(message2.getFooEnum(), TestOneof2.NestedEnum.BAR);
+ assertEquals(TestOneof2.NestedEnum.BAR, message2.getFooEnum());
}
// Message
@@ -1476,7 +1391,7 @@ public class GeneratedMessageTest extends TestCase {
TestOneof2.NestedMessage.newBuilder().setQuxInt(234).build()).build();
TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build();
assertTrue(message2.hasFooMessage());
- assertEquals(message2.getFooMessage().getQuxInt(), 234);
+ assertEquals(234, message2.getFooMessage().getQuxInt());
}
}
@@ -1488,7 +1403,7 @@ public class GeneratedMessageTest extends TestCase {
ByteString serialized = message.toByteString();
TestOneof2 message2 = TestOneof2.parseFrom(serialized);
assertTrue(message2.hasFooInt());
- assertEquals(message2.getFooInt(), 123);
+ assertEquals(123, message2.getFooInt());
}
// String
@@ -1498,7 +1413,7 @@ public class GeneratedMessageTest extends TestCase {
ByteString serialized = message.toByteString();
TestOneof2 message2 = TestOneof2.parseFrom(serialized);
assertTrue(message2.hasFooString());
- assertEquals(message2.getFooString(), "foo");
+ assertEquals("foo", message2.getFooString());
}
// Enum
@@ -1508,7 +1423,7 @@ public class GeneratedMessageTest extends TestCase {
ByteString serialized = message.toByteString();
TestOneof2 message2 = TestOneof2.parseFrom(serialized);
assertTrue(message2.hasFooEnum());
- assertEquals(message2.getFooEnum(), TestOneof2.NestedEnum.BAR);
+ assertEquals(TestOneof2.NestedEnum.BAR, message2.getFooEnum());
}
// Message
@@ -1519,7 +1434,7 @@ public class GeneratedMessageTest extends TestCase {
ByteString serialized = message.toByteString();
TestOneof2 message2 = TestOneof2.parseFrom(serialized);
assertTrue(message2.hasFooMessage());
- assertEquals(message2.getFooMessage().getQuxInt(), 234);
+ assertEquals(234, message2.getFooMessage().getQuxInt());
}
}
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 60c85450..d8e97d4f 100644
--- a/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java
@@ -32,6 +32,7 @@ package com.google.protobuf;
import static java.util.Arrays.asList;
+import com.google.protobuf.Internal.IntList;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
@@ -297,6 +298,20 @@ public class IntArrayListTest extends TestCase {
}
}
+ public void testRemoveEndOfCapacity() {
+ IntList toRemove = IntArrayList.emptyList().mutableCopyWithCapacity(1);
+ toRemove.addInt(3);
+ toRemove.remove(0);
+ assertEquals(0, toRemove.size());
+ }
+
+ public void testSublistRemoveEndOfCapacity() {
+ IntList toRemove = IntArrayList.emptyList().mutableCopyWithCapacity(1);
+ toRemove.addInt(3);
+ toRemove.subList(0, 1).clear();
+ assertEquals(0, toRemove.size());
+ }
+
private void assertImmutable(IntArrayList list) {
if (list.contains(1)) {
throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
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 16a808bf..1bcf63e7 100644
--- a/java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java
+++ b/java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java
@@ -273,6 +273,15 @@ final class IsValidUtf8TestUtil {
assertEquals(isRoundTrippable, Utf8.isValidUtf8(bytes));
assertEquals(isRoundTrippable, Utf8.isValidUtf8(bytes, 0, numBytes));
+ try {
+ assertEquals(s, Utf8.decodeUtf8(bytes, 0, numBytes));
+ } catch (InvalidProtocolBufferException e) {
+ if (isRoundTrippable) {
+ System.out.println("Could not decode utf-8");
+ outputFailure(byteChar, bytes, bytesReencoded);
+ }
+ }
+
// Test partial sequences.
// Partition numBytes into three segments (not necessarily non-empty).
int i = rnd.nextInt(numBytes);
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 5f013f3c..f27e8e51 100644
--- a/java/core/src/test/java/com/google/protobuf/LazyFieldTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LazyFieldTest.java
@@ -32,7 +32,6 @@ package com.google.protobuf;
import protobuf_unittest.UnittestProto.TestAllExtensions;
import protobuf_unittest.UnittestProto.TestAllTypes;
-import java.io.IOException;
import junit.framework.TestCase;
/**
@@ -89,6 +88,7 @@ public class LazyFieldTest extends TestCase {
assertFalse(message.equals(lazyField.getValue()));
}
+ @SuppressWarnings("EqualsIncompatibleType") // LazyField.equals() is not symmetric
public void testEqualsObjectEx() throws Exception {
TestAllExtensions message = TestUtil.getAllExtensionsSet();
LazyField lazyField = createLazyFieldFromMessage(message);
diff --git a/java/core/src/test/java/com/google/protobuf/LazyStringArrayListTest.java b/java/core/src/test/java/com/google/protobuf/LazyStringArrayListTest.java
index d2bee2a4..2fc3124d 100644
--- a/java/core/src/test/java/com/google/protobuf/LazyStringArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LazyStringArrayListTest.java
@@ -281,6 +281,7 @@ public class LazyStringArrayListTest extends TestCase {
assertGenericListImmutable(byteArrayList, byteArrayList.get(0));
}
+ @SuppressWarnings("unchecked")
private static <T> void assertGenericListImmutable(List<T> list, T value) {
try {
list.add(value);
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 538432f7..5ab80ca2 100644
--- a/java/core/src/test/java/com/google/protobuf/LiteTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LiteTest.java
@@ -33,6 +33,7 @@ package com.google.protobuf;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
+import com.google.protobuf.FieldPresenceTestProto.TestAllTypes;
import com.google.protobuf.UnittestImportLite.ImportEnumLite;
import com.google.protobuf.UnittestImportPublicLite.PublicImportMessageLite;
import com.google.protobuf.UnittestLite.ForeignEnumLite;
@@ -47,11 +48,21 @@ import com.google.protobuf.UnittestLite.TestAllTypesLite.RepeatedGroup;
import com.google.protobuf.UnittestLite.TestAllTypesLiteOrBuilder;
import com.google.protobuf.UnittestLite.TestHugeFieldNumbersLite;
import com.google.protobuf.UnittestLite.TestNestedExtensionLite;
+import map_lite_test.MapTestProto.TestMap;
+import map_lite_test.MapTestProto.TestMap.MessageValue;
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 java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.lang.reflect.Field;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
import junit.framework.TestCase;
/**
@@ -81,12 +92,11 @@ public class LiteTest extends TestCase {
// stuff to make sure the lite message is actually here and usable.
TestAllTypesLite message =
- TestAllTypesLite.newBuilder()
- .setOptionalInt32(123)
- .addRepeatedString("hello")
- .setOptionalNestedMessage(
- TestAllTypesLite.NestedMessage.newBuilder().setBb(7))
- .build();
+ TestAllTypesLite.newBuilder()
+ .setOptionalInt32(123)
+ .addRepeatedString("hello")
+ .setOptionalNestedMessage(TestAllTypesLite.NestedMessage.newBuilder().setBb(7))
+ .build();
ByteString data = message.toByteString();
@@ -98,63 +108,97 @@ public class LiteTest extends TestCase {
assertEquals(7, message2.getOptionalNestedMessage().getBb());
}
+ public void testLite_unknownEnumAtListBoundary() throws Exception {
+ ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
+ CodedOutputStream output = CodedOutputStream.newInstance(byteStream);
+ for (int i = 0; i < AbstractProtobufList.DEFAULT_CAPACITY; i++) {
+ output.writeInt32(TestAllTypesLite.REPEATED_NESTED_ENUM_FIELD_NUMBER, 1);
+ }
+ // 0 is not a valid enum value for NestedEnum
+ output.writeInt32(TestAllTypesLite.REPEATED_NESTED_ENUM_FIELD_NUMBER, 0);
+ output.flush();
+ // This tests a bug we had once with removal right at the boundary of the array. It would throw
+ // at runtime so no need to assert.
+ TestAllTypesLite.parseFrom(new ByteArrayInputStream(byteStream.toByteArray()));
+ }
+
public void testLiteExtensions() throws Exception {
// TODO(kenton): Unlike other features of the lite library, extensions are
// implemented completely differently from the regular library. We
// should probably test them more thoroughly.
TestAllExtensionsLite message =
- TestAllExtensionsLite.newBuilder()
- .setExtension(UnittestLite.optionalInt32ExtensionLite, 123)
- .addExtension(UnittestLite.repeatedStringExtensionLite, "hello")
- .setExtension(UnittestLite.optionalNestedEnumExtensionLite,
- TestAllTypesLite.NestedEnum.BAZ)
- .setExtension(UnittestLite.optionalNestedMessageExtensionLite,
- TestAllTypesLite.NestedMessage.newBuilder().setBb(7).build())
- .build();
+ TestAllExtensionsLite.newBuilder()
+ .setExtension(UnittestLite.optionalInt32ExtensionLite, 123)
+ .addExtension(UnittestLite.repeatedStringExtensionLite, "hello")
+ .setExtension(
+ UnittestLite.optionalNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAZ)
+ .setExtension(
+ UnittestLite.optionalNestedMessageExtensionLite,
+ TestAllTypesLite.NestedMessage.newBuilder().setBb(7).build())
+ .build();
// Test copying a message, since coping extensions actually does use a
// different code path between lite and regular libraries, and as of this
// writing, parsing hasn't been implemented yet.
TestAllExtensionsLite message2 = message.toBuilder().build();
- assertEquals(123, (int) message2.getExtension(
- UnittestLite.optionalInt32ExtensionLite));
- assertEquals(1, message2.getExtensionCount(
- UnittestLite.repeatedStringExtensionLite));
- assertEquals(1, message2.getExtension(
- UnittestLite.repeatedStringExtensionLite).size());
- assertEquals("hello", message2.getExtension(
- UnittestLite.repeatedStringExtensionLite, 0));
- assertEquals(TestAllTypesLite.NestedEnum.BAZ, message2.getExtension(
- UnittestLite.optionalNestedEnumExtensionLite));
- assertEquals(7, message2.getExtension(
- UnittestLite.optionalNestedMessageExtensionLite).getBb());
+ assertEquals(123, (int) message2.getExtension(UnittestLite.optionalInt32ExtensionLite));
+ assertEquals(1, message2.getExtensionCount(UnittestLite.repeatedStringExtensionLite));
+ assertEquals(1, message2.getExtension(UnittestLite.repeatedStringExtensionLite).size());
+ assertEquals("hello", message2.getExtension(UnittestLite.repeatedStringExtensionLite, 0));
+ assertEquals(
+ TestAllTypesLite.NestedEnum.BAZ,
+ message2.getExtension(UnittestLite.optionalNestedEnumExtensionLite));
+ assertEquals(7, message2.getExtension(UnittestLite.optionalNestedMessageExtensionLite).getBb());
}
-
+
public void testClone() {
- TestAllTypesLite.Builder expected = TestAllTypesLite.newBuilder()
- .setOptionalInt32(123);
- assertEquals(
- expected.getOptionalInt32(), expected.clone().getOptionalInt32());
-
- TestAllExtensionsLite.Builder expected2 = TestAllExtensionsLite.newBuilder()
- .setExtension(UnittestLite.optionalInt32ExtensionLite, 123);
+ TestAllTypesLite.Builder expected = TestAllTypesLite.newBuilder().setOptionalInt32(123);
+ assertEquals(expected.getOptionalInt32(), expected.clone().getOptionalInt32());
+
+ TestAllExtensionsLite.Builder expected2 =
+ TestAllExtensionsLite.newBuilder()
+ .setExtension(UnittestLite.optionalInt32ExtensionLite, 123);
assertEquals(
expected2.getExtension(UnittestLite.optionalInt32ExtensionLite),
expected2.clone().getExtension(UnittestLite.optionalInt32ExtensionLite));
}
-
+
public void testAddAll() {
try {
- TestAllTypesLite.newBuilder()
- .addAllRepeatedBytes(null);
+ TestAllTypesLite.newBuilder().addAllRepeatedBytes(null);
fail();
} catch (NullPointerException e) {
// expected.
}
}
-
+
+ public void testMemoization() throws Exception {
+ TestAllExtensionsLite message = TestUtilLite.getAllLiteExtensionsSet();
+
+ // Test serialized size is memoized
+ message.memoizedSerializedSize = -1;
+ int size = message.getSerializedSize();
+ assertTrue(size > 0);
+ assertEquals(size, message.memoizedSerializedSize);
+
+ // Test hashCode is memoized
+ assertEquals(0, message.memoizedHashCode);
+ int hashCode = message.hashCode();
+ assertTrue(hashCode != 0);
+ assertEquals(hashCode, message.memoizedHashCode);
+
+ // Test isInitialized is memoized
+ Field memo = message.getClass().getDeclaredField("memoizedIsInitialized");
+ memo.setAccessible(true);
+ memo.set(message, (byte) -1);
+ boolean initialized = message.isInitialized();
+ assertTrue(initialized);
+ // We have to cast to Byte first. Casting to byte causes a type error
+ assertEquals(1, ((Byte) memo.get(message)).intValue());
+ }
+
public void testSanityCopyOnWrite() throws InvalidProtocolBufferException {
// Since builders are implemented as a thin wrapper around a message
// instance, we attempt to verify that we can't cause the builder to modify
@@ -178,13 +222,11 @@ public class LiteTest extends TestCase {
assertEquals(ByteString.EMPTY, message.getOptionalBytes());
assertEquals(ByteString.copyFromUtf8("hi"), builder.getOptionalBytes());
messageAfterBuild = builder.build();
- assertEquals(
- ByteString.copyFromUtf8("hi"), messageAfterBuild.getOptionalBytes());
+ assertEquals(ByteString.copyFromUtf8("hi"), messageAfterBuild.getOptionalBytes());
assertEquals(ByteString.EMPTY, message.getOptionalBytes());
builder.clearOptionalBytes();
assertEquals(ByteString.EMPTY, builder.getOptionalBytes());
- assertEquals(
- ByteString.copyFromUtf8("hi"), messageAfterBuild.getOptionalBytes());
+ assertEquals(ByteString.copyFromUtf8("hi"), messageAfterBuild.getOptionalBytes());
message = builder.build();
builder.setOptionalCord("hi");
@@ -202,27 +244,23 @@ public class LiteTest extends TestCase {
assertEquals(ByteString.EMPTY, message.getOptionalCordBytes());
assertEquals(ByteString.copyFromUtf8("no"), builder.getOptionalCordBytes());
messageAfterBuild = builder.build();
- assertEquals(
- ByteString.copyFromUtf8("no"),
- messageAfterBuild.getOptionalCordBytes());
+ assertEquals(ByteString.copyFromUtf8("no"), messageAfterBuild.getOptionalCordBytes());
assertEquals(ByteString.EMPTY, message.getOptionalCordBytes());
builder.clearOptionalCord();
assertEquals(ByteString.EMPTY, builder.getOptionalCordBytes());
- assertEquals(
- ByteString.copyFromUtf8("no"),
- messageAfterBuild.getOptionalCordBytes());
-
+ assertEquals(ByteString.copyFromUtf8("no"), messageAfterBuild.getOptionalCordBytes());
+
message = builder.build();
builder.setOptionalDouble(1);
- assertEquals(0D, message.getOptionalDouble());
- assertEquals(1D, builder.getOptionalDouble());
+ assertEquals(0D, message.getOptionalDouble(), 0.0);
+ assertEquals(1D, builder.getOptionalDouble(), 0.0);
messageAfterBuild = builder.build();
- assertEquals(1D, messageAfterBuild.getOptionalDouble());
- assertEquals(0D, message.getOptionalDouble());
+ assertEquals(1D, messageAfterBuild.getOptionalDouble(), 0.0);
+ assertEquals(0D, message.getOptionalDouble(), 0.0);
builder.clearOptionalDouble();
- assertEquals(0D, builder.getOptionalDouble());
- assertEquals(1D, messageAfterBuild.getOptionalDouble());
-
+ assertEquals(0D, builder.getOptionalDouble(), 0.0);
+ assertEquals(1D, messageAfterBuild.getOptionalDouble(), 0.0);
+
message = builder.build();
builder.setOptionalFixed32(1);
assertEquals(0, message.getOptionalFixed32());
@@ -233,7 +271,7 @@ public class LiteTest extends TestCase {
builder.clearOptionalFixed32();
assertEquals(0, builder.getOptionalFixed32());
assertEquals(1, messageAfterBuild.getOptionalFixed32());
-
+
message = builder.build();
builder.setOptionalFixed64(1);
assertEquals(0L, message.getOptionalFixed64());
@@ -247,105 +285,72 @@ public class LiteTest extends TestCase {
message = builder.build();
builder.setOptionalFloat(1);
- assertEquals(0F, message.getOptionalFloat());
- assertEquals(1F, builder.getOptionalFloat());
+ assertEquals(0F, message.getOptionalFloat(), 0.0f);
+ assertEquals(1F, builder.getOptionalFloat(), 0.0f);
messageAfterBuild = builder.build();
- assertEquals(1F, messageAfterBuild.getOptionalFloat());
- assertEquals(0F, message.getOptionalFloat());
+ assertEquals(1F, messageAfterBuild.getOptionalFloat(), 0.0f);
+ assertEquals(0F, message.getOptionalFloat(), 0.0f);
builder.clearOptionalFloat();
- assertEquals(0F, builder.getOptionalFloat());
- assertEquals(1F, messageAfterBuild.getOptionalFloat());
+ assertEquals(0F, builder.getOptionalFloat(), 0.0f);
+ assertEquals(1F, messageAfterBuild.getOptionalFloat(), 0.0f);
message = builder.build();
builder.setOptionalForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR);
- assertEquals(
- ForeignEnumLite.FOREIGN_LITE_FOO, message.getOptionalForeignEnum());
- assertEquals(
- ForeignEnumLite.FOREIGN_LITE_BAR, builder.getOptionalForeignEnum());
+ assertEquals(ForeignEnumLite.FOREIGN_LITE_FOO, message.getOptionalForeignEnum());
+ assertEquals(ForeignEnumLite.FOREIGN_LITE_BAR, builder.getOptionalForeignEnum());
messageAfterBuild = builder.build();
- assertEquals(
- ForeignEnumLite.FOREIGN_LITE_BAR,
- messageAfterBuild.getOptionalForeignEnum());
- assertEquals(
- ForeignEnumLite.FOREIGN_LITE_FOO, message.getOptionalForeignEnum());
+ assertEquals(ForeignEnumLite.FOREIGN_LITE_BAR, messageAfterBuild.getOptionalForeignEnum());
+ assertEquals(ForeignEnumLite.FOREIGN_LITE_FOO, message.getOptionalForeignEnum());
builder.clearOptionalForeignEnum();
- assertEquals(
- ForeignEnumLite.FOREIGN_LITE_FOO, builder.getOptionalForeignEnum());
- assertEquals(
- ForeignEnumLite.FOREIGN_LITE_BAR,
- messageAfterBuild.getOptionalForeignEnum());
+ assertEquals(ForeignEnumLite.FOREIGN_LITE_FOO, builder.getOptionalForeignEnum());
+ assertEquals(ForeignEnumLite.FOREIGN_LITE_BAR, messageAfterBuild.getOptionalForeignEnum());
message = builder.build();
- ForeignMessageLite foreignMessage = ForeignMessageLite.newBuilder()
- .setC(1)
- .build();
+ ForeignMessageLite foreignMessage = ForeignMessageLite.newBuilder().setC(1).build();
builder.setOptionalForeignMessage(foreignMessage);
- assertEquals(
- ForeignMessageLite.getDefaultInstance(),
- message.getOptionalForeignMessage());
+ assertEquals(ForeignMessageLite.getDefaultInstance(), message.getOptionalForeignMessage());
assertEquals(foreignMessage, builder.getOptionalForeignMessage());
messageAfterBuild = builder.build();
assertEquals(foreignMessage, messageAfterBuild.getOptionalForeignMessage());
- assertEquals(
- ForeignMessageLite.getDefaultInstance(),
- message.getOptionalForeignMessage());
+ assertEquals(ForeignMessageLite.getDefaultInstance(), message.getOptionalForeignMessage());
builder.clearOptionalForeignMessage();
- assertEquals(
- ForeignMessageLite.getDefaultInstance(),
- builder.getOptionalForeignMessage());
+ assertEquals(ForeignMessageLite.getDefaultInstance(), builder.getOptionalForeignMessage());
assertEquals(foreignMessage, messageAfterBuild.getOptionalForeignMessage());
message = builder.build();
- ForeignMessageLite.Builder foreignMessageBuilder =
- ForeignMessageLite.newBuilder()
- .setC(3);
+ ForeignMessageLite.Builder foreignMessageBuilder = ForeignMessageLite.newBuilder().setC(3);
builder.setOptionalForeignMessage(foreignMessageBuilder);
- assertEquals(
- ForeignMessageLite.getDefaultInstance(),
- message.getOptionalForeignMessage());
+ assertEquals(ForeignMessageLite.getDefaultInstance(), message.getOptionalForeignMessage());
assertEquals(foreignMessageBuilder.build(), builder.getOptionalForeignMessage());
messageAfterBuild = builder.build();
assertEquals(foreignMessageBuilder.build(), messageAfterBuild.getOptionalForeignMessage());
- assertEquals(
- ForeignMessageLite.getDefaultInstance(),
- message.getOptionalForeignMessage());
+ assertEquals(ForeignMessageLite.getDefaultInstance(), message.getOptionalForeignMessage());
builder.clearOptionalForeignMessage();
- assertEquals(
- ForeignMessageLite.getDefaultInstance(),
- builder.getOptionalForeignMessage());
+ assertEquals(ForeignMessageLite.getDefaultInstance(), builder.getOptionalForeignMessage());
assertEquals(foreignMessageBuilder.build(), messageAfterBuild.getOptionalForeignMessage());
message = builder.build();
- OptionalGroup optionalGroup = OptionalGroup.newBuilder()
- .setA(1)
- .build();
+ OptionalGroup optionalGroup = OptionalGroup.newBuilder().setA(1).build();
builder.setOptionalGroup(optionalGroup);
- assertEquals(
- OptionalGroup.getDefaultInstance(), message.getOptionalGroup());
+ assertEquals(OptionalGroup.getDefaultInstance(), message.getOptionalGroup());
assertEquals(optionalGroup, builder.getOptionalGroup());
messageAfterBuild = builder.build();
assertEquals(optionalGroup, messageAfterBuild.getOptionalGroup());
- assertEquals(
- OptionalGroup.getDefaultInstance(), message.getOptionalGroup());
+ assertEquals(OptionalGroup.getDefaultInstance(), message.getOptionalGroup());
builder.clearOptionalGroup();
- assertEquals(
- OptionalGroup.getDefaultInstance(), builder.getOptionalGroup());
+ assertEquals(OptionalGroup.getDefaultInstance(), builder.getOptionalGroup());
assertEquals(optionalGroup, messageAfterBuild.getOptionalGroup());
message = builder.build();
- OptionalGroup.Builder optionalGroupBuilder = OptionalGroup.newBuilder()
- .setA(3);
+ OptionalGroup.Builder optionalGroupBuilder = OptionalGroup.newBuilder().setA(3);
builder.setOptionalGroup(optionalGroupBuilder);
- assertEquals(
- OptionalGroup.getDefaultInstance(), message.getOptionalGroup());
+ assertEquals(OptionalGroup.getDefaultInstance(), message.getOptionalGroup());
assertEquals(optionalGroupBuilder.build(), builder.getOptionalGroup());
messageAfterBuild = builder.build();
assertEquals(optionalGroupBuilder.build(), messageAfterBuild.getOptionalGroup());
- assertEquals(
- OptionalGroup.getDefaultInstance(), message.getOptionalGroup());
+ assertEquals(OptionalGroup.getDefaultInstance(), message.getOptionalGroup());
builder.clearOptionalGroup();
- assertEquals(
- OptionalGroup.getDefaultInstance(), builder.getOptionalGroup());
+ assertEquals(OptionalGroup.getDefaultInstance(), builder.getOptionalGroup());
assertEquals(optionalGroupBuilder.build(), messageAfterBuild.getOptionalGroup());
message = builder.build();
@@ -369,43 +374,29 @@ public class LiteTest extends TestCase {
builder.clearOptionalInt64();
assertEquals(0L, builder.getOptionalInt64());
assertEquals(1L, messageAfterBuild.getOptionalInt64());
-
+
message = builder.build();
- NestedMessage nestedMessage = NestedMessage.newBuilder()
- .setBb(1)
- .build();
+ NestedMessage nestedMessage = NestedMessage.newBuilder().setBb(1).build();
builder.setOptionalLazyMessage(nestedMessage);
- assertEquals(
- NestedMessage.getDefaultInstance(),
- message.getOptionalLazyMessage());
+ assertEquals(NestedMessage.getDefaultInstance(), message.getOptionalLazyMessage());
assertEquals(nestedMessage, builder.getOptionalLazyMessage());
messageAfterBuild = builder.build();
assertEquals(nestedMessage, messageAfterBuild.getOptionalLazyMessage());
- assertEquals(
- NestedMessage.getDefaultInstance(),
- message.getOptionalLazyMessage());
+ assertEquals(NestedMessage.getDefaultInstance(), message.getOptionalLazyMessage());
builder.clearOptionalLazyMessage();
- assertEquals(
- NestedMessage.getDefaultInstance(), builder.getOptionalLazyMessage());
+ assertEquals(NestedMessage.getDefaultInstance(), builder.getOptionalLazyMessage());
assertEquals(nestedMessage, messageAfterBuild.getOptionalLazyMessage());
message = builder.build();
- NestedMessage.Builder nestedMessageBuilder =
- NestedMessage.newBuilder()
- .setBb(3);
+ NestedMessage.Builder nestedMessageBuilder = NestedMessage.newBuilder().setBb(3);
builder.setOptionalLazyMessage(nestedMessageBuilder);
- assertEquals(
- NestedMessage.getDefaultInstance(),
- message.getOptionalLazyMessage());
+ assertEquals(NestedMessage.getDefaultInstance(), message.getOptionalLazyMessage());
assertEquals(nestedMessageBuilder.build(), builder.getOptionalLazyMessage());
messageAfterBuild = builder.build();
assertEquals(nestedMessageBuilder.build(), messageAfterBuild.getOptionalLazyMessage());
- assertEquals(
- NestedMessage.getDefaultInstance(),
- message.getOptionalLazyMessage());
+ assertEquals(NestedMessage.getDefaultInstance(), message.getOptionalLazyMessage());
builder.clearOptionalLazyMessage();
- assertEquals(
- NestedMessage.getDefaultInstance(), builder.getOptionalLazyMessage());
+ assertEquals(NestedMessage.getDefaultInstance(), builder.getOptionalLazyMessage());
assertEquals(nestedMessageBuilder.build(), messageAfterBuild.getOptionalLazyMessage());
message = builder.build();
@@ -465,19 +456,14 @@ public class LiteTest extends TestCase {
message = builder.build();
builder.setOptionalStringBytes(ByteString.copyFromUtf8("no"));
assertEquals(ByteString.EMPTY, message.getOptionalStringBytes());
- assertEquals(
- ByteString.copyFromUtf8("no"), builder.getOptionalStringBytes());
+ assertEquals(ByteString.copyFromUtf8("no"), builder.getOptionalStringBytes());
messageAfterBuild = builder.build();
- assertEquals(
- ByteString.copyFromUtf8("no"),
- messageAfterBuild.getOptionalStringBytes());
+ assertEquals(ByteString.copyFromUtf8("no"), messageAfterBuild.getOptionalStringBytes());
assertEquals(ByteString.EMPTY, message.getOptionalStringBytes());
builder.clearOptionalString();
assertEquals(ByteString.EMPTY, builder.getOptionalStringBytes());
- assertEquals(
- ByteString.copyFromUtf8("no"),
- messageAfterBuild.getOptionalStringBytes());
-
+ assertEquals(ByteString.copyFromUtf8("no"), messageAfterBuild.getOptionalStringBytes());
+
message = builder.build();
builder.setOptionalStringPiece("hi");
assertEquals("", message.getOptionalStringPiece());
@@ -492,18 +478,13 @@ public class LiteTest extends TestCase {
message = builder.build();
builder.setOptionalStringPieceBytes(ByteString.copyFromUtf8("no"));
assertEquals(ByteString.EMPTY, message.getOptionalStringPieceBytes());
- assertEquals(
- ByteString.copyFromUtf8("no"), builder.getOptionalStringPieceBytes());
+ assertEquals(ByteString.copyFromUtf8("no"), builder.getOptionalStringPieceBytes());
messageAfterBuild = builder.build();
- assertEquals(
- ByteString.copyFromUtf8("no"),
- messageAfterBuild.getOptionalStringPieceBytes());
+ assertEquals(ByteString.copyFromUtf8("no"), messageAfterBuild.getOptionalStringPieceBytes());
assertEquals(ByteString.EMPTY, message.getOptionalStringPieceBytes());
builder.clearOptionalStringPiece();
assertEquals(ByteString.EMPTY, builder.getOptionalStringPieceBytes());
- assertEquals(
- ByteString.copyFromUtf8("no"),
- messageAfterBuild.getOptionalStringPieceBytes());
+ assertEquals(ByteString.copyFromUtf8("no"), messageAfterBuild.getOptionalStringPieceBytes());
message = builder.build();
builder.setOptionalUint32(1);
@@ -540,16 +521,13 @@ public class LiteTest extends TestCase {
message = builder.build();
builder.addAllRepeatedBytes(singletonList(ByteString.copyFromUtf8("hi")));
assertEquals(emptyList(), message.getRepeatedBytesList());
- assertEquals(
- singletonList(ByteString.copyFromUtf8("hi")),
- builder.getRepeatedBytesList());
+ assertEquals(singletonList(ByteString.copyFromUtf8("hi")), builder.getRepeatedBytesList());
assertEquals(emptyList(), message.getRepeatedBytesList());
messageAfterBuild = builder.build();
builder.clearRepeatedBytes();
assertEquals(emptyList(), builder.getRepeatedBytesList());
assertEquals(
- singletonList(ByteString.copyFromUtf8("hi")),
- messageAfterBuild.getRepeatedBytesList());
+ singletonList(ByteString.copyFromUtf8("hi")), messageAfterBuild.getRepeatedBytesList());
message = builder.build();
builder.addAllRepeatedCord(singletonList("hi"));
@@ -602,12 +580,10 @@ public class LiteTest extends TestCase {
assertEquals(singletonList(1F), messageAfterBuild.getRepeatedFloatList());
message = builder.build();
- builder.addAllRepeatedForeignEnum(
- singletonList(ForeignEnumLite.FOREIGN_LITE_BAR));
+ builder.addAllRepeatedForeignEnum(singletonList(ForeignEnumLite.FOREIGN_LITE_BAR));
assertEquals(emptyList(), message.getRepeatedForeignEnumList());
assertEquals(
- singletonList(ForeignEnumLite.FOREIGN_LITE_BAR),
- builder.getRepeatedForeignEnumList());
+ singletonList(ForeignEnumLite.FOREIGN_LITE_BAR), builder.getRepeatedForeignEnumList());
assertEquals(emptyList(), message.getRepeatedForeignEnumList());
messageAfterBuild = builder.build();
builder.clearRepeatedForeignEnum();
@@ -619,23 +595,17 @@ public class LiteTest extends TestCase {
message = builder.build();
builder.addAllRepeatedForeignMessage(singletonList(foreignMessage));
assertEquals(emptyList(), message.getRepeatedForeignMessageList());
- assertEquals(
- singletonList(foreignMessage), builder.getRepeatedForeignMessageList());
+ assertEquals(singletonList(foreignMessage), builder.getRepeatedForeignMessageList());
assertEquals(emptyList(), message.getRepeatedForeignMessageList());
messageAfterBuild = builder.build();
builder.clearRepeatedForeignMessage();
assertEquals(emptyList(), builder.getRepeatedForeignMessageList());
- assertEquals(
- singletonList(foreignMessage),
- messageAfterBuild.getRepeatedForeignMessageList());
+ assertEquals(singletonList(foreignMessage), messageAfterBuild.getRepeatedForeignMessageList());
message = builder.build();
- builder.addAllRepeatedGroup(
- singletonList(RepeatedGroup.getDefaultInstance()));
+ builder.addAllRepeatedGroup(singletonList(RepeatedGroup.getDefaultInstance()));
assertEquals(emptyList(), message.getRepeatedGroupList());
- assertEquals(
- singletonList(RepeatedGroup.getDefaultInstance()),
- builder.getRepeatedGroupList());
+ assertEquals(singletonList(RepeatedGroup.getDefaultInstance()), builder.getRepeatedGroupList());
assertEquals(emptyList(), message.getRepeatedGroupList());
messageAfterBuild = builder.build();
builder.clearRepeatedGroup();
@@ -667,15 +637,12 @@ public class LiteTest extends TestCase {
message = builder.build();
builder.addAllRepeatedLazyMessage(singletonList(nestedMessage));
assertEquals(emptyList(), message.getRepeatedLazyMessageList());
- assertEquals(
- singletonList(nestedMessage), builder.getRepeatedLazyMessageList());
+ assertEquals(singletonList(nestedMessage), builder.getRepeatedLazyMessageList());
assertEquals(emptyList(), message.getRepeatedLazyMessageList());
messageAfterBuild = builder.build();
builder.clearRepeatedLazyMessage();
assertEquals(emptyList(), builder.getRepeatedLazyMessageList());
- assertEquals(
- singletonList(nestedMessage),
- messageAfterBuild.getRepeatedLazyMessageList());
+ assertEquals(singletonList(nestedMessage), messageAfterBuild.getRepeatedLazyMessageList());
message = builder.build();
builder.addAllRepeatedSfixed32(singletonList(1));
@@ -695,8 +662,7 @@ public class LiteTest extends TestCase {
messageAfterBuild = builder.build();
builder.clearRepeatedSfixed64();
assertEquals(emptyList(), builder.getRepeatedSfixed64List());
- assertEquals(
- singletonList(1L), messageAfterBuild.getRepeatedSfixed64List());
+ assertEquals(singletonList(1L), messageAfterBuild.getRepeatedSfixed64List());
message = builder.build();
builder.addAllRepeatedSint32(singletonList(1));
@@ -726,8 +692,7 @@ public class LiteTest extends TestCase {
messageAfterBuild = builder.build();
builder.clearRepeatedString();
assertEquals(emptyList(), builder.getRepeatedStringList());
- assertEquals(
- singletonList("hi"), messageAfterBuild.getRepeatedStringList());
+ assertEquals(singletonList("hi"), messageAfterBuild.getRepeatedStringList());
message = builder.build();
builder.addAllRepeatedStringPiece(singletonList("hi"));
@@ -737,8 +702,7 @@ public class LiteTest extends TestCase {
messageAfterBuild = builder.build();
builder.clearRepeatedStringPiece();
assertEquals(emptyList(), builder.getRepeatedStringPieceList());
- assertEquals(
- singletonList("hi"), messageAfterBuild.getRepeatedStringPieceList());
+ assertEquals(singletonList("hi"), messageAfterBuild.getRepeatedStringPieceList());
message = builder.build();
builder.addAllRepeatedUint32(singletonList(1));
@@ -773,16 +737,13 @@ public class LiteTest extends TestCase {
message = builder.build();
builder.addRepeatedBytes(ByteString.copyFromUtf8("hi"));
assertEquals(emptyList(), message.getRepeatedBytesList());
- assertEquals(
- singletonList(ByteString.copyFromUtf8("hi")),
- builder.getRepeatedBytesList());
+ assertEquals(singletonList(ByteString.copyFromUtf8("hi")), builder.getRepeatedBytesList());
assertEquals(emptyList(), message.getRepeatedBytesList());
messageAfterBuild = builder.build();
builder.clearRepeatedBytes();
assertEquals(emptyList(), builder.getRepeatedBytesList());
assertEquals(
- singletonList(ByteString.copyFromUtf8("hi")),
- messageAfterBuild.getRepeatedBytesList());
+ singletonList(ByteString.copyFromUtf8("hi")), messageAfterBuild.getRepeatedBytesList());
message = builder.build();
builder.addRepeatedCord("hi");
@@ -838,8 +799,7 @@ public class LiteTest extends TestCase {
builder.addRepeatedForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR);
assertEquals(emptyList(), message.getRepeatedForeignEnumList());
assertEquals(
- singletonList(ForeignEnumLite.FOREIGN_LITE_BAR),
- builder.getRepeatedForeignEnumList());
+ singletonList(ForeignEnumLite.FOREIGN_LITE_BAR), builder.getRepeatedForeignEnumList());
assertEquals(emptyList(), message.getRepeatedForeignEnumList());
messageAfterBuild = builder.build();
builder.clearRepeatedForeignEnum();
@@ -851,22 +811,17 @@ public class LiteTest extends TestCase {
message = builder.build();
builder.addRepeatedForeignMessage(foreignMessage);
assertEquals(emptyList(), message.getRepeatedForeignMessageList());
- assertEquals(
- singletonList(foreignMessage), builder.getRepeatedForeignMessageList());
+ assertEquals(singletonList(foreignMessage), builder.getRepeatedForeignMessageList());
assertEquals(emptyList(), message.getRepeatedForeignMessageList());
messageAfterBuild = builder.build();
builder.removeRepeatedForeignMessage(0);
assertEquals(emptyList(), builder.getRepeatedForeignMessageList());
- assertEquals(
- singletonList(foreignMessage),
- messageAfterBuild.getRepeatedForeignMessageList());
+ assertEquals(singletonList(foreignMessage), messageAfterBuild.getRepeatedForeignMessageList());
message = builder.build();
builder.addRepeatedGroup(RepeatedGroup.getDefaultInstance());
assertEquals(emptyList(), message.getRepeatedGroupList());
- assertEquals(
- singletonList(RepeatedGroup.getDefaultInstance()),
- builder.getRepeatedGroupList());
+ assertEquals(singletonList(RepeatedGroup.getDefaultInstance()), builder.getRepeatedGroupList());
assertEquals(emptyList(), message.getRepeatedGroupList());
messageAfterBuild = builder.build();
builder.removeRepeatedGroup(0);
@@ -898,15 +853,12 @@ public class LiteTest extends TestCase {
message = builder.build();
builder.addRepeatedLazyMessage(nestedMessage);
assertEquals(emptyList(), message.getRepeatedLazyMessageList());
- assertEquals(
- singletonList(nestedMessage), builder.getRepeatedLazyMessageList());
+ assertEquals(singletonList(nestedMessage), builder.getRepeatedLazyMessageList());
assertEquals(emptyList(), message.getRepeatedLazyMessageList());
messageAfterBuild = builder.build();
builder.removeRepeatedLazyMessage(0);
assertEquals(emptyList(), builder.getRepeatedLazyMessageList());
- assertEquals(
- singletonList(nestedMessage),
- messageAfterBuild.getRepeatedLazyMessageList());
+ assertEquals(singletonList(nestedMessage), messageAfterBuild.getRepeatedLazyMessageList());
message = builder.build();
builder.addRepeatedSfixed32(1);
@@ -926,8 +878,7 @@ public class LiteTest extends TestCase {
messageAfterBuild = builder.build();
builder.clearRepeatedSfixed64();
assertEquals(emptyList(), builder.getRepeatedSfixed64List());
- assertEquals(
- singletonList(1L), messageAfterBuild.getRepeatedSfixed64List());
+ assertEquals(singletonList(1L), messageAfterBuild.getRepeatedSfixed64List());
message = builder.build();
builder.addRepeatedSint32(1);
@@ -957,8 +908,7 @@ public class LiteTest extends TestCase {
messageAfterBuild = builder.build();
builder.clearRepeatedString();
assertEquals(emptyList(), builder.getRepeatedStringList());
- assertEquals(
- singletonList("hi"), messageAfterBuild.getRepeatedStringList());
+ assertEquals(singletonList("hi"), messageAfterBuild.getRepeatedStringList());
message = builder.build();
builder.addRepeatedStringPiece("hi");
@@ -968,8 +918,7 @@ public class LiteTest extends TestCase {
messageAfterBuild = builder.build();
builder.clearRepeatedStringPiece();
assertEquals(emptyList(), builder.getRepeatedStringPieceList());
- assertEquals(
- singletonList("hi"), messageAfterBuild.getRepeatedStringPieceList());
+ assertEquals(singletonList("hi"), messageAfterBuild.getRepeatedStringPieceList());
message = builder.build();
builder.addRepeatedUint32(1);
@@ -990,7 +939,7 @@ public class LiteTest extends TestCase {
builder.clearRepeatedUint64();
assertEquals(emptyList(), builder.getRepeatedUint64List());
assertEquals(singletonList(1L), messageAfterBuild.getRepeatedUint64List());
-
+
message = builder.build();
builder.addRepeatedBool(true);
messageAfterBuild = builder.build();
@@ -999,14 +948,13 @@ public class LiteTest extends TestCase {
assertEquals(true, messageAfterBuild.getRepeatedBool(0));
assertEquals(false, builder.getRepeatedBool(0));
builder.clearRepeatedBool();
-
+
message = builder.build();
builder.addRepeatedBytes(ByteString.copyFromUtf8("hi"));
messageAfterBuild = builder.build();
assertEquals(0, message.getRepeatedBytesCount());
builder.setRepeatedBytes(0, ByteString.EMPTY);
- assertEquals(
- ByteString.copyFromUtf8("hi"), messageAfterBuild.getRepeatedBytes(0));
+ assertEquals(ByteString.copyFromUtf8("hi"), messageAfterBuild.getRepeatedBytes(0));
assertEquals(ByteString.EMPTY, builder.getRepeatedBytes(0));
builder.clearRepeatedBytes();
@@ -1024,8 +972,7 @@ public class LiteTest extends TestCase {
messageAfterBuild = builder.build();
assertEquals(0, message.getRepeatedCordCount());
builder.setRepeatedCord(0, "");
- assertEquals(
- ByteString.copyFromUtf8("hi"), messageAfterBuild.getRepeatedCordBytes(0));
+ assertEquals(ByteString.copyFromUtf8("hi"), messageAfterBuild.getRepeatedCordBytes(0));
assertEquals(ByteString.EMPTY, builder.getRepeatedCordBytes(0));
builder.clearRepeatedCord();
@@ -1034,8 +981,8 @@ public class LiteTest extends TestCase {
messageAfterBuild = builder.build();
assertEquals(0, message.getRepeatedDoubleCount());
builder.setRepeatedDouble(0, 0D);
- assertEquals(1D, messageAfterBuild.getRepeatedDouble(0));
- assertEquals(0D, builder.getRepeatedDouble(0));
+ assertEquals(1D, messageAfterBuild.getRepeatedDouble(0), 0.0);
+ assertEquals(0D, builder.getRepeatedDouble(0), 0.0);
builder.clearRepeatedDouble();
message = builder.build();
@@ -1061,8 +1008,8 @@ public class LiteTest extends TestCase {
messageAfterBuild = builder.build();
assertEquals(0, message.getRepeatedFloatCount());
builder.setRepeatedFloat(0, 0F);
- assertEquals(1F, messageAfterBuild.getRepeatedFloat(0));
- assertEquals(0F, builder.getRepeatedFloat(0));
+ assertEquals(1F, messageAfterBuild.getRepeatedFloat(0), 0.0f);
+ assertEquals(0F, builder.getRepeatedFloat(0), 0.0f);
builder.clearRepeatedFloat();
message = builder.build();
@@ -1070,36 +1017,26 @@ public class LiteTest extends TestCase {
messageAfterBuild = builder.build();
assertEquals(0, message.getRepeatedForeignEnumCount());
builder.setRepeatedForeignEnum(0, ForeignEnumLite.FOREIGN_LITE_FOO);
- assertEquals(
- ForeignEnumLite.FOREIGN_LITE_BAR,
- messageAfterBuild.getRepeatedForeignEnum(0));
- assertEquals(
- ForeignEnumLite.FOREIGN_LITE_FOO, builder.getRepeatedForeignEnum(0));
+ assertEquals(ForeignEnumLite.FOREIGN_LITE_BAR, messageAfterBuild.getRepeatedForeignEnum(0));
+ assertEquals(ForeignEnumLite.FOREIGN_LITE_FOO, builder.getRepeatedForeignEnum(0));
builder.clearRepeatedForeignEnum();
message = builder.build();
builder.addRepeatedForeignMessage(foreignMessage);
messageAfterBuild = builder.build();
assertEquals(0, message.getRepeatedForeignMessageCount());
- builder.setRepeatedForeignMessage(
- 0, ForeignMessageLite.getDefaultInstance());
- assertEquals(
- foreignMessage, messageAfterBuild.getRepeatedForeignMessage(0));
- assertEquals(
- ForeignMessageLite.getDefaultInstance(),
- builder.getRepeatedForeignMessage(0));
+ builder.setRepeatedForeignMessage(0, ForeignMessageLite.getDefaultInstance());
+ assertEquals(foreignMessage, messageAfterBuild.getRepeatedForeignMessage(0));
+ assertEquals(ForeignMessageLite.getDefaultInstance(), builder.getRepeatedForeignMessage(0));
builder.clearRepeatedForeignMessage();
-
+
message = builder.build();
builder.addRepeatedForeignMessage(foreignMessageBuilder);
messageAfterBuild = builder.build();
assertEquals(0, message.getRepeatedForeignMessageCount());
- builder.setRepeatedForeignMessage(
- 0, ForeignMessageLite.getDefaultInstance());
+ builder.setRepeatedForeignMessage(0, ForeignMessageLite.getDefaultInstance());
assertEquals(foreignMessageBuilder.build(), messageAfterBuild.getRepeatedForeignMessage(0));
- assertEquals(
- ForeignMessageLite.getDefaultInstance(),
- builder.getRepeatedForeignMessage(0));
+ assertEquals(ForeignMessageLite.getDefaultInstance(), builder.getRepeatedForeignMessage(0));
builder.clearRepeatedForeignMessage();
message = builder.build();
@@ -1107,54 +1044,46 @@ public class LiteTest extends TestCase {
messageAfterBuild = builder.build();
assertEquals(0, message.getRepeatedForeignMessageCount());
builder.setRepeatedForeignMessage(0, foreignMessageBuilder);
- assertEquals(
- foreignMessage, messageAfterBuild.getRepeatedForeignMessage(0));
+ assertEquals(foreignMessage, messageAfterBuild.getRepeatedForeignMessage(0));
assertEquals(foreignMessageBuilder.build(), builder.getRepeatedForeignMessage(0));
builder.clearRepeatedForeignMessage();
message = builder.build();
- RepeatedGroup repeatedGroup = RepeatedGroup.newBuilder()
- .setA(1)
- .build();
+ RepeatedGroup repeatedGroup = RepeatedGroup.newBuilder().setA(1).build();
builder.addRepeatedGroup(repeatedGroup);
messageAfterBuild = builder.build();
assertEquals(0, message.getRepeatedGroupCount());
builder.setRepeatedGroup(0, RepeatedGroup.getDefaultInstance());
assertEquals(repeatedGroup, messageAfterBuild.getRepeatedGroup(0));
- assertEquals(
- RepeatedGroup.getDefaultInstance(), builder.getRepeatedGroup(0));
+ assertEquals(RepeatedGroup.getDefaultInstance(), builder.getRepeatedGroup(0));
builder.clearRepeatedGroup();
-
+
message = builder.build();
builder.addRepeatedGroup(0, repeatedGroup);
messageAfterBuild = builder.build();
assertEquals(0, message.getRepeatedGroupCount());
builder.setRepeatedGroup(0, RepeatedGroup.getDefaultInstance());
assertEquals(repeatedGroup, messageAfterBuild.getRepeatedGroup(0));
- assertEquals(
- RepeatedGroup.getDefaultInstance(), builder.getRepeatedGroup(0));
+ assertEquals(RepeatedGroup.getDefaultInstance(), builder.getRepeatedGroup(0));
builder.clearRepeatedGroup();
-
+
message = builder.build();
- RepeatedGroup.Builder repeatedGroupBuilder = RepeatedGroup.newBuilder()
- .setA(3);
+ RepeatedGroup.Builder repeatedGroupBuilder = RepeatedGroup.newBuilder().setA(3);
builder.addRepeatedGroup(repeatedGroupBuilder);
messageAfterBuild = builder.build();
assertEquals(0, message.getRepeatedGroupCount());
builder.setRepeatedGroup(0, RepeatedGroup.getDefaultInstance());
assertEquals(repeatedGroupBuilder.build(), messageAfterBuild.getRepeatedGroup(0));
- assertEquals(
- RepeatedGroup.getDefaultInstance(), builder.getRepeatedGroup(0));
+ assertEquals(RepeatedGroup.getDefaultInstance(), builder.getRepeatedGroup(0));
builder.clearRepeatedGroup();
-
+
message = builder.build();
builder.addRepeatedGroup(0, repeatedGroupBuilder);
messageAfterBuild = builder.build();
assertEquals(0, message.getRepeatedGroupCount());
builder.setRepeatedGroup(0, RepeatedGroup.getDefaultInstance());
assertEquals(repeatedGroupBuilder.build(), messageAfterBuild.getRepeatedGroup(0));
- assertEquals(
- RepeatedGroup.getDefaultInstance(), builder.getRepeatedGroup(0));
+ assertEquals(RepeatedGroup.getDefaultInstance(), builder.getRepeatedGroup(0));
builder.clearRepeatedGroup();
message = builder.build();
@@ -1174,45 +1103,41 @@ public class LiteTest extends TestCase {
assertEquals(1L, messageAfterBuild.getRepeatedInt64(0));
assertEquals(0L, builder.getRepeatedInt64(0));
builder.clearRepeatedInt64();
-
+
message = builder.build();
builder.addRepeatedLazyMessage(nestedMessage);
messageAfterBuild = builder.build();
assertEquals(0, message.getRepeatedLazyMessageCount());
builder.setRepeatedLazyMessage(0, NestedMessage.getDefaultInstance());
assertEquals(nestedMessage, messageAfterBuild.getRepeatedLazyMessage(0));
- assertEquals(
- NestedMessage.getDefaultInstance(), builder.getRepeatedLazyMessage(0));
+ assertEquals(NestedMessage.getDefaultInstance(), builder.getRepeatedLazyMessage(0));
builder.clearRepeatedLazyMessage();
-
+
message = builder.build();
builder.addRepeatedLazyMessage(0, nestedMessage);
messageAfterBuild = builder.build();
assertEquals(0, message.getRepeatedLazyMessageCount());
builder.setRepeatedLazyMessage(0, NestedMessage.getDefaultInstance());
assertEquals(nestedMessage, messageAfterBuild.getRepeatedLazyMessage(0));
- assertEquals(
- NestedMessage.getDefaultInstance(), builder.getRepeatedLazyMessage(0));
+ assertEquals(NestedMessage.getDefaultInstance(), builder.getRepeatedLazyMessage(0));
builder.clearRepeatedLazyMessage();
-
+
message = builder.build();
builder.addRepeatedLazyMessage(nestedMessageBuilder);
messageAfterBuild = builder.build();
assertEquals(0, message.getRepeatedLazyMessageCount());
builder.setRepeatedLazyMessage(0, NestedMessage.getDefaultInstance());
assertEquals(nestedMessageBuilder.build(), messageAfterBuild.getRepeatedLazyMessage(0));
- assertEquals(
- NestedMessage.getDefaultInstance(), builder.getRepeatedLazyMessage(0));
+ assertEquals(NestedMessage.getDefaultInstance(), builder.getRepeatedLazyMessage(0));
builder.clearRepeatedLazyMessage();
-
+
message = builder.build();
builder.addRepeatedLazyMessage(0, nestedMessageBuilder);
messageAfterBuild = builder.build();
assertEquals(0, message.getRepeatedLazyMessageCount());
builder.setRepeatedLazyMessage(0, NestedMessage.getDefaultInstance());
assertEquals(nestedMessageBuilder.build(), messageAfterBuild.getRepeatedLazyMessage(0));
- assertEquals(
- NestedMessage.getDefaultInstance(), builder.getRepeatedLazyMessage(0));
+ assertEquals(NestedMessage.getDefaultInstance(), builder.getRepeatedLazyMessage(0));
builder.clearRepeatedLazyMessage();
message = builder.build();
@@ -1265,9 +1190,7 @@ public class LiteTest extends TestCase {
messageAfterBuild = builder.build();
assertEquals(0L, message.getRepeatedStringCount());
builder.setRepeatedString(0, "");
- assertEquals(
- ByteString.copyFromUtf8("hi"),
- messageAfterBuild.getRepeatedStringBytes(0));
+ assertEquals(ByteString.copyFromUtf8("hi"), messageAfterBuild.getRepeatedStringBytes(0));
assertEquals(ByteString.EMPTY, builder.getRepeatedStringBytes(0));
builder.clearRepeatedString();
@@ -1285,9 +1208,7 @@ public class LiteTest extends TestCase {
messageAfterBuild = builder.build();
assertEquals(0L, message.getRepeatedStringPieceCount());
builder.setRepeatedStringPiece(0, "");
- assertEquals(
- ByteString.copyFromUtf8("hi"),
- messageAfterBuild.getRepeatedStringPieceBytes(0));
+ assertEquals(ByteString.copyFromUtf8("hi"), messageAfterBuild.getRepeatedStringPieceBytes(0));
assertEquals(ByteString.EMPTY, builder.getRepeatedStringPieceBytes(0));
builder.clearRepeatedStringPiece();
@@ -1311,18 +1232,14 @@ public class LiteTest extends TestCase {
message = builder.build();
assertEquals(0, message.getSerializedSize());
- builder.mergeFrom(TestAllTypesLite.newBuilder()
- .setOptionalBool(true)
- .build());
+ builder.mergeFrom(TestAllTypesLite.newBuilder().setOptionalBool(true).build());
assertEquals(0, message.getSerializedSize());
assertEquals(true, builder.build().getOptionalBool());
builder.clearOptionalBool();
message = builder.build();
assertEquals(0, message.getSerializedSize());
- builder.mergeFrom(TestAllTypesLite.newBuilder()
- .setOptionalBool(true)
- .build());
+ builder.mergeFrom(TestAllTypesLite.newBuilder().setOptionalBool(true).build());
assertEquals(0, message.getSerializedSize());
assertEquals(true, builder.build().getOptionalBool());
builder.clear();
@@ -1332,93 +1249,107 @@ public class LiteTest extends TestCase {
assertEquals(0, message.getSerializedSize());
builder.mergeOptionalForeignMessage(foreignMessage);
assertEquals(0, message.getSerializedSize());
- assertEquals(
- foreignMessage.getC(),
- builder.build().getOptionalForeignMessage().getC());
+ assertEquals(foreignMessage.getC(), builder.build().getOptionalForeignMessage().getC());
builder.clearOptionalForeignMessage();
message = builder.build();
assertEquals(0, message.getSerializedSize());
builder.mergeOptionalLazyMessage(nestedMessage);
assertEquals(0, message.getSerializedSize());
- assertEquals(
- nestedMessage.getBb(),
- builder.build().getOptionalLazyMessage().getBb());
+ assertEquals(nestedMessage.getBb(), builder.build().getOptionalLazyMessage().getBb());
builder.clearOptionalLazyMessage();
-
+
message = builder.build();
builder.setOneofString("hi");
- assertEquals(
- OneofFieldCase.ONEOFFIELD_NOT_SET, message.getOneofFieldCase());
+ assertEquals(OneofFieldCase.ONEOFFIELD_NOT_SET, message.getOneofFieldCase());
assertEquals(OneofFieldCase.ONEOF_STRING, builder.getOneofFieldCase());
assertEquals("hi", builder.getOneofString());
messageAfterBuild = builder.build();
- assertEquals(
- OneofFieldCase.ONEOF_STRING, messageAfterBuild.getOneofFieldCase());
+ assertEquals(OneofFieldCase.ONEOF_STRING, messageAfterBuild.getOneofFieldCase());
assertEquals("hi", messageAfterBuild.getOneofString());
builder.setOneofUint32(1);
- assertEquals(
- OneofFieldCase.ONEOF_STRING, messageAfterBuild.getOneofFieldCase());
+ assertEquals(OneofFieldCase.ONEOF_STRING, messageAfterBuild.getOneofFieldCase());
assertEquals("hi", messageAfterBuild.getOneofString());
assertEquals(OneofFieldCase.ONEOF_UINT32, builder.getOneofFieldCase());
assertEquals(1, builder.getOneofUint32());
TestAllTypesLiteOrBuilder messageOrBuilder = builder;
assertEquals(OneofFieldCase.ONEOF_UINT32, messageOrBuilder.getOneofFieldCase());
-
- TestAllExtensionsLite.Builder extendableMessageBuilder =
- TestAllExtensionsLite.newBuilder();
+
+ TestAllExtensionsLite.Builder extendableMessageBuilder = TestAllExtensionsLite.newBuilder();
TestAllExtensionsLite extendableMessage = extendableMessageBuilder.build();
- extendableMessageBuilder.setExtension(
- UnittestLite.optionalInt32ExtensionLite, 1);
- assertFalse(extendableMessage.hasExtension(
- UnittestLite.optionalInt32ExtensionLite));
+ extendableMessageBuilder.setExtension(UnittestLite.optionalInt32ExtensionLite, 1);
+ assertFalse(extendableMessage.hasExtension(UnittestLite.optionalInt32ExtensionLite));
extendableMessage = extendableMessageBuilder.build();
assertEquals(
- 1, (int) extendableMessageBuilder.getExtension(
- UnittestLite.optionalInt32ExtensionLite));
- assertEquals(
- 1, (int) extendableMessage.getExtension(
- UnittestLite.optionalInt32ExtensionLite));
- extendableMessageBuilder.setExtension(
- UnittestLite.optionalInt32ExtensionLite, 3);
+ 1, (int) extendableMessageBuilder.getExtension(UnittestLite.optionalInt32ExtensionLite));
+ assertEquals(1, (int) extendableMessage.getExtension(UnittestLite.optionalInt32ExtensionLite));
+ extendableMessageBuilder.setExtension(UnittestLite.optionalInt32ExtensionLite, 3);
assertEquals(
- 3, (int) extendableMessageBuilder.getExtension(
- UnittestLite.optionalInt32ExtensionLite));
- assertEquals(
- 1, (int) extendableMessage.getExtension(
- UnittestLite.optionalInt32ExtensionLite));
+ 3, (int) extendableMessageBuilder.getExtension(UnittestLite.optionalInt32ExtensionLite));
+ assertEquals(1, (int) extendableMessage.getExtension(UnittestLite.optionalInt32ExtensionLite));
extendableMessage = extendableMessageBuilder.build();
assertEquals(
- 3, (int) extendableMessageBuilder.getExtension(
- UnittestLite.optionalInt32ExtensionLite));
- assertEquals(
- 3, (int) extendableMessage.getExtension(
- UnittestLite.optionalInt32ExtensionLite));
-
+ 3, (int) extendableMessageBuilder.getExtension(UnittestLite.optionalInt32ExtensionLite));
+ assertEquals(3, (int) extendableMessage.getExtension(UnittestLite.optionalInt32ExtensionLite));
+
// No extension registry, so it should be in unknown fields.
- extendableMessage =
- TestAllExtensionsLite.parseFrom(extendableMessage.toByteArray());
- assertFalse(extendableMessage.hasExtension(
- UnittestLite.optionalInt32ExtensionLite));
-
+ extendableMessage = TestAllExtensionsLite.parseFrom(extendableMessage.toByteArray());
+ assertFalse(extendableMessage.hasExtension(UnittestLite.optionalInt32ExtensionLite));
+
extendableMessageBuilder = extendableMessage.toBuilder();
- extendableMessageBuilder.mergeFrom(TestAllExtensionsLite.newBuilder()
- .setExtension(UnittestLite.optionalFixed32ExtensionLite, 11)
- .build());
-
+ extendableMessageBuilder.mergeFrom(
+ TestAllExtensionsLite.newBuilder()
+ .setExtension(UnittestLite.optionalFixed32ExtensionLite, 11)
+ .build());
+
extendableMessage = extendableMessageBuilder.build();
ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance();
UnittestLite.registerAllExtensions(registry);
- extendableMessage = TestAllExtensionsLite.parseFrom(
- extendableMessage.toByteArray(), registry);
-
+ extendableMessage = TestAllExtensionsLite.parseFrom(extendableMessage.toByteArray(), registry);
+
// The unknown field was preserved.
+ assertEquals(3, (int) extendableMessage.getExtension(UnittestLite.optionalInt32ExtensionLite));
assertEquals(
- 3, (int) extendableMessage.getExtension(
- UnittestLite.optionalInt32ExtensionLite));
- assertEquals(
- 11, (int) extendableMessage.getExtension(
- UnittestLite.optionalFixed32ExtensionLite));
+ 11, (int) extendableMessage.getExtension(UnittestLite.optionalFixed32ExtensionLite));
+ }
+
+ public void testBuilderMergeFromNull() throws Exception {
+ try {
+ TestAllTypesLite.newBuilder().mergeFrom((TestAllTypesLite) null);
+ fail("Expected exception");
+ } catch (NullPointerException e) {
+ // Pass.
+ }
+ }
+
+ // Builder.mergeFrom() should keep existing extensions.
+ public void testBuilderMergeFromWithExtensions() throws Exception {
+ TestAllExtensionsLite message =
+ TestAllExtensionsLite.newBuilder()
+ .addExtension(UnittestLite.repeatedInt32ExtensionLite, 12)
+ .build();
+
+ ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance();
+ UnittestLite.registerAllExtensions(registry);
+
+ TestAllExtensionsLite.Builder builder = TestAllExtensionsLite.newBuilder();
+ builder.mergeFrom(message.toByteArray(), registry);
+ builder.mergeFrom(message.toByteArray(), registry);
+ TestAllExtensionsLite result = builder.build();
+ assertEquals(2, result.getExtensionCount(UnittestLite.repeatedInt32ExtensionLite));
+ assertEquals(12, result.getExtension(UnittestLite.repeatedInt32ExtensionLite, 0).intValue());
+ assertEquals(12, result.getExtension(UnittestLite.repeatedInt32ExtensionLite, 1).intValue());
+ }
+
+ // Builder.mergeFrom() should keep existing unknown fields.
+ public void testBuilderMergeFromWithUnknownFields() throws Exception {
+ TestAllTypesLite message = TestAllTypesLite.newBuilder().addRepeatedInt32(1).build();
+
+ NestedMessage.Builder builder = NestedMessage.newBuilder();
+ builder.mergeFrom(message.toByteArray());
+ builder.mergeFrom(message.toByteArray());
+ NestedMessage result = builder.build();
+ assertEquals(message.getSerializedSize() * 2, result.getSerializedSize());
}
public void testToStringDefaultInstance() throws Exception {
@@ -1426,140 +1357,174 @@ public class LiteTest extends TestCase {
}
public void testToStringScalarFieldsSuffixedWithList() throws Exception {
- assertToStringEquals("deceptively_named_list: 7", TestAllTypesLite.newBuilder()
- .setDeceptivelyNamedList(7)
- .build());
+ assertToStringEquals(
+ "deceptively_named_list: 7",
+ TestAllTypesLite.newBuilder().setDeceptivelyNamedList(7).build());
}
public void testToStringPrimitives() throws Exception {
- TestAllTypesLite proto = TestAllTypesLite.newBuilder()
- .setOptionalInt32(1)
- .setOptionalInt64(9223372036854775807L)
- .build();
+ 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();
+ 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();
+ 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();
+ TestAllTypesLite proto =
+ TestAllTypesLite.newBuilder().setOptionalString("foo\"bar\nbaz\\").build();
assertToStringEquals("optional_string: \"foo\\\"bar\\nbaz\\\\\"", proto);
- proto = TestAllTypesLite.newBuilder()
- .setOptionalString("\u6587")
- .build();
+ 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();
+ 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();
+ 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();
+ 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();
+ 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);
+ "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();
+ 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);
+ "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();
+ 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);
+ "[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());
+ 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);
+ "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();
+ 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();
+ 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();
+ TestAllTypesLite message = TestAllTypesLite.newBuilder().setOneofString("hello").build();
assertToStringEquals("oneof_string: \"hello\"", message);
}
+ public void testToStringMapFields() throws Exception {
+ TestMap message1 =
+ TestMap.newBuilder()
+ .putInt32ToStringField(1, "alpha")
+ .putInt32ToStringField(2, "beta")
+ .build();
+ assertToStringEquals(
+ "int32_to_string_field {\n"
+ + " key: 1\n"
+ + " value: \"alpha\"\n"
+ + "}\n"
+ + "int32_to_string_field {\n"
+ + " key: 2\n"
+ + " value: \"beta\"\n"
+ + "}",
+ message1);
+
+ TestMap message2 =
+ TestMap.newBuilder()
+ .putInt32ToMessageField(1, MessageValue.newBuilder().setValue(10).build())
+ .putInt32ToMessageField(2, MessageValue.newBuilder().setValue(20).build())
+ .build();
+ assertToStringEquals(
+ "int32_to_message_field {\n"
+ + " key: 1\n"
+ + " value {\n"
+ + " value: 10\n"
+ + " }\n"
+ + "}\n"
+ + "int32_to_message_field {\n"
+ + " key: 2\n"
+ + " value {\n"
+ + " value: 20\n"
+ + " }\n"
+ + "}",
+ message2);
+ }
+
// 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.
@@ -1573,38 +1538,38 @@ public class LiteTest extends TestCase {
}
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 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 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);
@@ -1613,27 +1578,26 @@ public class LiteTest extends TestCase {
}
public void testMergeFromStream_repeatedField() throws Exception {
- TestAllTypesLite.Builder builder = TestAllTypesLite.newBuilder()
- .addRepeatedString("hello");
+ 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);
+ TestAllTypesLite.Builder builder = TestAllTypesLite.newBuilder().setDefaultBool(true);
try {
builder.mergeFrom(CodedInputStream.newInstance("Invalid bytes".getBytes(Internal.UTF_8)));
fail();
- } catch (InvalidProtocolBufferException expected) {}
+ } 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);
@@ -1642,14 +1606,14 @@ public class LiteTest extends TestCase {
}
public void testMergeFromNoLazyFieldSharing() throws Exception {
- TestAllTypesLite.Builder sourceBuilder = TestAllTypesLite.newBuilder().setOptionalLazyMessage(
- TestAllTypesLite.NestedMessage.newBuilder().setBb(1));
+ TestAllTypesLite.Builder sourceBuilder =
+ TestAllTypesLite.newBuilder()
+ .setOptionalLazyMessage(TestAllTypesLite.NestedMessage.newBuilder().setBb(1));
TestAllTypesLite.Builder targetBuilder =
TestAllTypesLite.newBuilder().mergeFrom(sourceBuilder.build());
assertEquals(1, sourceBuilder.getOptionalLazyMessage().getBb());
// now change the sourceBuilder, and target value shouldn't be affected.
- sourceBuilder.setOptionalLazyMessage(
- TestAllTypesLite.NestedMessage.newBuilder().setBb(2));
+ sourceBuilder.setOptionalLazyMessage(TestAllTypesLite.NestedMessage.newBuilder().setBb(2));
assertEquals(1, targetBuilder.getOptionalLazyMessage().getBb());
}
@@ -1657,508 +1621,373 @@ public class LiteTest extends TestCase {
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();
+
+ TestAllTypesLite oneFieldSet = TestAllTypesLite.newBuilder().setDefaultBool(true).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setDefaultBytes(ByteString.EMPTY)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setDefaultBytes(ByteString.EMPTY).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setDefaultCord("")
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setDefaultCord("").build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setDefaultCordBytes(ByteString.EMPTY)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setDefaultCordBytes(ByteString.EMPTY).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setDefaultDouble(0)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setDefaultDouble(0).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setDefaultFixed32(0)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setDefaultFixed32(0).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setDefaultFixed64(0)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setDefaultFixed64(0).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setDefaultFloat(0)
- .build();
+
+ 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();
+
+ 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();
+
+ 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();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setDefaultInt32(0).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setDefaultInt64(0)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setDefaultInt64(0).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setDefaultNestedEnum(NestedEnum.BAR)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setDefaultNestedEnum(NestedEnum.BAR).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setDefaultSfixed32(0)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setDefaultSfixed32(0).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setDefaultSfixed64(0)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setDefaultSfixed64(0).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setDefaultSint32(0)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setDefaultSint32(0).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setDefaultSint64(0)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setDefaultSint64(0).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setDefaultString("")
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setDefaultString("").build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setDefaultStringBytes(ByteString.EMPTY)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setDefaultStringBytes(ByteString.EMPTY).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setDefaultStringPiece("")
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setDefaultStringPiece("").build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setDefaultStringPieceBytes(ByteString.EMPTY)
- .build();
+
+ oneFieldSet =
+ TestAllTypesLite.newBuilder().setDefaultStringPieceBytes(ByteString.EMPTY).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setDefaultUint32(0)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setDefaultUint32(0).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setDefaultUint64(0)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setDefaultUint64(0).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .addRepeatedBool(true)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedBool(true).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .addRepeatedBytes(ByteString.EMPTY)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedBytes(ByteString.EMPTY).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .addRepeatedCord("")
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedCord("").build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .addRepeatedCordBytes(ByteString.EMPTY)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedCordBytes(ByteString.EMPTY).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .addRepeatedDouble(0)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedDouble(0).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .addRepeatedFixed32(0)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedFixed32(0).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .addRepeatedFixed64(0)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedFixed64(0).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .addRepeatedFloat(0)
- .build();
+
+ 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();
+
+ 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();
+
+ 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();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedInt32(0).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .addRepeatedInt64(0)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedInt64(0).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .addRepeatedNestedEnum(NestedEnum.BAR)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedNestedEnum(NestedEnum.BAR).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .addRepeatedSfixed32(0)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedSfixed32(0).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .addRepeatedSfixed64(0)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedSfixed64(0).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .addRepeatedSint32(0)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedSint32(0).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .addRepeatedSint64(0)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedSint64(0).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .addRepeatedString("")
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedString("").build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .addRepeatedStringBytes(ByteString.EMPTY)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedStringBytes(ByteString.EMPTY).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .addRepeatedStringPiece("")
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedStringPiece("").build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .addRepeatedStringPieceBytes(ByteString.EMPTY)
- .build();
+
+ oneFieldSet =
+ TestAllTypesLite.newBuilder().addRepeatedStringPieceBytes(ByteString.EMPTY).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .addRepeatedUint32(0)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedUint32(0).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .addRepeatedUint64(0)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedUint64(0).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setOptionalBool(true)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setOptionalBool(true).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setOptionalBytes(ByteString.EMPTY)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setOptionalBytes(ByteString.EMPTY).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setOptionalCord("")
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setOptionalCord("").build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setOptionalCordBytes(ByteString.EMPTY)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setOptionalCordBytes(ByteString.EMPTY).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setOptionalDouble(0)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setOptionalDouble(0).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setOptionalFixed32(0)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setOptionalFixed32(0).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setOptionalFixed64(0)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setOptionalFixed64(0).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setOptionalFloat(0)
- .build();
+
+ 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();
+
+ 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();
+
+ 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();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setOptionalInt32(0).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setOptionalInt64(0)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setOptionalInt64(0).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setOptionalNestedEnum(NestedEnum.BAR)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setOptionalNestedEnum(NestedEnum.BAR).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setOptionalSfixed32(0)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setOptionalSfixed32(0).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setOptionalSfixed64(0)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setOptionalSfixed64(0).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setOptionalSint32(0)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setOptionalSint32(0).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setOptionalSint64(0)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setOptionalSint64(0).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setOptionalString("")
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setOptionalString("").build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setOptionalStringBytes(ByteString.EMPTY)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setOptionalStringBytes(ByteString.EMPTY).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setOptionalStringPiece("")
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setOptionalStringPiece("").build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setOptionalStringPieceBytes(ByteString.EMPTY)
- .build();
+
+ oneFieldSet =
+ TestAllTypesLite.newBuilder().setOptionalStringPieceBytes(ByteString.EMPTY).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setOptionalUint32(0)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setOptionalUint32(0).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setOptionalUint64(0)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setOptionalUint64(0).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setOneofBytes(ByteString.EMPTY)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setOneofBytes(ByteString.EMPTY).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setOneofLazyNestedMessage(NestedMessage.getDefaultInstance())
- .build();
+
+ oneFieldSet =
+ TestAllTypesLite.newBuilder()
+ .setOneofLazyNestedMessage(NestedMessage.getDefaultInstance())
+ .build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setOneofNestedMessage(NestedMessage.getDefaultInstance())
- .build();
+
+ oneFieldSet =
+ TestAllTypesLite.newBuilder()
+ .setOneofNestedMessage(NestedMessage.getDefaultInstance())
+ .build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setOneofString("")
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setOneofString("").build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setOneofStringBytes(ByteString.EMPTY)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setOneofStringBytes(ByteString.EMPTY).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
-
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setOneofUint32(0)
- .build();
+
+ oneFieldSet = TestAllTypesLite.newBuilder().setOneofUint32(0).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setOptionalForeignMessage(ForeignMessageLite.getDefaultInstance())
- .build();
+ oneFieldSet =
+ TestAllTypesLite.newBuilder()
+ .setOptionalForeignMessage(ForeignMessageLite.getDefaultInstance())
+ .build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setOptionalGroup(OptionalGroup.getDefaultInstance())
- .build();
+ oneFieldSet =
+ TestAllTypesLite.newBuilder().setOptionalGroup(OptionalGroup.getDefaultInstance()).build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setOptionalPublicImportMessage(PublicImportMessageLite.getDefaultInstance())
- .build();
+ oneFieldSet =
+ TestAllTypesLite.newBuilder()
+ .setOptionalPublicImportMessage(PublicImportMessageLite.getDefaultInstance())
+ .build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
- oneFieldSet = TestAllTypesLite.newBuilder()
- .setOptionalLazyMessage(NestedMessage.getDefaultInstance())
- .build();
+ oneFieldSet =
+ TestAllTypesLite.newBuilder()
+ .setOptionalLazyMessage(NestedMessage.getDefaultInstance())
+ .build();
assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-
+
assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
- oneFieldSet = TestAllTypesLite.newBuilder()
- .addRepeatedLazyMessage(NestedMessage.getDefaultInstance())
- .build();
+ 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();
+ 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);
@@ -2174,6 +2003,17 @@ public class LiteTest extends TestCase {
assertFalse(bar.equals(barPrime));
}
+ public void testEqualsAndHashCodeForTrickySchemaTypes() {
+ Foo foo1 = Foo.getDefaultInstance();
+ Foo foo2 = Foo.newBuilder().setSint64(1).build();
+ Foo foo3 = Foo.newBuilder().putMyMap("key", "value2").build();
+ Foo foo4 = Foo.newBuilder().setMyGroup(Foo.MyGroup.newBuilder().setValue(4).build()).build();
+
+ assertEqualsAndHashCodeAreFalse(foo1, foo2);
+ assertEqualsAndHashCodeAreFalse(foo1, foo3);
+ assertEqualsAndHashCodeAreFalse(foo1, foo4);
+ }
+
public void testOneofEquals() throws Exception {
TestOneofEquals.Builder builder = TestOneofEquals.newBuilder();
TestOneofEquals message1 = builder.build();
@@ -2183,29 +2023,27 @@ public class LiteTest extends TestCase {
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 fooWithOnlyValue = Foo.newBuilder().setValue(1).build();
- Foo fooWithValueAndExtension = fooWithOnlyValue.toBuilder()
- .setValue(1)
- .setExtension(Bar.fooExt, Bar.newBuilder()
- .setName("name")
- .build())
- .build();
+ Foo fooWithValueAndExtension =
+ fooWithOnlyValue
+ .toBuilder()
+ .setValue(1)
+ .setExtension(Bar.fooExt, Bar.newBuilder().setName("name").build())
+ .build();
Foo fooWithValueAndUnknownFields = Foo.parseFrom(fooWithValueAndExtension.toByteArray());
@@ -2214,30 +2052,27 @@ public class LiteTest extends TestCase {
}
public void testEqualsAndHashCodeWithExtensions() throws InvalidProtocolBufferException {
- Foo fooWithOnlyValue = Foo.newBuilder()
- .setValue(1)
- .build();
+ Foo fooWithOnlyValue = Foo.newBuilder().setValue(1).build();
- Foo fooWithValueAndExtension = fooWithOnlyValue.toBuilder()
- .setValue(1)
- .setExtension(Bar.fooExt, Bar.newBuilder()
- .setName("name")
- .build())
- .build();
+ Foo fooWithValueAndExtension =
+ fooWithOnlyValue
+ .toBuilder()
+ .setValue(1)
+ .setExtension(Bar.fooExt, Bar.newBuilder().setName("name").build())
+ .build();
assertEqualsAndHashCodeAreFalse(fooWithOnlyValue, fooWithValueAndExtension);
}
-
+
// 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();
-
+ TestAllTypesLite mine = TestAllTypesLite.newBuilder().setOneofString("Hello").build();
+
+ TestAllTypesLite other =
+ TestAllTypesLite.newBuilder()
+ .setOneofNestedMessage(NestedMessage.getDefaultInstance())
+ .build();
+
assertFalse(mine.equals(other));
assertFalse(other.equals(mine));
}
@@ -2270,4 +2105,277 @@ public class LiteTest extends TestCase {
// This tests that we don't infinite loop.
TestRecursiveOneof.getDefaultInstance().hashCode();
}
+
+ public void testParseFromByteBuffer() throws Exception {
+ TestAllTypesLite message =
+ TestAllTypesLite.newBuilder()
+ .setOptionalInt32(123)
+ .addRepeatedString("hello")
+ .setOptionalNestedMessage(TestAllTypesLite.NestedMessage.newBuilder().setBb(7))
+ .build();
+
+ TestAllTypesLite copy =
+ TestAllTypesLite.parseFrom(message.toByteString().asReadOnlyByteBuffer());
+
+ assertEquals(message, copy);
+ }
+
+ public void testParseFromByteBufferThrows() {
+ try {
+ TestAllTypesLite.parseFrom(ByteBuffer.wrap(new byte[] {0x5}));
+ fail();
+ } catch (InvalidProtocolBufferException expected) {
+ }
+
+ TestAllTypesLite message =
+ TestAllTypesLite.newBuilder().setOptionalInt32(123).addRepeatedString("hello").build();
+
+ ByteBuffer buffer = ByteBuffer.wrap(message.toByteArray(), 0, message.getSerializedSize() - 1);
+ try {
+ TestAllTypesLite.parseFrom(buffer);
+ fail();
+ } catch (InvalidProtocolBufferException expected) {
+ assertEquals(
+ TestAllTypesLite.newBuilder().setOptionalInt32(123).build(),
+ expected.getUnfinishedMessage());
+ }
+ }
+
+ public void testParseFromByteBuffer_extensions() throws Exception {
+ TestAllExtensionsLite message =
+ TestAllExtensionsLite.newBuilder()
+ .setExtension(UnittestLite.optionalInt32ExtensionLite, 123)
+ .addExtension(UnittestLite.repeatedStringExtensionLite, "hello")
+ .setExtension(
+ UnittestLite.optionalNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAZ)
+ .setExtension(
+ UnittestLite.optionalNestedMessageExtensionLite,
+ TestAllTypesLite.NestedMessage.newBuilder().setBb(7).build())
+ .build();
+
+ ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance();
+ UnittestLite.registerAllExtensions(registry);
+
+ TestAllExtensionsLite copy =
+ TestAllExtensionsLite.parseFrom(message.toByteString().asReadOnlyByteBuffer(), registry);
+
+ assertEquals(message, copy);
+ }
+
+ public void testParseFromByteBufferThrows_extensions() {
+ ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance();
+ UnittestLite.registerAllExtensions(registry);
+ try {
+ TestAllExtensionsLite.parseFrom(ByteBuffer.wrap(new byte[] {0x5}), registry);
+ fail();
+ } catch (InvalidProtocolBufferException expected) {
+ }
+
+ TestAllExtensionsLite message =
+ TestAllExtensionsLite.newBuilder()
+ .setExtension(UnittestLite.optionalInt32ExtensionLite, 123)
+ .addExtension(UnittestLite.repeatedStringExtensionLite, "hello")
+ .build();
+
+ ByteBuffer buffer = ByteBuffer.wrap(message.toByteArray(), 0, message.getSerializedSize() - 1);
+ try {
+ TestAllExtensionsLite.parseFrom(buffer, registry);
+ fail();
+ } catch (InvalidProtocolBufferException expected) {
+ assertEquals(
+ TestAllExtensionsLite.newBuilder()
+ .setExtension(UnittestLite.optionalInt32ExtensionLite, 123)
+ .build(),
+ expected.getUnfinishedMessage());
+ }
+ }
+
+ // Make sure we haven't screwed up the code generation for packing fields by default.
+ public void testPackedSerialization() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ builder.addRepeatedInt32(4321);
+ builder.addRepeatedNestedEnum(TestAllTypes.NestedEnum.BAZ);
+ TestAllTypes message = builder.build();
+
+ CodedInputStream in = CodedInputStream.newInstance(message.toByteArray());
+
+ while (!in.isAtEnd()) {
+ int tag = in.readTag();
+ assertEquals(WireFormat.WIRETYPE_LENGTH_DELIMITED, WireFormat.getTagWireType(tag));
+ in.skipField(tag);
+ }
+ }
+
+ public void testAddAllIteratesOnce() {
+ TestAllTypesLite.newBuilder()
+ .addAllRepeatedBool(new OneTimeIterableList(false))
+ .addAllRepeatedInt32(new OneTimeIterableList(0))
+ .addAllRepeatedInt64(new OneTimeIterableList(0L))
+ .addAllRepeatedFloat(new OneTimeIterableList(0f))
+ .addAllRepeatedDouble(new OneTimeIterableList(0d))
+ .addAllRepeatedBytes(new OneTimeIterableList(ByteString.EMPTY))
+ .addAllRepeatedString(new OneTimeIterableList(""))
+ .addAllRepeatedNestedMessage(new OneTimeIterableList(NestedMessage.getDefaultInstance()))
+ .addAllRepeatedBool(new OneTimeIterable(false))
+ .addAllRepeatedInt32(new OneTimeIterable(0))
+ .addAllRepeatedInt64(new OneTimeIterable(0L))
+ .addAllRepeatedFloat(new OneTimeIterable(0f))
+ .addAllRepeatedDouble(new OneTimeIterable(0d))
+ .addAllRepeatedBytes(new OneTimeIterable(ByteString.EMPTY))
+ .addAllRepeatedString(new OneTimeIterable(""))
+ .addAllRepeatedNestedMessage(new OneTimeIterable(NestedMessage.getDefaultInstance()))
+ .build();
+ }
+
+ public void testAddAllIteratesOnce_throwsOnNull() {
+ TestAllTypesLite.Builder builder = TestAllTypesLite.newBuilder();
+ try {
+ builder.addAllRepeatedBool(new OneTimeIterableList(true, false, (Boolean) null));
+ fail();
+ } catch (NullPointerException expected) {
+ assertEquals("Element at index 2 is null.", expected.getMessage());
+ assertEquals(0, builder.getRepeatedBoolCount());
+ }
+
+ try {
+ builder.addAllRepeatedBool(new OneTimeIterable(true, false, (Boolean) null));
+ fail();
+ } catch (NullPointerException expected) {
+ assertEquals("Element at index 2 is null.", expected.getMessage());
+ assertEquals(0, builder.getRepeatedBoolCount());
+ }
+
+ try {
+ builder = TestAllTypesLite.newBuilder();
+ builder.addAllRepeatedBool(new OneTimeIterableList((Boolean) null));
+ fail();
+ } catch (NullPointerException expected) {
+ assertEquals("Element at index 0 is null.", expected.getMessage());
+ assertEquals(0, builder.getRepeatedBoolCount());
+ }
+
+ try {
+ builder = TestAllTypesLite.newBuilder();
+ builder.addAllRepeatedInt32(new OneTimeIterableList((Integer) null));
+ fail();
+ } catch (NullPointerException expected) {
+ assertEquals("Element at index 0 is null.", expected.getMessage());
+ assertEquals(0, builder.getRepeatedInt32Count());
+ }
+
+ try {
+ builder = TestAllTypesLite.newBuilder();
+ builder.addAllRepeatedInt64(new OneTimeIterableList((Long) null));
+ fail();
+ } catch (NullPointerException expected) {
+ assertEquals("Element at index 0 is null.", expected.getMessage());
+ assertEquals(0, builder.getRepeatedInt64Count());
+ }
+
+ try {
+ builder = TestAllTypesLite.newBuilder();
+ builder.addAllRepeatedFloat(new OneTimeIterableList((Float) null));
+ fail();
+ } catch (NullPointerException expected) {
+ assertEquals("Element at index 0 is null.", expected.getMessage());
+ assertEquals(0, builder.getRepeatedFloatCount());
+ }
+
+ try {
+ builder = TestAllTypesLite.newBuilder();
+ builder.addAllRepeatedDouble(new OneTimeIterableList((Double) null));
+ fail();
+ } catch (NullPointerException expected) {
+ assertEquals("Element at index 0 is null.", expected.getMessage());
+ assertEquals(0, builder.getRepeatedDoubleCount());
+ }
+
+ try {
+ builder = TestAllTypesLite.newBuilder();
+ builder.addAllRepeatedBytes(new OneTimeIterableList((ByteString) null));
+ fail();
+ } catch (NullPointerException expected) {
+ assertEquals("Element at index 0 is null.", expected.getMessage());
+ assertEquals(0, builder.getRepeatedBytesCount());
+ }
+
+ try {
+ builder = TestAllTypesLite.newBuilder();
+ builder.addAllRepeatedString(new OneTimeIterableList("", "", (String) null, ""));
+ fail();
+ } catch (NullPointerException expected) {
+ assertEquals("Element at index 2 is null.", expected.getMessage());
+ assertEquals(0, builder.getRepeatedStringCount());
+ }
+
+ try {
+ builder = TestAllTypesLite.newBuilder();
+ builder.addAllRepeatedString(new OneTimeIterable("", "", (String) null, ""));
+ fail();
+ } catch (NullPointerException expected) {
+ assertEquals("Element at index 2 is null.", expected.getMessage());
+ assertEquals(0, builder.getRepeatedStringCount());
+ }
+
+ try {
+ builder = TestAllTypesLite.newBuilder();
+ builder.addAllRepeatedString(new OneTimeIterableList((String) null));
+ fail();
+ } catch (NullPointerException expected) {
+ assertEquals("Element at index 0 is null.", expected.getMessage());
+ assertEquals(0, builder.getRepeatedStringCount());
+ }
+
+ try {
+ builder = TestAllTypesLite.newBuilder();
+ builder.addAllRepeatedNestedMessage(new OneTimeIterableList((NestedMessage) null));
+ fail();
+ } catch (NullPointerException expected) {
+ assertEquals("Element at index 0 is null.", expected.getMessage());
+ assertEquals(0, builder.getRepeatedNestedMessageCount());
+ }
+ }
+
+ private static final class OneTimeIterableList<T> extends ArrayList<T> {
+ private boolean wasIterated = false;
+
+ OneTimeIterableList(T... contents) {
+ addAll(Arrays.asList(contents));
+ }
+
+ @Override
+ public Iterator<T> iterator() {
+ if (wasIterated) {
+ fail();
+ }
+ wasIterated = true;
+ return super.iterator();
+ }
+ }
+
+ private static final class OneTimeIterable<T> implements Iterable<T> {
+ private final List<T> list;
+ private boolean wasIterated = false;
+
+ OneTimeIterable(T... contents) {
+ list = Arrays.asList(contents);
+ }
+
+ @Override
+ public Iterator<T> iterator() {
+ if (wasIterated) {
+ fail();
+ }
+ wasIterated = true;
+ return list.iterator();
+ }
+ }
+
+ public void testNullExtensionRegistry() throws Exception {
+ try {
+ TestAllTypesLite.parseFrom(new byte[] {}, null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ }
}
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 6bbdfcaa..e50c7d1e 100644
--- a/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java
@@ -32,6 +32,7 @@ package com.google.protobuf;
import static java.util.Arrays.asList;
+import com.google.protobuf.Internal.LongList;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
@@ -297,6 +298,20 @@ public class LongArrayListTest extends TestCase {
}
}
+ public void testRemoveEndOfCapacity() {
+ LongList toRemove = LongArrayList.emptyList().mutableCopyWithCapacity(1);
+ toRemove.addLong(3);
+ toRemove.remove(0);
+ assertEquals(0, toRemove.size());
+ }
+
+ public void testSublistRemoveEndOfCapacity() {
+ LongList toRemove = LongArrayList.emptyList().mutableCopyWithCapacity(1);
+ toRemove.addLong(3);
+ toRemove.subList(0, 1).clear();
+ assertEquals(0, toRemove.size());
+ }
+
private void assertImmutable(LongArrayList list) {
if (list.contains(1L)) {
throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
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 0a14f584..da9195f9 100644
--- a/java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java
+++ b/java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java
@@ -408,12 +408,12 @@ public final class MapForProto2LiteTest extends TestCase {
TestMap map = tryParseTestMap(BizarroTestMap.newBuilder()
.putInt32ToInt32Field(5, bytes)
.build());
- assertEquals(map.getInt32ToInt32FieldOrDefault(5, -1), 0);
+ assertEquals(0, map.getInt32ToInt32FieldOrDefault(5, -1));
map = tryParseTestMap(BizarroTestMap.newBuilder()
.putInt32ToStringField(stringKey, 5)
.build());
- assertEquals(map.getInt32ToStringFieldOrDefault(0, null), "");
+ assertEquals("", map.getInt32ToStringFieldOrDefault(0, null));
map = tryParseTestMap(BizarroTestMap.newBuilder()
.putInt32ToBytesField(stringKey, 5)
@@ -423,7 +423,7 @@ public final class MapForProto2LiteTest extends TestCase {
map = tryParseTestMap(BizarroTestMap.newBuilder()
.putInt32ToEnumField(stringKey, bytes)
.build());
- assertEquals(map.getInt32ToEnumFieldOrDefault(0, null), TestMap.EnumValue.FOO);
+ assertEquals(TestMap.EnumValue.FOO, map.getInt32ToEnumFieldOrDefault(0, null));
try {
tryParseTestMap(BizarroTestMap.newBuilder()
@@ -439,7 +439,7 @@ public final class MapForProto2LiteTest extends TestCase {
map = tryParseTestMap(BizarroTestMap.newBuilder()
.putStringToInt32Field(stringKey, bytes)
.build());
- assertEquals(map.getStringToInt32FieldOrDefault(stringKey, -1), 0);
+ assertEquals(0, map.getStringToInt32FieldOrDefault(stringKey, -1));
}
public void testMergeFrom() throws Exception {
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 cfe4c453..bcfd927c 100644
--- a/java/core/src/test/java/com/google/protobuf/MapForProto2Test.java
+++ b/java/core/src/test/java/com/google/protobuf/MapForProto2Test.java
@@ -546,12 +546,12 @@ public class MapForProto2Test extends TestCase {
TestMap map = tryParseTestMap(BizarroTestMap.newBuilder()
.putInt32ToInt32Field(5, bytes)
.build());
- assertEquals(map.getInt32ToInt32FieldOrDefault(5, -1), 0);
+ assertEquals(0, map.getInt32ToInt32FieldOrDefault(5, -1));
map = tryParseTestMap(BizarroTestMap.newBuilder()
.putInt32ToStringField(stringKey, 5)
.build());
- assertEquals(map.getInt32ToStringFieldOrDefault(0, null), "");
+ assertEquals("", map.getInt32ToStringFieldOrDefault(0, null));
map = tryParseTestMap(BizarroTestMap.newBuilder()
.putInt32ToBytesField(stringKey, 5)
@@ -561,7 +561,7 @@ public class MapForProto2Test extends TestCase {
map = tryParseTestMap(BizarroTestMap.newBuilder()
.putInt32ToEnumField(stringKey, bytes)
.build());
- assertEquals(map.getInt32ToEnumFieldOrDefault(0, null), TestMap.EnumValue.FOO);
+ assertEquals(TestMap.EnumValue.FOO, map.getInt32ToEnumFieldOrDefault(0, null));
try {
tryParseTestMap(BizarroTestMap.newBuilder()
@@ -577,7 +577,7 @@ public class MapForProto2Test extends TestCase {
map = tryParseTestMap(BizarroTestMap.newBuilder()
.putStringToInt32Field(stringKey, bytes)
.build());
- assertEquals(map.getStringToInt32FieldOrDefault(stringKey, -1), 0);
+ assertEquals(0, map.getStringToInt32FieldOrDefault(stringKey, -1));
}
public void testMergeFrom() throws Exception {
@@ -759,6 +759,7 @@ public class MapForProto2Test extends TestCase {
assertEquals(55, message.getInt32ToInt32Field().get(55).intValue());
}
+ // See additional coverage in TextFormatTest.java.
public void testTextFormat() throws Exception {
TestMap.Builder builder = TestMap.newBuilder();
setMapValuesUsingAccessors(builder);
@@ -787,6 +788,24 @@ public class MapForProto2Test extends TestCase {
assertEquals(message.hashCode(), dynamicMessage.hashCode());
}
+ // Check that DynamicMessage handles map field serialization the same way as generated code
+ // regarding unset key and value field in a map entry.
+ public void testDynamicMessageUnsetKeyAndValue() throws Exception {
+ FieldDescriptor field = f("int32_to_int32_field");
+
+ Message dynamicDefaultInstance =
+ DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
+ Message.Builder builder = dynamicDefaultInstance.newBuilderForType();
+ // Add an entry without key and value.
+ builder.addRepeatedField(field, builder.newBuilderForField(field).build());
+ Message message = builder.build();
+ ByteString bytes = message.toByteString();
+ // Parse it back to the same generated type.
+ Message generatedMessage = TestMap.parseFrom(bytes);
+ // Assert the serialized bytes are equivalent.
+ assertEquals(generatedMessage.toByteString(), bytes);
+ }
+
public void testReflectionEqualsAndHashCode() throws Exception {
// Test that generated equals() and hashCode() will disregard the order
// of map entries when comparing/hashing map fields.
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 81e951cc..58efce92 100644
--- a/java/core/src/test/java/com/google/protobuf/MapTest.java
+++ b/java/core/src/test/java/com/google/protobuf/MapTest.java
@@ -30,7 +30,7 @@
package com.google.protobuf;
-
+import static org.junit.Assert.assertArrayEquals;
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.EnumDescriptor;
import com.google.protobuf.Descriptors.EnumValueDescriptor;
@@ -490,19 +490,13 @@ public class MapTest extends TestCase {
public void testPutForUnknownEnumValues() throws Exception {
TestMap.Builder builder = TestMap.newBuilder()
.putInt32ToEnumFieldValue(0, 0)
- .putInt32ToEnumFieldValue(1, 1);
-
- try {
- builder.putInt32ToEnumFieldValue(2, 1000); // unknown value.
- fail();
- } catch (IllegalArgumentException e) {
- // expected
- }
-
+ .putInt32ToEnumFieldValue(1, 1)
+ .putInt32ToEnumFieldValue(2, 1000); // unknown value.
TestMap message = builder.build();
assertEquals(0, message.getInt32ToEnumFieldValueOrThrow(0));
assertEquals(1, message.getInt32ToEnumFieldValueOrThrow(1));
- assertEquals(2, message.getInt32ToEnumFieldCount());
+ assertEquals(1000, message.getInt32ToEnumFieldValueOrThrow(2));
+ assertEquals(3, message.getInt32ToEnumFieldCount());
}
public void testPutChecksNullKeysAndValues() throws Exception {
@@ -582,12 +576,12 @@ public class MapTest extends TestCase {
TestMap map = tryParseTestMap(BizarroTestMap.newBuilder()
.putInt32ToInt32Field(5, bytes)
.build());
- assertEquals(map.getInt32ToInt32FieldOrDefault(5, -1), 0);
+ assertEquals(0, map.getInt32ToInt32FieldOrDefault(5, -1));
map = tryParseTestMap(BizarroTestMap.newBuilder()
.putInt32ToStringField(stringKey, 5)
.build());
- assertEquals(map.getInt32ToStringFieldOrDefault(0, null), "");
+ assertEquals("", map.getInt32ToStringFieldOrDefault(0, null));
map = tryParseTestMap(BizarroTestMap.newBuilder()
.putInt32ToBytesField(stringKey, 5)
@@ -597,7 +591,7 @@ public class MapTest extends TestCase {
map = tryParseTestMap(BizarroTestMap.newBuilder()
.putInt32ToEnumField(stringKey, bytes)
.build());
- assertEquals(map.getInt32ToEnumFieldOrDefault(0, null), TestMap.EnumValue.FOO);
+ assertEquals(TestMap.EnumValue.FOO, map.getInt32ToEnumFieldOrDefault(0, null));
try {
tryParseTestMap(BizarroTestMap.newBuilder()
@@ -613,7 +607,7 @@ public class MapTest extends TestCase {
map = tryParseTestMap(BizarroTestMap.newBuilder()
.putStringToInt32Field(stringKey, bytes)
.build());
- assertEquals(map.getStringToInt32FieldOrDefault(stringKey, -1), 0);
+ assertEquals(0, map.getStringToInt32FieldOrDefault(stringKey, -1));
}
public void testMergeFrom() throws Exception {
@@ -870,6 +864,7 @@ public class MapTest extends TestCase {
assertEquals(55, message.getInt32ToInt32Field().get(55).intValue());
}
+ // See additional coverage in TextFormatTest.java.
public void testTextFormat() throws Exception {
TestMap.Builder builder = TestMap.newBuilder();
setMapValuesUsingAccessors(builder);
@@ -898,6 +893,24 @@ public class MapTest extends TestCase {
assertEquals(message.hashCode(), dynamicMessage.hashCode());
}
+ // Check that DynamicMessage handles map field serialization the same way as generated code
+ // regarding unset key and value field in a map entry.
+ public void testDynamicMessageUnsetKeyAndValue() throws Exception {
+ FieldDescriptor field = f("int32_to_int32_field");
+
+ Message dynamicDefaultInstance =
+ DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
+ Message.Builder builder = dynamicDefaultInstance.newBuilderForType();
+ // Add an entry without key and value.
+ builder.addRepeatedField(field, builder.newBuilderForField(field).build());
+ Message message = builder.build();
+ ByteString bytes = message.toByteString();
+ // Parse it back to the same generated type.
+ Message generatedMessage = TestMap.parseFrom(bytes);
+ // Assert the serialized bytes are equivalent.
+ assertEquals(generatedMessage.toByteString(), bytes);
+ }
+
public void testReflectionEqualsAndHashCode() throws Exception {
// Test that generated equals() and hashCode() will disregard the order
// of map entries when comparing/hashing map fields.
@@ -1250,12 +1263,9 @@ public class MapTest extends TestCase {
builder.putInt32ToEnumFieldValue(1, TestMap.EnumValue.BAR.getNumber());
assertEquals(
TestMap.EnumValue.BAR.getNumber(), builder.getInt32ToEnumFieldValueOrThrow(1));
- try {
- builder.putInt32ToEnumFieldValue(1, -1);
- fail();
- } catch (IllegalArgumentException e) {
- // expected
- }
+ builder.putInt32ToEnumFieldValue(1, -1);
+ assertEquals(-1, builder.getInt32ToEnumFieldValueOrThrow(1));
+ assertEquals(TestMap.EnumValue.UNRECOGNIZED, builder.getInt32ToEnumFieldOrThrow(1));
builder.putStringToInt32Field("a", 1);
assertEquals(1, builder.getStringToInt32FieldOrThrow("a"));
@@ -1492,4 +1502,41 @@ public class MapTest extends TestCase {
map.put(key3, value3);
return map;
}
+
+ public void testMap_withNulls() {
+ TestMap.Builder builder = TestMap.newBuilder();
+
+ try {
+ builder.putStringToInt32Field(null, 3);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+
+ try {
+ builder.putAllStringToInt32Field(newMap(null, 3, "hi", 4));
+ fail();
+ } catch (NullPointerException expected) {
+ }
+
+ try {
+ builder.putInt32ToMessageField(3, null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+
+ try {
+ builder.putAllInt32ToMessageField(
+ MapTest.<Integer, MessageValue>newMap(4, null, 5, null));
+ fail();
+ } catch (NullPointerException expected) {
+ }
+
+ try {
+ builder.putAllInt32ToMessageField(null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+
+ assertArrayEquals(new byte[0], builder.build().toByteArray());
+ }
}
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 75b79a34..4fc8f78e 100644
--- a/java/core/src/test/java/com/google/protobuf/MessageTest.java
+++ b/java/core/src/test/java/com/google/protobuf/MessageTest.java
@@ -74,6 +74,14 @@ public class MessageTest extends TestCase {
"repeated_string: \"qux\"\n" +
"repeated_string: \"bar\"\n";
+ public void testParsingWithNullExtensionRegistry() throws Exception {
+ try {
+ TestAllTypes.parseFrom(new byte[] {}, null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ }
+
public void testMergeFrom() throws Exception {
TestAllTypes result =
TestAllTypes.newBuilder(MERGE_DEST)
@@ -321,8 +329,10 @@ public class MessageTest extends TestCase {
assertTrue(result.getField(result.getDescriptorForType()
.findFieldByName("repeated_foreign_message")) instanceof List<?>);
- assertEquals(result.getRepeatedFieldCount(result.getDescriptorForType()
- .findFieldByName("repeated_foreign_message")), 0);
+ assertEquals(
+ 0,
+ result.getRepeatedFieldCount(
+ result.getDescriptorForType().findFieldByName("repeated_foreign_message")));
}
/** Test reading repeated message from DynamicMessage. */
@@ -345,7 +355,9 @@ public class MessageTest extends TestCase {
assertTrue(result.getField(result.getDescriptorForType()
.findFieldByName("repeated_foreign_message")) instanceof List<?>);
- assertEquals(result.getRepeatedFieldCount(result.getDescriptorForType()
- .findFieldByName("repeated_foreign_message")), 2);
+ assertEquals(
+ 2,
+ result.getRepeatedFieldCount(
+ result.getDescriptorForType().findFieldByName("repeated_foreign_message")));
}
}
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 8c2e4c26..1e891112 100644
--- a/java/core/src/test/java/com/google/protobuf/ParserTest.java
+++ b/java/core/src/test/java/com/google/protobuf/ParserTest.java
@@ -30,9 +30,6 @@
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;
@@ -79,6 +76,8 @@ public class ParserTest extends TestCase {
new ByteArrayInputStream(data), registry));
assertMessageEquals(message, parser.parseFrom(
CodedInputStream.newInstance(data), registry));
+ assertMessageEquals(
+ message, parser.parseFrom(message.toByteString().asReadOnlyByteBuffer(), registry));
}
@SuppressWarnings("unchecked")
@@ -99,6 +98,7 @@ public class ParserTest extends TestCase {
new ByteArrayInputStream(data)));
assertMessageEquals(message, parser.parseFrom(
CodedInputStream.newInstance(data)));
+ assertMessageEquals(message, parser.parseFrom(message.toByteString().asReadOnlyByteBuffer()));
}
private void assertMessageEquals(
@@ -178,16 +178,12 @@ public class ParserTest extends TestCase {
public void testParseExtensions() throws Exception {
assertRoundTripEquals(TestUtil.getAllExtensionsSet(),
TestUtil.getExtensionRegistry());
- assertRoundTripEquals(
- TestUtilLite.getAllLiteExtensionsSet(), TestUtilLite.getExtensionRegistryLite());
}
public void testParsePacked() throws Exception {
assertRoundTripEquals(TestUtil.getPackedSet());
assertRoundTripEquals(TestUtil.getPackedExtensionsSet(),
TestUtil.getExtensionRegistry());
- assertRoundTripEquals(
- TestUtilLite.getLitePackedExtensionsSet(), TestUtilLite.getExtensionRegistryLite());
}
public void testParseDelimitedTo() throws Exception {
@@ -195,20 +191,11 @@ public class ParserTest extends TestCase {
TestAllTypes normalMessage = TestUtil.getAllSet();
ByteArrayOutputStream output = new ByteArrayOutputStream();
normalMessage.writeDelimitedTo(output);
-
- // Write MessageLite with packed extension fields.
- TestPackedExtensionsLite packedMessage = TestUtilLite.getLitePackedExtensionsSet();
- packedMessage.writeDelimitedTo(output);
+ normalMessage.writeDelimitedTo(output);
InputStream input = new ByteArrayInputStream(output.toByteArray());
- assertMessageEquals(
- normalMessage,
- normalMessage.getParserForType().parseDelimitedFrom(input));
- assertMessageEquals(
- packedMessage,
- packedMessage
- .getParserForType()
- .parseDelimitedFrom(input, TestUtilLite.getExtensionRegistryLite()));
+ assertMessageEquals(normalMessage, normalMessage.getParserForType().parseDelimitedFrom(input));
+ assertMessageEquals(normalMessage, normalMessage.getParserForType().parseDelimitedFrom(input));
}
public void testParseUnknownFields() throws Exception {
@@ -243,14 +230,6 @@ public class ParserTest extends TestCase {
assertEquals("hello", allTypes.getOptionalString());
}
- /** Helper method for {@link #testParsingMergeLite()}.*/
- private void assertMessageMerged(TestAllTypesLite allTypes)
- throws Exception {
- assertEquals(3, allTypes.getOptionalInt32());
- assertEquals(2, allTypes.getOptionalInt64());
- assertEquals("hello", allTypes.getOptionalString());
- }
-
public void testParsingMerge() throws Exception {
// Build messages.
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
@@ -312,68 +291,6 @@ public class ParserTest extends TestCase {
TestParsingMerge.repeatedExt));
}
- public void testParsingMergeLite() throws Exception {
- // Build messages.
- TestAllTypesLite.Builder builder =
- TestAllTypesLite.newBuilder();
- TestAllTypesLite msg1 = builder.setOptionalInt32(1).build();
- builder.clear();
- TestAllTypesLite msg2 = builder.setOptionalInt64(2).build();
- builder.clear();
- TestAllTypesLite msg3 = builder.setOptionalInt32(3)
- .setOptionalString("hello").build();
-
- // Build groups.
- TestParsingMergeLite.RepeatedFieldsGenerator.Group1 optionalG1 =
- TestParsingMergeLite.RepeatedFieldsGenerator.Group1.newBuilder()
- .setField1(msg1).build();
- TestParsingMergeLite.RepeatedFieldsGenerator.Group1 optionalG2 =
- TestParsingMergeLite.RepeatedFieldsGenerator.Group1.newBuilder()
- .setField1(msg2).build();
- TestParsingMergeLite.RepeatedFieldsGenerator.Group1 optionalG3 =
- TestParsingMergeLite.RepeatedFieldsGenerator.Group1.newBuilder()
- .setField1(msg3).build();
- TestParsingMergeLite.RepeatedFieldsGenerator.Group2 repeatedG1 =
- TestParsingMergeLite.RepeatedFieldsGenerator.Group2.newBuilder()
- .setField1(msg1).build();
- TestParsingMergeLite.RepeatedFieldsGenerator.Group2 repeatedG2 =
- TestParsingMergeLite.RepeatedFieldsGenerator.Group2.newBuilder()
- .setField1(msg2).build();
- TestParsingMergeLite.RepeatedFieldsGenerator.Group2 repeatedG3 =
- TestParsingMergeLite.RepeatedFieldsGenerator.Group2.newBuilder()
- .setField1(msg3).build();
-
- // Assign and serialize RepeatedFieldsGenerator.
- ByteString data = TestParsingMergeLite.RepeatedFieldsGenerator.newBuilder()
- .addField1(msg1).addField1(msg2).addField1(msg3)
- .addField2(msg1).addField2(msg2).addField2(msg3)
- .addField3(msg1).addField3(msg2).addField3(msg3)
- .addGroup1(optionalG1).addGroup1(optionalG2).addGroup1(optionalG3)
- .addGroup2(repeatedG1).addGroup2(repeatedG2).addGroup2(repeatedG3)
- .addExt1(msg1).addExt1(msg2).addExt1(msg3)
- .addExt2(msg1).addExt2(msg2).addExt2(msg3)
- .build().toByteString();
-
- // Parse TestParsingMergeLite.
- ExtensionRegistry registry = ExtensionRegistry.newInstance();
- UnittestLite.registerAllExtensions(registry);
- TestParsingMergeLite parsingMerge = TestParsingMergeLite.parser().parseFrom(data, registry);
-
- // Required and optional fields should be merged.
- assertMessageMerged(parsingMerge.getRequiredAllTypes());
- assertMessageMerged(parsingMerge.getOptionalAllTypes());
- assertMessageMerged(
- parsingMerge.getOptionalGroup().getOptionalGroupAllTypes());
- assertMessageMerged(parsingMerge.getExtension(
- TestParsingMergeLite.optionalExt));
-
- // Repeated fields should not be merged.
- assertEquals(3, parsingMerge.getRepeatedAllTypesCount());
- assertEquals(3, parsingMerge.getRepeatedGroupCount());
- assertEquals(3, parsingMerge.getExtensionCount(
- TestParsingMergeLite.repeatedExt));
- }
-
public void testParseDelimitedFrom_firstByteInterrupted_preservesCause() {
try {
TestUtil.getAllSet().parseDelimitedFrom(
diff --git a/java/core/src/test/java/com/google/protobuf/TestBadIdentifiers.java b/java/core/src/test/java/com/google/protobuf/TestBadIdentifiers.java
index 2c60fe0e..4af55429 100644
--- a/java/core/src/test/java/com/google/protobuf/TestBadIdentifiers.java
+++ b/java/core/src/test/java/com/google/protobuf/TestBadIdentifiers.java
@@ -92,5 +92,31 @@ public class TestBadIdentifiers extends TestCase {
assertEquals(0L, message.getExtension(
TestBadIdentifiersProto.TestConflictingFieldNames.int64FieldList).longValue());
+ assertEquals("", message.getFieldName32());
+ assertEquals("", message.getFieldName33());
+ assertEquals(0, message.get2Conflict34());
+ assertEquals(0, message.get2Conflict35());
+
+ }
+
+ public void testNumberFields() throws Exception {
+ TestBadIdentifiersProto.TestLeadingNumberFields message =
+ TestBadIdentifiersProto.TestLeadingNumberFields.getDefaultInstance();
+ // Make sure generated accessors are properly named.
+ assertFalse(message.has30DayImpressions());
+ assertEquals(0, message.get30DayImpressions());
+ assertEquals(0, message.get60DayImpressionsCount());
+ assertEquals(0, message.get60DayImpressionsList().size());
+
+ assertFalse(message.has2Underscores());
+ assertEquals("", message.get2Underscores());
+ assertEquals(0, message.get2RepeatedUnderscoresCount());
+ assertEquals(0, message.get2RepeatedUnderscoresList().size());
+
+ assertFalse(message.has32());
+ assertEquals(0, message.get32());
+ assertEquals(0, message.get64Count());
+ assertEquals(0, message.get64List().size());
+
}
}
diff --git a/java/core/src/test/java/com/google/protobuf/TestBadIdentifiersLite.java b/java/core/src/test/java/com/google/protobuf/TestBadIdentifiersLite.java
new file mode 100644
index 00000000..37f94c03
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/TestBadIdentifiersLite.java
@@ -0,0 +1,83 @@
+// 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;
+
+/**
+ * Tests that proto2 api generation doesn't cause compile errors when compiling protocol buffers
+ * that have names that would otherwise conflict if not fully qualified (like @Deprecated
+ * and @Override).
+ *
+ * <p>Forked from {@link TestBadIdentifiers}.
+ *
+ * @author jonp@google.com (Jon Perlow)
+ */
+public final class TestBadIdentifiersLite extends TestCase {
+
+ public void testCompilation() {
+ // If this compiles, it means the generation was correct.
+ TestBadIdentifiersProto.Deprecated.newBuilder();
+ TestBadIdentifiersProto.Override.newBuilder();
+ }
+
+ public void testConflictingFieldNames() throws Exception {
+ TestBadIdentifiersProto.TestConflictingFieldNames message =
+ TestBadIdentifiersProto.TestConflictingFieldNames.getDefaultInstance();
+ // Make sure generated accessors are properly named.
+ assertEquals(0, message.getInt32Field1Count());
+ assertEquals(0, message.getEnumField2Count());
+ assertEquals(0, message.getStringField3Count());
+ assertEquals(0, message.getBytesField4Count());
+ assertEquals(0, message.getMessageField5Count());
+
+ assertEquals(0, message.getInt32FieldCount11());
+ assertEquals(0, message.getEnumFieldCount12().getNumber());
+ assertEquals("", message.getStringFieldCount13());
+ assertEquals(ByteString.EMPTY, message.getBytesFieldCount14());
+ assertEquals(0, message.getMessageFieldCount15().getSerializedSize());
+
+ assertEquals(0, message.getInt32Field21Count());
+ assertEquals(0, message.getEnumField22Count());
+ assertEquals(0, message.getStringField23Count());
+ assertEquals(0, message.getBytesField24Count());
+ assertEquals(0, message.getMessageField25Count());
+
+ assertEquals(0, message.getInt32Field1List().size());
+ assertEquals(0, message.getInt32FieldList31());
+
+ assertEquals(0, message.getInt64FieldCount());
+ assertEquals(0L, message.getExtension(
+ TestBadIdentifiersProto.TestConflictingFieldNames.int64FieldCount).longValue());
+ assertEquals(0L, message.getExtension(
+ TestBadIdentifiersProto.TestConflictingFieldNames.int64FieldList).longValue());
+ }
+}
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 d4a18a22..b4bc3a3d 100644
--- a/java/core/src/test/java/com/google/protobuf/TestUtil.java
+++ b/java/core/src/test/java/com/google/protobuf/TestUtil.java
@@ -231,6 +231,7 @@ import protobuf_unittest.UnittestProto.TestAllTypesOrBuilder;
import protobuf_unittest.UnittestProto.TestOneof2;
import protobuf_unittest.UnittestProto.TestPackedExtensions;
import protobuf_unittest.UnittestProto.TestPackedTypes;
+import protobuf_unittest.UnittestProto.TestRequired;
import protobuf_unittest.UnittestProto.TestUnpackedTypes;
import java.io.File;
import java.io.IOException;
@@ -252,6 +253,11 @@ import junit.framework.Assert;
public final class TestUtil {
private TestUtil() {}
+ public static final TestRequired TEST_REQUIRED_UNINITIALIZED =
+ TestRequired.newBuilder().setA(1).buildPartial();
+ public static final TestRequired TEST_REQUIRED_INITIALIZED =
+ TestRequired.newBuilder().setA(1).setB(2).setC(3).build();
+
/** Helper to convert a String to ByteString. */
static ByteString toBytes(String str) {
return ByteString.copyFrom(str.getBytes(Internal.UTF_8));
@@ -2602,6 +2608,9 @@ public final class TestUtil {
case FOO_CORD:
Assert.assertTrue(message.hasFooCord());
break;
+ case FOO_STRING_PIECE:
+ Assert.assertTrue(message.hasFooStringPiece());
+ break;
case FOO_BYTES:
Assert.assertTrue(message.hasFooBytes());
break;
@@ -2619,6 +2628,8 @@ public final class TestUtil {
break;
case FOO_NOT_SET:
break;
+ default:
+ // TODO(b/18683919): go/enum-switch-lsc
}
}
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 6a91b02f..720061d2 100644
--- a/java/core/src/test/java/com/google/protobuf/TextFormatTest.java
+++ b/java/core/src/test/java/com/google/protobuf/TextFormatTest.java
@@ -30,9 +30,13 @@
package com.google.protobuf;
+import static com.google.protobuf.TestUtil.TEST_REQUIRED_INITIALIZED;
+import static com.google.protobuf.TestUtil.TEST_REQUIRED_UNINITIALIZED;
+
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.TextFormat.Parser.SingularOverwritePolicy;
+import map_test.MapTestProto.TestMap;
import protobuf_unittest.UnittestMset.TestMessageSetExtension1;
import protobuf_unittest.UnittestMset.TestMessageSetExtension2;
import protobuf_unittest.UnittestProto.OneString;
@@ -41,6 +45,7 @@ import protobuf_unittest.UnittestProto.TestAllTypes;
import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage;
import protobuf_unittest.UnittestProto.TestEmptyMessage;
import protobuf_unittest.UnittestProto.TestOneof2;
+import protobuf_unittest.UnittestProto.TestRequired;
import proto2_wireformat_unittest.UnittestMsetWireFormat.TestMessageSet;
import java.io.StringReader;
import java.util.List;
@@ -56,12 +61,11 @@ import junit.framework.TestCase;
public class TextFormatTest extends TestCase {
// A basic string with different escapable characters for testing.
- private final static String kEscapeTestString =
- "\"A string with ' characters \n and \r newlines and \t tabs and \001 "
- + "slashes \\";
+ private static final String ESCAPE_TEST_STRING =
+ "\"A string with ' characters \n and \r newlines and \t tabs and \001 " + "slashes \\";
// A representation of the above string with all the characters escaped.
- private final static String kEscapeTestStringEscaped =
+ private static final String ESCAPE_TEST_STRING_ESCAPED =
"\\\"A string with \\' characters \\n and \\r newlines "
+ "and \\t tabs and \\001 slashes \\\\";
@@ -167,6 +171,7 @@ public class TextFormatTest extends TestCase {
// Creates an example unknown field set.
private UnknownFieldSet makeUnknownFieldSet() {
+
return UnknownFieldSet.newBuilder()
.addField(5,
UnknownFieldSet.Field.newBuilder()
@@ -174,6 +179,12 @@ public class TextFormatTest extends TestCase {
.addFixed32(2)
.addFixed64(3)
.addLengthDelimited(ByteString.copyFromUtf8("4"))
+ .addLengthDelimited(UnknownFieldSet.newBuilder()
+ .addField(12,
+ UnknownFieldSet.Field.newBuilder()
+ .addVarint(6)
+ .build())
+ .build().toByteString())
.addGroup(
UnknownFieldSet.newBuilder()
.addField(10,
@@ -206,20 +217,23 @@ public class TextFormatTest extends TestCase {
.build();
assertEquals(
- "5: 1\n" +
- "5: 0x00000002\n" +
- "5: 0x0000000000000003\n" +
- "5: \"4\"\n" +
- "5 {\n" +
- " 10: 5\n" +
- "}\n" +
- "8: 1\n" +
- "8: 2\n" +
- "8: 3\n" +
- "15: 12379813812177893520\n" +
- "15: 0xabcd1234\n" +
- "15: 0xabcdef1234567890\n",
- TextFormat.printToString(message));
+ "5: 1\n"
+ + "5: 0x00000002\n"
+ + "5: 0x0000000000000003\n"
+ + "5: \"4\"\n"
+ + "5: {\n"
+ + " 12: 6\n"
+ + "}\n"
+ + "5 {\n"
+ + " 10: 5\n"
+ + "}\n"
+ + "8: 1\n"
+ + "8: 2\n"
+ + "8: 3\n"
+ + "15: 12379813812177893520\n"
+ + "15: 0xabcd1234\n"
+ + "15: 0xabcdef1234567890\n",
+ TextFormat.printToString(message));
}
public void testPrintField() throws Exception {
@@ -315,19 +329,58 @@ public class TextFormatTest extends TestCase {
// =================================================================
- public void testParse() throws Exception {
+ public void testMerge() throws Exception {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
TextFormat.merge(allFieldsSetText, builder);
TestUtil.assertAllFieldsSet(builder.build());
}
- public void testParseReader() throws Exception {
+ public void testParse() throws Exception {
+ TestUtil.assertAllFieldsSet(
+ TextFormat.parse(allFieldsSetText, TestAllTypes.class));
+ }
+
+ public void testMergeInitialized() throws Exception {
+ TestRequired.Builder builder = TestRequired.newBuilder();
+ TextFormat.merge(TEST_REQUIRED_INITIALIZED.toString(), builder);
+ assertEquals(TEST_REQUIRED_INITIALIZED.toString(),
+ builder.buildPartial().toString());
+ assertTrue(builder.isInitialized());
+ }
+
+ public void testParseInitialized() throws Exception {
+ TestRequired parsed =
+ TextFormat.parse(TEST_REQUIRED_INITIALIZED.toString(),
+ TestRequired.class);
+ assertEquals(TEST_REQUIRED_INITIALIZED.toString(), parsed.toString());
+ assertTrue(parsed.isInitialized());
+ }
+
+ public void testMergeUninitialized() throws Exception {
+ TestRequired.Builder builder = TestRequired.newBuilder();
+ TextFormat.merge(TEST_REQUIRED_UNINITIALIZED.toString(), builder);
+ assertEquals(TEST_REQUIRED_UNINITIALIZED.toString(),
+ builder.buildPartial().toString());
+ assertFalse(builder.isInitialized());
+ }
+
+ public void testParseUninitialized() throws Exception {
+ try {
+ TextFormat.parse(TEST_REQUIRED_UNINITIALIZED.toString(),
+ TestRequired.class);
+ fail("Expected UninitializedMessageException.");
+ } catch (UninitializedMessageException e) {
+ assertEquals("Message missing required fields: b, c", e.getMessage());
+ }
+ }
+
+ public void testMergeReader() throws Exception {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
TextFormat.merge(new StringReader(allFieldsSetText), builder);
TestUtil.assertAllFieldsSet(builder.build());
}
- public void testParseExtensions() throws Exception {
+ public void testMergeExtensions() throws Exception {
TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
TextFormat.merge(allExtensionsSetText,
TestUtil.getExtensionRegistry(),
@@ -335,7 +388,14 @@ public class TextFormatTest extends TestCase {
TestUtil.assertAllExtensionsSet(builder.build());
}
- public void testParseCompatibility() throws Exception {
+ public void testParseExtensions() throws Exception {
+ TestUtil.assertAllExtensionsSet(
+ TextFormat.parse(allExtensionsSetText,
+ TestUtil.getExtensionRegistry(),
+ TestAllExtensions.class));
+ }
+
+ public void testMergeAndParseCompatibility() throws Exception {
String original = "repeated_float: inf\n" +
"repeated_float: -inf\n" +
"repeated_float: nan\n" +
@@ -360,21 +420,29 @@ public class TextFormatTest extends TestCase {
"repeated_double: Infinity\n" +
"repeated_double: -Infinity\n" +
"repeated_double: NaN\n";
+
+ // Test merge().
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
TextFormat.merge(original, builder);
assertEquals(canonical, builder.build().toString());
+
+ // Test parse().
+ assertEquals(canonical,
+ TextFormat.parse(original, TestAllTypes.class).toString());
}
- public void testParseExotic() throws Exception {
+ public void testMergeAndParseExotic() throws Exception {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
TextFormat.merge(exoticText, builder);
// Too lazy to check things individually. Don't try to debug this
// if testPrintExotic() is failing.
assertEquals(canonicalExoticText, builder.build().toString());
+ assertEquals(canonicalExoticText,
+ TextFormat.parse(exoticText, TestAllTypes.class).toString());
}
- public void testParseMessageSet() throws Exception {
+ public void testMergeMessageSet() throws Exception {
ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
extensionRegistry.add(TestMessageSetExtension2.messageSetExtension);
@@ -400,7 +468,7 @@ public class TextFormatTest extends TestCase {
TestMessageSetExtension1.messageSetExtension).getI());
}
- public void testParseMessageSetWithOverwriteForbidden() throws Exception {
+ public void testMergeMessageSetWithOverwriteForbidden() throws Exception {
ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
extensionRegistry.add(TestMessageSetExtension2.messageSetExtension);
@@ -427,20 +495,20 @@ public class TextFormatTest extends TestCase {
}
}
- public void testParseNumericEnum() throws Exception {
+ public void testMergeNumericEnum() throws Exception {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
TextFormat.merge("optional_nested_enum: 2", builder);
assertEquals(TestAllTypes.NestedEnum.BAR, builder.getOptionalNestedEnum());
}
- public void testParseAngleBrackets() throws Exception {
+ public void testMergeAngleBrackets() throws Exception {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
TextFormat.merge("OptionalGroup: < a: 1 >", builder);
assertTrue(builder.hasOptionalGroup());
assertEquals(1, builder.getOptionalGroup().getA());
}
- public void testParseComment() throws Exception {
+ public void testMergeComment() throws Exception {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
TextFormat.merge(
"# this is a comment\n" +
@@ -452,6 +520,7 @@ public class TextFormatTest extends TestCase {
}
private void assertParseError(String error, String text) {
+ // Test merge().
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
try {
TextFormat.merge(text, TestUtil.getExtensionRegistry(), builder);
@@ -459,6 +528,15 @@ public class TextFormatTest extends TestCase {
} catch (TextFormat.ParseException e) {
assertEquals(error, e.getMessage());
}
+
+ // Test parse().
+ try {
+ TextFormat.parse(
+ text, TestUtil.getExtensionRegistry(), TestAllTypes.class);
+ fail("Expected parse exception.");
+ } catch (TextFormat.ParseException e) {
+ assertEquals(error, e.getMessage());
+ }
}
@@ -497,10 +575,10 @@ public class TextFormatTest extends TestCase {
"integer: 82301481290849012385230157",
"optional_int32: 82301481290849012385230157");
assertParseError(
- "1:16: Expected \"true\" or \"false\".",
+ "1:16: Expected \"true\" or \"false\". Found \"maybe\".",
"optional_bool: maybe");
assertParseError(
- "1:16: Expected \"true\" or \"false\".",
+ "1:16: Expected \"true\" or \"false\". Found \"2\".",
"optional_bool: 2");
assertParseError(
"1:18: Expected string.",
@@ -564,10 +642,8 @@ public class TextFormatTest extends TestCase {
TextFormat.unescapeBytes("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\""));
assertEquals("\0\001\007\b\f\n\r\t\013\\\'\"",
TextFormat.unescapeText("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\""));
- assertEquals(kEscapeTestStringEscaped,
- TextFormat.escapeText(kEscapeTestString));
- assertEquals(kEscapeTestString,
- TextFormat.unescapeText(kEscapeTestStringEscaped));
+ assertEquals(ESCAPE_TEST_STRING_ESCAPED, TextFormat.escapeText(ESCAPE_TEST_STRING));
+ assertEquals(ESCAPE_TEST_STRING, TextFormat.unescapeText(ESCAPE_TEST_STRING_ESCAPED));
// Invariant
assertEquals("hello",
@@ -860,7 +936,7 @@ public class TextFormatTest extends TestCase {
}
public void testShortDebugString_unknown() {
- assertEquals("5: 1 5: 0x00000002 5: 0x0000000000000003 5: \"4\" 5 { 10: 5 }"
+ assertEquals("5: 1 5: 0x00000002 5: 0x0000000000000003 5: \"4\" 5: { 12: 6 } 5 { 10: 5 }"
+ " 8: 1 8: 2 8: 3 15: 12379813812177893520 15: 0xabcd1234 15:"
+ " 0xabcdef1234567890",
TextFormat.shortDebugString(makeUnknownFieldSet()));
@@ -940,6 +1016,7 @@ public class TextFormatTest extends TestCase {
}
+ // See additional coverage in testOneofOverwriteForbidden and testMapOverwriteForbidden.
public void testParseNonRepeatedFields() throws Exception {
assertParseSuccessWithOverwriteForbidden(
"repeated_int32: 1\n" +
@@ -950,6 +1027,7 @@ public class TextFormatTest extends TestCase {
assertParseSuccessWithOverwriteForbidden(
"repeated_nested_message { bb: 1 }\n" +
"repeated_nested_message { bb: 2 }\n");
+
assertParseErrorWithOverwriteForbidden(
"3:17: Non-repeated field " +
"\"protobuf_unittest.TestAllTypes.optional_int32\" " +
@@ -988,6 +1066,7 @@ public class TextFormatTest extends TestCase {
assertParseSuccessWithOverwriteForbidden("repeated_int32: [ 1, 2 ]\n");
assertParseSuccessWithOverwriteForbidden("RepeatedGroup [{ a: 1 },{ a: 2 }]\n");
assertParseSuccessWithOverwriteForbidden("repeated_nested_message [{ bb: 1 }, { bb: 2 }]\n");
+ // See also testMapShortForm.
}
public void testParseShortRepeatedFormOfEmptyRepeatedFields() throws Exception {
@@ -995,6 +1074,7 @@ public class TextFormatTest extends TestCase {
assertParseSuccessWithOverwriteForbidden("repeated_int32: []\n");
assertParseSuccessWithOverwriteForbidden("RepeatedGroup []\n");
assertParseSuccessWithOverwriteForbidden("repeated_nested_message []\n");
+ // See also testMapShortFormEmpty.
}
public void testParseShortRepeatedFormWithTrailingComma() throws Exception {
@@ -1010,6 +1090,7 @@ public class TextFormatTest extends TestCase {
assertParseErrorWithOverwriteForbidden(
"1:37: Expected \"{\".",
"repeated_nested_message [{ bb: 1 }, ]\n");
+ // See also testMapShortFormTrailingComma.
}
public void testParseShortRepeatedFormOfNonRepeatedFields() throws Exception {
@@ -1058,6 +1139,90 @@ public class TextFormatTest extends TestCase {
}
// =======================================================================
+ // test map
+
+ public void testMapTextFormat() throws Exception {
+ TestMap message =
+ TestMap.newBuilder()
+ .putInt32ToStringField(10, "apple")
+ .putInt32ToStringField(20, "banana")
+ .putInt32ToStringField(30, "cherry")
+ .build();
+ String text = TextFormat.printToUnicodeString(message);
+ {
+ TestMap.Builder dest = TestMap.newBuilder();
+ TextFormat.merge(text, dest);
+ assertEquals(message, dest.build());
+ }
+ {
+ TestMap.Builder dest = TestMap.newBuilder();
+ parserWithOverwriteForbidden.merge(text, dest);
+ assertEquals(message, dest.build());
+ }
+ }
+
+ public void testMapShortForm() throws Exception {
+ String text =
+ "string_to_int32_field [{ key: 'x' value: 10 }, { key: 'y' value: 20 }]\n"
+ + "int32_to_message_field "
+ + "[{ key: 1 value { value: 100 } }, { key: 2 value: { value: 200 } }]\n";
+ TestMap.Builder dest = TestMap.newBuilder();
+ parserWithOverwriteForbidden.merge(text, dest);
+ TestMap message = dest.build();
+ assertEquals(2, message.getStringToInt32Field().size());
+ assertEquals(2, message.getInt32ToMessageField().size());
+ assertEquals(10, message.getStringToInt32Field().get("x").intValue());
+ assertEquals(200, message.getInt32ToMessageField().get(2).getValue());
+ }
+
+ public void testMapShortFormEmpty() throws Exception {
+ String text = "string_to_int32_field []\n"
+ + "int32_to_message_field: []\n";
+ TestMap.Builder dest = TestMap.newBuilder();
+ parserWithOverwriteForbidden.merge(text, dest);
+ TestMap message = dest.build();
+ assertEquals(0, message.getStringToInt32Field().size());
+ assertEquals(0, message.getInt32ToMessageField().size());
+ }
+
+ public void testMapShortFormTrailingComma() throws Exception {
+ String text = "string_to_int32_field [{ key: 'x' value: 10 }, ]\n";
+ TestMap.Builder dest = TestMap.newBuilder();
+ try {
+ parserWithOverwriteForbidden.merge(text, dest);
+ fail("Expected parse exception.");
+ } catch (TextFormat.ParseException e) {
+ assertEquals("1:48: Expected \"{\".", e.getMessage());
+ }
+ }
+
+ public void testMapOverwrite() throws Exception {
+ String text =
+ "int32_to_int32_field { key: 1 value: 10 }\n"
+ + "int32_to_int32_field { key: 2 value: 20 }\n"
+ + "int32_to_int32_field { key: 1 value: 30 }\n";
+
+ {
+ // With default parser, last value set for the key holds.
+ TestMap.Builder builder = TestMap.newBuilder();
+ defaultParser.merge(text, builder);
+ TestMap map = builder.build();
+ assertEquals(2, map.getInt32ToInt32Field().size());
+ assertEquals(30, map.getInt32ToInt32Field().get(1).intValue());
+ }
+
+ {
+ // With overwrite forbidden, same behavior.
+ // TODO(b/29122459): Expect parse exception here.
+ TestMap.Builder builder = TestMap.newBuilder();
+ defaultParser.merge(text, builder);
+ TestMap map = builder.build();
+ assertEquals(2, map.getInt32ToInt32Field().size());
+ assertEquals(30, map.getInt32ToInt32Field().get(1).intValue());
+ }
+ }
+
+ // =======================================================================
// test location information
public void testParseInfoTreeBuilding() throws Exception {
diff --git a/java/core/src/test/java/com/google/protobuf/UnknownEnumValueTest.java b/java/core/src/test/java/com/google/protobuf/UnknownEnumValueTest.java
index 8f45976f..88cbbf86 100644
--- a/java/core/src/test/java/com/google/protobuf/UnknownEnumValueTest.java
+++ b/java/core/src/test/java/com/google/protobuf/UnknownEnumValueTest.java
@@ -36,7 +36,6 @@ import com.google.protobuf.Descriptors.EnumValueDescriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.FieldPresenceTestProto.TestAllTypes;
import com.google.protobuf.TextFormat.ParseException;
-
import junit.framework.TestCase;
/**
@@ -151,18 +150,15 @@ public class UnknownEnumValueTest extends TestCase {
assertEquals(4321, unknown4321.getNumber());
assertEquals(5432, unknown5432.getNumber());
assertEquals(6543, unknown6543.getNumber());
-
+
// Unknown EnumValueDescriptor will map to UNRECOGNIZED.
assertEquals(
- TestAllTypes.NestedEnum.valueOf(unknown4321),
- TestAllTypes.NestedEnum.UNRECOGNIZED);
+ TestAllTypes.NestedEnum.UNRECOGNIZED, TestAllTypes.NestedEnum.valueOf(unknown4321));
assertEquals(
- TestAllTypes.NestedEnum.valueOf(unknown5432),
- TestAllTypes.NestedEnum.UNRECOGNIZED);
+ TestAllTypes.NestedEnum.UNRECOGNIZED, TestAllTypes.NestedEnum.valueOf(unknown5432));
assertEquals(
- TestAllTypes.NestedEnum.valueOf(unknown6543),
- TestAllTypes.NestedEnum.UNRECOGNIZED);
-
+ TestAllTypes.NestedEnum.UNRECOGNIZED, TestAllTypes.NestedEnum.valueOf(unknown6543));
+
// Setters also accept unknown EnumValueDescriptor.
builder.setField(optionalNestedEnumField, unknown6543);
builder.setRepeatedField(repeatedNestedEnumField, 0, unknown4321);
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 f8cb0aab..8ce0ca73 100644
--- a/java/core/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java
+++ b/java/core/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java
@@ -30,13 +30,24 @@
package com.google.protobuf;
+import static junit.framework.TestCase.assertEquals;
+
import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
import com.google.protobuf.UnittestLite.TestAllTypesLite;
+import protobuf_unittest.UnittestProto;
+import protobuf_unittest.UnittestProto.ForeignEnum;
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestEmptyMessage;
+import protobuf_unittest.UnittestProto.TestPackedExtensions;
+import protobuf_unittest.UnittestProto.TestPackedTypes;
import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash;
import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Bar;
import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Foo;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.util.Arrays;
+import java.util.Map;
import junit.framework.TestCase;
/**
@@ -45,7 +56,44 @@ import junit.framework.TestCase;
* @author dweis@google.com (Daniel Weis)
*/
public class UnknownFieldSetLiteTest extends TestCase {
-
+ @Override
+ public void setUp() throws Exception {
+ allFields = TestUtil.getAllSet();
+ allFieldsData = allFields.toByteString();
+ emptyMessage = TestEmptyMessage.parseFrom(allFieldsData);
+ unknownFields = emptyMessage.getUnknownFields();
+ }
+
+ TestAllTypes allFields;
+ ByteString allFieldsData;
+
+ // Constructs a protocol buffer which contains fields with all the same
+ // numbers as allFieldsData except that each field is some other wire
+ // type.
+ private ByteString getBizarroData() throws Exception {
+ UnknownFieldSet.Builder bizarroFields = UnknownFieldSet.newBuilder();
+
+ UnknownFieldSet.Field varintField = UnknownFieldSet.Field.newBuilder().addVarint(1).build();
+ UnknownFieldSet.Field fixed32Field = UnknownFieldSet.Field.newBuilder().addFixed32(1).build();
+
+ for (Map.Entry<Integer, UnknownFieldSet.Field> entry : unknownFields.asMap().entrySet()) {
+ if (entry.getValue().getVarintList().isEmpty()) {
+ // Original field is not a varint, so use a varint.
+ bizarroFields.addField(entry.getKey(), varintField);
+ } else {
+ // Original field *is* a varint, so use something else.
+ bizarroFields.addField(entry.getKey(), fixed32Field);
+ }
+ }
+
+ return bizarroFields.build().toByteString();
+ }
+
+ // An empty message that has been parsed from allFieldsData. So, it has
+ // unknown fields of every type.
+ TestEmptyMessage emptyMessage;
+ UnknownFieldSet unknownFields;
+
public void testDefaultInstance() {
UnknownFieldSetLite unknownFields = UnknownFieldSetLite.getDefaultInstance();
@@ -87,6 +135,25 @@ public class UnknownFieldSetLiteTest extends TestCase {
assertEquals(foo.toByteString().size(), instance.getSerializedSize());
}
+ public void testHashCodeAfterDeserialization() throws IOException {
+ Foo foo = Foo.newBuilder()
+ .setValue(2)
+ .build();
+
+ Foo fooDeserialized = Foo.parseFrom(foo.toByteArray());
+
+ assertEquals(fooDeserialized, foo);
+ assertEquals(foo.hashCode(), fooDeserialized.hashCode());
+ }
+
+ public void testNewInstanceHashCode() {
+ UnknownFieldSetLite emptyFieldSet = UnknownFieldSetLite.getDefaultInstance();
+ UnknownFieldSetLite paddedFieldSet = UnknownFieldSetLite.newInstance();
+
+ assertEquals(emptyFieldSet, paddedFieldSet);
+ assertEquals(emptyFieldSet.hashCode(), paddedFieldSet.hashCode());
+ }
+
public void testMergeVarintField() throws IOException {
UnknownFieldSetLite unknownFields = UnknownFieldSetLite.newInstance();
unknownFields.mergeVarintField(10, 2);
@@ -331,4 +398,203 @@ public class UnknownFieldSetLiteTest extends TestCase {
}
return ByteString.copyFrom(byteArrayOutputStream.toByteArray());
}
+
+ public void testSerializeLite() throws Exception {
+ UnittestLite.TestEmptyMessageLite emptyMessageLite =
+ UnittestLite.TestEmptyMessageLite.parseFrom(allFieldsData);
+ assertEquals(allFieldsData.size(), emptyMessageLite.getSerializedSize());
+ ByteString data = emptyMessageLite.toByteString();
+ TestAllTypes message = TestAllTypes.parseFrom(data);
+ TestUtil.assertAllFieldsSet(message);
+ assertEquals(allFieldsData, data);
+ }
+
+ public void testAllExtensionsLite() throws Exception {
+ TestAllExtensions allExtensions = TestUtil.getAllExtensionsSet();
+ ByteString allExtensionsData = allExtensions.toByteString();
+ UnittestLite.TestEmptyMessageLite emptyMessageLite =
+ UnittestLite.TestEmptyMessageLite.parser().parseFrom(allExtensionsData);
+ ByteString data = emptyMessageLite.toByteString();
+ TestAllExtensions message = TestAllExtensions.parseFrom(data, TestUtil.getExtensionRegistry());
+ TestUtil.assertAllExtensionsSet(message);
+ assertEquals(allExtensionsData, data);
+ }
+
+ public void testAllPackedFieldsLite() throws Exception {
+ TestPackedTypes allPackedFields = TestUtil.getPackedSet();
+ ByteString allPackedData = allPackedFields.toByteString();
+ UnittestLite.TestEmptyMessageLite emptyMessageLite =
+ UnittestLite.TestEmptyMessageLite.parseFrom(allPackedData);
+ ByteString data = emptyMessageLite.toByteString();
+ TestPackedTypes message = TestPackedTypes.parseFrom(data, TestUtil.getExtensionRegistry());
+ TestUtil.assertPackedFieldsSet(message);
+ assertEquals(allPackedData, data);
+ }
+
+ public void testAllPackedExtensionsLite() throws Exception {
+ TestPackedExtensions allPackedExtensions = TestUtil.getPackedExtensionsSet();
+ ByteString allPackedExtensionsData = allPackedExtensions.toByteString();
+ UnittestLite.TestEmptyMessageLite emptyMessageLite =
+ UnittestLite.TestEmptyMessageLite.parseFrom(allPackedExtensionsData);
+ ByteString data = emptyMessageLite.toByteString();
+ TestPackedExtensions message =
+ TestPackedExtensions.parseFrom(data, TestUtil.getExtensionRegistry());
+ TestUtil.assertPackedExtensionsSet(message);
+ assertEquals(allPackedExtensionsData, data);
+ }
+
+ public void testCopyFromLite() throws Exception {
+ UnittestLite.TestEmptyMessageLite emptyMessageLite =
+ UnittestLite.TestEmptyMessageLite.parseFrom(allFieldsData);
+ UnittestLite.TestEmptyMessageLite emptyMessageLite2 =
+ UnittestLite.TestEmptyMessageLite.newBuilder().mergeFrom(emptyMessageLite).build();
+ assertEquals(emptyMessageLite.toByteString(), emptyMessageLite2.toByteString());
+ }
+
+ public void testMergeFromLite() throws Exception {
+ TestAllTypes message1 =
+ TestAllTypes.newBuilder()
+ .setOptionalInt32(1)
+ .setOptionalString("foo")
+ .addRepeatedString("bar")
+ .setOptionalNestedEnum(TestAllTypes.NestedEnum.BAZ)
+ .build();
+
+ TestAllTypes message2 =
+ TestAllTypes.newBuilder()
+ .setOptionalInt64(2)
+ .setOptionalString("baz")
+ .addRepeatedString("qux")
+ .setOptionalForeignEnum(ForeignEnum.FOREIGN_BAZ)
+ .build();
+
+ ByteString data1 = message1.toByteString();
+ UnittestLite.TestEmptyMessageLite emptyMessageLite1 =
+ UnittestLite.TestEmptyMessageLite.parseFrom(data1);
+ ByteString data2 = message2.toByteString();
+ UnittestLite.TestEmptyMessageLite emptyMessageLite2 =
+ UnittestLite.TestEmptyMessageLite.parseFrom(data2);
+
+ message1 = TestAllTypes.newBuilder(message1).mergeFrom(message2).build();
+ emptyMessageLite1 =
+ UnittestLite.TestEmptyMessageLite.newBuilder(emptyMessageLite1)
+ .mergeFrom(emptyMessageLite2)
+ .build();
+
+ data1 = emptyMessageLite1.toByteString();
+ message2 = TestAllTypes.parseFrom(data1);
+
+ assertEquals(message1, message2);
+ }
+
+ public void testWrongTypeTreatedAsUnknownLite() throws Exception {
+ // Test that fields of the wrong wire type are treated like unknown fields
+ // when parsing.
+
+ ByteString bizarroData = getBizarroData();
+ TestAllTypes allTypesMessage = TestAllTypes.parseFrom(bizarroData);
+ UnittestLite.TestEmptyMessageLite emptyMessageLite =
+ UnittestLite.TestEmptyMessageLite.parseFrom(bizarroData);
+ ByteString data = emptyMessageLite.toByteString();
+ TestAllTypes allTypesMessage2 = TestAllTypes.parseFrom(data);
+
+ assertEquals(allTypesMessage.toString(), allTypesMessage2.toString());
+ }
+
+ public void testUnknownExtensionsLite() throws Exception {
+ // Make sure fields are properly parsed to the UnknownFieldSet even when
+ // they are declared as extension numbers.
+
+ UnittestLite.TestEmptyMessageWithExtensionsLite message =
+ UnittestLite.TestEmptyMessageWithExtensionsLite.parseFrom(allFieldsData);
+
+ assertEquals(allFieldsData, message.toByteString());
+ }
+
+ public void testWrongExtensionTypeTreatedAsUnknownLite() throws Exception {
+ // Test that fields of the wrong wire type are treated like unknown fields
+ // when parsing extensions.
+
+ ByteString bizarroData = getBizarroData();
+ TestAllExtensions allExtensionsMessage = TestAllExtensions.parseFrom(bizarroData);
+ UnittestLite.TestEmptyMessageLite emptyMessageLite =
+ UnittestLite.TestEmptyMessageLite.parseFrom(bizarroData);
+
+ // All fields should have been interpreted as unknown, so the byte strings
+ // should be the same.
+ assertEquals(emptyMessageLite.toByteString(), allExtensionsMessage.toByteString());
+ }
+
+ public void testParseUnknownEnumValueLite() throws Exception {
+ Descriptors.FieldDescriptor singularField =
+ TestAllTypes.getDescriptor().findFieldByName("optional_nested_enum");
+ Descriptors.FieldDescriptor repeatedField =
+ TestAllTypes.getDescriptor().findFieldByName("repeated_nested_enum");
+ assertNotNull(singularField);
+ assertNotNull(repeatedField);
+
+ ByteString data =
+ UnknownFieldSet.newBuilder()
+ .addField(
+ singularField.getNumber(),
+ UnknownFieldSet.Field.newBuilder()
+ .addVarint(TestAllTypes.NestedEnum.BAR.getNumber())
+ .addVarint(5) // not valid
+ .build())
+ .addField(
+ repeatedField.getNumber(),
+ UnknownFieldSet.Field.newBuilder()
+ .addVarint(TestAllTypes.NestedEnum.FOO.getNumber())
+ .addVarint(4) // not valid
+ .addVarint(TestAllTypes.NestedEnum.BAZ.getNumber())
+ .addVarint(6) // not valid
+ .build())
+ .build()
+ .toByteString();
+
+ UnittestLite.TestEmptyMessageLite emptyMessageLite =
+ UnittestLite.TestEmptyMessageLite.parseFrom(data);
+ data = emptyMessageLite.toByteString();
+
+ {
+ TestAllTypes message = TestAllTypes.parseFrom(data);
+ assertEquals(TestAllTypes.NestedEnum.BAR, message.getOptionalNestedEnum());
+ assertEquals(
+ Arrays.asList(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ),
+ message.getRepeatedNestedEnumList());
+ assertEquals(
+ Arrays.asList(5L),
+ message.getUnknownFields().getField(singularField.getNumber()).getVarintList());
+ assertEquals(
+ Arrays.asList(4L, 6L),
+ message.getUnknownFields().getField(repeatedField.getNumber()).getVarintList());
+ }
+
+ {
+ TestAllExtensions message =
+ TestAllExtensions.parseFrom(data, TestUtil.getExtensionRegistry());
+ assertEquals(
+ TestAllTypes.NestedEnum.BAR,
+ message.getExtension(UnittestProto.optionalNestedEnumExtension));
+ assertEquals(
+ Arrays.asList(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ),
+ message.getExtension(UnittestProto.repeatedNestedEnumExtension));
+ assertEquals(
+ Arrays.asList(5L),
+ message.getUnknownFields().getField(singularField.getNumber()).getVarintList());
+ assertEquals(
+ Arrays.asList(4L, 6L),
+ message.getUnknownFields().getField(repeatedField.getNumber()).getVarintList());
+ }
+ }
+
+ public void testClearLite() throws Exception {
+ UnittestLite.TestEmptyMessageLite emptyMessageLite1 =
+ UnittestLite.TestEmptyMessageLite.parseFrom(allFieldsData);
+ UnittestLite.TestEmptyMessageLite emptyMessageLite2 =
+ UnittestLite.TestEmptyMessageLite.newBuilder().mergeFrom(emptyMessageLite1).clear().build();
+ assertEquals(0, emptyMessageLite2.getSerializedSize());
+ ByteString data = emptyMessageLite2.toByteString();
+ assertEquals(0, data.size());
+ }
}
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 f81e90b4..1a84806a 100644
--- a/java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
+++ b/java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
@@ -445,208 +445,4 @@ public class UnknownFieldSetTest extends TestCase {
}
// =================================================================
-
- public void testSerializeLite() throws Exception {
- UnittestLite.TestEmptyMessageLite emptyMessageLite =
- UnittestLite.TestEmptyMessageLite.parseFrom(allFieldsData);
- assertEquals(allFieldsData.size(), emptyMessageLite.getSerializedSize());
- ByteString data = emptyMessageLite.toByteString();
- TestAllTypes message = TestAllTypes.parseFrom(data);
- TestUtil.assertAllFieldsSet(message);
- assertEquals(allFieldsData, data);
- }
-
- public void testAllExtensionsLite() throws Exception {
- TestAllExtensions allExtensions = TestUtil.getAllExtensionsSet();
- ByteString allExtensionsData = allExtensions.toByteString();
- UnittestLite.TestEmptyMessageLite emptyMessageLite =
- UnittestLite.TestEmptyMessageLite.parser().parseFrom(allExtensionsData);
- ByteString data = emptyMessageLite.toByteString();
- TestAllExtensions message =
- TestAllExtensions.parseFrom(data, TestUtil.getExtensionRegistry());
- TestUtil.assertAllExtensionsSet(message);
- assertEquals(allExtensionsData, data);
- }
-
- public void testAllPackedFieldsLite() throws Exception {
- TestPackedTypes allPackedFields = TestUtil.getPackedSet();
- ByteString allPackedData = allPackedFields.toByteString();
- UnittestLite.TestEmptyMessageLite emptyMessageLite =
- UnittestLite.TestEmptyMessageLite.parseFrom(allPackedData);
- ByteString data = emptyMessageLite.toByteString();
- TestPackedTypes message =
- TestPackedTypes.parseFrom(data, TestUtil.getExtensionRegistry());
- TestUtil.assertPackedFieldsSet(message);
- assertEquals(allPackedData, data);
- }
-
- public void testAllPackedExtensionsLite() throws Exception {
- TestPackedExtensions allPackedExtensions = TestUtil.getPackedExtensionsSet();
- ByteString allPackedExtensionsData = allPackedExtensions.toByteString();
- UnittestLite.TestEmptyMessageLite emptyMessageLite =
- UnittestLite.TestEmptyMessageLite.parseFrom(allPackedExtensionsData);
- ByteString data = emptyMessageLite.toByteString();
- TestPackedExtensions message =
- TestPackedExtensions.parseFrom(data, TestUtil.getExtensionRegistry());
- TestUtil.assertPackedExtensionsSet(message);
- assertEquals(allPackedExtensionsData, data);
- }
-
- public void testCopyFromLite() throws Exception {
- UnittestLite.TestEmptyMessageLite emptyMessageLite =
- UnittestLite.TestEmptyMessageLite.parseFrom(allFieldsData);
- UnittestLite.TestEmptyMessageLite emptyMessageLite2 =
- UnittestLite.TestEmptyMessageLite.newBuilder()
- .mergeFrom(emptyMessageLite).build();
- assertEquals(emptyMessageLite.toByteString(), emptyMessageLite2.toByteString());
- }
-
- public void testMergeFromLite() throws Exception {
- TestAllTypes message1 = TestAllTypes.newBuilder()
- .setOptionalInt32(1)
- .setOptionalString("foo")
- .addRepeatedString("bar")
- .setOptionalNestedEnum(TestAllTypes.NestedEnum.BAZ)
- .build();
-
- TestAllTypes message2 = TestAllTypes.newBuilder()
- .setOptionalInt64(2)
- .setOptionalString("baz")
- .addRepeatedString("qux")
- .setOptionalForeignEnum(ForeignEnum.FOREIGN_BAZ)
- .build();
-
- ByteString data1 = message1.toByteString();
- UnittestLite.TestEmptyMessageLite emptyMessageLite1 =
- UnittestLite.TestEmptyMessageLite.parseFrom(data1);
- ByteString data2 = message2.toByteString();
- UnittestLite.TestEmptyMessageLite emptyMessageLite2 =
- UnittestLite.TestEmptyMessageLite.parseFrom(data2);
-
- message1 = TestAllTypes.newBuilder(message1).mergeFrom(message2).build();
- emptyMessageLite1 = UnittestLite.TestEmptyMessageLite.newBuilder(emptyMessageLite1)
- .mergeFrom(emptyMessageLite2).build();
-
- data1 = emptyMessageLite1.toByteString();
- message2 = TestAllTypes.parseFrom(data1);
-
- assertEquals(message1, message2);
- }
-
- public void testWrongTypeTreatedAsUnknownLite() throws Exception {
- // Test that fields of the wrong wire type are treated like unknown fields
- // when parsing.
-
- ByteString bizarroData = getBizarroData();
- TestAllTypes allTypesMessage = TestAllTypes.parseFrom(bizarroData);
- UnittestLite.TestEmptyMessageLite emptyMessageLite =
- UnittestLite.TestEmptyMessageLite.parseFrom(bizarroData);
- ByteString data = emptyMessageLite.toByteString();
- TestAllTypes allTypesMessage2 = TestAllTypes.parseFrom(data);
-
- assertEquals(allTypesMessage.toString(), allTypesMessage2.toString());
- }
-
- public void testUnknownExtensionsLite() throws Exception {
- // Make sure fields are properly parsed to the UnknownFieldSet even when
- // they are declared as extension numbers.
-
- UnittestLite.TestEmptyMessageWithExtensionsLite message =
- UnittestLite.TestEmptyMessageWithExtensionsLite.parseFrom(allFieldsData);
-
- assertEquals(allFieldsData, message.toByteString());
- }
-
- public void testWrongExtensionTypeTreatedAsUnknownLite() throws Exception {
- // Test that fields of the wrong wire type are treated like unknown fields
- // when parsing extensions.
-
- ByteString bizarroData = getBizarroData();
- TestAllExtensions allExtensionsMessage =
- TestAllExtensions.parseFrom(bizarroData);
- UnittestLite.TestEmptyMessageLite emptyMessageLite =
- UnittestLite.TestEmptyMessageLite.parseFrom(bizarroData);
-
- // All fields should have been interpreted as unknown, so the byte strings
- // should be the same.
- assertEquals(emptyMessageLite.toByteString(),
- allExtensionsMessage.toByteString());
- }
-
- public void testParseUnknownEnumValueLite() throws Exception {
- Descriptors.FieldDescriptor singularField =
- TestAllTypes.getDescriptor().findFieldByName("optional_nested_enum");
- Descriptors.FieldDescriptor repeatedField =
- TestAllTypes.getDescriptor().findFieldByName("repeated_nested_enum");
- assertNotNull(singularField);
- assertNotNull(repeatedField);
-
- ByteString data =
- UnknownFieldSet.newBuilder()
- .addField(singularField.getNumber(),
- UnknownFieldSet.Field.newBuilder()
- .addVarint(TestAllTypes.NestedEnum.BAR.getNumber())
- .addVarint(5) // not valid
- .build())
- .addField(repeatedField.getNumber(),
- UnknownFieldSet.Field.newBuilder()
- .addVarint(TestAllTypes.NestedEnum.FOO.getNumber())
- .addVarint(4) // not valid
- .addVarint(TestAllTypes.NestedEnum.BAZ.getNumber())
- .addVarint(6) // not valid
- .build())
- .build()
- .toByteString();
-
- UnittestLite.TestEmptyMessageLite emptyMessageLite =
- UnittestLite.TestEmptyMessageLite.parseFrom(data);
- data = emptyMessageLite.toByteString();
-
- {
- TestAllTypes message = TestAllTypes.parseFrom(data);
- assertEquals(TestAllTypes.NestedEnum.BAR,
- message.getOptionalNestedEnum());
- assertEquals(
- Arrays.asList(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ),
- message.getRepeatedNestedEnumList());
- assertEquals(Arrays.asList(5L),
- message.getUnknownFields()
- .getField(singularField.getNumber())
- .getVarintList());
- assertEquals(Arrays.asList(4L, 6L),
- message.getUnknownFields()
- .getField(repeatedField.getNumber())
- .getVarintList());
- }
-
- {
- TestAllExtensions message =
- TestAllExtensions.parseFrom(data, TestUtil.getExtensionRegistry());
- assertEquals(TestAllTypes.NestedEnum.BAR,
- message.getExtension(UnittestProto.optionalNestedEnumExtension));
- assertEquals(
- Arrays.asList(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ),
- message.getExtension(UnittestProto.repeatedNestedEnumExtension));
- assertEquals(Arrays.asList(5L),
- message.getUnknownFields()
- .getField(singularField.getNumber())
- .getVarintList());
- assertEquals(Arrays.asList(4L, 6L),
- message.getUnknownFields()
- .getField(repeatedField.getNumber())
- .getVarintList());
- }
- }
-
- public void testClearLite() throws Exception {
- UnittestLite.TestEmptyMessageLite emptyMessageLite1 =
- UnittestLite.TestEmptyMessageLite.parseFrom(allFieldsData);
- UnittestLite.TestEmptyMessageLite emptyMessageLite2 =
- UnittestLite.TestEmptyMessageLite.newBuilder()
- .mergeFrom(emptyMessageLite1).clear().build();
- assertEquals(0, emptyMessageLite2.getSerializedSize());
- ByteString data = emptyMessageLite2.toByteString();
- assertEquals(0, data.size());
- }
-
}
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 370860c2..03c33ecf 100644
--- a/java/core/src/test/java/com/google/protobuf/WireFormatTest.java
+++ b/java/core/src/test/java/com/google/protobuf/WireFormatTest.java
@@ -30,14 +30,13 @@
package com.google.protobuf;
-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;
+import protobuf_unittest.UnittestProto.TestExtensionInsideTable;
import protobuf_unittest.UnittestProto.TestFieldOrderings;
import protobuf_unittest.UnittestProto.TestOneof2;
import protobuf_unittest.UnittestProto.TestOneofBackwardsCompatible;
@@ -125,32 +124,6 @@ public class WireFormatTest extends TestCase {
TestUtil.assertPackedFieldsSet(message2);
}
- public void testSerializeExtensionsLite() throws Exception {
- // TestAllTypes and TestAllExtensions should have compatible wire formats,
- // so if we serialize a TestAllExtensions then parse it as TestAllTypes
- // it should work.
-
- TestAllExtensionsLite message = TestUtilLite.getAllLiteExtensionsSet();
- ByteString rawBytes = message.toByteString();
- assertEquals(rawBytes.size(), message.getSerializedSize());
-
- TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
-
- TestUtil.assertAllFieldsSet(message2);
- }
-
- public void testSerializePackedExtensionsLite() throws Exception {
- // TestPackedTypes and TestPackedExtensions should have compatible wire
- // formats; check that they serialize to the same string.
- TestPackedExtensionsLite message = TestUtilLite.getLitePackedExtensionsSet();
- ByteString rawBytes = message.toByteString();
-
- TestPackedTypes message2 = TestUtil.getPackedSet();
- ByteString rawBytes2 = message2.toByteString();
-
- assertEquals(rawBytes, rawBytes2);
- }
-
public void testParseExtensions() throws Exception {
// TestAllTypes and TestAllExtensions should have compatible wire formats,
// so if we serialize a TestAllTypes then parse it as TestAllExtensions
@@ -180,48 +153,6 @@ public class WireFormatTest extends TestCase {
TestUtil.assertPackedExtensionsSet(message2);
}
- public void testParseExtensionsLite() throws Exception {
- // TestAllTypes and TestAllExtensions should have compatible wire formats,
- // so if we serialize a TestAllTypes then parse it as TestAllExtensions
- // it should work.
-
- TestAllTypes message = TestUtil.getAllSet();
- ByteString rawBytes = message.toByteString();
-
- ExtensionRegistryLite registry_lite = TestUtilLite.getExtensionRegistryLite();
-
- TestAllExtensionsLite message2 =
- TestAllExtensionsLite.parseFrom(rawBytes, registry_lite);
-
- TestUtil.assertAllExtensionsSet(message2);
-
- // Try again using a full extension registry.
- ExtensionRegistry registry = TestUtil.getExtensionRegistry();
-
- TestAllExtensionsLite message3 =
- TestAllExtensionsLite.parseFrom(rawBytes, registry);
-
- TestUtil.assertAllExtensionsSet(message3);
- }
-
- public void testParsePackedExtensionsLite() throws Exception {
- // Ensure that packed extensions can be properly parsed.
- TestPackedExtensionsLite message = TestUtilLite.getLitePackedExtensionsSet();
- ByteString rawBytes = message.toByteString();
-
- ExtensionRegistryLite registry = TestUtilLite.getExtensionRegistryLite();
-
- TestPackedExtensionsLite message2 =
- TestPackedExtensionsLite.parseFrom(rawBytes, registry);
-
- TestUtil.assertPackedExtensionsSet(message2);
- }
-
- public void testExtensionsSerializedSize() throws Exception {
- assertNotSame(TestUtil.getAllSet().getSerializedSize(),
- TestUtil.getAllExtensionsSet().getSerializedSize());
- }
-
public void testSerializeDelimited() throws Exception {
ByteArrayOutputStream output = new ByteArrayOutputStream();
TestUtil.getAllSet().writeDelimitedTo(output);
@@ -305,6 +236,26 @@ public class WireFormatTest extends TestCase {
getTestFieldOrderingsRegistry());
assertEquals(source, dest);
}
+
+ private static ExtensionRegistry getTestExtensionInsideTableRegistry() {
+ ExtensionRegistry result = ExtensionRegistry.newInstance();
+ result.add(UnittestProto.testExtensionInsideTableExtension);
+ return result;
+ }
+
+ public void testExtensionInsideTable() throws Exception {
+ // Make sure the extension within the range of table is parsed correctly in experimental
+ // runtime.
+ TestExtensionInsideTable source =
+ TestExtensionInsideTable.newBuilder()
+ .setField1(1)
+ .setExtension(UnittestProto.testExtensionInsideTableExtension, 23)
+ .build();
+ TestExtensionInsideTable dest =
+ TestExtensionInsideTable.parseFrom(source.toByteString(),
+ getTestExtensionInsideTableRegistry());
+ assertEquals(source, dest);
+ }
public void testParseMultipleExtensionRangesDynamic() throws Exception {
// Same as above except with DynamicMessage.
diff --git a/java/core/src/test/proto/com/google/protobuf/deprecated_file.proto b/java/core/src/test/proto/com/google/protobuf/deprecated_file.proto
new file mode 100644
index 00000000..ca90e927
--- /dev/null
+++ b/java/core/src/test/proto/com/google/protobuf/deprecated_file.proto
@@ -0,0 +1,38 @@
+// 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 deprecated_file;
+
+option deprecated = true;
+
+// TODO (liujisi): Add deprecation options on messages, enums fields as well and
+// add tests to verify those annotations are actually generated.
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 6eef42c5..b18b0d79 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
@@ -46,6 +46,14 @@ message TestOneofEquals {
message Foo {
optional int32 value = 1;
repeated Bar bar = 2;
+ map<string, string> my_map = 3;
+ oneof Single {
+ sint64 sint64 = 4;
+ // LINT: ALLOW_GROUPS
+ group MyGroup = 5 {
+ optional int32 value = 1;
+ }
+ }
extensions 100 to max;
}
diff --git a/java/core/src/test/proto/com/google/protobuf/map_lite_test.proto b/java/core/src/test/proto/com/google/protobuf/map_lite_test.proto
new file mode 100644
index 00000000..c04f5d57
--- /dev/null
+++ b/java/core/src/test/proto/com/google/protobuf/map_lite_test.proto
@@ -0,0 +1,111 @@
+// 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 map_lite_test;
+
+option optimize_for = LITE_RUNTIME;
+option java_package = "map_lite_test";
+option java_outer_classname = "MapTestProto";
+
+message TestMap {
+ message MessageValue {
+ int32 value = 1;
+ }
+ enum EnumValue {
+ FOO = 0;
+ BAR = 1;
+ BAZ = 2;
+ QUX = 3;
+ }
+
+ map<int32, int32> int32_to_int32_field = 1;
+ map<int32, string> int32_to_string_field = 2;
+ map<int32, bytes> int32_to_bytes_field = 3;
+ map<int32, EnumValue> int32_to_enum_field = 4;
+ map<int32, MessageValue> int32_to_message_field = 5;
+ map<string, int32> string_to_int32_field = 6;
+ map<uint32, int32> uint32_to_int32_field = 7;
+ map<int64, int32> int64_to_int32_field = 8;
+}
+
+// Used to test that a nested builder containing map fields will properly
+// propagate the onChange event and mark its parent dirty when a change
+// is made to a map field.
+message TestOnChangeEventPropagation {
+ TestMap optional_message = 1;
+}
+
+// a decoy of TestMap for testing parsing errors
+message BizarroTestMap {
+ map<int32, bytes> int32_to_int32_field = 1; // same key type, different value
+ map<string, int32> int32_to_string_field = 2; // different key and value types
+ map<string, int32> int32_to_bytes_field = 3; // different key types, same value
+ map<string, bytes> int32_to_enum_field = 4; // different key and value types
+ map<string, bytes> int32_to_message_field = 5; // different key and value types
+ map<string, bytes> string_to_int32_field = 6; // same key type, different value
+}
+
+// Used to test that java reserved words can be used as protobuf field names
+// Not all reserved words are tested (to avoid bloat) but instead an arbitrary
+// subset of them chosen to cover various keyword categories like
+// type, modifier, declaration, etc.
+message ReservedAsMapField {
+ map<string, uint32> if = 1;
+ map<string, uint32> const = 2;
+ map<string, uint32> private = 3;
+ map<string, uint32> class = 4;
+ map<string, uint32> int = 5;
+ map<string, uint32> void = 6;
+ map<string, uint32> string = 7; // These are also proto keywords
+ map<string, uint32> package = 8;
+ map<string, uint32> enum = 9; // Most recent Java reserved word
+ map<string, uint32> null = 10;
+ // null is not a 'reserved word' per se but as a literal needs similar care
+}
+
+message ReservedAsMapFieldWithEnumValue {
+ enum SampleEnum {
+ A = 0;
+ B = 1;
+ }
+ map<string, SampleEnum> if = 1;
+ map<string, SampleEnum> const = 2;
+ map<string, SampleEnum> private = 3;
+ map<string, SampleEnum> class = 4;
+ map<string, SampleEnum> int = 5;
+ map<string, SampleEnum> void = 6;
+ map<string, SampleEnum> string = 7; // These are also proto keywords
+ map<string, SampleEnum> package = 8;
+ map<string, SampleEnum> enum = 9; // Most recent Java reserved word
+ map<string, SampleEnum> null = 10;
+ // null is not a 'reserved word' per se but as a literal needs similar care
+}
diff --git a/java/core/src/test/proto/com/google/protobuf/test_bad_identifiers.proto b/java/core/src/test/proto/com/google/protobuf/test_bad_identifiers.proto
index d2c77936..ff5bf3ae 100644
--- a/java/core/src/test/proto/com/google/protobuf/test_bad_identifiers.proto
+++ b/java/core/src/test/proto/com/google/protobuf/test_bad_identifiers.proto
@@ -148,6 +148,12 @@ message TestConflictingFieldNames {
// the method getInt32FieldList().
required int32 int32_field_list = 31; // NO_PROTO3
+ // These field pairs have the same Java converted name
+ optional string field_name = 32; // NO_PROTO3
+ optional string field__name = 33; // NO_PROTO3
+ optional int32 _2conflict = 34; // NO_PROTO3
+ optional int32 __2conflict = 35;
+
extensions 1000 to max; // NO_PROTO3
repeated int64 int64_field = 41;
@@ -166,3 +172,14 @@ message TestMapField {
map<int32, int32> map_field = 1;
}
+
+message TestLeadingNumberFields {
+ optional int32 _30day_impressions = 1;
+ repeated string _60day_impressions = 2;
+
+ optional string __2_underscores = 3;
+ repeated string __2repeated_underscores = 4;
+
+ optional int32 _32 = 32;
+ repeated int64 _64 = 64;
+}