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
The following commit(s) were added to refs/heads/master by this push:
new 0a8f536 better support for deserializing list types
0a8f536 is described below
commit 0a8f5369805a0cc14392ba868f17e826e5edc732
Author: Alex Heneveld <[email protected]>
AuthorDate: Thu Jan 21 22:54:47 2021 +0000
better support for deserializing list types
---
.../resolve/jackson/AsPropertyIfAmbiguous.java | 51 +++++++++++++++++++++-
...BrooklynRegisteredTypeJacksonSerialization.java | 7 ++-
...klynRegisteredTypeJacksonSerializationTest.java | 27 ++++++++++++
.../core/resolve/jackson/MapperTestFixture.java | 9 ++++
4 files changed, 91 insertions(+), 3 deletions(-)
diff --git
a/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/AsPropertyIfAmbiguous.java
b/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/AsPropertyIfAmbiguous.java
index 2cd99b8..26fc860 100644
---
a/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/AsPropertyIfAmbiguous.java
+++
b/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/AsPropertyIfAmbiguous.java
@@ -23,6 +23,7 @@ import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.core.type.WritableTypeId;
+import com.fasterxml.jackson.core.util.JsonParserSequence;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JavaType;
@@ -32,7 +33,9 @@ import com.fasterxml.jackson.databind.jsontype.TypeIdResolver;
import com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer;
import com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeSerializer;
import com.fasterxml.jackson.databind.util.TokenBuffer;
+import java.util.function.Supplier;
import
org.apache.brooklyn.core.resolve.jackson.AsPropertyIfAmbiguous.HasBaseType;
+import org.apache.brooklyn.util.exceptions.Exceptions;
import org.apache.brooklyn.util.javalang.Reflections;
import java.io.IOException;
@@ -131,7 +134,6 @@ public class AsPropertyIfAmbiguous {
return delegate.deserializeTypedFromObject(p, ctxt);
}
}
-
return super.deserializeTypedFromObject(p, ctxt);
}
@@ -141,6 +143,7 @@ public class AsPropertyIfAmbiguous {
}
// deserialize list-like things
+ @Override
protected Object _deserialize(JsonParser p, DeserializationContext
ctxt) throws IOException {
if (p.isExpectedStartArrayToken()) {
// when we suppress types for collections, the deserializer
@@ -150,7 +153,7 @@ public class AsPropertyIfAmbiguous {
JsonDeserializer<Object> deser = _findDeserializer(ctxt,
typeId);
if (p.currentToken() == JsonToken.END_ARRAY) {
- return deser.getNullValue(ctxt);
+ return deser.getEmptyValue(ctxt);
}
return deser.deserialize(p, ctxt);
} else {
@@ -158,5 +161,49 @@ public class AsPropertyIfAmbiguous {
}
}
+ @Override
+ protected Object _deserializeTypedForId(JsonParser p,
DeserializationContext ctxt,
+ TokenBuffer tb) throws
IOException
+ {
+ // first part copied from parent
+
+ String typeId = p.getText();
+ JsonDeserializer<Object> deser = _findDeserializer(ctxt, typeId);
+ if (_typeIdVisible) { // need to merge id back in JSON input?
+ if (tb == null) {
+ tb = new TokenBuffer(p, ctxt);
+ }
+ tb.writeFieldName(p.getCurrentName());
+ tb.writeString(typeId);
+ }
+ if (tb != null) { // need to put back skipped properties?
+ // 02-Jul-2016, tatu: Depending on for JsonParserSequence is
initialized it may
+ // try to access current token; ensure there isn't one
+ p.clearCurrentToken();
+ p = JsonParserSequence.createFlattened(false, tb.asParser(p),
p);
+ }
+ // Must point to the next value; tb had no current, jp pointed to
VALUE_STRING:
+ p.nextToken(); // to skip past String value
+ // deserializer should take care of closing END_OBJECT as well
+
+ boolean wasEndToken = (p.currentToken() == JsonToken.END_OBJECT);
+ try {
+ return deser.deserialize(p, ctxt);
+ } catch (Exception e) {
+ Exceptions.propagateIfFatal(e);
+ if (wasEndToken) {
+ // new -- we allow e.g. `{ type: list-extended }` to mean
it is a list;
+ // however the only way to set values for it in the same
object would be to define a custom deserializer for it;
+ // normal use case is that context implies e.g.
list-extended, then collection deserializer does the right thing when it is
used.
+ // but if we got an empty map somehow, e.g. user supplied,
don't use it.
+ Object candidate = deser.getEmptyValue(ctxt);
+ if (candidate!=null) {
+ return candidate;
+ }
+ }
+ throw e;
+ }
+ }
+
}
}
\ No newline at end of file
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 507f93c..e9724c8 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
@@ -59,7 +59,7 @@ public class BrooklynRegisteredTypeJacksonSerialization {
@Override
public T deserialize(JsonParser p, DeserializationContext ctxt) throws
IOException, JsonProcessingException {
try {
- Object target =
mgmt.getTypeRegistry().createBean(type.getRegisteredType(), null, null);
+ Object target = getEmptyValue(ctxt);
JsonDeserializer<Object> delegate =
ctxt.findContextualValueDeserializer(ctxt.constructType(target.getClass()),
null);
delegate.deserialize(p, ctxt, target);
return (T)target;
@@ -67,6 +67,11 @@ public class BrooklynRegisteredTypeJacksonSerialization {
throw Exceptions.propagate(e);
}
}
+
+ public Object getEmptyValue(DeserializationContext ctxt) throws
JsonMappingException {
+ // empty for us is the underlying definition, not null
+ return mgmt.getTypeRegistry().createBean(type.getRegisteredType(),
null, null);
+ }
}
static class RegisteredTypeDeserializers extends SimpleDeserializers {
diff --git
a/core/src/test/java/org/apache/brooklyn/core/resolve/jackson/BrooklynRegisteredTypeJacksonSerializationTest.java
b/core/src/test/java/org/apache/brooklyn/core/resolve/jackson/BrooklynRegisteredTypeJacksonSerializationTest.java
index 0dc9fd7..af56d66 100644
---
a/core/src/test/java/org/apache/brooklyn/core/resolve/jackson/BrooklynRegisteredTypeJacksonSerializationTest.java
+++
b/core/src/test/java/org/apache/brooklyn/core/resolve/jackson/BrooklynRegisteredTypeJacksonSerializationTest.java
@@ -26,6 +26,7 @@ import
org.apache.brooklyn.core.typereg.BasicTypeImplementationPlan;
import org.apache.brooklyn.core.typereg.JavaClassNameTypePlanTransformer;
import org.apache.brooklyn.core.typereg.RegisteredTypes;
import org.apache.brooklyn.test.Asserts;
+import org.apache.brooklyn.util.collections.MutableList;
import org.testng.Assert;
import org.testng.annotations.Test;
@@ -92,4 +93,30 @@ public class BrooklynRegisteredTypeJacksonSerializationTest
extends BrooklynMgmt
Asserts.assertEquals(((SampleBean)impl).z, "zzz");
}
+ static class ListExtended extends MutableList<String> {
+ }
+
+ @Test
+ public void testExtendedListBeanRegisteredType() throws Exception {
+ RegisteredType rt = RegisteredTypes.bean("list-extended", "1",
+ new BasicTypeImplementationPlan(BeanWithTypeUtils.FORMAT,
+ "type: " + ListExtended.class.getName()
+ ));
+
((BasicBrooklynTypeRegistry)mgmt().getTypeRegistry()).addToLocalUnpersistedTypeRegistry(rt,
false);
+
+ Object impl = mgmt().getTypeRegistry().create(rt, null, null);
+ Asserts.assertInstanceOf(impl, ListExtended.class);
+
+ impl =
mgmt().getTypeRegistry().createBeanFromPlan(BeanWithTypePlanTransformer.FORMAT,
+ "type: list-extended"
+ , null, null);
+ Assert.assertTrue( ((ListExtended)impl).isEmpty() );
+
+ Object impl2 = deser("[]", rt);
+ Assert.assertTrue( ((ListExtended)impl2).isEmpty() );
+
+ Object impl3 = deser("[3]", rt);
+ Assert.assertEquals( ((ListExtended)impl3).size(), 1 );
+ }
+
}
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 ecacdfd..c92ef37 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 org.apache.brooklyn.api.typereg.RegisteredType;
import org.apache.brooklyn.util.core.task.BasicExecutionContext;
import org.apache.brooklyn.util.core.task.BasicExecutionManager;
import org.apache.brooklyn.util.core.task.Tasks;
@@ -53,6 +54,14 @@ public interface MapperTestFixture {
}
}
+ default <T> T deser(String v, RegisteredType type) {
+ try {
+ return mapper().readValue(v, BrooklynJacksonType.of(type));
+ } catch (JsonProcessingException e) {
+ throw Exceptions.propagate(e);
+ }
+ }
+
default <T> T deser(String v) {
return (T) deser(v, Object.class);
}