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:56 UTC
[brooklyn-server] 04/06: apply the object-reference serialization
mechanism to conversion
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);
+ }
+
}