This is an automated email from the ASF dual-hosted git repository.
iuliana 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 529983a add support and docs for coercing and resolving WrappedValue
instances
new 71ec87d Merge pull request #1120 from
ahgittin/wrapped-values-resolution
529983a is described below
commit 529983af68fe4bafa82c64478559b1a4bf6d900c
Author: Alex Heneveld <[email protected]>
AuthorDate: Thu Oct 29 12:22:11 2020 +0000
add support and docs for coercing and resolving WrappedValue instances
---
.../core/resolve/jackson/WrappedValue.java | 13 ++++--
.../jackson/WrappedValuesSerialization.java | 18 ---------
.../brooklyn/util/core/flags/TypeCoercions.java | 47 ++++++++++++++++++++++
.../brooklyn/util/core/task/DeferredSupplier.java | 4 +-
.../jackson/WrappedValuesSerializationTest.java | 42 +++++++++++++++++++
5 files changed, 101 insertions(+), 23 deletions(-)
diff --git
a/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/WrappedValue.java
b/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/WrappedValue.java
index a5f22d9..666aa00 100644
---
a/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/WrappedValue.java
+++
b/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/WrappedValue.java
@@ -21,13 +21,20 @@ package org.apache.brooklyn.core.resolve.jackson;
import com.google.common.base.Preconditions;
import java.util.Objects;
import java.util.function.Supplier;
+import org.apache.brooklyn.util.core.task.DeferredSupplier;
/**
* Wraps a value which might be constant or might come from a supplier.
* The pattern where fields are of this type is used to assist with
(de)serialization
* where values might come from a DSL.
+ *
+ * This will be unwrapped using {@link
org.apache.brooklyn.util.core.flags.TypeCoercions}
+ * if it contains a value (unless a WrappedValue is requested), but not if it
uses a supplier.
+ * Any object can be coerced to a {@link WrappedValue} using {@link
org.apache.brooklyn.util.core.flags.TypeCoercions}.
+ *
+ * It will always be unwrapped (attempted) using {@link
org.apache.brooklyn.util.core.task.Tasks#resolving(Object)}.
*/
-public class WrappedValue<T> implements Supplier<T> {
+public class WrappedValue<T> implements Supplier<T>,
com.google.common.base.Supplier<T>, DeferredSupplier<T> {
final static WrappedValue<?> NULL_WRAPPED_VALUE = new WrappedValue<>(null,
false);
final T value;
final Supplier<T> supplier;
@@ -75,14 +82,14 @@ public class WrappedValue<T> implements Supplier<T> {
public static <T> WrappedValue<T> of(Object x) {
if (x instanceof Supplier) return ofSupplier((Supplier<T>)x);
- if (x instanceof com.google.common.base.Supplier) return
ofSupplier((com.google.common.base.Supplier<T>)x);
+ if (x instanceof com.google.common.base.Supplier) return
ofGuavaSupplier((com.google.common.base.Supplier<T>)x);
return new WrappedValue<>(x, false);
}
public static <T> WrappedValue<T> ofConstant(T x) {
return new WrappedValue<>(x, false);
}
public static <T> WrappedValue<T> ofSupplier(Supplier<T> x) { return new
WrappedValue<>(x, true); }
- public static <T> WrappedValue<T>
ofSupplier(com.google.common.base.Supplier<T> x) { return new
WrappedValue<>(new GuavaSupplierAsJavaSupplier<>(
(com.google.common.base.Supplier<T>)x ), true); }
+ public static <T> WrappedValue<T>
ofGuavaSupplier(com.google.common.base.Supplier<T> x) { return new
WrappedValue<>(new GuavaSupplierAsJavaSupplier<>(
(com.google.common.base.Supplier<T>)x ), true); }
public static <T> WrappedValue<T> ofNull() { return
(WrappedValue<T>)NULL_WRAPPED_VALUE; }
public T get() {
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 1d09f25..42a2702 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
@@ -67,10 +67,6 @@ public class WrappedValuesSerialization {
TokenBuffer b = new TokenBuffer(p, ctxt);
b.copyCurrentStructure(p);
try {
-// // could do this first for primitives, but no need
as the object serializer below will do the same
-// TreeNode v =
b.asParserOnFirstToken().readValueAsTree();
-// if (v instanceof ValueNode) return
((ValueNode)v).asText(); // this makes strings for everything; would need to
do all the subtypes of ValueNode
-
// this should work for primitives, objects, and suppliers
(which will declare type)
// only time it won't is where generics are used to drop
the type declaration during serialization
JavaType genericType = getGenericType(typeDeserializer);
@@ -84,17 +80,6 @@ public class WrappedValuesSerialization {
// fall back to just using object
try {
return
ctxt.findRootValueDeserializer(ctxt.constructType(Object.class)).deserialize(b.asParserOnFirstToken(),
ctxt);
- // above should be sufficient, but if not we could try the
below:
-// Object result
ctxt.findNonContextualValueDeserializer(ctxt.constructType(Object.class)).deserialize(b.asParserOnFirstToken(),
ctxt);
-// try {
-// if (result instanceof Map) {
-// // if we got a map, try reading it as typed
-// return
ctxt.findRootValueDeserializer(ctxt.constructType(Object.class)).deserialize(b.asParserOnFirstToken(),
ctxt);
-// }
-// } catch (Exception e) {
-// exceptions.add(e);
-// }
-// return result;
} catch (Exception e) {
exceptions.add(e);
}
@@ -220,9 +205,6 @@ public class WrappedValuesSerialization {
.registerModule(new SimpleModule()
.addSerializer(WrappedValue.class, new
WrappedValueSerializer())
.addDeserializer(WrappedValue.class, new
WrappedValueDeserializer())
-// .setDeserializerModifier(new
ConfigurableBeanDeserializerModifier()
-//
.addPostConstructFunction(WrappedValuesSerialization::ensureWrappedValuesInitialized)
-// )
);
}
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 536ae66..0049c96 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
@@ -28,6 +28,7 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
import org.apache.brooklyn.api.sensor.Sensor;
import org.apache.brooklyn.core.internal.BrooklynInitialization;
import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
+import org.apache.brooklyn.core.resolve.jackson.WrappedValue;
import org.apache.brooklyn.core.sensor.Sensors;
import org.apache.brooklyn.util.JavaGroovyEquivalents;
import org.apache.brooklyn.util.core.ClassLoaderUtils;
@@ -269,6 +270,16 @@ public class TypeCoercions {
public BrooklynCommonAdaptorTypeCoercions(TypeCoercerExtensible
coercer) { super(coercer); }
+ public CommonAdaptorTypeCoercions registerAllAdapters() {
+ super.registerAllAdapters();
+ registerWrappedValueAdapters();
+
+ //these are deliberately not included here, but added by routines
which need them
+ // registerInstanceForClassnameAdapter
+
+ return this;
+ }
+
@SuppressWarnings("rawtypes")
@Override
public void registerClassForNameAdapters() {
@@ -307,6 +318,42 @@ public class TypeCoercions {
}
});
}
+
+ public void registerWrappedValueAdapters() {
+ registerAdapter("10-unwrap-wrapped-value", new TryCoercer() {
+ @Override
+ public <T> Maybe<T> tryCoerce(Object input,
TypeToken<T> type) {
+ if (!(input instanceof WrappedValue)) {
+ return null;
+ }
+ if
(WrappedValue.class.isAssignableFrom(type.getRawType())) {
+ // don't unwrap if a wrapped value is wanted
(won't come here anyway)
+ return null;
+ }
+ WrappedValue<?> w = (WrappedValue<?>) input;
+ if (w.getSupplier()!=null) {
+ // don't unwrap if it is a supplier
+ return null;
+ }
+ return (Maybe) Maybe.of(((WrappedValue<?>)
input).get());
+ }
+ });
+ registerAdapter("99-wrap-to-wrapped-value", new TryCoercer() {
+ @Override
+ public <T> Maybe<T> tryCoerce(Object input, TypeToken<T> type)
{
+ if (!WrappedValue.class.equals(type.getRawType())) {
+ // only applies if a WrappedValue is wanted
+ return null;
+ }
+ if (input instanceof WrappedValue) {
+ // already wrapped (won't come here anyway, unless
possibly thing _in_ the wrapped value needs generic coercion)
+ return null;
+ }
+ // note, generics on type are not respected
+ return Maybe.of( (T) WrappedValue.ofConstant(input) );
+ }
+ });
+ }
}
public static TypeCoercer asTypeCoercer() {
diff --git
a/core/src/main/java/org/apache/brooklyn/util/core/task/DeferredSupplier.java
b/core/src/main/java/org/apache/brooklyn/util/core/task/DeferredSupplier.java
index 4a19a74..1a617ad 100644
---
a/core/src/main/java/org/apache/brooklyn/util/core/task/DeferredSupplier.java
+++
b/core/src/main/java/org/apache/brooklyn/util/core/task/DeferredSupplier.java
@@ -22,8 +22,8 @@ import com.google.common.base.Supplier;
/**
* A class that supplies objects of a single type. When used as a ConfigKey
value,
- * the evaluation is deferred until getConfig() is called. The returned value
will then
- * be coerced to the correct type.
+ * the evaluation is deferred until getConfig() or {@link
Tasks#resolving(Object)} is called.
+ * The returned value will then be coerced to the correct type.
*
* Subsequent calls to getConfig will result in further calls to
deferredProvider.get(),
* rather than reusing the result. If you want to reuse the result, consider
instead
diff --git
a/core/src/test/java/org/apache/brooklyn/core/resolve/jackson/WrappedValuesSerializationTest.java
b/core/src/test/java/org/apache/brooklyn/core/resolve/jackson/WrappedValuesSerializationTest.java
index 25aec9a..fe1b16b 100644
---
a/core/src/test/java/org/apache/brooklyn/core/resolve/jackson/WrappedValuesSerializationTest.java
+++
b/core/src/test/java/org/apache/brooklyn/core/resolve/jackson/WrappedValuesSerializationTest.java
@@ -22,6 +22,13 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.function.Supplier;
import
org.apache.brooklyn.core.resolve.jackson.WrappedValue.WrappedValuesInitialized;
import org.apache.brooklyn.test.Asserts;
+import org.apache.brooklyn.util.core.flags.TypeCoercions;
+import
org.apache.brooklyn.util.core.flags.TypeCoercions.BrooklynCommonAdaptorTypeCoercions;
+import org.apache.brooklyn.util.core.task.BasicExecutionContext;
+import org.apache.brooklyn.util.core.task.BasicExecutionManager;
+import org.apache.brooklyn.util.core.task.Tasks;
+import org.apache.brooklyn.util.guava.Maybe;
+import org.apache.brooklyn.util.javalang.JavaClassNames;
import org.testng.Assert;
import org.testng.annotations.Test;
@@ -116,4 +123,39 @@ public class WrappedValuesSerializationTest implements
MapperTestFixture {
Assert.assertEquals(b2.x.get().x.get(), "hello");
}
+ @Test
+ public void testWrappedValueCoercion() throws Exception {
+ ObjectWithWrappedValueString a = new ObjectWithWrappedValueString();
+
+ a.x = WrappedValue.of("hello");
+ Assert.assertEquals(TypeCoercions.coerce(a.x, String.class), "hello");
+ Assert.assertEquals(TypeCoercions.coerce(a.x, Object.class), a.x);
+ Assert.assertEquals(TypeCoercions.coerce(a.x, WrappedValue.class),
a.x);
+
+ a.x = WrappedValue.ofSupplier((Supplier) () -> "hello");
+ Asserts.assertNotPresent(TypeCoercions.tryCoerce(a.x, String.class));
+ }
+
+ @Test
+ public void testWrappedValueResolution() throws Exception {
+ ObjectWithWrappedValueString a = new ObjectWithWrappedValueString();
+
+ a.x = WrappedValue.of("hello");
+ Assert.assertEquals(resolve(a.x, String.class).get(), "hello");
+ Assert.assertEquals(resolve(a.x, Object.class).get(), "hello");
+ Assert.assertEquals(resolve(a.x, WrappedValue.class).get().get(),
"hello");
+
+ a.x = WrappedValue.ofSupplier((Supplier) () -> "hello");
+ Asserts.assertEquals(resolve(a.x, String.class).get(), "hello");
+ Asserts.assertEquals(resolve(a.x, Object.class).get(), "hello");
+ Asserts.assertEquals(resolve(a.x, WrappedValue.class).get().get(),
"hello");
+ }
+
+ protected <T> Maybe<T> resolve(Object o, Class<T> type) {
+ BasicExecutionManager execManager = new
BasicExecutionManager("test-context-"+ JavaClassNames.niceClassAndMethod());
+ BasicExecutionContext execContext = new
BasicExecutionContext(execManager);
+
+ return
Tasks.resolving(o).as(type).context(execContext).deep().getMaybe();
+ }
+
}