You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2021/08/14 01:54:52 UTC

[brooklyn-server] branch master updated (8906243 -> f72e7c2)

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

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


    from 8906243  Merge pull request #1215 from ahgittin/more-deprecation
     new dce8284  minor tidies to launcher/viewer and cleanup, for tests
     new a159211  minor tidies to launcher/viewer and cleanup, for tests
     new bc2583d  serialization and deserialization that puts/gets objects to a backing map and writes references
     new 5dd7b3c  remove exploratory jackson stuff that isn't needed
     new 5b70d1b  apply the object-reference serialization mechanism to conversion
     new f72e7c2  Merge branch 'serializing-with-references'

The 6 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 core/pom.xml                                       |   4 +
 .../core/resolve/jackson/BeanWithTypeUtils.java    |  43 +++++-
 ...BrooklynRegisteredTypeJacksonSerialization.java |  10 ++
 .../jackson/ObjectReferencingSerialization.java    | 161 +++++++++++++++++++++
 .../jackson/WrappedValuesSerialization.java        |  11 +-
 .../brooklyn/util/core/flags/TypeCoercions.java    |   8 +-
 .../BrooklynMiscJacksonSerializationTest.java      |  57 +++++++-
 .../core/resolve/jackson/MapperTestFixture.java    |  18 +++
 .../util/core/internal/TypeCoercionsTest.java      |  15 ++
 .../apache/brooklyn/launcher/BrooklynLauncher.java |   1 +
 .../launcher/blueprints/AbstractBlueprintTest.java |   7 +-
 11 files changed, 318 insertions(+), 17 deletions(-)
 create mode 100644 core/src/main/java/org/apache/brooklyn/core/resolve/jackson/ObjectReferencingSerialization.java

[brooklyn-server] 06/06: Merge branch 'serializing-with-references'

Posted by he...@apache.org.
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 f72e7c2ab33ac1bce81b858d9650bfb0af9d77f5
Merge: dce8284 5b70d1b
Author: Alex Heneveld <al...@cloudsoftcorp.com>
AuthorDate: Sat Aug 14 02:54:41 2021 +0100

    Merge branch 'serializing-with-references'

 core/pom.xml                                       |   4 +
 .../core/resolve/jackson/BeanWithTypeUtils.java    |  43 +++++-
 ...BrooklynRegisteredTypeJacksonSerialization.java |  10 ++
 .../jackson/ObjectReferencingSerialization.java    | 161 +++++++++++++++++++++
 .../jackson/WrappedValuesSerialization.java        |  11 +-
 .../brooklyn/util/core/flags/TypeCoercions.java    |   8 +-
 .../BrooklynMiscJacksonSerializationTest.java      |  57 +++++++-
 .../core/resolve/jackson/MapperTestFixture.java    |  18 +++
 .../util/core/internal/TypeCoercionsTest.java      |  15 ++
 9 files changed, 316 insertions(+), 11 deletions(-)

[brooklyn-server] 04/06: apply the object-reference serialization mechanism to conversion

Posted by he...@apache.org.
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 5b70d1bf5a315cb479031710ac083542e6d233fa
Author: Alex Heneveld <al...@cloudsoftcorp.com>
AuthorDate: Sat Aug 14 02:17:31 2021 +0100

    apply the object-reference serialization mechanism to conversion
    
    fixing the failing test, and some tidy up
---
 .../core/resolve/jackson/BeanWithTypeUtils.java    | 24 ++++++++--
 .../jackson/ObjectReferencingSerialization.java    | 54 ++++++++++++++++++++--
 .../BrooklynMiscJacksonSerializationTest.java      | 36 +++++++++------
 3 files changed, 92 insertions(+), 22 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 cf30094..896d493 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
@@ -27,6 +27,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.SerializationFeature;
 import com.fasterxml.jackson.databind.json.JsonMapper;
 import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
+import com.google.common.annotations.Beta;
 import com.google.common.reflect.TypeToken;
 import java.util.*;
 import java.util.Map.Entry;
