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
commit c8987208d507681b67c5d4323b87407fb67893b8 Author: Alex Heneveld <[email protected]> AuthorDate: Thu Sep 30 16:01:40 2021 +0100 logic for looking at merger of typetokens --- .../org/apache/brooklyn/util/guava/TypeTokens.java | 36 ++++++++++++++++++++++ .../apache/brooklyn/util/guava/TypeTokensTest.java | 7 +++++ 2 files changed, 43 insertions(+) diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/guava/TypeTokens.java b/utils/common/src/main/java/org/apache/brooklyn/util/guava/TypeTokens.java index 28c1f1c..19ff464 100644 --- a/utils/common/src/main/java/org/apache/brooklyn/util/guava/TypeTokens.java +++ b/utils/common/src/main/java/org/apache/brooklyn/util/guava/TypeTokens.java @@ -19,6 +19,7 @@ package org.apache.brooklyn.util.guava; import com.fasterxml.jackson.databind.type.ArrayType; +import com.google.common.annotations.Beta; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; @@ -185,4 +186,39 @@ public class TypeTokens { return getGenericParameterTypeTokensWhenUpcastToClass(t, (Class)clazz); } + /** find the lowest common ancestor of the two types, filling in generics info, and ignoring Object; but that's hard so this does some heuristics for common cases */ + @Beta + public static TypeToken<?> union(TypeToken<?> t1, TypeToken<?> t2, boolean ignoreObject) { + if (t1.equals(t2)) return t1; + + if (ignoreObject) { + if (t1.getRawType().equals(Object.class)) return t2; + if (t2.getRawType().equals(Object.class)) return t1; + } + + if (t1.getRawType().equals(t2.getRawType())) { + // if equal, prefer one whose generics are more specific + TypeToken<?>[] tokens1 = getGenericParameterTypeTokens(t1); + TypeToken<?>[] tokens2 = getGenericParameterTypeTokens(t1); + if (tokens1.length>0 && tokens2.length>0) { + // just look at first one to see who wins + TypeToken<?> union0 = union(tokens1[0], tokens2[0], true); + if (union0==tokens2[0]) return t2; + return t1; + } else if (tokens2.length>0) { + return t2; + } + return t1; + } + + // prefer an ancestor (ideally we'd infer generics if needed at the parent, but skip for now) + if (t1.isAssignableFrom(t2)) return t1; + if (t2.isAssignableFrom(t1)) return t2; + if (t1.getRawType().isAssignableFrom(t2.getRawType())) return t1; + if (t2.getRawType().isAssignableFrom(t1.getRawType())) return t2; + + // can't figure anything out, just pick one + return t1; + } + } diff --git a/utils/common/src/test/java/org/apache/brooklyn/util/guava/TypeTokensTest.java b/utils/common/src/test/java/org/apache/brooklyn/util/guava/TypeTokensTest.java index edcf55d..ab63e51 100644 --- a/utils/common/src/test/java/org/apache/brooklyn/util/guava/TypeTokensTest.java +++ b/utils/common/src/test/java/org/apache/brooklyn/util/guava/TypeTokensTest.java @@ -24,6 +24,7 @@ import java.util.List; import java.util.Map; import org.apache.brooklyn.test.Asserts; import org.apache.brooklyn.util.collections.MutableList; +import org.apache.brooklyn.util.collections.MutableMap; import org.apache.brooklyn.util.exceptions.UserFacingException; import org.testng.Assert; import org.testng.annotations.Test; @@ -37,4 +38,10 @@ public class TypeTokensTest { Assert.assertEquals(genericArguments, MutableList.of(TypeToken.of(String.class), TypeToken.of(Integer.class))); } + @Test + public void testLowestCommonAncestor() { + TypeToken<?> map1 = new TypeToken<Map<String,Integer>>() {}; + Assert.assertEquals( TypeTokens.union(TypeToken.of(MutableMap.class), map1, true), map1); + } + }
