preserve generics info when resolving config keys, more places previously we converted to Class in places, losing generic info for resolution
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/312131c8 Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/312131c8 Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/312131c8 Branch: refs/heads/master Commit: 312131c8b4032d2c78831af825b96a05e36bce6b Parents: 3e57b14 Author: Alex Heneveld <alex.henev...@cloudsoftcorp.com> Authored: Fri Aug 31 11:15:34 2018 +0100 Committer: Alex Heneveld <alex.henev...@cloudsoftcorp.com> Committed: Fri Aug 31 11:15:34 2018 +0100 ---------------------------------------------------------------------- .../brooklyn/api/effector/ParameterType.java | 3 ++ .../brooklyn/camp/brooklyn/spi/dsl/DslTest.java | 27 ++++++---- .../brooklyn/core/config/BasicConfigKey.java | 2 +- .../config/internal/AbstractConfigMapImpl.java | 15 +++--- .../core/effector/BasicParameterType.java | 38 +++++++++++--- .../brooklyn/core/effector/EffectorTasks.java | 2 +- .../brooklyn/core/effector/Effectors.java | 18 +++++-- .../apache/brooklyn/core/entity/Entities.java | 2 +- .../internal/DeferredBrooklynProperties.java | 2 +- .../core/mgmt/internal/EffectorUtils.java | 2 +- .../brooklyn/core/sensor/StaticSensor.java | 3 +- .../brooklyn/enricher/stock/Transformer.java | 2 +- .../apache/brooklyn/util/core/task/Tasks.java | 38 ++++++++++---- .../brooklyn/util/core/task/ValueResolver.java | 53 +++++++++++--------- .../util/core/task/ValueResolverIterator.java | 7 +-- .../core/effector/EffectorMetadataTest.java | 2 +- .../brooklyn/util/core/task/TasksTest.java | 3 +- .../rest/transform/EffectorTransformer.java | 2 +- 18 files changed, 144 insertions(+), 77 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/312131c8/api/src/main/java/org/apache/brooklyn/api/effector/ParameterType.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/brooklyn/api/effector/ParameterType.java b/api/src/main/java/org/apache/brooklyn/api/effector/ParameterType.java index 07e86bd..2f0949a 100644 --- a/api/src/main/java/org/apache/brooklyn/api/effector/ParameterType.java +++ b/api/src/main/java/org/apache/brooklyn/api/effector/ParameterType.java @@ -22,6 +22,8 @@ import java.io.Serializable; import javax.management.MBeanParameterInfo; +import com.google.common.reflect.TypeToken; + /** * Similar to the concepts in the JMX {@link MBeanParameterInfo} class. * @@ -34,6 +36,7 @@ public interface ParameterType<T> extends Serializable { public String getName(); public Class<T> getParameterClass(); + public TypeToken<T> getParameterType(); /** * The canonical name of the parameter class; especially useful if the class http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/312131c8/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslTest.java ---------------------------------------------------------------------- diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslTest.java index 04b6bf1..c3a7154 100644 --- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslTest.java +++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslTest.java @@ -57,6 +57,7 @@ import com.google.common.base.Function; import com.google.common.base.Functions; import com.google.common.base.Supplier; import com.google.common.collect.ImmutableList; +import com.google.common.reflect.TypeToken; import com.google.common.util.concurrent.ListenableScheduledFuture; import com.google.common.util.concurrent.ListeningScheduledExecutorService; import com.google.common.util.concurrent.MoreExecutors; @@ -96,14 +97,14 @@ public class DslTest extends BrooklynAppUnitTestSupport { @Test public void testAttributeWhenReadyEmptyDoesNotBlock() throws Exception { BrooklynDslDeferredSupplier<?> dsl = BrooklynDslCommon.attributeWhenReady(TestApplication.MY_ATTRIBUTE.getName()); - Maybe<?> actualValue = execDslRealRealQuick(dsl, TestApplication.MY_ATTRIBUTE.getType(), app); + Maybe<?> actualValue = execDslRealRealQuick(dsl, TestApplication.MY_ATTRIBUTE.getTypeToken(), app); assertTrue(actualValue.isAbsent()); } @Test public void testAttributeWhenReadyEmptyImmediatelyDoesNotBlock() throws Exception { BrooklynDslDeferredSupplier<?> dsl = BrooklynDslCommon.attributeWhenReady(TestApplication.MY_ATTRIBUTE.getName()); - Maybe<?> actualValue = execDslImmediately(dsl, TestApplication.MY_ATTRIBUTE.getType(), app, true); + Maybe<?> actualValue = execDslImmediately(dsl, TestApplication.MY_ATTRIBUTE.getTypeToken(), app, true); assertTrue(actualValue.isAbsent()); } @@ -211,7 +212,7 @@ public class DslTest extends BrooklynAppUnitTestSupport { BrooklynDslDeferredSupplier<?> attributeDsl = BrooklynDslCommon.attributeWhenReady(TestApplication.MY_ATTRIBUTE.getName()); app.config().set((ConfigKey)configKey, attributeDsl); // ugly cast because val is DSL, resolving to a string BrooklynDslDeferredSupplier<?> configDsl = BrooklynDslCommon.config(configKey.getName()); - Maybe<?> actualValue = execDslImmediately(configDsl, configKey.getType(), app, true); + Maybe<?> actualValue = execDslImmediately(configDsl, configKey.getTypeToken(), app, true); assertTrue(actualValue.isAbsent()); } @@ -338,13 +339,13 @@ public class DslTest extends BrooklynAppUnitTestSupport { private static class DslTestWorker implements Runnable { protected final TestApplication parent; protected final BrooklynDslDeferredSupplier<?> dsl; - protected final Class<?> type; + protected final TypeToken<?> type; protected EntitySpec<? extends TestEntity> childSpec = EntitySpec.create(TestEntity.class); protected int resolverIterations = MANY_RESOLVER_ITERATIONS; protected boolean satisfiedAsynchronously = false; private boolean wrapInTaskForImmediately = true; - public DslTestWorker(TestApplication parent, BrooklynDslDeferredSupplier<?> dsl, Class<?> type) { + public DslTestWorker(TestApplication parent, BrooklynDslDeferredSupplier<?> dsl, TypeToken<?> type) { this.parent = checkNotNull(parent, "parent"); this.dsl = checkNotNull(dsl, "dsl"); this.type = checkNotNull(type, "type"); @@ -409,7 +410,7 @@ public class DslTest extends BrooklynAppUnitTestSupport { private ListenableScheduledFuture<?> future; public AttributeWhenReadyTestWorker(TestApplication parent, AttributeSensor<String> sensor, BrooklynDslDeferredSupplier<?> dsl) { - super(parent, dsl, sensor.getType()); + super(parent, dsl, sensor.getTypeToken()); this.sensor = sensor; } @@ -449,7 +450,7 @@ public class DslTest extends BrooklynAppUnitTestSupport { private static class SelfTestWorker extends DslTestWorker { public SelfTestWorker(TestApplication parent, BrooklynDslDeferredSupplier<?> dsl) { - super(parent, dsl, Entity.class); + super(parent, dsl, TypeToken.of(Entity.class)); } @Override @@ -465,7 +466,7 @@ public class DslTest extends BrooklynAppUnitTestSupport { private static class ParentTestWorker extends DslTestWorker { public ParentTestWorker(TestApplication parent, BrooklynDslDeferredSupplier<?> dsl) { - super(parent, dsl, Entity.class); + super(parent, dsl, TypeToken.of(Entity.class)); } @Override @@ -488,7 +489,7 @@ public class DslTest extends BrooklynAppUnitTestSupport { } public ConfigTestWorker(TestApplication parent, ConfigKey<?> config, Function<? super Entity, ConfigValuePair> valueFunction, BrooklynDslDeferredSupplier<?> dsl) { - super(parent, dsl, config.getType()); + super(parent, dsl, config.getTypeToken()); this.config = config; this.valueFunction = valueFunction; } @@ -536,6 +537,9 @@ public class DslTest extends BrooklynAppUnitTestSupport { } static Maybe<?> execDslImmediately(final BrooklynDslDeferredSupplier<?> dsl, final Class<?> type, final Entity context, boolean execInTask) throws Exception { + return execDslImmediately(dsl, TypeToken.of(type), context, execInTask); + } + static Maybe<?> execDslImmediately(final BrooklynDslDeferredSupplier<?> dsl, final TypeToken<?> type, final Entity context, boolean execInTask) throws Exception { // Exec'ing immediately will call DSL in current thread. It needs to find the context entity, // and does this using BrooklynTaskTags.getTargetOrContextEntity(Tasks.current()). // If we are not in a task executed by the context entity, then this lookup will fail. @@ -560,11 +564,14 @@ public class DslTest extends BrooklynAppUnitTestSupport { } } - static Maybe<?> execDslRealRealQuick(BrooklynDslDeferredSupplier<?> dsl, Class<?> type, Entity context) { + static Maybe<?> execDslRealRealQuick(BrooklynDslDeferredSupplier<?> dsl, TypeToken<?> type, Entity context) { return execDslEventually(dsl, type, context, ValueResolver.REAL_REAL_QUICK_WAIT); } static Maybe<?> execDslEventually(BrooklynDslDeferredSupplier<?> dsl, Class<?> type, Entity context, Duration timeout) { + return execDslEventually(dsl, TypeToken.of(type), context, timeout); + } + static Maybe<?> execDslEventually(BrooklynDslDeferredSupplier<?> dsl, TypeToken<?> type, Entity context, Duration timeout) { return Tasks.resolving(dsl).as(type) .context(context) .description("Computing "+dsl) http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/312131c8/core/src/main/java/org/apache/brooklyn/core/config/BasicConfigKey.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/config/BasicConfigKey.java b/core/src/main/java/org/apache/brooklyn/core/config/BasicConfigKey.java index b2ec95d..28026c9 100644 --- a/core/src/main/java/org/apache/brooklyn/core/config/BasicConfigKey.java +++ b/core/src/main/java/org/apache/brooklyn/core/config/BasicConfigKey.java @@ -444,7 +444,7 @@ public class BasicConfigKey<T> implements ConfigKeySelfExtracting<T>, Serializab if (ValueResolver.supportsDeepResolution(v)) { return Tasks.resolveDeepValue(v, Object.class, exec, "Resolving deep config "+name); } else { - return Tasks.resolveValue(v, getType(), exec, "Resolving config "+name); + return Tasks.resolveValue(v, getTypeToken(), exec, "Resolving config "+name); } } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/312131c8/core/src/main/java/org/apache/brooklyn/core/config/internal/AbstractConfigMapImpl.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/config/internal/AbstractConfigMapImpl.java b/core/src/main/java/org/apache/brooklyn/core/config/internal/AbstractConfigMapImpl.java index 8ee78c8..9e68099 100644 --- a/core/src/main/java/org/apache/brooklyn/core/config/internal/AbstractConfigMapImpl.java +++ b/core/src/main/java/org/apache/brooklyn/core/config/internal/AbstractConfigMapImpl.java @@ -64,6 +64,7 @@ import org.slf4j.LoggerFactory; import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; +import com.google.common.reflect.TypeToken; public abstract class AbstractConfigMapImpl<TContainer extends BrooklynObject> implements ConfigMapWithInheritance<TContainer> { @@ -363,7 +364,7 @@ public abstract class AbstractConfigMapImpl<TContainer extends BrooklynObject> i } @SuppressWarnings("unchecked") - protected <T> T coerceDefaultValue(TContainer container, String name, Object value, Class<T> type) { + protected <T> T coerceDefaultValue(TContainer container, String name, Object value, TypeToken<T> type) { if (type==null || value==null) return (T) value; ExecutionContext exec = getExecutionContext(container); try { @@ -405,7 +406,7 @@ public abstract class AbstractConfigMapImpl<TContainer extends BrooklynObject> i final ConfigKey<T> ownKey = ownKey1; @SuppressWarnings("unchecked") // NB: can't use ""+getContainerImpl() as this can loop in the case of locations looking up ports - final Class<T> type = (Class<T>) moreSpecificOrWarningPreferringFirst(ownKey, queryKey, ""+getContainer().getId()+"["+getContainer().getDisplayName()+"]"); + final TypeToken<T> type = (TypeToken<T>) moreSpecificOrWarningPreferringFirst(ownKey, queryKey, ""+getContainer().getId()+"["+getContainer().getDisplayName()+"]"); // takes type of own key (or query key if own key not available) // takes default of own key if available and has default, else of query key @@ -455,13 +456,13 @@ public abstract class AbstractConfigMapImpl<TContainer extends BrooklynObject> i } } - private static Class<?> moreSpecificOrWarningPreferringFirst(ConfigKey<?> ownKey, ConfigKey<?> queryKey, String context) { + private static TypeToken<?> moreSpecificOrWarningPreferringFirst(ConfigKey<?> ownKey, ConfigKey<?> queryKey, String context) { if (ownKey==null && queryKey==null) return null; - if (queryKey==null) return ownKey.getType(); - if (ownKey==null) return queryKey.getType(); + if (queryKey==null) return ownKey.getTypeToken(); + if (ownKey==null) return queryKey.getTypeToken(); - Class<?> ownType = ownKey.getType(); - Class<?> queryType = queryKey.getType(); + TypeToken<?> ownType = ownKey.getTypeToken(); + TypeToken<?> queryType = queryKey.getTypeToken(); if (queryType.isAssignableFrom(ownType)) { // own type is same or more specific, normal path return ownType; http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/312131c8/core/src/main/java/org/apache/brooklyn/core/effector/BasicParameterType.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/effector/BasicParameterType.java b/core/src/main/java/org/apache/brooklyn/core/effector/BasicParameterType.java index 264459f..1d6f537 100644 --- a/core/src/main/java/org/apache/brooklyn/core/effector/BasicParameterType.java +++ b/core/src/main/java/org/apache/brooklyn/core/effector/BasicParameterType.java @@ -22,15 +22,17 @@ import java.util.Collections; import java.util.Map; import org.apache.brooklyn.api.effector.ParameterType; +import org.apache.brooklyn.util.core.flags.TypeCoercions; import com.google.common.base.MoreObjects; import com.google.common.base.Objects; +import com.google.common.reflect.TypeToken; public class BasicParameterType<T> implements ParameterType<T> { private static final long serialVersionUID = -5521879180483663919L; private String name; - private Class<T> type; + private TypeToken<T> type; private String description; private Boolean hasDefaultValue = null; private T defaultValue = null; @@ -42,24 +44,40 @@ public class BasicParameterType<T> implements ParameterType<T> { @SuppressWarnings("unchecked") public BasicParameterType(Map<?, ?> arguments) { if (arguments.containsKey("name")) name = (String) arguments.get("name"); - if (arguments.containsKey("type")) type = (Class<T>) arguments.get("type"); + if (arguments.containsKey("type")) type = TypeCoercions.coerce(arguments.get("type"), TypeToken.class); if (arguments.containsKey("description")) description = (String) arguments.get("description"); if (arguments.containsKey("defaultValue")) defaultValue = (T) arguments.get("defaultValue"); } public BasicParameterType(String name, Class<T> type) { - this(name, type, null, null, false); + this(name, TypeToken.of(type), null, null, false); } public BasicParameterType(String name, Class<T> type, String description) { - this(name, type, description, null, false); + this(name, TypeToken.of(type), description, null, false); } public BasicParameterType(String name, Class<T> type, String description, T defaultValue) { - this(name, type, description, defaultValue, true); + this(name, TypeToken.of(type), description, defaultValue, true); } public BasicParameterType(String name, Class<T> type, String description, T defaultValue, boolean hasDefaultValue) { + this(name, TypeToken.of(type), description, defaultValue, hasDefaultValue); + } + + public BasicParameterType(String name, TypeToken<T> type) { + this(name, type, null, null, false); + } + + public BasicParameterType(String name, TypeToken<T> type, String description) { + this(name, type, description, null, false); + } + + public BasicParameterType(String name, TypeToken<T> type, String description, T defaultValue) { + this(name, type, description, defaultValue, true); + } + + public BasicParameterType(String name, TypeToken<T> type, String description, T defaultValue, boolean hasDefaultValue) { this.name = name; this.type = type; this.description = description; @@ -74,11 +92,15 @@ public class BasicParameterType<T> implements ParameterType<T> { @Override public String getName() { return name; } + @SuppressWarnings("unchecked") + @Override + public Class<T> getParameterClass() { return (Class<T>) type.getRawType(); } + @Override - public Class<T> getParameterClass() { return type; } + public TypeToken<T> getParameterType() { return type; } @Override - public String getParameterClassName() { return type.getCanonicalName(); } + public String getParameterClassName() { return type.toString(); } @Override public String getDescription() { return description; } @@ -111,7 +133,7 @@ public class BasicParameterType<T> implements ParameterType<T> { return (obj instanceof ParameterType) && Objects.equal(name, ((ParameterType<?>)obj).getName()) && Objects.equal(description, ((ParameterType<?>)obj).getDescription()) && - Objects.equal(type, ((ParameterType<?>)obj).getParameterClass()) && + Objects.equal(type, ((ParameterType<?>)obj).getParameterType()) && Objects.equal(defaultValue, ((ParameterType<?>)obj).getDefaultValue()); } } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/312131c8/core/src/main/java/org/apache/brooklyn/core/effector/EffectorTasks.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/effector/EffectorTasks.java b/core/src/main/java/org/apache/brooklyn/core/effector/EffectorTasks.java index db49227..c2a3c6b 100644 --- a/core/src/main/java/org/apache/brooklyn/core/effector/EffectorTasks.java +++ b/core/src/main/java/org/apache/brooklyn/core/effector/EffectorTasks.java @@ -132,7 +132,7 @@ public class EffectorTasks { } public static <T> ConfigKey<T> asConfigKey(ParameterType<T> t) { - return ConfigKeys.newConfigKey(t.getParameterClass(), t.getName()); + return ConfigKeys.newConfigKey(t.getParameterType(), t.getName()); } public static <T> ParameterTask<T> parameter(ParameterType<T> t) { http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/312131c8/core/src/main/java/org/apache/brooklyn/core/effector/Effectors.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/effector/Effectors.java b/core/src/main/java/org/apache/brooklyn/core/effector/Effectors.java index 653c607..00dd80d 100644 --- a/core/src/main/java/org/apache/brooklyn/core/effector/Effectors.java +++ b/core/src/main/java/org/apache/brooklyn/core/effector/Effectors.java @@ -37,7 +37,6 @@ import org.apache.brooklyn.core.effector.EffectorTasks.EffectorMarkingTaskFactor import org.apache.brooklyn.core.effector.EffectorTasks.EffectorTaskFactory; import org.apache.brooklyn.core.entity.Entities; import org.apache.brooklyn.core.entity.EntityInternal; -import org.apache.brooklyn.util.collections.MutableMap; import org.apache.brooklyn.util.core.config.ConfigBag; import org.apache.brooklyn.util.core.task.Tasks; import org.apache.brooklyn.util.text.Strings; @@ -48,6 +47,7 @@ import com.google.common.base.Objects; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.common.reflect.TypeToken; public class Effectors { @@ -81,6 +81,15 @@ public class Effectors { public <V> EffectorBuilder<T> parameter(Class<V> paramType, String paramName, String paramDescription, V defaultValue) { return parameter(new BasicParameterType<V>(paramName, paramType, paramDescription, defaultValue)); } + public EffectorBuilder<T> parameter(TypeToken<?> paramType, String paramName) { + return parameter(paramType, paramName, null, null); + } + public EffectorBuilder<T> parameter(TypeToken<?> paramType, String paramName, String paramDescription) { + return parameter(paramType, paramName, paramDescription, null); + } + public <V> EffectorBuilder<T> parameter(TypeToken<V> paramType, String paramName, String paramDescription, V defaultValue) { + return parameter(new BasicParameterType<V>(paramName, paramType, paramDescription, defaultValue)); + } public <V> EffectorBuilder<T> parameter(ConfigKey<V> key) { return parameter(asParameterType(key)); } @@ -165,15 +174,14 @@ public class Effectors { throw new UnsupportedOperationException("No implementation registered for effector "+eff+" on "+entity); } - @SuppressWarnings({ "unchecked", "rawtypes" }) public static <V> ParameterType<V> asParameterType(ConfigKey<V> key) { return key.hasDefaultValue() - ? new BasicParameterType<V>(key.getName(), (Class)key.getType(), key.getDescription(), key.getDefaultValue()) - : new BasicParameterType<V>(key.getName(), (Class)key.getType(), key.getDescription()); + ? new BasicParameterType<V>(key.getName(), key.getTypeToken(), key.getDescription(), key.getDefaultValue()) + : new BasicParameterType<V>(key.getName(), key.getTypeToken(), key.getDescription()); } public static <V> ConfigKey<V> asConfigKey(ParameterType<V> paramType) { - return ConfigKeys.newConfigKey(paramType.getParameterClass(), paramType.getName(), paramType.getDescription(), paramType.getDefaultValue()); + return ConfigKeys.newConfigKey(paramType.getParameterType(), paramType.getName(), paramType.getDescription(), paramType.getDefaultValue()); } /** convenience for {@link #invocationParallel(Effector, Map, Iterable)} */ http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/312131c8/core/src/main/java/org/apache/brooklyn/core/entity/Entities.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/Entities.java b/core/src/main/java/org/apache/brooklyn/core/entity/Entities.java index 2e38a34..f794793 100644 --- a/core/src/main/java/org/apache/brooklyn/core/entity/Entities.java +++ b/core/src/main/java/org/apache/brooklyn/core/entity/Entities.java @@ -1013,7 +1013,7 @@ public class Entities { @Override public T get() { try { TypeToken<T> type = new TypeToken<T>(sensor.getType()) {}; - return Tasks.resolveValue(task, (Class<T>) type.getRawType(), ((EntityInternal) entity).getExecutionContext(), "attributeSupplierWhenReady"); + return Tasks.resolveValue(task, type, ((EntityInternal) entity).getExecutionContext(), "attributeSupplierWhenReady"); } catch (Exception e) { throw Exceptions.propagate(e); } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/312131c8/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/DeferredBrooklynProperties.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/DeferredBrooklynProperties.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/DeferredBrooklynProperties.java index c57e37e..b391bb2 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/DeferredBrooklynProperties.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/DeferredBrooklynProperties.java @@ -91,7 +91,7 @@ public class DeferredBrooklynProperties implements BrooklynProperties { if (transformed instanceof DeferredSupplier) { ExecutionContext exec = mgmt.getServerExecutionContext(); try { - result = Tasks.resolveValue(transformed, key.getType(), exec); + result = Tasks.resolveValue(transformed, key.getTypeToken(), exec); } catch (ExecutionException | InterruptedException e) { throw Exceptions.propagate(e); } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/312131c8/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EffectorUtils.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EffectorUtils.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EffectorUtils.java index 245c1c5..45e9871 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EffectorUtils.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EffectorUtils.java @@ -164,7 +164,7 @@ public class EffectorUtils { throw new IllegalArgumentException("Invalid arguments (missing argument "+it+") for effector "+eff+": "+Sanitizer.sanitize(m)); } - newArgs.add(TypeCoercions.coerce(v, it.getParameterClass())); + newArgs.add(TypeCoercions.coerce(v, it.getParameterType())); newArgsNeeded--; } if (newArgsNeeded>0) http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/312131c8/core/src/main/java/org/apache/brooklyn/core/sensor/StaticSensor.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/sensor/StaticSensor.java b/core/src/main/java/org/apache/brooklyn/core/sensor/StaticSensor.java index 6a609fa..4c10f41 100644 --- a/core/src/main/java/org/apache/brooklyn/core/sensor/StaticSensor.java +++ b/core/src/main/java/org/apache/brooklyn/core/sensor/StaticSensor.java @@ -63,7 +63,6 @@ public class StaticSensor<T> extends AddSensor<T> { timeout = params.get(TIMEOUT); } - @SuppressWarnings("unchecked") @Override public void apply(final EntityLocal entity) { super.apply(entity); @@ -71,7 +70,7 @@ public class StaticSensor<T> extends AddSensor<T> { class ResolveValue implements Callable<Maybe<T>> { @Override public Maybe<T> call() throws Exception { - return Tasks.resolving(value).as((Class<T>)sensor.getType()).timeout(timeout).getMaybe(); + return Tasks.resolving(value).as(sensor.getTypeToken()).timeout(timeout).getMaybe(); } } final Task<Maybe<T>> resolveValue = Tasks.<Maybe<T>>builder().displayName("resolving " + value).body(new ResolveValue()).build(); http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/312131c8/core/src/main/java/org/apache/brooklyn/enricher/stock/Transformer.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/enricher/stock/Transformer.java b/core/src/main/java/org/apache/brooklyn/enricher/stock/Transformer.java index 6b73159..b41de3d 100644 --- a/core/src/main/java/org/apache/brooklyn/enricher/stock/Transformer.java +++ b/core/src/main/java/org/apache/brooklyn/enricher/stock/Transformer.java @@ -131,7 +131,7 @@ public class Transformer<T,U> extends AbstractTransformer<T,U> { // (or Maybe.absent) without blocking. // Otherwise, the Tasks.resolving will give it its best shot at resolving without // blocking on external events (such as waiting for another entity's sensor). - return (U) Tasks.resolving(rawVal).as(targetSensor.getType()) + return (U) Tasks.resolving(rawVal).as(targetSensor.getTypeToken()) .context(entity) .description("Computing sensor "+targetSensor+" from "+rawVal) .deep(true) http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/312131c8/core/src/main/java/org/apache/brooklyn/util/core/task/Tasks.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/Tasks.java b/core/src/main/java/org/apache/brooklyn/util/core/task/Tasks.java index 8ca3baf..dc42e64 100644 --- a/core/src/main/java/org/apache/brooklyn/util/core/task/Tasks.java +++ b/core/src/main/java/org/apache/brooklyn/util/core/task/Tasks.java @@ -56,6 +56,7 @@ import com.google.common.base.Preconditions; import com.google.common.base.Predicate; import com.google.common.base.Supplier; import com.google.common.collect.Iterables; +import com.google.common.reflect.TypeToken; public class Tasks { @@ -133,35 +134,48 @@ public class Tasks { /** creates a {@link ValueResolver} instance which allows significantly more customization than * the various {@link #resolveValue(Object, Class, ExecutionContext)} methods here */ - public static <T> ValueResolver<T> resolving(Object v, Class<T> type) { + public static <T> ValueResolver<T> resolving(Object v, TypeToken<T> type) { return new ValueResolver<T>(v, type); } + /** @see #resolving(Object, TypeToken) */ + public static <T> ValueResolver<T> resolving(Object v, Class<T> type) { + return new ValueResolver<T>(v, TypeToken.of(type)); + } public static ValueResolver.ResolverBuilderPretype resolving(Object v) { return new ValueResolver.ResolverBuilderPretype(v); } - @SuppressWarnings("unchecked") public static <T> ValueResolver<T> resolving(ConfigBag config, ConfigKey<T> key) { - return new ValueResolver.ResolverBuilderPretype(config.getStringKey(key.getName())).as((Class<T>)key.getType()); + return new ValueResolver.ResolverBuilderPretype(config.getStringKey(key.getName())).as(key.getTypeToken()); } - /** @see #resolveValue(Object, Class, ExecutionContext, String) */ - public static <T> T resolveValue(Object v, Class<T> type, @Nullable ExecutionContext exec) throws ExecutionException, InterruptedException { + /** @see #resolveValue(Object, TypeToken, ExecutionContext, String) */ + public static <T> T resolveValue(Object v, TypeToken<T> type, @Nullable ExecutionContext exec) throws ExecutionException, InterruptedException { return new ValueResolver<T>(v, type).context(exec).get(); } + /** @see #resolveValue(Object, TypeToken) */ + public static <T> T resolveValue(Object v, Class<T> type, @Nullable ExecutionContext exec) throws ExecutionException, InterruptedException { + return resolveValue(v, TypeToken.of(type), exec); + } /** attempt to resolve the given value as the given type, waiting on futures, submitting if necessary, * and coercing as allowed by TypeCoercions; * contextMessage (optional) will be displayed in status reports while it waits (e.g. the name of the config key being looked up). * if no execution context supplied (null) this method will throw an exception if the object is an unsubmitted task */ - public static <T> T resolveValue(Object v, Class<T> type, @Nullable ExecutionContext exec, String contextMessage) throws ExecutionException, InterruptedException { + public static <T> T resolveValue(Object v, TypeToken<T> type, @Nullable ExecutionContext exec, String contextMessage) throws ExecutionException, InterruptedException { return new ValueResolver<T>(v, type).context(exec).description(contextMessage).get(); } + /** @see #resolveValue(Object, TypeToken, ExecutionContext, String) */ + public static <T> T resolveValue(Object v, Class<T> type, @Nullable ExecutionContext exec, String contextMessage) throws ExecutionException, InterruptedException { + return resolveValue(v, TypeToken.of(type), exec, contextMessage); + } - /** - * @see #resolveDeepValue(Object, Class, ExecutionContext, String) - */ + /** @see #resolveDeepValue(Object, TypeToken, ExecutionContext, String) */ + public static Object resolveDeepValue(Object v, TypeToken<?> type, ExecutionContext exec) throws ExecutionException, InterruptedException { + return resolveDeepValue(v, type, exec, null); + } + /** @see #resolveDeepValue(Object, Class, ExecutionContext, String) */ public static Object resolveDeepValue(Object v, Class<?> type, ExecutionContext exec) throws ExecutionException, InterruptedException { return resolveDeepValue(v, type, exec, null); } @@ -178,9 +192,13 @@ public class Tasks { * {@link #resolveValue(Object, Class, ExecutionContext, String)} which will accept {@link Map} and {@link Collection} * as the required type. */ - public static <T> T resolveDeepValue(Object v, Class<T> type, ExecutionContext exec, String contextMessage) throws ExecutionException, InterruptedException { + public static <T> T resolveDeepValue(Object v, TypeToken<T> type, ExecutionContext exec, String contextMessage) throws ExecutionException, InterruptedException { return new ValueResolver<T>(v, type).context(exec).deep(true).description(contextMessage).get(); } + /** @see #resolveDeepValue(Object, TypeToken, ExecutionContext, String) */ + public static <T> T resolveDeepValue(Object v, Class<T> type, ExecutionContext exec, String contextMessage) throws ExecutionException, InterruptedException { + return resolveDeepValue(v, TypeToken.of(type), exec, contextMessage); + } /** sets extra status details on the current task, if possible (otherwise does nothing). * the extra status is presented in Task.getStatusDetails(true) http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/312131c8/core/src/main/java/org/apache/brooklyn/util/core/task/ValueResolver.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/ValueResolver.java b/core/src/main/java/org/apache/brooklyn/util/core/task/ValueResolver.java index e91693c..f6588f8 100644 --- a/core/src/main/java/org/apache/brooklyn/util/core/task/ValueResolver.java +++ b/core/src/main/java/org/apache/brooklyn/util/core/task/ValueResolver.java @@ -105,7 +105,7 @@ public class ValueResolver<T> implements DeferredSupplier<T>, Iterable<Maybe<Obj private static final Logger log = LoggerFactory.getLogger(ValueResolver.class); final Object value; - final Class<T> type; + final TypeToken<T> typeT; ExecutionContext exec; String description; boolean forceDeep; @@ -127,17 +127,17 @@ public class ValueResolver<T> implements DeferredSupplier<T>, Iterable<Maybe<Obj AtomicBoolean started = new AtomicBoolean(false); boolean expired; - ValueResolver(Object v, Class<T> type) { + ValueResolver(Object v, TypeToken<T> type) { this.value = v; - this.type = type; + this.typeT = type; checkTypeNotNull(); parentOriginalValue = null; parentTimer = null; } - ValueResolver(Object v, Class<T> type, ValueResolver<?> parent) { + ValueResolver(Object v, TypeToken<T> type, ValueResolver<?> parent) { this.value = v; - this.type = type; + this.typeT = type; checkTypeNotNull(); exec = parent.exec; @@ -163,6 +163,9 @@ public class ValueResolver<T> implements DeferredSupplier<T>, Iterable<Maybe<Obj this.v = v; } public <T> ValueResolver<T> as(Class<T> type) { + return as(TypeToken.of(type)); + } + public <T> ValueResolver<T> as(TypeToken<T> type) { return new ValueResolver<T>(v, type); } } @@ -170,13 +173,13 @@ public class ValueResolver<T> implements DeferredSupplier<T>, Iterable<Maybe<Obj /** returns a copy of this resolver which can be queried, even if the original (single-use instance) has already been copied */ @Override public ValueResolver<T> clone() { - return cloneReplacingValueAndType(value, type); + return cloneReplacingValueAndType(value, typeT); } - <S> ValueResolver<S> cloneReplacingValueAndType(Object newValue, Class<S> superType) { + <S> ValueResolver<S> cloneReplacingValueAndType(Object newValue, TypeToken<S> superType) { // superType expected to be either type or Object.class - if (!superType.isAssignableFrom(type)) { - throw new IllegalStateException("superType must be assignable from " + type); + if (!superType.isAssignableFrom(typeT)) { + throw new IllegalStateException("superType must be assignable from " + typeT); } ValueResolver<S> result = new ValueResolver<S>(newValue, superType) .context(exec).description(description) @@ -186,7 +189,7 @@ public class ValueResolver<T> implements DeferredSupplier<T>, Iterable<Maybe<Obj .immediately(immediately) .recursive(recursive); if (returnDefaultOnGet) { - if (!superType.isInstance(defaultValue)) { + if (!superType.getRawType().isInstance(defaultValue)) { throw new IllegalStateException("Existing default value " + defaultValue + " not compatible with new type " + superType); } @SuppressWarnings("unchecked") @@ -303,7 +306,7 @@ public class ValueResolver<T> implements DeferredSupplier<T>, Iterable<Maybe<Obj } protected void checkTypeNotNull() { - if (type==null) + if (typeT==null) throw new NullPointerException("type must be set to resolve, for '"+value+"'"+(description!=null ? ", "+description : "")); } @@ -345,7 +348,7 @@ public class ValueResolver<T> implements DeferredSupplier<T>, Iterable<Maybe<Obj exec = BasicExecutionContext.getCurrentExecutionContext(); } - if (!recursive && type != Object.class) { + if (!recursive && typeT.getRawType() != Object.class) { throw new IllegalStateException("When non-recursive resolver requested the return type must be Object " + "as the immediately resolved value could be a number of (deferred) types."); } @@ -362,7 +365,7 @@ public class ValueResolver<T> implements DeferredSupplier<T>, Iterable<Maybe<Obj //if the expected type is a closure or map and that's what we have, we're done (or if it's null); //but not allowed to return a future or DeferredSupplier as the resolved value - if (v==null || (!forceDeep && type.isInstance(v) && !Future.class.isInstance(v) && !DeferredSupplier.class.isInstance(v) && !TaskFactory.class.isInstance(v))) + if (v==null || (!forceDeep && typeT.getRawType().isInstance(v) && !Future.class.isInstance(v) && !DeferredSupplier.class.isInstance(v) && !TaskFactory.class.isInstance(v))) return Maybe.of((T) v); try { @@ -406,7 +409,7 @@ public class ValueResolver<T> implements DeferredSupplier<T>, Iterable<Maybe<Obj return (result.isPresent()) ? recursive - ? new ValueResolver<T>(result.get(), type, this).getMaybe() + ? new ValueResolver<T>(result.get(), typeT, this).getMaybe() : result : result; } catch (ImmediateSupplier.ImmediateUnsupportedException e) { @@ -512,6 +515,10 @@ public class ValueResolver<T> implements DeferredSupplier<T>, Iterable<Maybe<Obj } else { if (supportsDeepResolution(v)) { + + // FIXME-TT why is this done + if (2>1) throw new IllegalStateException("Deep resolution with type "+typeT); + // restrict deep resolution to the same set of types as calling code; // in particular need to avoid for "interesting iterables" such as PortRange @@ -519,11 +526,11 @@ public class ValueResolver<T> implements DeferredSupplier<T>, Iterable<Maybe<Obj //and if a map or list we look inside Map result = Maps.newLinkedHashMap(); for (Map.Entry<?,?> entry : ((Map<?,?>)v).entrySet()) { - Maybe<?> kk = new ValueResolver(entry.getKey(), type, this) + Maybe<?> kk = new ValueResolver(entry.getKey(), typeT, this) .description( (description!=null ? description+", " : "") + "map key "+entry.getKey() ) .getMaybe(); if (kk.isAbsent()) return (Maybe<T>)kk; - Maybe<?> vv = new ValueResolver(entry.getValue(), type, this) + Maybe<?> vv = new ValueResolver(entry.getValue(), typeT, this) .description( (description!=null ? description+", " : "") + "map value for key "+kk.get() ) .getMaybe(); if (vv.isAbsent()) return (Maybe<T>)vv; @@ -535,7 +542,7 @@ public class ValueResolver<T> implements DeferredSupplier<T>, Iterable<Maybe<Obj Set result = Sets.newLinkedHashSet(); int count = 0; for (Object it : (Set)v) { - Maybe<?> vv = new ValueResolver(it, type, this) + Maybe<?> vv = new ValueResolver(it, typeT, this) .description( (description!=null ? description+", " : "") + "entry "+count ) .getMaybe(); if (vv.isAbsent()) return (Maybe<T>)vv; @@ -548,7 +555,7 @@ public class ValueResolver<T> implements DeferredSupplier<T>, Iterable<Maybe<Obj List result = Lists.newArrayList(); int count = 0; for (Object it : (Iterable)v) { - Maybe<?> vv = new ValueResolver(it, type, this) + Maybe<?> vv = new ValueResolver(it, typeT, this) .description( (description!=null ? description+", " : "") + "entry "+count ) .getMaybe(); if (vv.isAbsent()) return (Maybe<T>)vv; @@ -559,7 +566,7 @@ public class ValueResolver<T> implements DeferredSupplier<T>, Iterable<Maybe<Obj } } - return TypeCoercions.tryCoerce(v, TypeToken.of(type)); + return TypeCoercions.tryCoerce(v, typeT); } } catch (Exception e) { @@ -579,7 +586,7 @@ public class ValueResolver<T> implements DeferredSupplier<T>, Iterable<Maybe<Obj } if (recursive) { - return new ValueResolver(v, type, this).getMaybe(); + return new ValueResolver(v, typeT, this).getMaybe(); } else { return (Maybe<T>) Maybe.of(v); } @@ -598,12 +605,12 @@ public class ValueResolver<T> implements DeferredSupplier<T>, Iterable<Maybe<Obj if (parentOriginalValue!=null) return parentOriginalValue; return value; } - protected Class<T> getType() { - return type; + protected TypeToken<T> getTypeToken() { + return typeT; } @Override public String toString() { - return JavaClassNames.cleanSimpleClassName(this)+"["+JavaClassNames.cleanSimpleClassName(type)+" "+value+"]"; + return JavaClassNames.cleanSimpleClassName(this)+"["+typeT+" "+value+"]"; } } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/312131c8/core/src/main/java/org/apache/brooklyn/util/core/task/ValueResolverIterator.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/ValueResolverIterator.java b/core/src/main/java/org/apache/brooklyn/util/core/task/ValueResolverIterator.java index 0e6fe4d..39c5faf 100644 --- a/core/src/main/java/org/apache/brooklyn/util/core/task/ValueResolverIterator.java +++ b/core/src/main/java/org/apache/brooklyn/util/core/task/ValueResolverIterator.java @@ -27,6 +27,7 @@ import org.apache.brooklyn.util.guava.Maybe; import com.google.common.base.Predicate; import com.google.common.base.Predicates; +import com.google.common.reflect.TypeToken; /** * Resolve one step at a time, returning intermediate results or absent if there's a resolve error. @@ -118,7 +119,7 @@ public class ValueResolverIterator<T> implements Iterator<Maybe<Object>> { } private ValueResolver<Object> createIterativeResolver(Object value) { - return resolver.cloneReplacingValueAndType(value, Object.class) + return resolver.cloneReplacingValueAndType(value, TypeToken.of(Object.class)) .recursive(false); } @@ -179,10 +180,10 @@ public class ValueResolverIterator<T> implements Iterator<Maybe<Object>> { return (Maybe<T>) last; } } - return coerceValue(last, resolver.getType()); + return coerceValue(last, resolver.getTypeToken()); } - private Maybe<T> coerceValue(Maybe<Object> valueMaybe, Class<T> type) { + private Maybe<T> coerceValue(Maybe<Object> valueMaybe, TypeToken<T> type) { if (valueMaybe.isPresent()) { T coercedValue = TypeCoercions.coerce(valueMaybe.get(), type); return Maybe.of(coercedValue); http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/312131c8/core/src/test/java/org/apache/brooklyn/core/effector/EffectorMetadataTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/core/effector/EffectorMetadataTest.java b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorMetadataTest.java index 1f1be85..afc8a1c 100644 --- a/core/src/test/java/org/apache/brooklyn/core/effector/EffectorMetadataTest.java +++ b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorMetadataTest.java @@ -112,7 +112,7 @@ public class EffectorMetadataTest extends BrooklynAppUnitTestSupport { private void assertParameterEqual(ParameterType<?> actual, ParameterType<?> expected) { assertEquals(actual.getName(), expected.getName(), "actual="+actual); assertEquals(actual.getDescription(), expected.getDescription(), "actual="+actual); - assertEquals(actual.getParameterClass(), expected.getParameterClass(), "actual="+actual); + assertEquals(actual.getParameterType(), expected.getParameterType(), "actual="+actual); assertEquals(actual.getParameterClassName(), expected.getParameterClassName(), "actual="+actual); } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/312131c8/core/src/test/java/org/apache/brooklyn/util/core/task/TasksTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/util/core/task/TasksTest.java b/core/src/test/java/org/apache/brooklyn/util/core/task/TasksTest.java index 6b4a795..e36fadd 100644 --- a/core/src/test/java/org/apache/brooklyn/util/core/task/TasksTest.java +++ b/core/src/test/java/org/apache/brooklyn/util/core/task/TasksTest.java @@ -49,6 +49,7 @@ import org.testng.annotations.Test; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import com.google.common.reflect.TypeToken; import com.google.common.util.concurrent.Callables; @@ -113,7 +114,7 @@ public class TasksTest extends BrooklynAppUnitTestSupport { } private void assertResolvesValue(Object actual, Class<?> type, Object expected) throws Exception { - Object result = Tasks.resolveValue(actual, type, executionContext); + Object result = Tasks.resolveValue(actual, TypeToken.of(type), executionContext); assertEquals(result, expected); } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/312131c8/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/EffectorTransformer.java ---------------------------------------------------------------------- diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/EffectorTransformer.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/EffectorTransformer.java index 9569425..b54cfae 100644 --- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/EffectorTransformer.java +++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/EffectorTransformer.java @@ -80,7 +80,7 @@ public class EffectorTransformer { protected static EffectorSummary.ParameterSummary<?> parameterSummary(Entity entity, ParameterType<?> parameterType) { try { Maybe<?> defaultValue = Tasks.resolving(parameterType.getDefaultValue()) - .as(parameterType.getParameterClass()) + .as(parameterType.getParameterType()) .context(entity) .immediately(true) .getMaybe();