Repository: brooklyn-server
Updated Branches:
  refs/heads/master e1b2bf2a6 -> f0a2995b4


allow collection merger to specify which value is preferred on conflict


Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/85f07ac7
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/85f07ac7
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/85f07ac7

Branch: refs/heads/master
Commit: 85f07ac7dd10b17f379f368ff42bc896f0fb02a1
Parents: e1b2bf2
Author: Alex Heneveld <alex.henev...@cloudsoftcorp.com>
Authored: Mon Sep 17 16:52:25 2018 +0100
Committer: Alex Heneveld <alex.henev...@cloudsoftcorp.com>
Committed: Mon Sep 17 16:52:25 2018 +0100

----------------------------------------------------------------------
 .../util/collections/CollectionMerger.java      | 35 +++++++++++++++-----
 1 file changed, 26 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/85f07ac7/utils/common/src/main/java/org/apache/brooklyn/util/collections/CollectionMerger.java
----------------------------------------------------------------------
diff --git 
a/utils/common/src/main/java/org/apache/brooklyn/util/collections/CollectionMerger.java
 
b/utils/common/src/main/java/org/apache/brooklyn/util/collections/CollectionMerger.java
index c7e1742..337e4cc 100644
--- 
a/utils/common/src/main/java/org/apache/brooklyn/util/collections/CollectionMerger.java
+++ 
b/utils/common/src/main/java/org/apache/brooklyn/util/collections/CollectionMerger.java
@@ -35,6 +35,8 @@ import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Sets;
 
+/** Does a configurable deep merge, taking the order from the first argument,
+ * and configurable through the builder how to act on lists or conflicts. */
 @Beta
 public class CollectionMerger {
     
@@ -42,14 +44,17 @@ public class CollectionMerger {
         protected int depth = Integer.MAX_VALUE;
         protected boolean mergeNestedMaps = true;
         protected boolean mergeNestedLists = false;
+        protected boolean preferSecondOnConflict = false;
         
+        /** Sets effectively infinite {@link #depth(int)} (the default) */
         public Builder deep(boolean val) {
             return depth(val ? Integer.MAX_VALUE : 1);
         }
         /**
          * Depth 1 means a shallow copy - i.e. only looking one layer down 
(e.g. at the values within the top-level map).
          * Depth 2 would mean going one-deep into the values inside the 
top-level map/list/set.
-         * 
+         * Default is infinite.
+s         * 
          * By default, depth only applies to nested maps. One needs to set 
{@link #mergeNestedLists(boolean)} for 
          * it to do this to nested iterables.
          */
@@ -58,14 +63,25 @@ public class CollectionMerger {
             this.depth = val;
             return this;
         }
+        /** @deprecated since 1.0, never did anything */
+        @Deprecated
         public Builder mergeNestedMaps(boolean val) {
             this.mergeNestedMaps = val;
             return this;
         }
+        /** By default lists will not be merged, and either the first or 
second will be kept 
+         * depending on {@link #preferSecondOnConflict(boolean)}. Set this to 
true to cause
+         * lists in the second merge argument to be appended to lists in the 
first. 
+         */
         public Builder mergeNestedLists(boolean val) {
             this.mergeNestedLists = val;
             return this;
         }
+        /** defaults to false, so if there is an unmergeable conflict, e.g. 
two strings, the first will be kept */
+        public Builder preferSecondOnConflict(boolean val) {
+            this.preferSecondOnConflict = val;
+            return this;
+        }
         public CollectionMerger build() {
             return new CollectionMerger(this);
         }
@@ -74,15 +90,15 @@ public class CollectionMerger {
     public static Builder builder() {
         return new Builder();
     }
-
+    
     protected final int depth;
-    protected final boolean mergeNestedMaps;
     protected final boolean mergeNestedLists;
+    protected final boolean preferSecondOnConflict;
 
     protected CollectionMerger(Builder builder) {
         this.depth = builder.depth;
-        this.mergeNestedMaps = builder.mergeNestedMaps;
         this.mergeNestedLists = builder.mergeNestedLists;
+        this.preferSecondOnConflict = builder.preferSecondOnConflict;
     }
     
     public Map<?, ?> merge(Map<?, ?> map1, Map<?, ?> map2) {
@@ -115,13 +131,14 @@ public class CollectionMerger {
             return val1.get();
         }
         
+        Object conflictResult = preferSecondOnConflict ? val2.get() : 
val1.get(); 
         if (val1.get() instanceof Map) {
             Map<?,?> map1 = (Map<?, ?>) val1.get();
             if (val2.get() instanceof Map) {
                 return mergeMapsImpl(map1, (Map<?, ?>) val2.get(), 
depthRemaining, visited);
             } else {
                 // incompatible types; not merging
-                return val1.get();
+                return conflictResult;
             }
         }
         if (val1.get() instanceof Iterable) {
@@ -133,10 +150,10 @@ public class CollectionMerger {
                 return mergeIterablesImpl(iter1, (Iterable<?>) val2.get(), 
depthRemaining, visited);
             } else {
                 // incompatible types; not merging
-                return val1.get();
+                return conflictResult;
             }
         }
-        return val1.get();
+        return conflictResult;
     }
 
     private Map<?, ?> mergeMapsImpl(Map<?, ?> val1, Map<?, ?> val2, int 
depthRemaining, Visited visited) {
@@ -227,8 +244,8 @@ public class CollectionMerger {
         
         protected boolean isTrivial(Object o) {
             if (o == null)  return true;
-            if (o instanceof Map && ((Map)o).isEmpty()) return true;
-            if (o instanceof Iterable && Iterables.isEmpty(((Iterable)o))) 
return true;
+            if (o instanceof Map && ((Map<?,?>)o).isEmpty()) return true;
+            if (o instanceof Iterable && Iterables.isEmpty(((Iterable<?>)o))) 
return true;
             Class<?> clazz = o.getClass();
             return clazz.isEnum() || clazz.isPrimitive() || 
TRIVIAL_CLASSES.contains(clazz);
         }

Reply via email to