You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by gn...@apache.org on 2016/06/13 18:29:53 UTC

svn commit: r1748298 - in /aries/trunk/blueprint/blueprint-core/src: main/java/org/apache/aries/blueprint/container/AggregateConverter.java test/java/org/apache/aries/blueprint/container/BeanRecipeTest.java

Author: gnodet
Date: Mon Jun 13 18:29:53 2016
New Revision: 1748298

URL: http://svn.apache.org/viewvc?rev=1748298&view=rev
Log:
[ARIES-1572] Fix more complicated generic conversions

Modified:
    aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/AggregateConverter.java
    aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/container/BeanRecipeTest.java

Modified: aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/AggregateConverter.java
URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/AggregateConverter.java?rev=1748298&r1=1748297&r2=1748298&view=diff
==============================================================================
--- aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/AggregateConverter.java (original)
+++ aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/AggregateConverter.java Mon Jun 13 18:29:53 2016
@@ -20,7 +20,9 @@ import java.io.ByteArrayInputStream;
 import java.lang.reflect.Array;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.security.AccessControlContext;
@@ -476,17 +478,90 @@ public class AggregateConverter implemen
                     return true;
                 }
             }
+        } else {
+            ReifiedType t = getExactSuperType(from, to.getRawClass());
+            if (t != null) {
+                return isTypeAssignable(t, to);
+            }
         }
-        Type t = from.getRawClass().getGenericSuperclass();
-        if (t != null && isTypeAssignable(new GenericType(t), to)) {
-            return true;
+        return false;
+    }
+
+    private static ReifiedType getExactSuperType(ReifiedType from, Class<?> to) {
+        if (from.getRawClass() == to) {
+            return from;
+        }
+        if (!to.isAssignableFrom(from.getRawClass())) {
+            return null;
+        }
+        for (ReifiedType superType: getExactDirectSuperTypes(from)) {
+            ReifiedType result = getExactSuperType(superType, to);
+            if (result != null)
+                return result;
+        }
+        return null;
+    }
+
+    public static ReifiedType[] getExactDirectSuperTypes(ReifiedType type) {
+        Class<?> clazz = type.getRawClass();
+        Type[] superInterfaces = clazz.getGenericInterfaces();
+        Type superClass = clazz.getGenericSuperclass();
+        // the only supertype of an interface without superinterfaces is Object
+        if (superClass == null && superInterfaces.length == 0 && clazz.isInterface()) {
+            return new ReifiedType[] { new GenericType(Object.class) };
+        }
+        ReifiedType[] result;
+        int resultIndex;
+        if (superClass == null) {
+            result = new ReifiedType[superInterfaces.length];
+            resultIndex = 0;
+        } else {
+            result = new ReifiedType[superInterfaces.length + 1];
+            resultIndex = 1;
+            result[0] = mapTypeParameters(superClass, type);
         }
-        for (Type ti : from.getRawClass().getGenericInterfaces()) {
-            if (ti != null && isTypeAssignable(new GenericType(ti), to)) {
-                return true;
+        for (Type superInterface : superInterfaces) {
+            result[resultIndex++] = mapTypeParameters(superInterface, type);
+        }
+        return result;
+    }
+
+    private static ReifiedType mapTypeParameters(Type toMapType, ReifiedType typeAndParams) {
+        if (typeAndParams.size() == 0 && typeAndParams.getRawClass().getTypeParameters().length > 0) {
+            // Missing generics information, return erased type
+            return new GenericType(new GenericType(toMapType).getRawClass());
+        }
+        if (toMapType instanceof Class) {
+            return new GenericType(toMapType);
+        }
+        Map<TypeVariable<?>, GenericType> map = new HashMap<TypeVariable<?>, GenericType>();
+        for (int i = 0; i < typeAndParams.size(); i++) {
+            map.put(typeAndParams.getRawClass().getTypeParameters()[i], (GenericType) typeAndParams.getActualTypeArgument(i));
+        }
+        return map(map, toMapType);
+    }
+
+
+    private static GenericType map(Map<TypeVariable<?>, GenericType> map, Type type) {
+        if (type instanceof Class) {
+            return new GenericType(type);
+        }
+        if (type instanceof TypeVariable) {
+            TypeVariable<?> tv = (TypeVariable<?>) type;
+            if (!map.containsKey(type)) {
+                throw new IllegalArgumentException("Unable to resolve TypeVariable: " + tv);
             }
+            return map.get(type);
         }
-        return false;
+        if (type instanceof ParameterizedType) {
+            ParameterizedType pType = (ParameterizedType) type;
+            GenericType[] args = new GenericType[pType.getActualTypeArguments().length];
+            for (int i = 0; i < args.length; i++) {
+                args[i] = map(map, pType.getActualTypeArguments()[i]);
+            }
+            return new GenericType((Class<?>) pType.getRawType(), args);
+        }
+        throw new RuntimeException("not implemented: mapping " + type.getClass() + " (" + type + ")");
     }
 
     private static boolean isWildcardCompatible(ReifiedType from, ReifiedType to) {

Modified: aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/container/BeanRecipeTest.java
URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/container/BeanRecipeTest.java?rev=1748298&r1=1748297&r2=1748298&view=diff
==============================================================================
--- aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/container/BeanRecipeTest.java (original)
+++ aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/container/BeanRecipeTest.java Mon Jun 13 18:29:53 2016
@@ -68,6 +68,16 @@ public class BeanRecipeTest {
         public ExampleService(Example<String> e) {}
     }
 
+    static public interface BaseInterface<T> { }
+    static public interface ExtendedInterface<T0, T1> extends BaseInterface<T1> {}
+    static public class MyClass implements ExtendedInterface<String, Integer> { }
+    static public class MyClass2<T> implements BaseInterface<T> { }
+    static public class MyClass3 extends MyClass2<Long> { }
+    static public class MyService {
+        public MyService(BaseInterface<? extends Number> e) {}
+    }
+
+
     static public interface A {
         String getA();
         void setA(String a);
@@ -126,6 +136,26 @@ public class BeanRecipeTest {
         recipe.setArgTypes(Arrays.<String>asList((String) null));
         ExecutionContext.Holder.setContext(new BlueprintRepository(container));
         recipe.create();
+    }
+
+    @Test
+    public void parameterWithComplexGenerics1() throws Exception {
+        BlueprintContainerImpl container = new BlueprintContainerImpl(null, null, null, null, null, null, null, null, null, null);
+        BeanRecipe recipe = new BeanRecipe("example", container, MyService.class, false);
+        recipe.setArguments(Arrays.<Object>asList(new MyClass()));
+        recipe.setArgTypes(Arrays.<String>asList((String) null));
+        ExecutionContext.Holder.setContext(new BlueprintRepository(container));
+        recipe.create();
+    }
+
+    @Test
+    public void parameterWithComplexGenerics2() throws Exception {
+        BlueprintContainerImpl container = new BlueprintContainerImpl(null, null, null, null, null, null, null, null, null, null);
+        BeanRecipe recipe = new BeanRecipe("example", container, MyService.class, false);
+        recipe.setArguments(Arrays.<Object>asList(new MyClass3()));
+        recipe.setArgTypes(Arrays.<String>asList((String) null));
+        ExecutionContext.Holder.setContext(new BlueprintRepository(container));
+        recipe.create();
     }
 
     @Test