diff options
Diffstat (limited to 'java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java')
-rw-r--r-- | java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java | 138 |
1 files changed, 85 insertions, 53 deletions
diff --git a/java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java b/java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java index dc2f4b84..4a13fb1d 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 @@ -34,10 +34,10 @@ import com.google.protobuf.Descriptors.Descriptor; import com.google.protobuf.Descriptors.FieldDescriptor; import com.google.protobuf.FieldMask; import com.google.protobuf.Message; - import java.util.ArrayList; import java.util.List; import java.util.Map.Entry; +import java.util.SortedMap; import java.util.TreeMap; import java.util.logging.Logger; @@ -59,26 +59,29 @@ import java.util.logging.Logger; * intersection to two FieldMasks and traverse all fields specified by the * FieldMask in a message tree. */ -class FieldMaskTree { - private static final Logger logger = - Logger.getLogger(FieldMaskTree.class.getName()); - - private static final String FIELD_PATH_SEPARATOR_REGEX = "\\."; +final class FieldMaskTree { + private static final Logger logger = Logger.getLogger(FieldMaskTree.class.getName()); + + private static final String FIELD_PATH_SEPARATOR_REGEX = "\\."; - private static class Node { - public TreeMap<String, Node> children = new TreeMap<String, Node>(); + private static final class Node { + final SortedMap<String, Node> children = new TreeMap<String, Node>(); } private final Node root = new Node(); - /** Creates an empty FieldMaskTree. */ - public FieldMaskTree() {} - - /** Creates a FieldMaskTree for a given FieldMask. */ - public FieldMaskTree(FieldMask mask) { + /** + * Creates an empty FieldMaskTree. + */ + FieldMaskTree() {} + + /** + * Creates a FieldMaskTree for a given FieldMask. + */ + FieldMaskTree(FieldMask mask) { mergeFromFieldMask(mask); } - + @Override public String toString() { return FieldMaskUtil.toString(toFieldMask()); @@ -94,7 +97,7 @@ class FieldMaskTree { * Likewise, if the field path to add is a sub-path of an existing leaf node, * nothing will be changed in the tree. */ - public FieldMaskTree addFieldPath(String path) { + FieldMaskTree addFieldPath(String path) { String[] parts = path.split(FIELD_PATH_SEPARATOR_REGEX); if (parts.length == 0) { return this; @@ -121,19 +124,21 @@ class FieldMaskTree { node.children.clear(); return this; } - + /** * Merges all field paths in a FieldMask into this tree. */ - public FieldMaskTree mergeFromFieldMask(FieldMask mask) { + FieldMaskTree mergeFromFieldMask(FieldMask mask) { for (String path : mask.getPathsList()) { addFieldPath(path); } return this; } - /** Converts this tree to a FieldMask. */ - public FieldMask toFieldMask() { + /** + * Converts this tree to a FieldMask. + */ + FieldMask toFieldMask() { if (root.children.isEmpty()) { return FieldMask.getDefaultInstance(); } @@ -142,24 +147,24 @@ class FieldMaskTree { return FieldMask.newBuilder().addAllPaths(paths).build(); } - /** Gathers all field paths in a sub-tree. */ + /** + * Gathers all field paths in a sub-tree. + */ private void getFieldPaths(Node node, String path, List<String> paths) { if (node.children.isEmpty()) { paths.add(path); return; } for (Entry<String, Node> entry : node.children.entrySet()) { - String childPath = path.isEmpty() - ? entry.getKey() : path + "." + entry.getKey(); + String childPath = path.isEmpty() ? entry.getKey() : path + "." + entry.getKey(); getFieldPaths(entry.getValue(), childPath, paths); } } /** - * Adds the intersection of this tree with the given {@code path} to - * {@code output}. + * Adds the intersection of this tree with the given {@code path} to {@code output}. */ - public void intersectFieldPath(String path, FieldMaskTree output) { + void intersectFieldPath(String path, FieldMaskTree output) { if (root.children.isEmpty()) { return; } @@ -190,14 +195,11 @@ class FieldMaskTree { } /** - * Merges all fields specified by this FieldMaskTree from {@code source} to - * {@code destination}. + * Merges all fields specified by this FieldMaskTree from {@code source} to {@code destination}. */ - public void merge(Message source, Message.Builder destination, - FieldMaskUtil.MergeOptions options) { + void merge(Message source, Message.Builder destination, FieldMaskUtil.MergeOptions options) { if (source.getDescriptorForType() != destination.getDescriptorForType()) { - throw new IllegalArgumentException( - "Cannot merge messages of different types."); + throw new IllegalArgumentException("Cannot merge messages of different types."); } if (root.children.isEmpty()) { return; @@ -205,33 +207,54 @@ class FieldMaskTree { merge(root, "", source, destination, options); } - /** Merges all fields specified by a sub-tree from {@code source} to - * {@code destination}. + /** + * Merges all fields specified by a sub-tree from {@code source} to {@code destination}. */ - private void merge(Node node, String path, Message source, - Message.Builder destination, FieldMaskUtil.MergeOptions options) { - assert source.getDescriptorForType() == destination.getDescriptorForType(); - + private void merge( + Node node, + String path, + Message source, + Message.Builder destination, + FieldMaskUtil.MergeOptions options) { + if (source.getDescriptorForType() != destination.getDescriptorForType()) { + throw new IllegalArgumentException( + String.format( + "source (%s) and destination (%s) descriptor must be equal", + source.getDescriptorForType(), destination.getDescriptorForType())); + } + Descriptor descriptor = source.getDescriptorForType(); for (Entry<String, Node> entry : node.children.entrySet()) { - FieldDescriptor field = - descriptor.findFieldByName(entry.getKey()); + FieldDescriptor field = descriptor.findFieldByName(entry.getKey()); if (field == null) { - logger.warning("Cannot find field \"" + entry.getKey() - + "\" in message type " + descriptor.getFullName()); + logger.warning( + "Cannot find field \"" + + entry.getKey() + + "\" in message type " + + descriptor.getFullName()); continue; } if (!entry.getValue().children.isEmpty()) { - if (field.isRepeated() - || field.getJavaType() != FieldDescriptor.JavaType.MESSAGE) { - logger.warning("Field \"" + field.getFullName() + "\" is not a " - + "singluar message field and cannot have sub-fields."); + if (field.isRepeated() || field.getJavaType() != FieldDescriptor.JavaType.MESSAGE) { + logger.warning( + "Field \"" + + field.getFullName() + + "\" is not a " + + "singluar message field and cannot have sub-fields."); continue; } - String childPath = path.isEmpty() - ? entry.getKey() : path + "." + entry.getKey(); - merge(entry.getValue(), childPath, (Message) source.getField(field), - destination.getFieldBuilder(field), options); + if (!source.hasField(field) && !destination.hasField(field)) { + // If the message field is not present in both source and destination, skip recursing + // so we don't create unnecessary empty messages. + continue; + } + String childPath = path.isEmpty() ? entry.getKey() : path + "." + entry.getKey(); + merge( + entry.getValue(), + childPath, + (Message) source.getField(field), + destination.getFieldBuilder(field), + options); continue; } if (field.isRepeated()) { @@ -245,13 +268,22 @@ class FieldMaskTree { } else { if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { if (options.replaceMessageFields()) { - destination.setField(field, source.getField(field)); + if (!source.hasField(field)) { + destination.clearField(field); + } else { + destination.setField(field, source.getField(field)); + } } else { - destination.getFieldBuilder(field).mergeFrom( - (Message) source.getField(field)); + if (source.hasField(field)) { + destination.getFieldBuilder(field).mergeFrom((Message) source.getField(field)); + } } } else { - destination.setField(field, source.getField(field)); + if (source.hasField(field) || !options.replacePrimitiveFields()) { + destination.setField(field, source.getField(field)); + } else { + destination.clearField(field); + } } } } |