aboutsummaryrefslogtreecommitdiffhomepage
path: root/java/core
diff options
context:
space:
mode:
authorGravatar Feng Xiao <xfxyjwf@gmail.com>2016-07-13 13:47:51 -0700
committerGravatar Feng Xiao <xfxyjwf@gmail.com>2016-07-13 13:48:40 -0700
commit9086d9643903c608ab015b0b7d903547a4e7b6f3 (patch)
treeb47053ab6f6bde20b55c4fff4019c68a7c45545c /java/core
parent70c1ac756d3cd8fa04725f82f0ad1a30404c3bb3 (diff)
Integrate from internal code base.
Diffstat (limited to 'java/core')
-rw-r--r--java/core/src/main/java/com/google/protobuf/CodedOutputStream.java38
-rw-r--r--java/core/src/main/java/com/google/protobuf/DynamicMessage.java8
-rw-r--r--java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java50
-rw-r--r--java/core/src/test/java/com/google/protobuf/LazyStringArrayListTest.java3
4 files changed, 98 insertions, 1 deletions
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 576a350f..4f5a9b77 100644
--- a/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
+++ b/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
@@ -145,6 +145,44 @@ public abstract class CodedOutputStream extends ByteOutput {
}
/**
+ * Configures serialization to be deterministic.
+ *
+ * <p>The deterministic serialization guarantees that for a given binary, equal (defined by the
+ * {@code equals()} methods in protos) messages will always be serialized to the same bytes. This
+ * implies:
+ *
+ * <ul>
+ * <li>repeated serialization of a message will return the same bytes
+ * <li>different processes of the same binary (which may be executing on different machines) will
+ * serialize equal messages to the same bytes.
+ * </ul>
+ *
+ * <p>Note the deterministic serialization is NOT canonical across languages; it is also unstable
+ * across different builds with schema changes due to unknown fields. Users who need canonical
+ * serialization, e.g. persistent storage in a canonical form, fingerprinting, etc, should define
+ * their own canonicalization specification and implement the serializer using reflection APIs
+ * rather than relying on this API.
+ *
+ * <p> Once set, the serializer will: (Note this is an implementation detail and may subject to
+ * change in the future)
+ *
+ * <ul>
+ * <li> sort map entries by keys in lexicographical order or numerical order. Note: For string
+ * keys, the order is based on comparing the Unicode value of each character in the strings.
+ * The order may be different from the deterministic serialization in other languages where
+ * maps are sorted on the lexicographical order of the UTF8 encoded keys.
+ * </ul>
+ */
+ public final void useDeterministicSerialization() {
+ serializationDeterministic = true;
+ }
+
+ boolean isSerializationDeterministic() {
+ return serializationDeterministic;
+ }
+ private boolean serializationDeterministic;
+
+ /**
* Create a new {@code CodedOutputStream} that writes to the given {@link ByteBuffer}.
*
* @deprecated the size parameter is no longer used since use of an internal buffer is useless
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 859a9e8f..c54da67f 100644
--- a/java/core/src/main/java/com/google/protobuf/DynamicMessage.java
+++ b/java/core/src/main/java/com/google/protobuf/DynamicMessage.java
@@ -526,6 +526,14 @@ public final class DynamicMessage extends AbstractMessage {
fields.clearField(oldField);
}
oneofCases[index] = field;
+ } else if (field.getFile().getSyntax() == Descriptors.FileDescriptor.Syntax.PROTO3) {
+ if (!field.isRepeated()
+ && field.getJavaType() != FieldDescriptor.JavaType.MESSAGE
+ && value.equals(field.getDefaultValue())) {
+ // In proto3, setting a field to its default value is equivalent to clearing the field.
+ fields.clearField(field);
+ return this;
+ }
}
fields.setField(field, value);
return this;
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 82f4216b..4a42c897 100644
--- a/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java
+++ b/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java
@@ -31,6 +31,8 @@
package com.google.protobuf;
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 com.google.protobuf.FieldPresenceTestProto.TestAllTypes;
import com.google.protobuf.FieldPresenceTestProto.TestOptionalFieldsOnly;
@@ -253,6 +255,54 @@ public class FieldPresenceTest extends TestCase {
assertEquals(4, message.getAllFields().size());
}
+ public void testFieldPresenceDynamicMessage() {
+ Descriptor descriptor = TestAllTypes.getDescriptor();
+ FieldDescriptor optionalInt32Field = descriptor.findFieldByName("optional_int32");
+ FieldDescriptor optionalStringField = descriptor.findFieldByName("optional_string");
+ FieldDescriptor optionalBytesField = descriptor.findFieldByName("optional_bytes");
+ FieldDescriptor optionalNestedEnumField = descriptor.findFieldByName("optional_nested_enum");
+ EnumDescriptor enumDescriptor = optionalNestedEnumField.getEnumType();
+ EnumValueDescriptor defaultEnumValueDescriptor = enumDescriptor.getValues().get(0);
+ EnumValueDescriptor nonDefaultEnumValueDescriptor = enumDescriptor.getValues().get(1);
+
+ DynamicMessage defaultInstance = DynamicMessage.getDefaultInstance(descriptor);
+ // Field not present.
+ DynamicMessage message = defaultInstance.newBuilderForType().build();
+ assertFalse(message.hasField(optionalInt32Field));
+ assertFalse(message.hasField(optionalStringField));
+ assertFalse(message.hasField(optionalBytesField));
+ assertFalse(message.hasField(optionalNestedEnumField));
+ assertEquals(0, message.getAllFields().size());
+
+ // Field set to non-default value is seen as present.
+ message =
+ defaultInstance
+ .newBuilderForType()
+ .setField(optionalInt32Field, 1)
+ .setField(optionalStringField, "x")
+ .setField(optionalBytesField, ByteString.copyFromUtf8("y"))
+ .setField(optionalNestedEnumField, nonDefaultEnumValueDescriptor)
+ .build();
+ assertTrue(message.hasField(optionalInt32Field));
+ assertTrue(message.hasField(optionalStringField));
+ assertTrue(message.hasField(optionalBytesField));
+ assertTrue(message.hasField(optionalNestedEnumField));
+ assertEquals(4, message.getAllFields().size());
+
+ // Field set to default value is seen as not present.
+ message = message.toBuilder()
+ .setField(optionalInt32Field, 0)
+ .setField(optionalStringField, "")
+ .setField(optionalBytesField, ByteString.EMPTY)
+ .setField(optionalNestedEnumField, defaultEnumValueDescriptor)
+ .build();
+ assertFalse(message.hasField(optionalInt32Field));
+ assertFalse(message.hasField(optionalStringField));
+ assertFalse(message.hasField(optionalBytesField));
+ assertFalse(message.hasField(optionalNestedEnumField));
+ assertEquals(0, message.getAllFields().size());
+ }
+
public void testMessageField() {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
assertFalse(builder.hasOptionalNestedMessage());
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 0f42ac50..497c4df2 100644
--- a/java/core/src/test/java/com/google/protobuf/LazyStringArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LazyStringArrayListTest.java
@@ -35,6 +35,7 @@ import static java.util.Arrays.asList;
import junit.framework.TestCase;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.List;
@@ -233,7 +234,7 @@ public class LazyStringArrayListTest extends TestCase {
}
try {
- list.addAllByteArray(asList(BYTE_STRING_A.toByteArray()));
+ list.addAllByteArray(Collections.singletonList(BYTE_STRING_A.toByteArray()));
fail();
} catch (UnsupportedOperationException e) {
// expected