You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by al...@apache.org on 2017/03/10 13:51:16 UTC
[4/5] brooklyn-server git commit: $brooklyn:object - support coercing
args
$brooklyn:object - support coercing args
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/7ddca12d
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/7ddca12d
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/7ddca12d
Branch: refs/heads/master
Commit: 7ddca12d489796bd916b1f8b70586b93dbdaabfa
Parents: acfcb91
Author: Aled Sage <al...@gmail.com>
Authored: Wed Mar 8 22:11:16 2017 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Wed Mar 8 23:45:41 2017 +0000
----------------------------------------------------------------------
.../spi/dsl/methods/BrooklynDslCommon.java | 5 +-
.../brooklyn/camp/brooklyn/ObjectsYamlTest.java | 18 +++++
.../brooklyn/util/core/flags/TypeCoercions.java | 14 ++++
.../brooklyn/util/javalang/Reflections.java | 77 ++++++++++++++++----
.../brooklyn/util/javalang/ReflectionsTest.java | 21 +++++-
5 files changed, 120 insertions(+), 15 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/7ddca12d/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java
index 2bc8878..9fbab0e 100644
--- a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java
+++ b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java
@@ -63,6 +63,7 @@ import org.apache.brooklyn.util.core.task.Tasks;
import org.apache.brooklyn.util.exceptions.Exceptions;
import org.apache.brooklyn.util.guava.Maybe;
import org.apache.brooklyn.util.javalang.Reflections;
+import org.apache.brooklyn.util.javalang.coerce.TypeCoercer;
import org.apache.brooklyn.util.net.Urls;
import org.apache.commons.beanutils.BeanUtils;
import org.slf4j.Logger;
@@ -70,6 +71,7 @@ import org.slf4j.LoggerFactory;
import com.google.common.base.Function;
import com.google.common.base.Objects;
+import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
@@ -697,7 +699,8 @@ public class BrooklynDslCommon {
public static Object create(Class<?> type, String factoryMethodName, List<?> factoryMethodArgs, Map<String,?> fields, Map<String,?> config) {
try {
- Object bean = Reflections.invokeMethodFromArgs(type, factoryMethodName, factoryMethodArgs).get();
+ Optional<TypeCoercer> coercer = Optional.of(TypeCoercions.asTypeCoercer());
+ Object bean = Reflections.invokeMethodFromArgs(type, factoryMethodName, factoryMethodArgs, false, coercer).get();
BeanUtils.populate(bean, fields);
if (config.size() > 0) {
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/7ddca12d/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ObjectsYamlTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ObjectsYamlTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ObjectsYamlTest.java
index 01aa477..ec9937c 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ObjectsYamlTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ObjectsYamlTest.java
@@ -40,6 +40,7 @@ import org.apache.brooklyn.util.collections.MutableSet;
import org.apache.brooklyn.util.core.config.ConfigBag;
import org.apache.brooklyn.util.core.flags.SetFromFlag;
import org.apache.brooklyn.util.core.flags.TypeCoercions;
+import org.apache.brooklyn.util.time.Time;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.Assert;
@@ -397,6 +398,23 @@ public class ObjectsYamlTest extends AbstractYamlTest {
assertEquals(testObject.getNumber(), Integer.valueOf(1));
assertEquals(testObject.getObject(), "myDefaultThird");
}
+
+ @Test
+ public void testBrooklynObjectWithFactoryMethodWithArgCoercion() throws Exception {
+ Entity testEntity = setupAndCheckTestEntityInBasicYamlWith(
+ " brooklyn.config:",
+ " test.confObject:",
+ " $brooklyn:object:",
+ " type: " + Time.class.getName(),
+ " factoryMethod.name: makeDateString",
+ " factoryMethod.args:",
+ " - 1000",
+ " - yyyy-MM-dd'T'HH:mm:ss",
+ " - UTC");
+
+ String val = (String) testEntity.getConfig(TestEntity.CONF_OBJECT);
+ assertEquals(val, "1970-01-01T00:00:01");
+ }
@Test
public void testFieldsAsDeferredSuppliers() throws Exception {
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/7ddca12d/core/src/main/java/org/apache/brooklyn/util/core/flags/TypeCoercions.java
----------------------------------------------------------------------
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 923a082..29d8d4b 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
@@ -254,4 +254,18 @@ public class TypeCoercions {
}
}
+
+ public static TypeCoercer asTypeCoercer() {
+ return new TypeCoercer() {
+ @Override public <T> T coerce(Object input, Class<T> type) {
+ return TypeCoercions.coerce(input, type);
+ }
+ @Override public <T> Maybe<T> tryCoerce(Object input, Class<T> type) {
+ return TypeCoercions.tryCoerce(input, type);
+ }
+ @Override public <T> Maybe<T> tryCoerce(Object input, TypeToken<T> type) {
+ return TypeCoercions.tryCoerce(input, type);
+ }
+ };
+ }
}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/7ddca12d/utils/common/src/main/java/org/apache/brooklyn/util/javalang/Reflections.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/javalang/Reflections.java b/utils/common/src/main/java/org/apache/brooklyn/util/javalang/Reflections.java
index fba72b5..abcaf47 100644
--- a/utils/common/src/main/java/org/apache/brooklyn/util/javalang/Reflections.java
+++ b/utils/common/src/main/java/org/apache/brooklyn/util/javalang/Reflections.java
@@ -48,6 +48,7 @@ import org.apache.brooklyn.util.collections.MutableList;
import org.apache.brooklyn.util.collections.MutableMap;
import org.apache.brooklyn.util.exceptions.Exceptions;
import org.apache.brooklyn.util.guava.Maybe;
+import org.apache.brooklyn.util.javalang.coerce.TypeCoercer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -840,19 +841,33 @@ public class Reflections {
public static Maybe<Object> invokeMethodFromArgs(Object clazzOrInstance, String method, List<?> args) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
return invokeMethodFromArgs(clazzOrInstance, method, args, false);
}
+
/** as {@link #invokeMethodFromArgs(Object, String, List)} but giving control over whether to set it accessible */
public static Maybe<Object> invokeMethodFromArgs(Object clazzOrInstance, String method, List<?> args, boolean setAccessible) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
+ return invokeMethodFromArgs(clazzOrInstance, method, args, setAccessible, Optional.<TypeCoercer>absent());
+ }
+
+ /** as {@link #invokeMethodFromArgs(Object, String, List)} but giving control over whether to set it accessible */
+ public static Maybe<Object> invokeMethodFromArgs(Object clazzOrInstance, String method, List<?> args, boolean setAccessible, Optional<? extends TypeCoercer> coercer) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
Maybe<Method> maybeMethod = getMethodFromArgs(clazzOrInstance, method, args);
+ if (coercer.isPresent() && maybeMethod.isAbsent()) {
+ maybeMethod = getMethodFromArgs(clazzOrInstance, method, args, coercer);
+ }
if (maybeMethod.isAbsent()) {
return Maybe.absent(Maybe.getException(maybeMethod));
}
Method m = maybeMethod.get();
- return Maybe.of(invokeMethodFromArgs(clazzOrInstance, m, args, setAccessible));
+ return Maybe.of(invokeMethodFromArgs(clazzOrInstance, m, args, setAccessible, coercer));
}
/** searches for the given method on the given clazz or instance, doing reasonably good matching on args etc */
public static Maybe<Method> getMethodFromArgs(Object clazzOrInstance, String method, List<?> args) {
+ return getMethodFromArgs(clazzOrInstance, method, args, Optional.<TypeCoercer>absent());
+ }
+
+ /** searches for the given method on the given clazz or instance, doing reasonably good matching on args etc */
+ public static Maybe<Method> getMethodFromArgs(Object clazzOrInstance, String method, List<?> args, Optional<? extends TypeCoercer> coercer) {
Preconditions.checkNotNull(clazzOrInstance, "clazz or instance");
Preconditions.checkNotNull(method, "method");
Preconditions.checkNotNull(args, "args to "+method);
@@ -870,12 +885,11 @@ public class Reflections {
if (method.equals(m.getName())) {
Class<?>[] parameterTypes = m.getParameterTypes();
if (m.isVarArgs()) {
- if (typesMatchUpTo(argsArray, parameterTypes, parameterTypes.length-1)) {
+ if (typesMatchUpTo(argsArray, parameterTypes, parameterTypes.length-1, coercer)) {
Class<?> varargType = parameterTypes[parameterTypes.length-1].getComponentType();
boolean varargsMatch = true;
for (int i=parameterTypes.length-1; i<argsArray.length; i++) {
- if (!Boxing.boxedType(varargType).isInstance(argsArray[i]) ||
- (varargType.isPrimitive() && argsArray[i]==null)) {
+ if (!typeMatches(argsArray[i], varargType, coercer)) {
varargsMatch = false;
break;
}
@@ -885,7 +899,7 @@ public class Reflections {
}
}
}
- if (typesMatch(argsArray, parameterTypes)) {
+ if (typesMatch(argsArray, parameterTypes, coercer)) {
return Maybe.of(m);
}
}
@@ -910,6 +924,12 @@ public class Reflections {
/** as {@link #invokeMethodFromArgs(Object, Method, List)} but giving control over whether to set it accessible */
public static Object invokeMethodFromArgs(Object clazzOrInstance, Method m, List<?> args, boolean setAccessible)
throws IllegalAccessException, InvocationTargetException {
+ return invokeMethodFromArgs(clazzOrInstance, m, args, setAccessible, Optional.<TypeCoercer>absent());
+ }
+
+ /** as {@link #invokeMethodFromArgs(Object, Method, List)} but giving control over whether to set it accessible */
+ public static Object invokeMethodFromArgs(Object clazzOrInstance, Method m, List<?> args, boolean setAccessible, Optional<? extends TypeCoercer> coercer)
+ throws IllegalAccessException, InvocationTargetException {
Preconditions.checkNotNull(clazzOrInstance, "clazz or instance");
Preconditions.checkNotNull(m, "method");
Preconditions.checkNotNull(args, "args to "+m);
@@ -928,38 +948,69 @@ public class Reflections {
Class<?> varargType = parameterTypes[parameterTypes.length-1].getComponentType();
Object varargs = Array.newInstance(varargType, argsArray.length+1 - parameterTypes.length);
for (int i=parameterTypes.length-1; i<argsArray.length; i++) {
- Boxing.setInArray(varargs, i+1-parameterTypes.length, argsArray[i], varargType);
+ Object arg = coercer.isPresent() ? coercer.get().coerce(argsArray[i], varargType) : argsArray[i];
+ Boxing.setInArray(varargs, i+1-parameterTypes.length, arg, varargType);
}
Object[] newArgsArray = new Object[parameterTypes.length];
- System.arraycopy(argsArray, 0, newArgsArray, 0, parameterTypes.length-1);
+ for (int i = 0; i < parameterTypes.length - 1; i++) {
+ Object arg = coercer.isPresent() ? coercer.get().coerce(argsArray[i], parameterTypes[i]) : argsArray[i];
+ newArgsArray[i] = arg;
+ }
newArgsArray[parameterTypes.length-1] = varargs;
if (setAccessible) m.setAccessible(true);
return m.invoke(instance, newArgsArray);
} else {
+ Object[] newArgsArray;
+ if (coercer.isPresent()) {
+ newArgsArray = new Object[parameterTypes.length];
+ for (int i = 0; i < parameterTypes.length; i++) {
+ Object arg = coercer.get().coerce(argsArray[i], parameterTypes[i]);
+ newArgsArray[i] = arg;
+ }
+ } else {
+ newArgsArray = argsArray;
+ }
if (setAccessible) m.setAccessible(true);
- return m.invoke(instance, argsArray);
+ return m.invoke(instance, newArgsArray);
}
}
/** true iff all args match the corresponding types */
public static boolean typesMatch(Object[] argsArray, Class<?>[] parameterTypes) {
+ return typesMatch(argsArray, parameterTypes, Optional.<TypeCoercer>absent());
+ }
+
+ /** true iff all args match the corresponding types */
+ public static boolean typesMatch(Object[] argsArray, Class<?>[] parameterTypes, Optional<? extends TypeCoercer> coercer) {
if (argsArray.length != parameterTypes.length)
return false;
- return typesMatchUpTo(argsArray, parameterTypes, argsArray.length);
+ return typesMatchUpTo(argsArray, parameterTypes, argsArray.length, coercer);
}
-
+
/** true iff the initial N args match the corresponding types */
public static boolean typesMatchUpTo(Object[] argsArray, Class<?>[] parameterTypes, int lengthRequired) {
+ return typesMatchUpTo(argsArray, parameterTypes, lengthRequired, Optional.<TypeCoercer>absent());
+ }
+
+ /** true iff the initial N args match the corresponding types */
+ public static boolean typesMatchUpTo(Object[] argsArray, Class<?>[] parameterTypes, int lengthRequired, Optional<? extends TypeCoercer> coercer) {
if (argsArray.length < lengthRequired || parameterTypes.length < lengthRequired)
return false;
for (int i=0; i<lengthRequired; i++) {
- if (argsArray[i]==null) continue;
- if (Boxing.boxedType(parameterTypes[i]).isInstance(argsArray[i])) continue;
- return false;
+ if (!typeMatches(argsArray[i], parameterTypes[i], coercer)) return false;
}
return true;
}
+ /** true iff the initial N args match the corresponding types */
+ public static boolean typeMatches(Object arg, Class<?> parameterType, Optional<? extends TypeCoercer> coercer) {
+ if (parameterType.isPrimitive() && arg == null) return false;
+ if (arg == null) return true;
+ if (Boxing.boxedType(parameterType).isInstance(arg)) return true;
+ if (coercer.isPresent() && coercer.get().tryCoerce(arg, parameterType).isPresent()) return true;
+ return false;
+ }
+
/**
* Gets all the interfaces implemented by the given type, including its parent classes.
*
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/7ddca12d/utils/common/src/test/java/org/apache/brooklyn/util/javalang/ReflectionsTest.java
----------------------------------------------------------------------
diff --git a/utils/common/src/test/java/org/apache/brooklyn/util/javalang/ReflectionsTest.java b/utils/common/src/test/java/org/apache/brooklyn/util/javalang/ReflectionsTest.java
index 52aee8c..ba4b1d3 100644
--- a/utils/common/src/test/java/org/apache/brooklyn/util/javalang/ReflectionsTest.java
+++ b/utils/common/src/test/java/org/apache/brooklyn/util/javalang/ReflectionsTest.java
@@ -26,10 +26,13 @@ import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
-import org.apache.brooklyn.util.javalang.Reflections;
+import org.apache.brooklyn.util.javalang.coerce.CommonAdaptorTypeCoercions;
+import org.apache.brooklyn.util.javalang.coerce.TypeCoercer;
+import org.apache.brooklyn.util.javalang.coerce.TypeCoercerExtensible;
import org.testng.Assert;
import org.testng.annotations.Test;
+import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
@@ -129,6 +132,22 @@ public class ReflectionsTest {
}
@Test
+ public void testInvocationCoercingArgs() throws Exception {
+ TypeCoercerExtensible rawCoercer = TypeCoercerExtensible.newDefault();
+ new CommonAdaptorTypeCoercions(rawCoercer).registerAllAdapters();
+ Optional<TypeCoercer> coercer = Optional.<TypeCoercer>of(rawCoercer);
+
+ Method m1Short = CI1.class.getMethod("m1", String.class, int.class);
+ Method m1Long = CI1.class.getMethod("m1", String.class, int.class, int.class, int[].class);
+ Assert.assertEquals(m1Short.invoke(null, "hello", 1), "hello1");
+ Assert.assertEquals(m1Long.invoke(null, "hello", 1, 2, new int[] { 3, 4}), "hello10");
+
+ Assert.assertEquals(Reflections.invokeMethodFromArgs(CI1.class, "m1", Arrays.<Object>asList('a', "2"), false, coercer).get(), "a2");
+ Assert.assertEquals(Reflections.invokeMethodFromArgs(CI1.class, "m1", Arrays.<Object>asList('a', "3", "4", "5"), false, coercer).get(), "a12");
+ Assert.assertEquals(Reflections.invokeMethodFromArgs(CI1.class, "m1", Arrays.<Object>asList('a', (byte)3, (byte)4, (byte)5), false, coercer).get(), "a12");
+ }
+
+ @Test
public void testMethodInvocation() throws Exception {
Method m1Short = CI1.class.getMethod("m1", String.class, int.class);
Method m1Long = CI1.class.getMethod("m1", String.class, int.class, int.class, int[].class);