From cf14183bcd5485b4a71541599ddce0b35eb71352 Mon Sep 17 00:00:00 2001 From: Jisi Liu Date: Thu, 28 Apr 2016 14:34:59 -0700 Subject: Down integrate from Google internal. --- .../com/google/protobuf/util/FieldMaskTree.java | 6 ++- .../com/google/protobuf/util/FieldMaskUtil.java | 45 ++++++++++++++++++---- .../google/protobuf/util/FieldMaskTreeTest.java | 20 ++++++++++ .../google/protobuf/util/FieldMaskUtilTest.java | 9 +++++ 4 files changed, 71 insertions(+), 9 deletions(-) (limited to 'java/util') diff --git a/java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java b/java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java index d6a2f6fa..668d65ab 100644 --- a/java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java +++ b/java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java @@ -264,7 +264,11 @@ class FieldMaskTree { } } } else { - destination.setField(field, source.getField(field)); + if (source.hasField(field) || !options.replacePrimitiveFields()) { + destination.setField(field, source.getField(field)); + } else { + destination.clearField(field); + } } } } diff --git a/java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java b/java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java index 0b3060a7..96961521 100644 --- a/java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java +++ b/java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java @@ -211,14 +211,19 @@ public class FieldMaskUtil { public static FieldMask normalize(FieldMask mask) { return new FieldMaskTree(mask).toFieldMask(); } - + /** - * Creates an union of two FieldMasks. + * Creates a union of two or more FieldMasks. */ - public static FieldMask union(FieldMask mask1, FieldMask mask2) { - return new FieldMaskTree(mask1).mergeFromFieldMask(mask2).toFieldMask(); + public static FieldMask union( + FieldMask firstMask, FieldMask secondMask, FieldMask... otherMasks) { + FieldMaskTree maskTree = new FieldMaskTree(firstMask).mergeFromFieldMask(secondMask); + for (FieldMask mask : otherMasks) { + maskTree.mergeFromFieldMask(mask); + } + return maskTree.toFieldMask(); } - + /** * Calculates the intersection of two FieldMasks. */ @@ -237,6 +242,9 @@ public class FieldMaskUtil { public static final class MergeOptions { private boolean replaceMessageFields = false; private boolean replaceRepeatedFields = false; + // TODO(b/28277137): change the default behavior to always replace primitive fields after + // fixing all failing TAP tests. + private boolean replacePrimitiveFields = false; /** * Whether to replace message fields (i.e., discard existing content in @@ -257,7 +265,23 @@ public class FieldMaskUtil { public boolean replaceRepeatedFields() { return replaceRepeatedFields; } - + + /** + * Whether to replace primitive (non-repeated and non-message) fields in + * destination message fields with the source primitive fields (i.e., if the + * field is set in the source, the value is copied to the + * destination; if the field is unset in the source, the field is cleared + * from the destination) when merging. + * + *

Default behavior is to always set the value of the source primitive + * field to the destination primitive field, and if the source field is + * unset, the default value of the source field is copied to the + * destination. + */ + public boolean replacePrimitiveFields() { + return replacePrimitiveFields; + } + public void setReplaceMessageFields(boolean value) { replaceMessageFields = value; } @@ -265,10 +289,15 @@ public class FieldMaskUtil { public void setReplaceRepeatedFields(boolean value) { replaceRepeatedFields = value; } + + public void setReplacePrimitiveFields(boolean value) { + replacePrimitiveFields = value; + } } - + /** - * Merges fields specified by a FieldMask from one message to another. + * Merges fields specified by a FieldMask from one message to another with the + * specified merge options. */ public static void merge(FieldMask mask, Message source, Message.Builder destination, MergeOptions options) { diff --git a/java/util/src/test/java/com/google/protobuf/util/FieldMaskTreeTest.java b/java/util/src/test/java/com/google/protobuf/util/FieldMaskTreeTest.java index 618e0072..3ee0fc6e 100644 --- a/java/util/src/test/java/com/google/protobuf/util/FieldMaskTreeTest.java +++ b/java/util/src/test/java/com/google/protobuf/util/FieldMaskTreeTest.java @@ -237,5 +237,25 @@ public class FieldMaskTreeTest extends TestCase { builder.getPayloadBuilder().setOptionalUint32(2000); new FieldMaskTree().addFieldPath("payload").merge(clearedSource, builder, options); assertEquals(false, builder.hasPayload()); + + // Test merging unset primitive fields. + builder = source.toBuilder(); + builder.getPayloadBuilder().clearOptionalInt32(); + NestedTestAllTypes sourceWithPayloadInt32Unset = builder.build(); + builder = source.toBuilder(); + new FieldMaskTree() + .addFieldPath("payload.optional_int32") + .merge(sourceWithPayloadInt32Unset, builder, options); + assertEquals(true, builder.getPayload().hasOptionalInt32()); + assertEquals(0, builder.getPayload().getOptionalInt32()); + + // Change to clear unset primitive fields. + options.setReplacePrimitiveFields(true); + builder = source.toBuilder(); + new FieldMaskTree() + .addFieldPath("payload.optional_int32") + .merge(sourceWithPayloadInt32Unset, builder, options); + assertEquals(true, builder.hasPayload()); + assertEquals(false, builder.getPayload().hasOptionalInt32()); } } diff --git a/java/util/src/test/java/com/google/protobuf/util/FieldMaskUtilTest.java b/java/util/src/test/java/com/google/protobuf/util/FieldMaskUtilTest.java index a312fc33..194f7b9c 100644 --- a/java/util/src/test/java/com/google/protobuf/util/FieldMaskUtilTest.java +++ b/java/util/src/test/java/com/google/protobuf/util/FieldMaskUtilTest.java @@ -152,6 +152,15 @@ public class FieldMaskUtilTest extends TestCase { FieldMask result = FieldMaskUtil.union(mask1, mask2); assertEquals("bar,foo", FieldMaskUtil.toString(result)); } + + public void testUnion_usingVarArgs() throws Exception { + FieldMask mask1 = FieldMaskUtil.fromString("foo"); + FieldMask mask2 = FieldMaskUtil.fromString("foo.bar,bar.quz"); + FieldMask mask3 = FieldMaskUtil.fromString("bar.quz"); + FieldMask mask4 = FieldMaskUtil.fromString("bar"); + FieldMask result = FieldMaskUtil.union(mask1, mask2, mask3, mask4); + assertEquals("bar,foo", FieldMaskUtil.toString(result)); + } public void testIntersection() throws Exception { // Only test a simple case here and expect -- cgit v1.2.3