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 361d4cacaf6a9cf7fa90b659a400e1ed56c2dc4f
Author: Alex Heneveld <[email protected]>
AuthorDate: Sat Aug 14 04:38:44 2021 +0100

    more object-reference deserialization tweaks
---
 .../core/resolve/jackson/BeanWithTypeUtils.java    | 27 ++++++++++++---------
 ...BrooklynRegisteredTypeJacksonSerialization.java |  5 ++--
 .../jackson/ObjectReferencingSerialization.java    | 28 ++++++++++++++++++----
 .../util/core/internal/TypeCoercionsTest.java      | 11 ++++++++-
 4 files changed, 52 insertions(+), 19 deletions(-)

diff --git 
a/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/BeanWithTypeUtils.java
 
b/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/BeanWithTypeUtils.java
index 896d493..5cc11ef 100644
--- 
a/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/BeanWithTypeUtils.java
+++ 
b/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/BeanWithTypeUtils.java
@@ -125,7 +125,17 @@ public class BeanWithTypeUtils {
      */
 
     public static <T> T convert(ManagementContext mgmt, Object 
mapOrListToSerializeThenDeserialize, TypeToken<T> type, boolean 
allowRegisteredTypes, BrooklynClassLoadingContext loader, boolean 
allowJavaTypes) throws JsonProcessingException {
-        // try with complex types are saved as objects rather than serialized
+        try {
+            return convertDeeply(mgmt, mapOrListToSerializeThenDeserialize, 
type, allowRegisteredTypes, loader, allowJavaTypes);
+
+        } catch (Exception e) {
+            return convertShallow(mgmt, mapOrListToSerializeThenDeserialize, 
type, allowRegisteredTypes, loader, allowJavaTypes);
+        }
+    }
+
+    @Beta
+    public static <T> T convertShallow(ManagementContext mgmt, Object 
mapOrListToSerializeThenDeserialize, TypeToken<T> type, boolean 
allowRegisteredTypes, BrooklynClassLoadingContext loader, boolean 
allowJavaTypes) throws JsonProcessingException {
+        // try with complex types are saved as objects rather than serialized, 
but won't work if special deserialization is wanted to apply to a map inside a 
complex type
         ObjectMapper mapper = YAMLMapper.builder().build();
         mapper = BeanWithTypeUtils.applyCommonMapperConfig(mapper, mgmt, 
allowRegisteredTypes, loader, allowJavaTypes);
         mapper = new 
ObjectReferencingSerialization().useAndApplytoMapper(mapper);
@@ -135,16 +145,11 @@ public class BeanWithTypeUtils {
     }
 
     @Beta
-    public static <T> T convertExtra(ManagementContext mgmt, Object 
mapOrListToSerializeThenDeserialize, TypeToken<T> type, boolean 
allowRegisteredTypes, BrooklynClassLoadingContext loader, boolean 
allowJavaTypes) throws JsonProcessingException {
-        try {
-            return convert(mgmt, mapOrListToSerializeThenDeserialize, type, 
allowRegisteredTypes, loader, allowJavaTypes);
-
-        } catch (Exception e) {
-            // try full serialization - but won't work if things being written 
cannot be deserialized
-            ObjectMapper m = newMapper(mgmt, allowRegisteredTypes, loader, 
allowJavaTypes);
-            String serialization = 
m.writeValueAsString(mapOrListToSerializeThenDeserialize);
-            return m.readValue(serialization, 
BrooklynJacksonType.asJavaType(m, type));
-        }
+    public static <T> T convertDeeply(ManagementContext mgmt, Object 
mapOrListToSerializeThenDeserialize, TypeToken<T> type, boolean 
allowRegisteredTypes, BrooklynClassLoadingContext loader, boolean 
allowJavaTypes) throws JsonProcessingException {
+        // try full serialization - but won't work if things being written 
cannot be deserialized, eg due to unknown type
+        ObjectMapper m = newMapper(mgmt, allowRegisteredTypes, loader, 
allowJavaTypes);
+        String serialization = 
m.writeValueAsString(mapOrListToSerializeThenDeserialize);
+        return m.readValue(serialization, BrooklynJacksonType.asJavaType(m, 
type));
     }
 
     public static <T> Maybe<T> tryConvertOrAbsentUsingContext(Maybe<Object> 
input, TypeToken<T> type) {
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/BrooklynRegisteredTypeJacksonSerialization.java
 
b/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/BrooklynRegisteredTypeJacksonSerialization.java
index b7dbad4..5351716 100644
--- 
a/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/BrooklynRegisteredTypeJacksonSerialization.java
+++ 
b/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/BrooklynRegisteredTypeJacksonSerialization.java
@@ -228,10 +228,11 @@ public class BrooklynRegisteredTypeJacksonSerialization {
     public static ObjectMapper apply(ObjectMapper mapper, ManagementContext 
mgmt, boolean allowRegisteredTypes, BrooklynClassLoadingContext loader, boolean 
allowPojoJavaTypes) {
         // the type resolver is extended to recognise brooklyn registered type 
names
         // and return a subtype of jackson JavaType
-        mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
-
         mapper.setDefaultTyping(new BrtTypeResolverBuilder(mgmt, 
allowRegisteredTypes, loader, allowPojoJavaTypes));
 
+//        // this is tempting but it breaks places where we rely on type: ... 
to tell us the type
+//        mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
+
         SimpleModule module = new SimpleModule();
         if (allowRegisteredTypes) {
             module.setDeserializers(new RegisteredTypeDeserializers(mgmt));
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/ObjectReferencingSerialization.java
 
b/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/ObjectReferencingSerialization.java
index 28314a3..219e110 100644
--- 
a/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/ObjectReferencingSerialization.java
+++ 
b/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/ObjectReferencingSerialization.java
@@ -37,8 +37,10 @@ import com.fasterxml.jackson.databind.ser.std.StdSerializer;
 import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
 import com.google.common.collect.BiMap;
 import com.google.common.collect.HashBiMap;
+import com.google.common.reflect.TypeToken;
 import java.io.IOException;
 import java.io.StringReader;
+import java.lang.reflect.Type;
 import 
org.apache.brooklyn.core.resolve.jackson.BrooklynJacksonSerializationUtils.ConfigurableBeanDeserializerModifier;
 import org.apache.brooklyn.util.core.flags.TypeCoercions;
 import org.apache.brooklyn.util.text.Identifiers;
@@ -143,13 +145,29 @@ public class ObjectReferencingSerialization {
         @Override
         protected Object deserializeWrapper(JsonParser jp, 
DeserializationContext ctxt, BiFunctionThrowsIoException<JsonParser, 
DeserializationContext, Object> nestedDeserialize) throws IOException {
             String v = jp.getCurrentToken()== JsonToken.VALUE_STRING ? 
jp.getValueAsString() : null;
-            Class<?> expected = ctxt.getContextualType()==null ? null : 
ctxt.getContextualType().getRawClass();
-            if (expected==null) expected = Object.class;
-            if (v!=null && !String.class.equals(expected)) {
+            if (v!=null) {
+                Type expected = _valueType!=null ? _valueType : _valueClass;
+
+                // not sure if we ever need to look at contextual type
+                Type expected2 = ctxt.getContextualType()==null ? null : 
ctxt.getContextualType();
+                if (expected2!=null) {
+                    if (expected==null) {
+                        expected = expected2;
+                    } else {
+                        // we have two expectations
+                        LOG.debug("Object reference deserialization ambiguity, 
expected "+expected+" and "+expected2);
+                    }
+                }
+                if (expected==null) {
+                    expected = Object.class;
+                }
+
                 Object result = backingMap.get(v);
                 if (result!=null) {
-                    if (!expected.isInstance(result)) {
-                        return TypeCoercions.coerce(result, expected);
+                    // Because of how 
UntypedObjectDeserializer.deserializeWithType treats strings
+                    // we cannot trust string being expected (if we could, we 
could exclude backing map lookup!)
+                    if (!String.class.equals(expected)) {
+                        result = TypeCoercions.coerce(result, 
TypeToken.of(expected));
                     }
                     return result;
                 }
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 1a81ae9..3216736 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
@@ -19,6 +19,7 @@
 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;
@@ -425,15 +426,23 @@ public class TypeCoercionsTest {
 
     public static class ClassWithMap {
         Map<String,Object> properties = MutableMap.of();
+        Map<String,List<MyClazz>> propsList = MutableMap.of();
     }
 
     @Test
     public void testObjectInMapCoercion() {
-        ClassWithMap r1 = TypeCoercions.coerce(MutableMap.of("properties", 
MutableMap.of("x", 1)), ClassWithMap.class);
+        ClassWithMap r1 =
+                TypeCoercions.coerce(MutableMap.of("properties", 
MutableMap.of("x", 1)), ClassWithMap.class);
         Assert.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);
+
+        r1 = TypeCoercions.coerce(MutableMap.of(
+                "properties", MutableMap.of("x", new MyClazz()),
+                "propsList", MutableMap.of("y", MutableList.of(new MyClazz()))
+                ), ClassWithMap.class);
+        Asserts.assertInstanceOf(((List)r1.propsList.get("y")).get(0), 
MyClazz.class);
     }
 
 }

Reply via email to