This is an automated email from the ASF dual-hosted git repository.

heneveld pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/brooklyn-server.git

commit dd89910600c41b65cc17050bcd27a621da02f9ca
Author: Alex Heneveld <[email protected]>
AuthorDate: Thu May 25 15:27:00 2023 +0100

    stricter coercion to maps
    
    previously allows "x" to be the {x: null} map; this has been removed unless 
there is at least one colon, e.g. 'key: value, key2' still allowed
    
    also tidies where we thought 'key = value' would be parsed as a map but it 
wasn't due to test artifacts
---
 .../workflow/steps/variables/TransformMerge.java   |  2 +
 .../util/core/internal/TypeCoercionsTest.java      | 98 +++++++++++++---------
 .../coerce/CommonAdaptorTypeCoercions.java         | 15 +++-
 .../util/javalang/coerce/TypeCoercionsTest.java    | 35 ++------
 4 files changed, 80 insertions(+), 70 deletions(-)

diff --git 
a/core/src/main/java/org/apache/brooklyn/core/workflow/steps/variables/TransformMerge.java
 
b/core/src/main/java/org/apache/brooklyn/core/workflow/steps/variables/TransformMerge.java
index aabc425179..ea15cc6f90 100644
--- 
a/core/src/main/java/org/apache/brooklyn/core/workflow/steps/variables/TransformMerge.java
+++ 
b/core/src/main/java/org/apache/brooklyn/core/workflow/steps/variables/TransformMerge.java
@@ -29,6 +29,7 @@ import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.collections.MutableSet;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.text.QuotedStringTokenizer;
+import org.apache.brooklyn.util.text.Strings;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -104,6 +105,7 @@ public class TransformMerge extends 
WorkflowTransformDefault {
         };
 
         for (Object vi : (Iterable) v) {
+            if (vi instanceof String && Strings.isBlank((String)vi)) continue;
             try {
                 vi = wait ? 
context.resolveWaiting(WorkflowExpressionResolution.WorkflowExpressionStage.STEP_RUNNING,
 vi, TypeToken.of(type)) :
                         
context.resolve(WorkflowExpressionResolution.WorkflowExpressionStage.STEP_RUNNING,
 vi, TypeToken.of(type));
diff --git 
a/core/src/test/java/org/apache/brooklyn/util/core/internal/TypeCoercionsTest.java
 
b/core/src/test/java/org/apache/brooklyn/util/core/internal/TypeCoercionsTest.java
index 32167362c1..38e40ae234 100644
--- 
a/core/src/test/java/org/apache/brooklyn/util/core/internal/TypeCoercionsTest.java
+++ 
b/core/src/test/java/org/apache/brooklyn/util/core/internal/TypeCoercionsTest.java
@@ -20,9 +20,6 @@ package org.apache.brooklyn.util.core.internal;
 
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.util.collections.MutableList;
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertNull;
-import static org.testng.Assert.assertTrue;
 
 import java.math.BigDecimal;
 import java.math.BigInteger;
@@ -41,7 +38,9 @@ import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.collections.MutableSet;
 import org.apache.brooklyn.util.core.ClassLoaderUtils;
 import org.apache.brooklyn.util.core.flags.TypeCoercions;
+import org.apache.brooklyn.util.guava.Maybe;
 import org.apache.brooklyn.util.javalang.coerce.ClassCoercionException;
+import org.apache.brooklyn.util.javalang.coerce.CommonAdaptorTypeCoercions;
 import org.apache.brooklyn.util.text.StringPredicates;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -56,10 +55,25 @@ import com.google.common.reflect.TypeToken;
 
 import groovy.lang.GString;
 
+import static org.testng.Assert.*;
+
 public class TypeCoercionsTest {
 
     private static final Logger log = 
LoggerFactory.getLogger(TypeCoercionsTest.class);
-    
+
+    // largely a duplicate of upstream common coerce/TypeCoercionsTest
+    // but with a few extras; ideally would be reconciled
+
+    private static void assertMapsEqual(Map actual, Map expected) {
+        Assert.assertEquals(actual, expected);
+
+        // workaround for bug in testng assert when values are null
+        // PR https://github.com/testng-team/testng/pull/2914 opened, 
hopefully included in testng 7.9 then this can be removed
+        if (actual instanceof Map && expected instanceof Map) {
+            assertEquals( ((Map)actual).keySet(), ((Map)expected).keySet(), 
"Keys in map differ: "+actual.keySet()+" / "+expected.keySet() );
+        }
+    }
+
     @Test
     public void testCoerceCharSequenceToString() {
         assertEquals(TypeCoercions.coerce(new StringBuilder("abc"), 
String.class), "abc");
@@ -156,7 +170,7 @@ public class TypeCoercionsTest {
         assertEquals(TypeCoercions.coerce(BigInteger.ONE, int.class), 
(Integer)1);
         assertEquals(TypeCoercions.coerce(BigInteger.valueOf(Long.MAX_VALUE), 
Long.class), (Long)Long.MAX_VALUE);
         assertEquals(TypeCoercions.coerce(BigInteger.valueOf(Long.MAX_VALUE), 
long.class), (Long)Long.MAX_VALUE);
-        
+
         assertEquals(TypeCoercions.coerce(BigDecimal.valueOf(0.5), 
Double.class), 0.5d, 0.00001d);
         assertEquals(TypeCoercions.coerce(BigDecimal.valueOf(0.5), 
double.class), 0.5d, 0.00001d);
     }
@@ -195,13 +209,13 @@ public class TypeCoercionsTest {
     @Test
     public void testListToSetCoercion() {
         Set<?> s = TypeCoercions.coerce(ImmutableList.of(1), Set.class);
-        Assert.assertEquals(s, ImmutableSet.of(1));
+        assertEquals(s, ImmutableSet.of(1));
     }
     
     @Test
     public void testSetToListCoercion() {
         List<?> s = TypeCoercions.coerce(ImmutableSet.of(1), List.class);
-        Assert.assertEquals(s, ImmutableList.of(1));
+        assertEquals(s, ImmutableList.of(1));
     }
     
     @Test
@@ -223,41 +237,41 @@ public class TypeCoercionsTest {
     public void testListEntryCoercion() {
         @SuppressWarnings("serial")
         List<?> s = TypeCoercions.coerce(ImmutableList.of("java.lang.Integer", 
"java.lang.Double"), new TypeToken<List<Class<?>>>() { });
-        Assert.assertEquals(s, ImmutableList.of(Integer.class, Double.class));
+        assertEquals(s, ImmutableList.of(Integer.class, Double.class));
     }
     
     @Test
     public void testListEntryToSetCoercion() {
         @SuppressWarnings("serial")
         Set<?> s = TypeCoercions.coerce(ImmutableList.of("java.lang.Integer", 
"java.lang.Double"), new TypeToken<Set<Class<?>>>() { });
-        Assert.assertEquals(s, ImmutableSet.of(Integer.class, Double.class));
+        assertEquals(s, ImmutableSet.of(Integer.class, Double.class));
     }
     
     @Test
     public void testListEntryToCollectionCoercion() {
         @SuppressWarnings("serial")
         Collection<?> s = 
TypeCoercions.coerce(ImmutableList.of("java.lang.Integer", "java.lang.Double"), 
new TypeToken<Collection<Class<?>>>() { });
-        Assert.assertEquals(s, ImmutableList.of(Integer.class, Double.class));
+        assertEquals(s, ImmutableList.of(Integer.class, Double.class));
     }
 
     @Test
     public void testMapValueCoercion() {
         @SuppressWarnings("serial")
         Map<?,?> s = TypeCoercions.coerce(ImmutableMap.of("int", 
"java.lang.Integer", "double", "java.lang.Double"), new TypeToken<Map<String, 
Class<?>>>() { });
-        Assert.assertEquals(s, ImmutableMap.of("int", Integer.class, "double", 
Double.class));
+        assertMapsEqual(s, ImmutableMap.of("int", Integer.class, "double", 
Double.class));
     }
     
     @Test
     public void testMapKeyCoercion() {
         @SuppressWarnings("serial")
         Map<?,?> s = TypeCoercions.coerce(ImmutableMap.of("java.lang.Integer", 
"int", "java.lang.Double", "double"), new TypeToken<Map<Class<?>, String>>() { 
});
-        Assert.assertEquals(s, ImmutableMap.of(Integer.class, "int", 
Double.class, "double"));
+        assertMapsEqual(s, ImmutableMap.of(Integer.class, "int", Double.class, 
"double"));
     }
 
     @Test
     public void testStringToListCoercion() {
         List<?> s = TypeCoercions.coerce("a,b,c", List.class);
-        Assert.assertEquals(s, ImmutableList.of("a", "b", "c"));
+        assertEquals(s, ImmutableList.of("a", "b", "c"));
     }
 
     @Test
@@ -269,97 +283,105 @@ public class TypeCoercionsTest {
     @Test
     public void testJsonStringToMapCoercion() {
         Map<?,?> s = TypeCoercions.coerce("{ \"a\" : \"1\", b : 2 }", 
Map.class);
-        Assert.assertEquals(s, ImmutableMap.of("a", "1", "b", 2));
+        assertMapsEqual(s, ImmutableMap.of("a", "1", "b", 2));
     }
 
     @Test
     public void testJsonStringWithoutQuotesToMapCoercion() {
         Map<?,?> s = TypeCoercions.coerce("{ a : 1 }", Map.class);
-        Assert.assertEquals(s, ImmutableMap.of("a", 1));
+        assertMapsEqual(s, ImmutableMap.of("a", 1));
     }
 
     @Test
     public void testJsonComplexTypesToMapCoercion() {
         Map<?,?> s = TypeCoercions.coerce("{ a : [1, \"2\", '\"3\"'], b: { c: 
d, 'e': \"f\" } }", Map.class);
-        Assert.assertEquals(s, ImmutableMap.of("a", 
ImmutableList.<Object>of(1, "2", "\"3\""), 
+        assertMapsEqual(s, ImmutableMap.of("a", ImmutableList.<Object>of(1, 
"2", "\"3\""),
             "b", ImmutableMap.of("c", "d", "e", "f")));
     }
 
     @Test
     public void testJsonStringWithoutBracesToMapCoercion() {
         Map<?,?> s = TypeCoercions.coerce("a : 1", Map.class);
-        Assert.assertEquals(s, ImmutableMap.of("a", 1));
+        assertMapsEqual(s, ImmutableMap.of("a", 1));
     }
 
     @Test
     public void testJsonStringWithoutBracesWithMultipleToMapCoercion() {
         Map<?,?> s = TypeCoercions.coerce("a : 1, b : 2", Map.class);
-        Assert.assertEquals(s, ImmutableMap.of("a", 1, "b", 2));
+        assertMapsEqual(s, ImmutableMap.of("a", 1, "b", 2));
     }
 
-    @Test
+    @Test(enabled = false) //never actually worked, only seemed to because of 
bug in assertEquals(Map,Map)
     public void testKeyEqualsValueStringToMapCoercion() {
+        if (!CommonAdaptorTypeCoercions.PARSE_MAPS_WITH_EQUALS_SYMBOL) 
Assert.fail("Known to be unsupported");
         Map<?,?> s = TypeCoercions.coerce("a=1,b=2", Map.class);
-        Assert.assertEquals(s, ImmutableMap.of("a", "1", "b", "2"));
+        assertMapsEqual(s, ImmutableMap.of("a", "1", "b", "2"));
     }
 
     @Test
     public void testJsonStringWithoutBracesOrSpaceDisallowedAsMapCoercion() {
-        Map<?,?> s = TypeCoercions.coerce("a:1,b:2", Map.class);
-        Assert.assertEquals(s, ImmutableMap.of("a", "1", "b", "2"));
-        // NB: snakeyaml 1.17 required spaces after the colon, but 1.21 
accepts the above
+        Maybe<Map> s1 = TypeCoercions.tryCoerce("a:1,b:2", Map.class);
+        // NB: snakeyaml 1.17 required spaces after the colon, 1.21 accepts 
the above, but we explicitly disallow it
+        // (mileage may vary if you do something like a:1,b=2)
+        if (s1.isPresent()) Asserts.fail("Shouldn't allow colon without space 
when processing map; instead got: "+s1.get());
+
+        Map<?,?> s = TypeCoercions.coerce("a: 1,b: 2", Map.class);
+        assertMapsEqual(s, ImmutableMap.of("a", 1, "b", 2));
     }
-    
-    @Test
-    public void testEqualsInBracesMapCoercion() {
+
+    @Test(enabled = false) //never actually worked, only seemed to because of 
bug in assertEquals(Map,Map)
+    public void testEqualsInBracesMapCoercionLax() {
+        if (!CommonAdaptorTypeCoercions.PARSE_MAPS_WITH_EQUALS_SYMBOL) 
Assert.fail("Known to be unsupported");
         Map<?,?> s = TypeCoercions.coerce("{ a = 1, b = '2' }", Map.class);
-        Assert.assertEquals(s, ImmutableMap.of("a", 1, "b", "2"));
+        assertMapsEqual(s, ImmutableMap.of("a", 1, "b", "2"));
     }
 
-    @Test
+    @Test(enabled = false) //never actually worked, only seemed to because of 
bug in assertEquals(Map,Map)
     public void testKeyEqualsOrColonValueWithBracesStringToMapCoercion() {
+        if (!CommonAdaptorTypeCoercions.PARSE_MAPS_WITH_EQUALS_SYMBOL) 
Assert.fail("Known to be unsupported");
         Map<?,?> s = TypeCoercions.coerce("{ a=1, b: 2 }", Map.class);
-        Assert.assertEquals(s, ImmutableMap.of("a", "1", "b", 2));
+        assertMapsEqual(s, ImmutableMap.of("a", "1", "b", 2));
     }
 
-    @Test
+    @Test(enabled = false) //never actually worked, only seemed to because of 
bug in assertEquals(Map,Map)
     public void testKeyEqualsOrColonValueWithoutBracesStringToMapCoercion() {
+        if (!CommonAdaptorTypeCoercions.PARSE_MAPS_WITH_EQUALS_SYMBOL) 
Assert.fail("Known to be unsupported");
         Map<?,?> s = TypeCoercions.coerce("a=1, b: 2", Map.class);
-        Assert.assertEquals(s, ImmutableMap.of("a", "1", "b", 2));
+        assertMapsEqual(s, ImmutableMap.of("a", "1", "b", 2));
     }
 
     @SuppressWarnings("serial")
     @Test
     public void testYamlMapsDontGoTooFarWhenWantingListOfString() {
         List<?> s = TypeCoercions.coerce("[ a: 1, b: 2 ]", List.class);
-        Assert.assertEquals(s, ImmutableList.of(MutableMap.of("a", 1), 
MutableMap.of("b", 2)));
+        assertEquals(s, ImmutableList.of(MutableMap.of("a", 1), 
MutableMap.of("b", 2)));
         
         s = TypeCoercions.coerce("[ a: 1, b : 2 ]", new 
TypeToken<List<String>>() {});
-        Assert.assertEquals(s, ImmutableList.of("a: 1", "b : 2"));
+        assertEquals(s, ImmutableList.of("a: 1", "b : 2"));
     }
 
     @Test
     public void testURItoStringCoercion() {
         String s = TypeCoercions.coerce(URI.create("http://localhost:1234/";), 
String.class);
-        Assert.assertEquals(s, "http://localhost:1234/";);
+        assertEquals(s, "http://localhost:1234/";);
     }
 
     @Test
     public void testURLtoStringCoercion() throws MalformedURLException {
         String s = TypeCoercions.coerce(new URL("http://localhost:1234/";), 
String.class);
-        Assert.assertEquals(s, "http://localhost:1234/";);
+        assertEquals(s, "http://localhost:1234/";);
     }
 
     @Test
     public void testAs() {
         Integer x = TypeCoercions.coerce(new WithAs("3"), Integer.class);
-        Assert.assertEquals(x, (Integer)3);
+        assertEquals(x, (Integer)3);
     }
 
     @Test
     public void testFrom() {
         WithFrom x = TypeCoercions.coerce("3", WithFrom.class);
-        Assert.assertEquals(x.value, 3);
+        assertEquals(x.value, 3);
     }
 
     @Test
@@ -433,7 +455,7 @@ public class TypeCoercionsTest {
     public void testObjectInMapCoercion() {
         ClassWithMap r1 =
                 TypeCoercions.coerce(MutableMap.of("properties", 
MutableMap.of("x", 1)), ClassWithMap.class);
-        Assert.assertEquals(r1.properties.get("x"), 1);
+        assertEquals(r1.properties.get("x"), 1);
 
         r1 = TypeCoercions.coerce(MutableMap.of("properties", 
MutableMap.of("x", new MyClazz())), ClassWithMap.class);
         Asserts.assertInstanceOf(r1.properties.get("x"), MyClazz.class);
diff --git 
a/utils/common/src/main/java/org/apache/brooklyn/util/javalang/coerce/CommonAdaptorTypeCoercions.java
 
b/utils/common/src/main/java/org/apache/brooklyn/util/javalang/coerce/CommonAdaptorTypeCoercions.java
index 1a1ed20928..20c8649b40 100644
--- 
a/utils/common/src/main/java/org/apache/brooklyn/util/javalang/coerce/CommonAdaptorTypeCoercions.java
+++ 
b/utils/common/src/main/java/org/apache/brooklyn/util/javalang/coerce/CommonAdaptorTypeCoercions.java
@@ -62,6 +62,11 @@ import com.google.common.reflect.TypeToken;
 
 public class CommonAdaptorTypeCoercions {
 
+    // It might be nice to support key=value syntax when trying to parse 
things as maps.
+    // We have never supported this, but a bug in testng made it look like we 
did.
+    // This flags relevant areas of code and tests
+    public static final boolean PARSE_MAPS_WITH_EQUALS_SYMBOL = false;
+
     @Beta public static final double DELTA_FOR_COERCION = 0.000001;
 
     private final TypeCoercerExtensible coercer;
@@ -473,9 +478,15 @@ public class CommonAdaptorTypeCoercions {
                 };
                 
                 Maybe<Map<?, ?>> r1 = null;
-                
+
+                if (PARSE_MAPS_WITH_EQUALS_SYMBOL) {
+                    // implement it here if we support it. could perhaps 
simply replace with ": " ?
+                    // but ideally want more sophisticated quote processing 
and splitting
+                    throw new IllegalStateException("Parsing maps with equals 
not currently supported");
+                }
+
                 // first try wrapping in braces if needed
-                if (!inputS.trim().startsWith("{")) {
+                if (!inputS.trim().startsWith("{") && (inputS.contains(": "))) 
{
                     r1 = parseYaml.apply("{ "+inputS+" }");
                     if (r1.isPresent()) return (Maybe<T>) r1;
                     // fall back to parsing without braces, e.g. if it's 
multiline
diff --git 
a/utils/common/src/test/java/org/apache/brooklyn/util/javalang/coerce/TypeCoercionsTest.java
 
b/utils/common/src/test/java/org/apache/brooklyn/util/javalang/coerce/TypeCoercionsTest.java
index 8f85bf1e33..0a6ebd5105 100644
--- 
a/utils/common/src/test/java/org/apache/brooklyn/util/javalang/coerce/TypeCoercionsTest.java
+++ 
b/utils/common/src/test/java/org/apache/brooklyn/util/javalang/coerce/TypeCoercionsTest.java
@@ -38,6 +38,7 @@ import java.util.TimeZone;
 
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.util.collections.MutableSet;
+import org.apache.brooklyn.util.guava.Maybe;
 import org.apache.brooklyn.util.text.StringPredicates;
 import org.apache.commons.lang3.builder.EqualsBuilder;
 import org.slf4j.Logger;
@@ -347,6 +348,9 @@ public class TypeCoercionsTest {
     public void testJsonStringToMapCoercion() {
         Map<?,?> s = coerce("{ \"a\" : \"1\", b : 2 }", Map.class);
         Assert.assertEquals(s, ImmutableMap.of("a", "1", "b", 2));
+
+        Maybe<Map> result = coercer.tryCoerce("x", Map.class);
+        if (result.isPresent()) Asserts.fail("Should have failed, instead 
produced map "+result.get());
     }
 
     @Test
@@ -374,36 +378,7 @@ public class TypeCoercionsTest {
         Assert.assertEquals(s, ImmutableMap.of("a", 1, "b", 2));
     }
 
-    @Test
-    public void testKeyEqualsValueStringToMapCoercion() {
-        Map<?,?> s = coerce("a=1,b=2", Map.class);
-        Assert.assertEquals(s, ImmutableMap.of("a", "1", "b", "2"));
-    }
-
-    @Test
-    public void testJsonStringWithoutBracesOrSpaceDisallowedAsMapCoercion() {
-        Map<?,?> s = coerce("a:1,b:2", Map.class);
-        Assert.assertEquals(s, ImmutableMap.of("a", "1", "b", "2"));
-        // NB: snakeyaml 1.17 required spaces after the colon, but 1.21 
accepts the above
-    }
-    
-    @Test
-    public void testEqualsInBracesMapCoercion() {
-        Map<?,?> s = coerce("{ a = 1, b = '2' }", Map.class);
-        Assert.assertEquals(s, ImmutableMap.of("a", 1, "b", "2"));
-    }
-
-    @Test
-    public void testKeyEqualsOrColonValueWithBracesStringToMapCoercion() {
-        Map<?,?> s = coerce("{ a=1, b: 2 }", Map.class);
-        Assert.assertEquals(s, ImmutableMap.of("a", "1", "b", 2));
-    }
-
-    @Test
-    public void testKeyEqualsOrColonValueWithoutBracesStringToMapCoercion() {
-        Map<?,?> s = coerce("a=1, b: 2", Map.class);
-        Assert.assertEquals(s, ImmutableMap.of("a", "1", "b", 2));
-    }
+    // map tests removed, tested in downstream core/internalTypeCoercionsTest
 
     @Test
     public void testURItoStringCoercion() {

Reply via email to