@@ -124,9 +125,26 @@ public class BeanWithTypeUtils {
      */
 
     public static <T> T convert(ManagementContext mgmt, Object mapOrListToSerializeThenDeserialize, TypeToken<T> type, boolean allowRegisteredTypes, BrooklynClassLoadingContext loader, boolean allowJavaTypes) throws JsonProcessingException {
-        ObjectMapper m = newMapper(mgmt, allowRegisteredTypes, loader, allowJavaTypes);
-        String serialization = m.writeValueAsString(mapOrListToSerializeThenDeserialize);
-        return m.readValue(serialization, BrooklynJacksonType.asJavaType(m, type));
+        // try with complex types are saved as objects rather than serialized
+        ObjectMapper mapper = YAMLMapper.builder().build();
+        mapper = BeanWithTypeUtils.applyCommonMapperConfig(mapper, mgmt, allowRegisteredTypes, loader, allowJavaTypes);
+        mapper = new ObjectReferencingSerialization().useAndApplytoMapper(mapper);
+
+        String serialization = mapper.writeValueAsString(mapOrListToSerializeThenDeserialize);
+        return mapper.readValue(serialization, BrooklynJacksonType.asJavaType(mapper, type));
+    }
+
+    @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> Maybe<T> tryConvertOrAbsentUsingContext(Maybe<Object> input, TypeToken<T> type) {
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 465380b..28314a3 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
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 package org.apache.brooklyn.core.resolve.jackson;
 
 import com.fasterxml.jackson.core.JsonGenerator;
@@ -16,10 +34,13 @@ import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
 import com.fasterxml.jackson.databind.ser.BeanSerializerFactory;
 import com.fasterxml.jackson.databind.ser.SerializerFactory;
 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 java.io.IOException;
+import java.io.StringReader;
 import org.apache.brooklyn.core.resolve.jackson.BrooklynJacksonSerializationUtils.ConfigurableBeanDeserializerModifier;
+import org.apache.brooklyn.util.core.flags.TypeCoercions;
 import org.apache.brooklyn.util.text.Identifiers;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -31,13 +52,31 @@ public class ObjectReferencingSerialization {
 
     private static final Logger LOG = LoggerFactory.getLogger(ObjectReferencingSerialization.class);
 
-    public ObjectMapper useMapper(ObjectMapper mapper) {
-        BiMap<String,Object> backingMap = HashBiMap.create();
+    final BiMap<String,Object> backingMap = HashBiMap.create();
+    ObjectMapper mapper = null;
+
+    public Object serializeAndDeserialize(Object input) throws IOException {
+        return getMapper().readValue(new StringReader(getMapper().writer().writeValueAsString(input)), Object.class);
+    }
+
+    public BiMap<String, Object> getBackingMap() {
+        return backingMap;
+    }
+
+    public ObjectMapper getMapper() {
+        if (mapper==null) {
+            useAndApplytoMapper(YAMLMapper.builder().build());
+        }
+        return mapper;
+    }
+
+    public ObjectMapper useAndApplytoMapper(ObjectMapper mapper) {
         mapper.setSerializerFactory(ObjectReferencingSerializerFactory.extending(mapper.getSerializerFactory(), new ObjectReferenceSerializer(backingMap)));
         mapper = new ConfigurableBeanDeserializerModifier()
                 .addDeserializerWrapper(
                         d -> new ObjectReferencingJsonDeserializer(d, backingMap)
                 ).apply(mapper);
+        this.mapper = mapper;
         return mapper;
     }
 
@@ -104,9 +143,16 @@ 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;
-            if (v!=null) {
+            Class<?> expected = ctxt.getContextualType()==null ? null : ctxt.getContextualType().getRawClass();
+            if (expected==null) expected = Object.class;
+            if (v!=null && !String.class.equals(expected)) {
                 Object result = backingMap.get(v);
-                if (result!=null) return result;
+                if (result!=null) {
+                    if (!expected.isInstance(result)) {
+                        return TypeCoercions.coerce(result, expected);
+                    }
+                    return result;
+                }
             }
             return nestedDeserialize.apply(jp, ctxt);
         }
diff --git a/core/src/test/java/org/apache/brooklyn/core/resolve/jackson/BrooklynMiscJacksonSerializationTest.java b/core/src/test/java/org/apache/brooklyn/core/resolve/jackson/BrooklynMiscJacksonSerializationTest.java
index 281ad6b..83b7d29 100644
--- a/core/src/test/java/org/apache/brooklyn/core/resolve/jackson/BrooklynMiscJacksonSerializationTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/resolve/jackson/BrooklynMiscJacksonSerializationTest.java
@@ -21,6 +21,7 @@ package org.apache.brooklyn.core.resolve.jackson;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
 import com.google.common.reflect.TypeToken;
+import java.io.IOException;
 import java.util.Map;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.util.collections.MutableMap;
@@ -56,7 +57,7 @@ public class BrooklynMiscJacksonSerializationTest implements MapperTestFixture {
         Asserts.assertEquals(deser("\"1m\"", Duration.class), Duration.minutes(1));
     }
 
-    static class ObjWithoutIdentityInfoAnnotation {
+    static class ObjForSerializingAsReference {
         String foo;
 
         @Override
@@ -69,29 +70,34 @@ public class BrooklynMiscJacksonSerializationTest implements MapperTestFixture {
 
     @Test
     public void testCustomHandlerForReferences() throws Exception {
-        mapper = new ObjectReferencingSerialization().useMapper(
-                BeanWithTypeUtils.applyCommonMapperConfig(
-                    YAMLMapper.builder()
-//                        .handlerInstantiator(new AllBeansIdentityHandler())
-                        .build()
-                , null, false, null, true));
-
-        ObjWithoutIdentityInfoAnnotation f1 = new ObjWithoutIdentityInfoAnnotation(); f1.foo = "1";
-        ObjWithoutIdentityInfoAnnotation f2 = new ObjWithoutIdentityInfoAnnotation(); f2.foo = "2";
+        mapper = YAMLMapper.builder().build();
+        mapper = BeanWithTypeUtils.applyCommonMapperConfig(mapper, null, false, null, true);
+        mapper = new ObjectReferencingSerialization().useAndApplytoMapper(mapper);
+
+        ObjForSerializingAsReference f1 = new ObjForSerializingAsReference(); f1.foo = "1";
+        ObjForSerializingAsReference f2 = new ObjForSerializingAsReference(); f2.foo = "2";
         String out = ser(MutableMap.of("a", f1, "b", f2, "c", f1));
         LOG.info("Result of "+ JavaClassNames.niceClassAndMethod()+": "+out);
 
         Map in = deser(out,
-//                Map.class
-                new TypeToken<Map<String, ObjWithoutIdentityInfoAnnotation>>() {}
+                Map.class
+//                new TypeToken<Map<String, ObjForSerializingAsReference>>() {}
         );
-        ObjWithoutIdentityInfoAnnotation a = (ObjWithoutIdentityInfoAnnotation)in.get("a");
-        ObjWithoutIdentityInfoAnnotation b = (ObjWithoutIdentityInfoAnnotation)in.get("b");
-        ObjWithoutIdentityInfoAnnotation c = (ObjWithoutIdentityInfoAnnotation)in.get("c");
+        ObjForSerializingAsReference a = (ObjForSerializingAsReference)in.get("a");
+        ObjForSerializingAsReference b = (ObjForSerializingAsReference)in.get("b");
+        ObjForSerializingAsReference c = (ObjForSerializingAsReference)in.get("c");
         Asserts.assertTrue(a.foo.equals(c.foo), "expected same foo value for a and c - "+a+" != "+c);
         Asserts.assertTrue(!b.foo.equals(c.foo), "expected different foo value for a and b");
         Asserts.assertTrue(a == c, "expected same instance for a and c - "+a+" != "+c);
         Asserts.assertTrue(a != b, "expected different instance for a and b");
     }
 
+    @Test
+    public void testObjectReferences() throws IOException {
+        ObjForSerializingAsReference f1 = new ObjForSerializingAsReference(); f1.foo = "1";
+        Object f2 = new ObjectReferencingSerialization().serializeAndDeserialize(f1);
+        Asserts.assertEquals(f1, f2);
+        Asserts.assertTrue(f1==f2, "different instances for "+f1+" and "+f2);
+    }
+
 }

[brooklyn-server] 05/06: minor tidies to launcher/viewer and cleanup, for tests

Posted by he...@apache.org.
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 dce828451d8ef9be78f24d8050eb343039a5ddbd
Author: Alex Heneveld <al...@cloudsoftcorp.com>
AuthorDate: Sat Aug 14 01:49:31 2021 +0100

    minor tidies to launcher/viewer and cleanup, for tests
---
 .../main/java/org/apache/brooklyn/launcher/BrooklynLauncher.java   | 1 +
 .../apache/brooklyn/launcher/blueprints/AbstractBlueprintTest.java | 7 +------
 2 files changed, 2 insertions(+), 6 deletions(-)

diff --git a/launcher/src/main/java/org/apache/brooklyn/launcher/BrooklynLauncher.java b/launcher/src/main/java/org/apache/brooklyn/launcher/BrooklynLauncher.java
index 46cee52..8c1bf5b 100644
--- a/launcher/src/main/java/org/apache/brooklyn/launcher/BrooklynLauncher.java
+++ b/launcher/src/main/java/org/apache/brooklyn/launcher/BrooklynLauncher.java
@@ -421,6 +421,7 @@ public class BrooklynLauncher extends BasicLauncher<BrooklynLauncher> {
         if (webServer != null) {
             try {
                 webServer.stop();
+                webServer = null;
             } catch (Exception e) {
                 LOG.warn("Error stopping web-server; continuing with termination", e);
             }
diff --git a/launcher/src/test/java/org/apache/brooklyn/launcher/blueprints/AbstractBlueprintTest.java b/launcher/src/test/java/org/apache/brooklyn/launcher/blueprints/AbstractBlueprintTest.java
index 7d6bcc4..0c57f2d 100644
--- a/launcher/src/test/java/org/apache/brooklyn/launcher/blueprints/AbstractBlueprintTest.java
+++ b/launcher/src/test/java/org/apache/brooklyn/launcher/blueprints/AbstractBlueprintTest.java
@@ -205,12 +205,7 @@ public abstract class AbstractBlueprintTest {
     }
     
     protected void runTest(Reader yaml) throws Exception {
-        final Application app = launcher.launchAppYaml(yaml);
-        
-        assertNoFires(app);
-        
-        Application newApp = rebind();
-        assertNoFires(newApp);
+        runTest(launcher.launchAppYaml(yaml), this::assertNoFires);
     }
     
     protected void assertNoFires(final Entity app) {

[brooklyn-server] 01/06: minor tidies to launcher/viewer and cleanup, for tests

Posted by he...@apache.org.
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 a15921188eeb08845b9ede54fbc4f94eac4372b8
Author: Alex Heneveld <al...@cloudsoftcorp.com>
AuthorDate: Sat Aug 14 01:49:31 2021 +0100

    minor tidies to launcher/viewer and cleanup, for tests
---
 .../main/java/org/apache/brooklyn/launcher/BrooklynLauncher.java   | 1 +
 .../apache/brooklyn/launcher/blueprints/AbstractBlueprintTest.java | 7 +------
 2 files changed, 2 insertions(+), 6 deletions(-)

diff --git a/launcher/src/main/java/org/apache/brooklyn/launcher/BrooklynLauncher.java b/launcher/src/main/java/org/apache/brooklyn/launcher/BrooklynLauncher.java
index 46cee52..8c1bf5b 100644
--- a/launcher/src/main/java/org/apache/brooklyn/launcher/BrooklynLauncher.java
+++ b/launcher/src/main/java/org/apache/brooklyn/launcher/BrooklynLauncher.java
@@ -421,6 +421,7 @@ public class BrooklynLauncher extends BasicLauncher<BrooklynLauncher> {
         if (webServer != null) {
             try {
                 webServer.stop();
+                webServer = null;
             } catch (Exception e) {
                 LOG.warn("Error stopping web-server; continuing with termination", e);
             }
diff --git a/launcher/src/test/java/org/apache/brooklyn/launcher/blueprints/AbstractBlueprintTest.java b/launcher/src/test/java/org/apache/brooklyn/launcher/blueprints/AbstractBlueprintTest.java
index 7d6bcc4..0c57f2d 100644
--- a/launcher/src/test/java/org/apache/brooklyn/launcher/blueprints/AbstractBlueprintTest.java
+++ b/launcher/src/test/java/org/apache/brooklyn/launcher/blueprints/AbstractBlueprintTest.java
@@ -205,12 +205,7 @@ public abstract class AbstractBlueprintTest {
     }
     
     protected void runTest(Reader yaml) throws Exception {
-        final Application app = launcher.launchAppYaml(yaml);
-        
-        assertNoFires(app);
-        
-        Application newApp = rebind();
-        assertNoFires(newApp);
+        runTest(launcher.launchAppYaml(yaml), this::assertNoFires);
     }
     
     protected void assertNoFires(final Entity app) {

[brooklyn-server] 02/06: serialization and deserialization that puts/gets objects to a backing map and writes references

Posted by he...@apache.org.
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 bc2583d402b8ac1e9cde1350904e6a73b0646e23
Author: Alex Heneveld <al...@cloudsoftcorp.com>
AuthorDate: Sat Aug 14 01:50:35 2021 +0100

    serialization and deserialization that puts/gets objects to a backing map and writes references
---
 core/pom.xml                                       |   4 +
 .../core/resolve/jackson/BeanWithTypeUtils.java    |  19 ++-
 ...BrooklynRegisteredTypeJacksonSerialization.java |  10 ++
 .../jackson/ObjectReferencingSerialization.java    | 172 +++++++++++++++++++++
 .../jackson/WrappedValuesSerialization.java        |  11 +-
 .../brooklyn/util/core/flags/TypeCoercions.java    |   8 +-
 .../BrooklynMiscJacksonSerializationTest.java      | 165 +++++++++++++++++++-
 .../core/resolve/jackson/MapperTestFixture.java    |  18 +++
 .../util/core/internal/TypeCoercionsTest.java      |  15 ++
 9 files changed, 414 insertions(+), 8 deletions(-)

diff --git a/core/pom.xml b/core/pom.xml
index cd5a2c5..c03c64f 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -164,6 +164,10 @@
             <artifactId>jackson-databind</artifactId>
         </dependency>
         <dependency>
+            <groupId>com.fasterxml.jackson.dataformat</groupId>
+            <artifactId>jackson-dataformat-yaml</artifactId>
+        </dependency>
+        <dependency>
             <groupId>com.fasterxml.jackson.jaxrs</groupId>
             <artifactId>jackson-jaxrs-json-provider</artifactId>
         </dependency>
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 7c31bf9..cf30094 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
@@ -18,9 +18,15 @@
  */
 package org.apache.brooklyn.core.resolve.jackson;
 
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
 import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationFeature;
 import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
 import com.fasterxml.jackson.databind.json.JsonMapper;
+import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
 import com.google.common.reflect.TypeToken;
 import java.util.*;
 import java.util.Map.Entry;
@@ -50,8 +56,14 @@ public class BeanWithTypeUtils {
 
     /** also see {@link org.apache.brooklyn.util.core.json.BrooklynObjectsJsonMapper#newMapper(ManagementContext)} */
     public static ObjectMapper newMapper(ManagementContext mgmt, boolean allowRegisteredTypes, BrooklynClassLoadingContext loader, boolean allowBasicJavaTypes) {
-        JsonMapper mapper = newSimpleMapper();
+        return applyCommonMapperConfig(newSimpleMapper(), mgmt, allowRegisteredTypes, loader, allowBasicJavaTypes);
+    }
+
+    public static ObjectMapper newYamlMapper(ManagementContext mgmt, boolean allowRegisteredTypes, BrooklynClassLoadingContext loader, boolean allowBasicJavaTypes) {
+        return applyCommonMapperConfig(newSimpleYamlMapper(), mgmt, allowRegisteredTypes, loader, allowBasicJavaTypes);
+    }
 
+    public static ObjectMapper applyCommonMapperConfig(ObjectMapper mapper, ManagementContext mgmt, boolean allowRegisteredTypes, BrooklynClassLoadingContext loader, boolean allowBasicJavaTypes) {
         BrooklynRegisteredTypeJacksonSerialization.apply(mapper, mgmt, allowRegisteredTypes, loader, allowBasicJavaTypes);
         WrappedValuesSerialization.apply(mapper, mgmt);
         mapper = new ConfigurableBeanDeserializerModifier()
@@ -68,6 +80,11 @@ public class BeanWithTypeUtils {
         return JsonMapper.builder().build();
     }
 
+    public static YAMLMapper newSimpleYamlMapper() {
+        // for use with json maps (no special type resolution, even the field "type" is ignored)
+        return YAMLMapper.builder().build();
+    }
+
     public static boolean isPureJson(Object o) {
         return isJsonAndOthers(o, oo -> false);
     }
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 e9724c8..b7dbad4 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
@@ -18,9 +18,12 @@
  */
 package org.apache.brooklyn.core.resolve.jackson;
 
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.annotation.JsonInclude.Include;
 import com.fasterxml.jackson.annotation.JsonTypeInfo;
 import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
 import com.fasterxml.jackson.core.JsonParser;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.*;
@@ -122,6 +125,11 @@ public class BrooklynRegisteredTypeJacksonSerialization {
                     return context.constructType(fromLoader.get());
                 }
             }
+            // TODO - this would be nice to support complex types
+//            if (type is present in a registered type) {
+//                get the bundle of registered type
+//                use that classloader to instantiate the type
+//            }
             if (allowPojoJavaTypes) {
                 return super.typeFromId(context, id);
             }
@@ -220,6 +228,8 @@ 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));
 
         SimpleModule module = new SimpleModule();
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
new file mode 100644
index 0000000..27005c1
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/ObjectReferencingSerialization.java
@@ -0,0 +1,172 @@
+package org.apache.brooklyn.core.resolve.jackson;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.BeanDescription;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JavaType;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.cfg.SerializerFactoryConfig;
+import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
+import com.fasterxml.jackson.databind.ser.BeanSerializerFactory;
+import com.fasterxml.jackson.databind.ser.SerializerFactory;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
+import java.io.IOException;
+import java.util.Map;
+import org.apache.brooklyn.core.resolve.jackson.BrooklynJacksonSerializationUtils.ConfigurableBeanDeserializerModifier;
+import org.apache.brooklyn.util.text.Identifiers;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ObjectReferencingSerialization {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ObjectReferencingSerialization.class);
+
+    public ObjectMapper useMapper(ObjectMapper mapper) {
+        BiMap<String,Object> backingMap = HashBiMap.create();
+        mapper.setSerializerFactory(ObjectReferencingSerializerFactory.extending(mapper.getSerializerFactory(), new ObjectReferenceSerializer(backingMap)));
+        mapper = new ConfigurableBeanDeserializerModifier()
+                .addDeserializerWrapper(
+                        d -> new ObjectReferencingJsonDeserializer(d, backingMap)
+                ).apply(mapper);
+
+//        mapper.registerModule(new SimpleModule()
+//                .addSerializer(Object.class, new ObjectReferenceSerializer(backingMap))
+//                .addDeserializer(Object.class, new ObjectReferenceDeserializer(backingMap))
+//        );
+        return mapper;
+    }
+
+
+    static class ObjectReference {
+        String id;
+        public ObjectReference() {}
+        public ObjectReference(String id) { this.id = id; }
+    }
+
+
+    static class ObjectReferenceSerializer extends StdSerializer<Object> {
+        private final BiMap<String, Object> backingMap;
+
+        public ObjectReferenceSerializer(BiMap<String, Object> backingMap) {
+            super(Object.class);
+            this.backingMap = backingMap;
+        }
+
+        @Override
+        public void serializeWithType(Object value, JsonGenerator gen, SerializerProvider serializers, TypeSerializer typeSer) throws IOException {
+            serialize(value, gen, serializers);
+        }
+
+        @Override
+        public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
+            String id = backingMap.inverse().get(value);
+            if (id==null) {
+                id = Identifiers.makeRandomId(12);
+                backingMap.put(id, value);
+            }
+
+            gen.writeObjectRef(id);
+
+//            serializers.findValueSerializer(Map.class, null).serializeWithType(MutableMap.of("@ref", id), gen, serializers,
+//                    serializers.findTypeSerializer(serializers.constructType(Object.class)));
+        }
+    }
+
+    static class ObjectReferenceDeserializer extends JsonDeserializer<Object> {
+        public ObjectReferenceDeserializer(Map<String, Object> backingMap) {
+        }
+
+        @Override
+        public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
+            return null;
+        }
+    }
+
+    public static class ObjectReferencingSerializerFactory extends BeanSerializerFactory {
+        private final ObjectReferenceSerializer serializer;
+
+        protected ObjectReferencingSerializerFactory(ObjectReferenceSerializer serializer, SerializerFactoryConfig config) {
+            super(config);
+            this.serializer = serializer;
+        }
+
+        public static ObjectReferencingSerializerFactory extending(SerializerFactory factory, ObjectReferenceSerializer serializer) {
+            if (factory == null) return new ObjectReferencingSerializerFactory(serializer, null);
+            if (factory instanceof BeanSerializerFactory) return new ObjectReferencingSerializerFactory(serializer, ((BeanSerializerFactory) factory).getFactoryConfig() );
+            throw new IllegalStateException("Cannot extend "+factory);
+        }
+        @Override
+        public ObjectReferencingSerializerFactory withConfig(SerializerFactoryConfig config) {
+            if (_factoryConfig == config) return this;
+            return new ObjectReferencingSerializerFactory(serializer, config);
+        }
+
+        // --- our special behaviour
+
+        @Override
+        protected JsonSerializer<Object> constructBeanOrAddOnSerializer(SerializerProvider prov, JavaType type, BeanDescription beanDesc, boolean staticTyping) throws JsonMappingException {
+            return serializer;
+        }
+    }
+
+    static class ObjectReferencingJsonDeserializer extends JacksonBetterDelegatingDeserializer {
+        private final BiMap<String, Object> backingMap;
+
+        public ObjectReferencingJsonDeserializer(JsonDeserializer<?> d, BiMap<String, Object> backingMap) {
+            super(d, (d2) -> new ObjectReferencingJsonDeserializer(d2, backingMap));
+            this.backingMap = backingMap;
+        }
+
+        @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;
+            if (v!=null) {
+                Object result = backingMap.get(v);
+                if (result!=null) return result;
+            }
+            return nestedDeserialize.apply(jp, ctxt);
+        }
+    }
+//
+//    public static class ObjectReferencingDeserializerFactory extends BeanDeserializerFactory {
+//        protected ObjectReferencingDeserializerFactory(DeserializerFactoryConfig config) {
+//            super(config);
+//        }
+//
+//        public static ObjectReferencingDeserializerFactory extending(DeserializerFactory factory) {
+//            if (factory == null) return new ObjectReferencingDeserializerFactory(null);
+//            if (factory instanceof ObjectReferencingDeserializerFactory) return (ObjectReferencingDeserializerFactory) factory;
+//            if (factory instanceof BeanDeserializerFactory) return new ObjectReferencingDeserializerFactory( ((BeanDeserializerFactory) factory).getFactoryConfig() );
+//            throw new IllegalStateException("Cannot extend "+factory);
+//        }
+//        @Override
+//        public ObjectReferencingDeserializerFactory withConfig(DeserializerFactoryConfig config) {
+//            if (_factoryConfig == config) return this;
+//            return new ObjectReferencingDeserializerFactory(config);
+//        }
+//
+//        // --- our special behaviour
+//
+//
+//        @Override
+//        protected BeanDeserializerBuilder constructBeanDeserializerBuilder(DeserializationContext ctxt, BeanDescription beanDesc) {
+//            return new BeanDeserializerBuilder(beanDesc, ctxt) {
+//                {
+//                    _objectIdReader = new ObjectIdReader() {
+//
+//                    };
+//                }
+//            };
+//        }
+//    }
+
+}
diff --git a/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/WrappedValuesSerialization.java b/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/WrappedValuesSerialization.java
index 49b42a8..d91ee70 100644
--- a/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/WrappedValuesSerialization.java
+++ b/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/WrappedValuesSerialization.java
@@ -199,16 +199,19 @@ public class WrappedValuesSerialization {
             if (factory.getClass() == BeanSerializerFactory.class) return new NullWrappedValueSuppressingBeanSerializerFactory( ((BeanSerializerFactory) factory).getFactoryConfig() );
             throw new IllegalStateException("Cannot extend "+factory);
         }
+        @Override
+        public SerializerFactory withConfig(SerializerFactoryConfig config) {
+            if (_factoryConfig == config) return this;
+            return new NullWrappedValueSuppressingBeanSerializerFactory(config);
+        }
+
+        // --- our special behaviour
 
         @Override
         protected PropertyBuilder constructPropertyBuilder(SerializationConfig config, BeanDescription beanDesc) {
             return new NullWrappedValueSuppressingPropertyBuilder(config, beanDesc);
         }
 
-        public SerializerFactory withConfig(SerializerFactoryConfig config) {
-            if (_factoryConfig == config) return this;
-            return new NullWrappedValueSuppressingBeanSerializerFactory(config);
-        }
     }
 
     public static <T> T ensureWrappedValuesInitialized(T x) {
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/flags/TypeCoercions.java b/core/src/main/java/org/apache/brooklyn/util/core/flags/TypeCoercions.java
index b708869..f10e676 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/flags/TypeCoercions.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/flags/TypeCoercions.java
@@ -354,13 +354,19 @@ public class TypeCoercions {
         public void registerBeanWithTypeAdapter() {
             // if we want to do bean-with-type coercion ... probably nice to do if it doesn't already match
             registerAdapter("80-bean-with-type", new TryCoercer() {
+
                 @Override
                 public <T> Maybe<T> tryCoerce(Object input, TypeToken<T> type) {
                     if (!(input instanceof Map || input instanceof Collection || Boxing.isPrimitiveOrBoxedObject(input))) {
                         return null;
                     }
                     if (BeanWithTypeUtils.isConversionRecommended(Maybe.of(input), type)) {
-                        return BeanWithTypeUtils.tryConvertOrAbsentUsingContext(Maybe.of(input), type);
+                        try {
+                            Maybe<T> result = BeanWithTypeUtils.tryConvertOrAbsentUsingContext(Maybe.of(input), type);
+                            return result;
+                        } catch (Exception e) {
+                            return Maybe.absent(e);
+                        }
                     }
                     return null;
                 }
diff --git a/core/src/test/java/org/apache/brooklyn/core/resolve/jackson/BrooklynMiscJacksonSerializationTest.java b/core/src/test/java/org/apache/brooklyn/core/resolve/jackson/BrooklynMiscJacksonSerializationTest.java
index a2297c7..1a609b9 100644
--- a/core/src/test/java/org/apache/brooklyn/core/resolve/jackson/BrooklynMiscJacksonSerializationTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/resolve/jackson/BrooklynMiscJacksonSerializationTest.java
@@ -18,16 +18,42 @@
  */
 package org.apache.brooklyn.core.resolve.jackson;
 
+import com.fasterxml.jackson.annotation.JsonIdentityInfo;
+import com.fasterxml.jackson.annotation.ObjectIdGenerator;
+import com.fasterxml.jackson.annotation.ObjectIdGenerator.IdKey;
+import com.fasterxml.jackson.annotation.ObjectIdGenerators.StringIdGenerator;
+import com.fasterxml.jackson.annotation.ObjectIdResolver;
+import com.fasterxml.jackson.databind.DeserializationConfig;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.KeyDeserializer;
 import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationConfig;
+import com.fasterxml.jackson.databind.cfg.HandlerInstantiator;
+import com.fasterxml.jackson.databind.cfg.MapperConfig;
+import com.fasterxml.jackson.databind.introspect.Annotated;
+import com.fasterxml.jackson.databind.json.JsonMapper;
+import com.fasterxml.jackson.databind.jsontype.TypeIdResolver;
+import com.fasterxml.jackson.databind.jsontype.TypeResolverBuilder;
+import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
+import com.google.common.reflect.TypeToken;
+import java.util.Map;
 import org.apache.brooklyn.test.Asserts;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.javalang.JavaClassNames;
 import org.apache.brooklyn.util.time.Duration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.testng.annotations.Test;
 
 public class BrooklynMiscJacksonSerializationTest implements MapperTestFixture {
 
-    public ObjectMapper mapper() {
-        ObjectMapper mapper = BeanWithTypeUtils.newMapper(null, false, null, true);
+    private static final Logger LOG = LoggerFactory.getLogger(BrooklynMiscJacksonSerializationTest.class);
+
+    private ObjectMapper mapper;
 
+    public ObjectMapper mapper() {
+        if (mapper==null) mapper = BeanWithTypeUtils.newMapper(null, false, null, true);
         return mapper;
     }
 
@@ -46,5 +72,140 @@ public class BrooklynMiscJacksonSerializationTest implements MapperTestFixture {
         Asserts.assertEquals(deser("\"1m\"", Duration.class), Duration.minutes(1));
     }
 
+    static class ObjWithoutIdentityInfoAnnotation {
+        String foo;
+
+        @Override
+        public String toString() {
+            return "Obj{" +
+                    "foo='" + foo + '\'' +
+                    "}@"+ System.identityHashCode(this);
+        }
+    }
+
+    public static class AllBeansIdentityHandler extends HandlerInstantiator {
+        @Override
+        public JsonDeserializer<?> deserializerInstance(DeserializationConfig config, Annotated annotated, Class<?> deserClass) {
+            return null;
+        }
+        @Override
+        public KeyDeserializer keyDeserializerInstance(DeserializationConfig config, Annotated annotated, Class<?> keyDeserClass) {
+            return null;
+        }
+        @Override
+        public JsonSerializer<?> serializerInstance(SerializationConfig config, Annotated annotated, Class<?> serClass) {
+            return null;
+        }
+        @Override
+        public TypeResolverBuilder<?> typeResolverBuilderInstance(MapperConfig<?> config, Annotated annotated, Class<?> builderClass) {
+            return null;
+        }
+        @Override
+        public TypeIdResolver typeIdResolverInstance(MapperConfig<?> config, Annotated annotated, Class<?> resolverClass) {
+            return null;
+        }
+
+        @Override
+        public ObjectIdGenerator<?> objectIdGeneratorInstance(MapperConfig<?> config, Annotated annotated, Class<?> implClass) {
+            return new StringIdGenerator();
+        }
+
+        @Override
+        public ObjectIdResolver resolverIdGeneratorInstance(MapperConfig<?> config, Annotated annotated, Class<?> implClass) {
+            return new MapBasedInstanceResolver();
+        }
+    }
+
+    static class MapBasedInstanceResolver implements ObjectIdResolver {
+
+        Map<IdKey,Object> objectsById = MutableMap.of();
+
+        @Override
+        public void bindItem(IdKey id, Object pojo) {
+            objectsById.put(id, pojo);
+        }
+
+        @Override
+        public Object resolveId(IdKey id) {
+            Object result = objectsById.get(id);
+            if (result!=null) return result;
+            // seems to happen for YAMLMapper, it doesn't call bindItem
+            LOG.warn("No object recorded for ID "+id+"; returning null during deserialization");
+            return null;
+        }
+
+        @Override
+        public ObjectIdResolver newForDeserialization(Object context) {
+            return this;
+        }
+
+        @Override
+        public boolean canUseFor(ObjectIdResolver resolverType) {
+            return true;
+        }
+    }
+
+    @JsonIdentityInfo(property="@object_id", generator=StringIdGenerator.class, resolver= MapBasedInstanceResolver.class)
+    static class ObjWithIdentityInfoAnnotation extends ObjWithoutIdentityInfoAnnotation {}
+
+    @Test
+    public void testHowObjectIdAndReferences() throws Exception {
+        mapper =
+                BeanWithTypeUtils.applyCommonMapperConfig(
+                    JsonMapper.builder().build()
+
+                // YAML doesn't seem to call "bindItem" whereas JSON mapper does
+//                    YAMLMapper.builder().
+////                        configure(YAMLGenerator.Feature.USE_NATIVE_OBJECT_ID, true).
+//                        build()
+
+                    , null, false, null, true)
+        ;
+//        mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
+
+        ObjWithIdentityInfoAnnotation f1 = new ObjWithIdentityInfoAnnotation(); f1.foo = "1";
+        ObjWithIdentityInfoAnnotation f2 = new ObjWithIdentityInfoAnnotation(); f2.foo = "2";
+        String out = ser(MutableMap.of("a", f1, "b", f2, "c", f1));
+        LOG.info("Result of "+ JavaClassNames.niceClassAndMethod()+": "+out);
+
+        Map in = deser(out,
+//                Map.class
+                new TypeToken<Map<String, ObjWithIdentityInfoAnnotation>>() {}
+                );
+        ObjWithIdentityInfoAnnotation a = (ObjWithIdentityInfoAnnotation)in.get("a");
+        ObjWithIdentityInfoAnnotation b = (ObjWithIdentityInfoAnnotation)in.get("b");
+        ObjWithIdentityInfoAnnotation c = (ObjWithIdentityInfoAnnotation)in.get("c");
+        Asserts.assertTrue(a.foo.equals(c.foo), "expected same foo value for a and c - "+a+" != "+c);
+        Asserts.assertTrue(!b.foo.equals(c.foo), "expected different foo value for a and b");
+        Asserts.assertTrue(a == c, "expected same instance for a and c - "+a+" != "+c);
+        Asserts.assertTrue(a != b, "expected different instance for a and b");
+    }
+
+    @Test
+    public void testCustomHandlerForReferences() throws Exception {
+        mapper = new ObjectReferencingSerialization().useMapper(
+                BeanWithTypeUtils.applyCommonMapperConfig(
+                    YAMLMapper.builder()
+//                        .handlerInstantiator(new AllBeansIdentityHandler())
+                        .build()
+                , null, false, null, true));
+
+        ObjWithoutIdentityInfoAnnotation f1 = new ObjWithoutIdentityInfoAnnotation(); f1.foo = "1";
+        ObjWithoutIdentityInfoAnnotation f2 = new ObjWithoutIdentityInfoAnnotation(); f2.foo = "2";
+        String out = ser(MutableMap.of("a", f1, "b", f2, "c", f1));
+        LOG.info("Result of "+ JavaClassNames.niceClassAndMethod()+": "+out);
+
+        Map in = deser(out,
+//                Map.class
+                new TypeToken<Map<String, ObjWithoutIdentityInfoAnnotation>>() {}
+        );
+        ObjWithoutIdentityInfoAnnotation a = (ObjWithoutIdentityInfoAnnotation)in.get("a");
+        ObjWithoutIdentityInfoAnnotation b = (ObjWithoutIdentityInfoAnnotation)in.get("b");
+        ObjWithoutIdentityInfoAnnotation c = (ObjWithoutIdentityInfoAnnotation)in.get("c");
+        Asserts.assertTrue(a.foo.equals(c.foo), "expected same foo value for a and c - "+a+" != "+c);
+        Asserts.assertTrue(!b.foo.equals(c.foo), "expected different foo value for a and b");
+        Asserts.assertTrue(a == c, "expected same instance for a and c - "+a+" != "+c);
+        Asserts.assertTrue(a != b, "expected different instance for a and b");
+    }
 
 }
diff --git a/core/src/test/java/org/apache/brooklyn/core/resolve/jackson/MapperTestFixture.java b/core/src/test/java/org/apache/brooklyn/core/resolve/jackson/MapperTestFixture.java
index c92ef37..387ee77 100644
--- a/core/src/test/java/org/apache/brooklyn/core/resolve/jackson/MapperTestFixture.java
+++ b/core/src/test/java/org/apache/brooklyn/core/resolve/jackson/MapperTestFixture.java
@@ -21,6 +21,7 @@ package org.apache.brooklyn.core.resolve.jackson;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.google.common.collect.Iterables;
+import com.google.common.reflect.TypeToken;
 import org.apache.brooklyn.api.typereg.RegisteredType;
 import org.apache.brooklyn.util.core.task.BasicExecutionContext;
 import org.apache.brooklyn.util.core.task.BasicExecutionManager;
@@ -46,6 +47,14 @@ public interface MapperTestFixture {
         }
     }
 
+    default <T> String ser(T v, TypeToken<T> type) {
+        try {
+            return mapper().writerFor(BrooklynJacksonType.asTypeReference(type)).writeValueAsString(v);
+        } catch (JsonProcessingException e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+
     default <T> T deser(String v, Class<T> type) {
         try {
             return mapper().readValue(v, type);
@@ -54,6 +63,15 @@ public interface MapperTestFixture {
         }
     }
 
+
+    default <T> T deser(String v, TypeToken<T> type) {
+        try {
+            return mapper().readValue(v, BrooklynJacksonType.asTypeReference(type));
+        } catch (JsonProcessingException e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+
     default <T> T deser(String v, RegisteredType type) {
         try {
             return mapper().readValue(v, BrooklynJacksonType.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 5e07c1f..1a81ae9 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
@@ -18,6 +18,7 @@
  */
 package org.apache.brooklyn.util.core.internal;
 
+import org.apache.brooklyn.test.Asserts;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNull;
 import static org.testng.Assert.assertTrue;
@@ -421,4 +422,18 @@ public class TypeCoercionsTest {
     
     public static class MyClazz implements MyInterface {
     }
+
+    public static class ClassWithMap {
+        Map<String,Object> properties = MutableMap.of();
+    }
+
+    @Test
+    public void testObjectInMapCoercion() {
+        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);
+    }
+
 }

[brooklyn-server] 03/06: remove exploratory jackson stuff that isn't needed

Posted by he...@apache.org.
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 5dd7b3cc6061d632c8f96acf63225024beffe726
Author: Alex Heneveld <al...@cloudsoftcorp.com>
AuthorDate: Sat Aug 14 02:12:37 2021 +0100

    remove exploratory jackson stuff that isn't needed
---
 .../jackson/ObjectReferencingSerialization.java    |  63 +-----------
 .../BrooklynMiscJacksonSerializationTest.java      | 114 ---------------------
 2 files changed, 3 insertions(+), 174 deletions(-)

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 27005c1..465380b 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
@@ -2,7 +2,6 @@ package org.apache.brooklyn.core.resolve.jackson;
 
 import com.fasterxml.jackson.core.JsonGenerator;
 import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.core.JsonToken;
 import com.fasterxml.jackson.databind.BeanDescription;
 import com.fasterxml.jackson.databind.DeserializationContext;
@@ -20,7 +19,6 @@ import com.fasterxml.jackson.databind.ser.std.StdSerializer;
 import com.google.common.collect.BiMap;
 import com.google.common.collect.HashBiMap;
 import java.io.IOException;
-import java.util.Map;
 import org.apache.brooklyn.core.resolve.jackson.BrooklynJacksonSerializationUtils.ConfigurableBeanDeserializerModifier;
 import org.apache.brooklyn.util.text.Identifiers;
 import org.slf4j.Logger;
@@ -28,6 +26,9 @@ import org.slf4j.LoggerFactory;
 
 public class ObjectReferencingSerialization {
 
+    // some other explorations of approaches, including object id, are in the git history;
+    // but this seemed the best as object id was harder to use for all bean types
+
     private static final Logger LOG = LoggerFactory.getLogger(ObjectReferencingSerialization.class);
 
     public ObjectMapper useMapper(ObjectMapper mapper) {
@@ -37,22 +38,9 @@ public class ObjectReferencingSerialization {
                 .addDeserializerWrapper(
                         d -> new ObjectReferencingJsonDeserializer(d, backingMap)
                 ).apply(mapper);
-
-//        mapper.registerModule(new SimpleModule()
-//                .addSerializer(Object.class, new ObjectReferenceSerializer(backingMap))
-//                .addDeserializer(Object.class, new ObjectReferenceDeserializer(backingMap))
-//        );
         return mapper;
     }
 
-
-    static class ObjectReference {
-        String id;
-        public ObjectReference() {}
-        public ObjectReference(String id) { this.id = id; }
-    }
-
-
     static class ObjectReferenceSerializer extends StdSerializer<Object> {
         private final BiMap<String, Object> backingMap;
 
@@ -75,19 +63,6 @@ public class ObjectReferencingSerialization {
             }
 
             gen.writeObjectRef(id);
-
-//            serializers.findValueSerializer(Map.class, null).serializeWithType(MutableMap.of("@ref", id), gen, serializers,
-//                    serializers.findTypeSerializer(serializers.constructType(Object.class)));
-        }
-    }
-
-    static class ObjectReferenceDeserializer extends JsonDeserializer<Object> {
-        public ObjectReferenceDeserializer(Map<String, Object> backingMap) {
-        }
-
-        @Override
-        public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
-            return null;
         }
     }
 
@@ -136,37 +111,5 @@ public class ObjectReferencingSerialization {
             return nestedDeserialize.apply(jp, ctxt);
         }
     }
-//
-//    public static class ObjectReferencingDeserializerFactory extends BeanDeserializerFactory {
-//        protected ObjectReferencingDeserializerFactory(DeserializerFactoryConfig config) {
-//            super(config);
-//        }
-//
-//        public static ObjectReferencingDeserializerFactory extending(DeserializerFactory factory) {
-//            if (factory == null) return new ObjectReferencingDeserializerFactory(null);
-//            if (factory instanceof ObjectReferencingDeserializerFactory) return (ObjectReferencingDeserializerFactory) factory;
-//            if (factory instanceof BeanDeserializerFactory) return new ObjectReferencingDeserializerFactory( ((BeanDeserializerFactory) factory).getFactoryConfig() );
-//            throw new IllegalStateException("Cannot extend "+factory);
-//        }
-//        @Override
-//        public ObjectReferencingDeserializerFactory withConfig(DeserializerFactoryConfig config) {
-//            if (_factoryConfig == config) return this;
-//            return new ObjectReferencingDeserializerFactory(config);
-//        }
-//
-//        // --- our special behaviour
-//
-//
-//        @Override
-//        protected BeanDeserializerBuilder constructBeanDeserializerBuilder(DeserializationContext ctxt, BeanDescription beanDesc) {
-//            return new BeanDeserializerBuilder(beanDesc, ctxt) {
-//                {
-//                    _objectIdReader = new ObjectIdReader() {
-//
-//                    };
-//                }
-//            };
-//        }
-//    }
 
 }
diff --git a/core/src/test/java/org/apache/brooklyn/core/resolve/jackson/BrooklynMiscJacksonSerializationTest.java b/core/src/test/java/org/apache/brooklyn/core/resolve/jackson/BrooklynMiscJacksonSerializationTest.java
index 1a609b9..281ad6b 100644
--- a/core/src/test/java/org/apache/brooklyn/core/resolve/jackson/BrooklynMiscJacksonSerializationTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/resolve/jackson/BrooklynMiscJacksonSerializationTest.java
@@ -18,23 +18,7 @@
  */
 package org.apache.brooklyn.core.resolve.jackson;
 
-import com.fasterxml.jackson.annotation.JsonIdentityInfo;
-import com.fasterxml.jackson.annotation.ObjectIdGenerator;
-import com.fasterxml.jackson.annotation.ObjectIdGenerator.IdKey;
-import com.fasterxml.jackson.annotation.ObjectIdGenerators.StringIdGenerator;
-import com.fasterxml.jackson.annotation.ObjectIdResolver;
-import com.fasterxml.jackson.databind.DeserializationConfig;
-import com.fasterxml.jackson.databind.JsonDeserializer;
-import com.fasterxml.jackson.databind.JsonSerializer;
-import com.fasterxml.jackson.databind.KeyDeserializer;
 import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.SerializationConfig;
-import com.fasterxml.jackson.databind.cfg.HandlerInstantiator;
-import com.fasterxml.jackson.databind.cfg.MapperConfig;
-import com.fasterxml.jackson.databind.introspect.Annotated;
-import com.fasterxml.jackson.databind.json.JsonMapper;
-import com.fasterxml.jackson.databind.jsontype.TypeIdResolver;
-import com.fasterxml.jackson.databind.jsontype.TypeResolverBuilder;
 import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
 import com.google.common.reflect.TypeToken;
 import java.util.Map;
@@ -83,104 +67,6 @@ public class BrooklynMiscJacksonSerializationTest implements MapperTestFixture {
         }
     }
 
-    public static class AllBeansIdentityHandler extends HandlerInstantiator {
-        @Override
-        public JsonDeserializer<?> deserializerInstance(DeserializationConfig config, Annotated annotated, Class<?> deserClass) {
-            return null;
-        }
-        @Override
-        public KeyDeserializer keyDeserializerInstance(DeserializationConfig config, Annotated annotated, Class<?> keyDeserClass) {
-            return null;
-        }
-        @Override
-        public JsonSerializer<?> serializerInstance(SerializationConfig config, Annotated annotated, Class<?> serClass) {
-            return null;
-        }
-        @Override
-        public TypeResolverBuilder<?> typeResolverBuilderInstance(MapperConfig<?> config, Annotated annotated, Class<?> builderClass) {
-            return null;
-        }
-        @Override
-        public TypeIdResolver typeIdResolverInstance(MapperConfig<?> config, Annotated annotated, Class<?> resolverClass) {
-            return null;
-        }
-
-        @Override
-        public ObjectIdGenerator<?> objectIdGeneratorInstance(MapperConfig<?> config, Annotated annotated, Class<?> implClass) {
-            return new StringIdGenerator();
-        }
-
-        @Override
-        public ObjectIdResolver resolverIdGeneratorInstance(MapperConfig<?> config, Annotated annotated, Class<?> implClass) {
-            return new MapBasedInstanceResolver();
-        }
-    }
-
-    static class MapBasedInstanceResolver implements ObjectIdResolver {
-
-        Map<IdKey,Object> objectsById = MutableMap.of();
-
-        @Override
-        public void bindItem(IdKey id, Object pojo) {
-            objectsById.put(id, pojo);
-        }
-
-        @Override
-        public Object resolveId(IdKey id) {
-            Object result = objectsById.get(id);
-            if (result!=null) return result;
-            // seems to happen for YAMLMapper, it doesn't call bindItem
-            LOG.warn("No object recorded for ID "+id+"; returning null during deserialization");
-            return null;
-        }
-
-        @Override
-        public ObjectIdResolver newForDeserialization(Object context) {
-            return this;
-        }
-
-        @Override
-        public boolean canUseFor(ObjectIdResolver resolverType) {
-            return true;
-        }
-    }
-
-    @JsonIdentityInfo(property="@object_id", generator=StringIdGenerator.class, resolver= MapBasedInstanceResolver.class)
-    static class ObjWithIdentityInfoAnnotation extends ObjWithoutIdentityInfoAnnotation {}
-
-    @Test
-    public void testHowObjectIdAndReferences() throws Exception {
-        mapper =
-                BeanWithTypeUtils.applyCommonMapperConfig(
-                    JsonMapper.builder().build()
-
-                // YAML doesn't seem to call "bindItem" whereas JSON mapper does
-//                    YAMLMapper.builder().
-////                        configure(YAMLGenerator.Feature.USE_NATIVE_OBJECT_ID, true).
-//                        build()
-
-                    , null, false, null, true)
-        ;
-//        mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
-
-        ObjWithIdentityInfoAnnotation f1 = new ObjWithIdentityInfoAnnotation(); f1.foo = "1";
-        ObjWithIdentityInfoAnnotation f2 = new ObjWithIdentityInfoAnnotation(); f2.foo = "2";
-        String out = ser(MutableMap.of("a", f1, "b", f2, "c", f1));
-        LOG.info("Result of "+ JavaClassNames.niceClassAndMethod()+": "+out);
-
-        Map in = deser(out,
-//                Map.class
-                new TypeToken<Map<String, ObjWithIdentityInfoAnnotation>>() {}
-                );
-        ObjWithIdentityInfoAnnotation a = (ObjWithIdentityInfoAnnotation)in.get("a");
-        ObjWithIdentityInfoAnnotation b = (ObjWithIdentityInfoAnnotation)in.get("b");
-        ObjWithIdentityInfoAnnotation c = (ObjWithIdentityInfoAnnotation)in.get("c");
-        Asserts.assertTrue(a.foo.equals(c.foo), "expected same foo value for a and c - "+a+" != "+c);
-        Asserts.assertTrue(!b.foo.equals(c.foo), "expected different foo value for a and b");
-        Asserts.assertTrue(a == c, "expected same instance for a and c - "+a+" != "+c);
-        Asserts.assertTrue(a != b, "expected different instance for a and b");
-    }
-
     @Test
     public void testCustomHandlerForReferences() throws Exception {
         mapper = new ObjectReferencingSerialization().useMapper(