TypeCoercions: recursively unpack for List<T> - e.g. if given â1,2â for type List<Integer>, then first pass will coerce to List.of(â1â, â2â), and second pass will coerce to List.of(1,2)
Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/e3154097 Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/e3154097 Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/e3154097 Branch: refs/heads/master Commit: e3154097506624c6c385a64fc6a2e5c466039b8d Parents: beb87db Author: Aled Sage <[email protected]> Authored: Fri Nov 7 19:44:14 2014 +0000 Committer: Aled Sage <[email protected]> Committed: Mon Nov 10 11:34:35 2014 +0000 ---------------------------------------------------------------------- .../java/brooklyn/util/flags/TypeCoercions.java | 16 ++++++++++++++-- .../brooklyn/util/internal/TypeCoercionsTest.java | 6 ++++++ 2 files changed, 20 insertions(+), 2 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e3154097/core/src/main/java/brooklyn/util/flags/TypeCoercions.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/util/flags/TypeCoercions.java b/core/src/main/java/brooklyn/util/flags/TypeCoercions.java index f3caeaf..ec08ad0 100644 --- a/core/src/main/java/brooklyn/util/flags/TypeCoercions.java +++ b/core/src/main/java/brooklyn/util/flags/TypeCoercions.java @@ -64,6 +64,7 @@ import brooklyn.util.yaml.Yamls; import com.google.common.base.CaseFormat; import com.google.common.base.Function; +import com.google.common.base.Objects; import com.google.common.base.Preconditions; import com.google.common.base.Predicate; import com.google.common.collect.HashBasedTable; @@ -235,7 +236,18 @@ public class TypeCoercions { Map<Class, Function> adapters = registry.row(targetType); for (Map.Entry<Class, Function> entry : adapters.entrySet()) { if (entry.getKey().isInstance(value)) { - return (T) entry.getValue().apply(value); + T result = (T) entry.getValue().apply(value); + + // Check if need to unwrap again (e.g. if want List<Integer> and are given a String "1,2,3" + // then we'll have so far converted to List.of("1", "2", "3"). Call recursively. + // First check that value has changed, to avoid stack overflow! + if (!Objects.equal(value, result) && targetTypeToken.getType() instanceof ParameterizedType) { + // Could duplicate check for `result instanceof Collection` etc; but recursive call + // will be fine as if that doesn't match we'll safely reach `targetType.isInstance(value)` + // and just return the result. + return coerce(result, targetTypeToken); + } + return result; } } } @@ -459,7 +471,7 @@ public class TypeCoercions { return null; } - public synchronized static <A,B> void registerAdapter(Class<A> sourceType, Class<B> targetType, Function<A,B> fn) { + public synchronized static <A,B> void registerAdapter(Class<A> sourceType, Class<B> targetType, Function<? super A,B> fn) { registry.put(targetType, sourceType, fn); } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e3154097/core/src/test/java/brooklyn/util/internal/TypeCoercionsTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/brooklyn/util/internal/TypeCoercionsTest.java b/core/src/test/java/brooklyn/util/internal/TypeCoercionsTest.java index 8ac1e9c..b4d0470 100644 --- a/core/src/test/java/brooklyn/util/internal/TypeCoercionsTest.java +++ b/core/src/test/java/brooklyn/util/internal/TypeCoercionsTest.java @@ -222,6 +222,12 @@ public class TypeCoercionsTest { } @Test + @SuppressWarnings("serial") + public void testCoerceRecursivelyStringToGenericsCollection() { + assertEquals(TypeCoercions.coerce("1,2", new TypeToken<List<Integer>>() {}), ImmutableList.of(1, 2)); + } + + @Test public void testJsonStringToMapCoercion() { Map<?,?> s = TypeCoercions.coerce("{ \"a\" : \"1\", b : 2 }", Map.class); Assert.assertEquals(s, ImmutableMap.of("a", "1", "b", 2));
