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 2018/01/30 22:05:18 UTC

svn commit: r1822706 [1/2] - in /aries/trunk/blueprint/blueprint-core/src: main/java/org/apache/aries/blueprint/container/ main/java/org/apache/aries/blueprint/utils/generics/ test/java/org/apache/aries/blueprint/ test/java/org/apache/aries/blueprint/c...

Author: gnodet
Date: Tue Jan 30 22:05:17 2018
New Revision: 1822706

URL: http://svn.apache.org/viewvc?rev=1822706&view=rev
Log:
[ARIES-960] Improve generics support to support type inference

Added:
    aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/utils/generics/
    aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/utils/generics/ClassUtil.java
    aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/utils/generics/GenericsUtil.java
    aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/utils/generics/OwbGenericArrayTypeImpl.java
    aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/utils/generics/OwbParametrizedTypeImpl.java
    aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/utils/generics/OwbTypeVariableImpl.java
    aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/utils/generics/OwbWildcardTypeImpl.java
    aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/utils/generics/TypeInference.java
    aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/container/TypeInferenceTest.java
    aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/pojos/DummyServiceTrackerCustomizer.java
    aries/trunk/blueprint/blueprint-core/src/test/resources/test-generics-mix.xml
Modified:
    aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BeanRecipe.java
    aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/WiringTest.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/BeanRecipe.java
URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BeanRecipe.java?rev=1822706&r1=1822705&r2=1822706&view=diff
==============================================================================
--- aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BeanRecipe.java (original)
+++ aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BeanRecipe.java Tue Jan 30 22:05:17 2018
@@ -21,7 +21,6 @@ package org.apache.aries.blueprint.conta
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
 import java.lang.reflect.Type;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -45,6 +44,8 @@ import org.apache.aries.blueprint.proxy.
 import org.apache.aries.blueprint.services.ExtendedBlueprintContainer;
 import org.apache.aries.blueprint.utils.ReflectionUtils;
 import org.apache.aries.blueprint.utils.ReflectionUtils.PropertyDescriptor;
+import org.apache.aries.blueprint.utils.generics.OwbParametrizedTypeImpl;
+import org.apache.aries.blueprint.utils.generics.TypeInference;
 import org.apache.aries.proxy.UnableToProxyException;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
@@ -55,7 +56,6 @@ import org.osgi.service.blueprint.reflec
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import static org.apache.aries.blueprint.utils.ReflectionUtils.getPublicMethods;
 import static org.apache.aries.blueprint.utils.ReflectionUtils.getRealCause;
 
 /**
@@ -342,10 +342,10 @@ public class BeanRecipe extends Abstract
             throw new ComponentDefinitionException("No factoryMethod nor class is defined for this bean");
         }
         // Map of matching constructors
-        Map<Constructor, List<Object>> matches = findMatchingConstructors(getType(), args, argTypes);
+        Map<Constructor<?>, List<Object>> matches = findMatchingConstructors(getType(), args, argTypes);
         if (matches.size() == 1) {
             try {
-                Map.Entry<Constructor, List<Object>> match = matches.entrySet().iterator().next();
+                Map.Entry<Constructor<?>, List<Object>> match = matches.entrySet().iterator().next();
                 return newInstance(match.getKey(), match.getValue().toArray());
             } catch (Throwable e) {
                 throw wrapAsCompDefEx(e);
@@ -366,271 +366,102 @@ public class BeanRecipe extends Abstract
         return type == null ? null : type.getName();
     }
 
-    private Map<Method, List<Object>> findMatchingMethods(Class type, String name, boolean instance, List<Object> args, List<ReifiedType> types) {
-        Map<Method, List<Object>> matches = new HashMap<Method, List<Object>>();
-        // Get constructors
-        List<Method> methods = new ArrayList<Method>(Arrays.asList(getPublicMethods(type)));
-        // Discard any signature with wrong cardinality
-        for (Iterator<Method> it = methods.iterator(); it.hasNext();) {
-            Method mth = it.next();
-            if (!mth.getName().equals(name)) {
-                it.remove();
-            } else if (mth.getParameterTypes().length != args.size()) {
-                it.remove();
-            } else if (instance ^ !Modifier.isStatic(mth.getModifiers())) {
-                it.remove();
-            } else if (mth.isBridge()) {
-                it.remove();
-            }
-        }
-        
-        // on some JVMs (J9) hidden static methods are returned by Class.getMethods so we need to weed them out
-        // to reduce ambiguity
-        if (!instance) {
-        	methods = applyStaticHidingRules(methods);
-        }
-        
-        // Find a direct match with assignment
-        if (matches.size() != 1) {
-            Map<Method, List<Object>> nmatches = new HashMap<Method, List<Object>>();
-            for (Method mth : methods) {
-                boolean found = true;
-                List<Object> match = new ArrayList<Object>();
-                for (int i = 0; i < args.size(); i++) {
-                    ReifiedType argType = new GenericType(mth.getGenericParameterTypes()[i]);
-                    if (types.get(i) != null && !argType.getRawClass().equals(types.get(i).getRawClass())) {
-                        found = false;
-                        break;
-                    }
-                    // If the arg is an Unwrappered bean then we need to do the assignment
-                    // check against the unwrappered bean itself.
-                    Object arg = args.get(i);
-                    Object argToTest = arg;
-                    if (arg instanceof UnwrapperedBeanHolder)
-                    	argToTest = ((UnwrapperedBeanHolder)arg).unwrapperedBean;
-                    if (!AggregateConverter.isAssignable(argToTest, argType)) {
-                        found = false;
-                        break;
-                    }
-                    try {
-                        match.add(convert(arg, mth.getGenericParameterTypes()[i]));
-                    } catch (Throwable t) {
-                        found = false;
-                        break;
-                    }
-                }
-                if (found) {
-                    nmatches.put(mth, match);
+    private Map<Constructor<?>, List<Object>> findMatchingConstructors(Class type, List<Object> args, List<ReifiedType> types) {
+        List<TypeInference.TypedObject> targs = getTypedObjects(args, types);
+        TypeInference.Converter cnv = new TIConverter();
+        List<TypeInference.Match<Constructor<?>>> m = TypeInference.findMatchingConstructors(type, targs, cnv, reorderArguments);
+        if (!m.isEmpty()) {
+            int score = m.iterator().next().getScore();
+            final Iterator<TypeInference.Match<Constructor<?>>> each = m.iterator();
+            while (each.hasNext()) {
+                if (each.next().getScore() > score) {
+                    each.remove();
                 }
             }
-            if (nmatches.size() > 0) {
-                matches = nmatches;
-            }
         }
-        // Find a direct match with conversion
-        if (matches.size() != 1) {
-            Map<Method, List<Object>> nmatches = new HashMap<Method, List<Object>>();
-            for (Method mth : methods) {
-                boolean found = true;
-                List<Object> match = new ArrayList<Object>();
-                for (int i = 0; i < args.size(); i++) {
-                    ReifiedType argType = new GenericType(mth.getGenericParameterTypes()[i]);
-                    if (types.get(i) != null && !argType.getRawClass().equals(types.get(i).getRawClass())) {
-                        found = false;
-                        break;
-                    }
-                    try {
-                        Object val = convert(args.get(i), argType);
-                        match.add(val);
-                    } catch (Throwable t) {
-                        found = false;
-                        break;
-                    }
-                }
-                if (found) {
-                    nmatches.put(mth, match);
-                }
-            }
-            if (nmatches.size() > 0) {
-                matches = nmatches;
+        Map<Constructor<?>, List<Object>> map = new HashMap<Constructor<?>, List<Object>>();
+        for (TypeInference.Match<Constructor<?>> match : m) {
+            List<Object> nargs = new ArrayList<Object>();
+            for (TypeInference.TypedObject to : match.getArgs()) {
+                nargs.add(to.getValue());
             }
+            map.put(match.getMember(), nargs);
         }
-        // Start reordering with assignment
-        if (matches.size() != 1 && reorderArguments && args.size() > 1) {
-            Map<Method, List<Object>> nmatches = new HashMap<Method, List<Object>>();
-            for (Method mth : methods) {
-                ArgumentMatcher matcher = new ArgumentMatcher(mth.getGenericParameterTypes(), false);
-                List<Object> match = matcher.match(args, types);
-                if (match != null) {
-                    nmatches.put(mth, match);
-                }
-            }
-            if (nmatches.size() > 0) {
-                matches = nmatches;
-            }
-        }
-        // Start reordering with conversion
-        if (matches.size() != 1 && reorderArguments && args.size() > 1) {
-            Map<Method, List<Object>> nmatches = new HashMap<Method, List<Object>>();
-            for (Method mth : methods) {
-                ArgumentMatcher matcher = new ArgumentMatcher(mth.getGenericParameterTypes(), true);
-                List<Object> match = matcher.match(args, types);
-                if (match != null) {
-                    nmatches.put(mth, match);
-                }
-            }
-            if (nmatches.size() > 0) {
-                matches = nmatches;
-            }
-        }
-        
-        return matches;
-    }
-    
-    private static List<Method> applyStaticHidingRules(Collection<Method> methods) {
-    	List<Method> result = new ArrayList<Method>(methods.size());
-    	for (Method m : methods) {
-    		boolean toBeAdded = true;
-
-    		Iterator<Method> it = result.iterator();
-    		inner: while (it.hasNext()) {
-    			Method other = it.next();
-    			if (hasIdenticalParameters(m, other)) {
-    				Class<?> mClass = m.getDeclaringClass();
-    				Class<?> otherClass = other.getDeclaringClass();
-    				
-    				if (mClass.isAssignableFrom(otherClass)) {
-    					toBeAdded = false;
-    					break inner;
-    				} else if (otherClass.isAssignableFrom(mClass)) {
-    					it.remove();
-    				}
-    			}
-    		}
-    		
-    		if (toBeAdded) result.add(m);
-    	}
-    	
-    	return result;
-    }
-    
-    private static boolean hasIdenticalParameters(Method one, Method two) {
-		Class<?>[] oneTypes = one.getParameterTypes();
-		Class<?>[] twoTypes = two.getParameterTypes();
-    	
-		if (oneTypes.length != twoTypes.length) return false;
-		
-		for (int i=0; i<oneTypes.length; i++) {
-			if (!oneTypes[i].equals(twoTypes[i])) return false;
-		}
-		
-		return true;
-    }
-
-    private Map<Constructor, List<Object>> findMatchingConstructors(Class type, List<Object> args, List<ReifiedType> types) {
-        Map<Constructor, List<Object>> matches = new HashMap<Constructor, List<Object>>();
-        // Get constructors
-        List<Constructor> constructors = new ArrayList<Constructor>(Arrays.asList(type.getConstructors()));
-        // Discard any signature with wrong cardinality
-        for (Iterator<Constructor> it = constructors.iterator(); it.hasNext();) {
-            if (it.next().getParameterTypes().length != args.size()) {
-                it.remove();
-            }
-        }
-        // Find a direct match with assignment
-        if (matches.size() != 1) {
-            Map<Constructor, List<Object>> nmatches = new HashMap<Constructor, List<Object>>();
-            for (Constructor cns : constructors) {
-                boolean found = true;
-                List<Object> match = new ArrayList<Object>();
-                for (int i = 0; i < args.size(); i++) {
-                    ReifiedType argType = new GenericType(cns.getGenericParameterTypes()[i]);
-                    if (types.get(i) != null && !argType.getRawClass().equals(types.get(i).getRawClass())) {
-                        found = false;
-                        break;
-                    }
-                    // If the arg is an Unwrappered bean then we need to do the assignment
-                    // check against the unwrappered bean itself.
-                    Object arg = args.get(i);
-                    Object argToTest = arg;
-                    if (arg instanceof UnwrapperedBeanHolder)
-                    	argToTest = ((UnwrapperedBeanHolder)arg).unwrapperedBean;
-                    if (!AggregateConverter.isAssignable(argToTest, argType)) {
-                        found = false;
-                        break;
-                    }
-                    try {
-                        match.add(convert(arg, cns.getGenericParameterTypes()[i]));
-                    } catch (Throwable t) {
-                        found = false;
-                        break;
-                    }
-                }
-                if (found) {
-                    nmatches.put(cns, match);
-                }
-            }
-            if (nmatches.size() > 0) {
-                matches = nmatches;
-            }
+        return map;
+    }
+
+    private Map<Method, List<Object>> findMatchingMethods(Class type, String name, boolean instance, List<Object> args, List<ReifiedType> types) {
+        List<TypeInference.TypedObject> targs = getTypedObjects(args, types);
+        TypeInference.Converter cnv = new TIConverter();
+        List<TypeInference.Match<Method>> m;
+        if (instance) {
+            m = TypeInference.findMatchingMethods(type, name, targs, cnv, reorderArguments);
+        } else {
+            m = TypeInference.findMatchingStatics(type, name, targs, cnv, reorderArguments);
         }
-        // Find a direct match with conversion
-        if (matches.size() != 1) {
-            Map<Constructor, List<Object>> nmatches = new HashMap<Constructor, List<Object>>();
-            for (Constructor cns : constructors) {
-                boolean found = true;
-                List<Object> match = new ArrayList<Object>();
-                for (int i = 0; i < args.size(); i++) {
-                    ReifiedType argType = new GenericType(cns.getGenericParameterTypes()[i]);
-                    if (types.get(i) != null && !argType.getRawClass().equals(types.get(i).getRawClass())) {
-                        found = false;
-                        break;
-                    }
-                    try {
-                        Object val = convert(args.get(i), argType);
-                        match.add(val);
-                    } catch (Throwable t) {
-                        found = false;
-                        break;
-                    }
+        if (!m.isEmpty()) {
+            int score = m.iterator().next().getScore();
+            final Iterator<TypeInference.Match<Method>> each = m.iterator();
+            while (each.hasNext()) {
+                if (each.next().getScore() > score) {
+                    each.remove();
                 }
-                if (found) {
-                    nmatches.put(cns, match);
-                }
-            }
-            if (nmatches.size() > 0) {
-                matches = nmatches;
             }
         }
-        // Start reordering with assignment
-        if (matches.size() != 1 && reorderArguments && arguments.size() > 1) {
-            Map<Constructor, List<Object>> nmatches = new HashMap<Constructor, List<Object>>();
-            for (Constructor cns : constructors) {
-                ArgumentMatcher matcher = new ArgumentMatcher(cns.getGenericParameterTypes(), false);
-                List<Object> match = matcher.match(args, types);
-                if (match != null) {
-                    nmatches.put(cns, match);
-                }
+        Map<Method, List<Object>> map = new HashMap<Method, List<Object>>();
+        for (TypeInference.Match<Method> match : m) {
+            List<Object> nargs = new ArrayList<Object>();
+            for (TypeInference.TypedObject to : match.getArgs()) {
+                nargs.add(to.getValue());
             }
-            if (nmatches.size() > 0) {
-                matches = nmatches;
+            map.put(match.getMember(), nargs);
+        }
+        return map;
+    }
+
+    private class TIConverter implements TypeInference.Converter {
+        public TypeInference.TypedObject convert(TypeInference.TypedObject from, Type to) throws Exception {
+            Object arg = BeanRecipe.this.convert(from.getValue(), new GenericType(to));
+            return new TypeInference.TypedObject(to, arg);
+        }
+    }
+
+    private Type toType(ReifiedType rt) {
+        if (rt.size() > 0) {
+            Type[] at = new Type[rt.size()];
+            for (int j = 0; j < at.length; j++) {
+                at[j] = toType(rt.getActualTypeArgument(j));
             }
+            return new OwbParametrizedTypeImpl(null, rt.getRawClass(), at);
+        } else {
+            return rt.getRawClass();
         }
-        // Start reordering with conversion
-        if (matches.size() != 1 && reorderArguments && arguments.size() > 1) {
-            Map<Constructor, List<Object>> nmatches = new HashMap<Constructor, List<Object>>();
-            for (Constructor cns : constructors) {
-                ArgumentMatcher matcher = new ArgumentMatcher(cns.getGenericParameterTypes(), true);
-                List<Object> match = matcher.match(args, types);
-                if (match != null) {
-                    nmatches.put(cns, match);
+    }
+
+    private List<TypeInference.TypedObject> getTypedObjects(List<Object> args, List<ReifiedType> types) {
+        List<TypeInference.TypedObject> targs = new ArrayList<TypeInference.TypedObject>();
+        for (int i = 0; i < args.size(); i++) {
+            Type t;
+            Object o = args.get(i);
+            ReifiedType rt = types.get(i);
+            if (rt == null && o != null) {
+                Object ot = o instanceof UnwrapperedBeanHolder ? ((UnwrapperedBeanHolder) o).unwrapperedBean : o;
+                rt = new GenericType(ot.getClass());
+            }
+            if (rt != null) {
+                if (rt.size() == 0 && rt.getRawClass().getTypeParameters().length > 0 && rt.getRawClass() != Class.class) {
+                    GenericType[] tt = new GenericType[rt.getRawClass().getTypeParameters().length];
+                    Arrays.fill(tt, 0, tt.length, new GenericType(Object.class));
+                    rt = new GenericType(rt.getRawClass(), tt);
                 }
+                t = toType(rt);
+            } else {
+                t = null;
             }
-            if (nmatches.size() > 0) {
-                matches = nmatches;
-            }
+
+            targs.add(new TypeInference.TypedObject(t, o));
         }
-        return matches;
+        return targs;
     }
 
     /**
@@ -1028,7 +859,7 @@ public class BeanRecipe extends Abstract
             List<Object> list = new ArrayList<Object>();
             for (TypeEntry entry : entries) {
                 if (entry.argument == UNMATCHED) {
-                    throw new RuntimeException("There are unmatched types");
+                    throw new RuntimeException("There are unmatched generics");
                 } else {
                     list.add(entry.argument);
                 }

Added: aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/utils/generics/ClassUtil.java
URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/utils/generics/ClassUtil.java?rev=1822706&view=auto
==============================================================================
--- aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/utils/generics/ClassUtil.java (added)
+++ aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/utils/generics/ClassUtil.java Tue Jan 30 22:05:17 2018
@@ -0,0 +1,246 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.blueprint.utils.generics;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+
+/**
+ * Utility classes with respect to the class operations.
+ *
+ * @author <a href="mailto:gurkanerdogdu@yahoo.com">Gurkan Erdogdu</a>
+ * @since 1.0
+ */
+public final class ClassUtil
+{
+    public static final Map<Class<?>, Class<?>> PRIMITIVE_TO_WRAPPERS_MAP;
+
+    static
+    {
+        Map<Class<?>, Class<?>> primitiveToWrappersMap = new HashMap<Class<?>, Class<?>>();
+        primitiveToWrappersMap.put(Integer.TYPE,Integer.class);
+        primitiveToWrappersMap.put(Float.TYPE,Float.class);
+        primitiveToWrappersMap.put(Double.TYPE,Double.class);
+        primitiveToWrappersMap.put(Character.TYPE,Character.class);
+        primitiveToWrappersMap.put(Long.TYPE,Long.class);
+        primitiveToWrappersMap.put(Byte.TYPE,Byte.class);
+        primitiveToWrappersMap.put(Short.TYPE,Short.class);
+        primitiveToWrappersMap.put(Boolean.TYPE,Boolean.class);
+        primitiveToWrappersMap.put(Void.TYPE,Void.class);
+        PRIMITIVE_TO_WRAPPERS_MAP = Collections.unmodifiableMap(primitiveToWrappersMap);
+    }
+
+    public static final Type[] NO_TYPES = new Type[0];
+
+    /*
+     * Private constructor
+     */
+    private ClassUtil()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public static boolean isSame(Type type1, Type type2)
+    {
+        if ((type1 instanceof Class) && ((Class<?>)type1).isPrimitive())
+        {
+            type1 = PRIMITIVE_TO_WRAPPERS_MAP.get(type1);
+        }
+        if ((type2 instanceof Class) && ((Class<?>)type2).isPrimitive())
+        {
+            type2 = PRIMITIVE_TO_WRAPPERS_MAP.get(type2);
+        }
+        return type1 == type2;
+    }
+
+    public static Class<?> getPrimitiveWrapper(Class<?> clazz)
+    {
+        return PRIMITIVE_TO_WRAPPERS_MAP.get(clazz);
+
+    }
+
+    /**
+     * Gets the class of the given type arguments.
+     * <p>
+     * If the given type {@link Type} parameters is an instance of the
+     * {@link ParameterizedType}, it returns the raw type otherwise it return
+     * the casted {@link Class} of the type argument.
+     * </p>
+     * 
+     * @param type class or parametrized type
+     * @return
+     */
+    public static Class<?> getClass(Type type)
+    {
+        return getClazz(type);
+    }
+
+
+    /**
+     * Returns true if type is an instance of <code>ParameterizedType</code>
+     * else otherwise.
+     * 
+     * @param type type of the artifact
+     * @return true if type is an instance of <code>ParameterizedType</code>
+     */
+    public static boolean isParametrizedType(Type type)
+    {
+        return type instanceof ParameterizedType;
+    }
+    
+    /**
+     * Returns true if type is an instance of <code>WildcardType</code>
+     * else otherwise.
+     * 
+     * @param type type of the artifact
+     * @return true if type is an instance of <code>WildcardType</code>
+     */    
+    public static boolean isWildCardType(Type type)
+    {
+        return type instanceof WildcardType;
+    }
+
+
+    /**
+     * Returns true if rhs is assignable type
+     * to the lhs, false otherwise.
+     * 
+     * @param lhs left hand side class
+     * @param rhs right hand side class
+     * @return true if rhs is assignable to lhs
+     */
+    public static boolean isClassAssignableFrom(Class<?> lhs, Class<?> rhs)
+    {
+        if(lhs.isPrimitive())
+        {
+            lhs = getPrimitiveWrapper(lhs);
+        }
+        
+        if(rhs.isPrimitive())
+        {
+            rhs = getPrimitiveWrapper(rhs);
+        }
+
+        if (lhs.isAssignableFrom(rhs))
+        {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Return raw class type for given type.
+     * @param type base type instance
+     * @return class type for given type
+     */
+    public static Class<?> getClazz(Type type)
+    {
+        if(type instanceof ParameterizedType)
+        {
+            ParameterizedType pt = (ParameterizedType)type;
+            return (Class<?>)pt.getRawType();                
+        }
+        else if(type instanceof Class)
+        {
+            return (Class<?>)type;
+        }
+        else if(type instanceof GenericArrayType)
+        {
+            GenericArrayType arrayType = (GenericArrayType)type;
+            return Array.newInstance(getClazz(arrayType.getGenericComponentType()), 0).getClass();
+        }
+        else if (type instanceof WildcardType)
+        {
+            WildcardType wildcardType = (WildcardType)type;
+            Type[] bounds = wildcardType.getUpperBounds();
+            if (bounds.length > 1)
+            {
+                throw new IllegalArgumentException("Illegal use of wild card type with more than one upper bound: " + wildcardType);
+            }
+            else if (bounds.length == 0)
+            {
+                return Object.class;
+            }
+            else
+            {
+                return getClass(bounds[0]);
+            }
+        }
+        else if (type instanceof TypeVariable)
+        {
+            TypeVariable<?> typeVariable = (TypeVariable<?>)type;
+            if (typeVariable.getBounds().length > 1)
+            {
+                throw new IllegalArgumentException("Illegal use of type variable with more than one bound: " + typeVariable);
+            }
+            else
+            {
+                Type[] bounds = typeVariable.getBounds();
+                if (bounds.length == 0)
+                {
+                    return Object.class;
+                }
+                else
+                {
+                    return getClass(bounds[0]);
+                }
+            }
+        }
+        else
+        {
+            throw new IllegalArgumentException("Unsupported type " + type);
+        }
+    }
+
+
+    public static boolean isRawClassEquals(Type ipType, Type apiType)
+    {
+        Class ipClass = getRawPrimitiveType(ipType);
+        Class apiClass  = getRawPrimitiveType(apiType);
+
+        if (ipClass == null || apiClass == null)
+        {
+            // we found some illegal generics
+            return false;
+        }
+
+        return ipClass.equals(apiClass);
+    }
+
+    private static Class getRawPrimitiveType(Type type)
+    {
+        if (type instanceof Class)
+        {
+            if (((Class) type).isPrimitive())
+            {
+                return getPrimitiveWrapper((Class) type);
+            }
+            return (Class) type;
+        }
+
+        if (type instanceof ParameterizedType)
+        {
+            return getRawPrimitiveType(((ParameterizedType) type).getRawType());
+        }
+
+        return null;
+    }
+}

Added: aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/utils/generics/GenericsUtil.java
URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/utils/generics/GenericsUtil.java?rev=1822706&view=auto
==============================================================================
--- aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/utils/generics/GenericsUtil.java (added)
+++ aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/utils/generics/GenericsUtil.java Tue Jan 30 22:05:17 2018
@@ -0,0 +1,1154 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.blueprint.utils.generics;
+
+
+import java.lang.reflect.*;
+import java.util.*;
+
+/**
+ * Utility classes for generic type operations.
+ */
+public final class GenericsUtil
+{
+    public static boolean satisfiesDependency(boolean isDelegateOrEvent, boolean isProducer, Type injectionPointType, Type beanType)
+    {
+        if (beanType instanceof TypeVariable || beanType instanceof WildcardType || beanType instanceof GenericArrayType)
+        {
+            return isAssignableFrom(isDelegateOrEvent, isProducer, injectionPointType, beanType);
+        }
+        else
+        {
+            Type injectionPointRawType = injectionPointType instanceof ParameterizedType? ((ParameterizedType)injectionPointType).getRawType(): injectionPointType;
+            Type beanRawType = beanType instanceof ParameterizedType? ((ParameterizedType)beanType).getRawType(): beanType;
+            
+            if  (ClassUtil.isSame(injectionPointRawType, beanRawType))
+            {
+                return isAssignableFrom(isDelegateOrEvent, isProducer, injectionPointType, beanType);
+            }
+        }
+
+        return false;
+    }
+
+    public static boolean satisfiesDependencyRaw(boolean isDelegateOrEvent, boolean isProducer, Type injectionPointType, Type beanType)
+    {
+        if (beanType instanceof TypeVariable || beanType instanceof WildcardType || beanType instanceof GenericArrayType)
+        {
+            return isAssignableFrom(isDelegateOrEvent, isProducer, injectionPointType, beanType);
+        }
+        else
+        {
+            Type injectionPointRawType = injectionPointType instanceof ParameterizedType? ((ParameterizedType)injectionPointType).getRawType(): injectionPointType;
+            Type beanRawType = beanType instanceof ParameterizedType? ((ParameterizedType)beanType).getRawType(): beanType;
+
+            if  (ClassUtil.isSame(injectionPointRawType, beanRawType))
+            {
+                return isAssignableFrom(isDelegateOrEvent, isProducer, injectionPointRawType, beanRawType);
+            }
+            else
+            {
+                Class bean = (Class) beanType;
+                if (bean.getSuperclass() != null && ClassUtil.isRawClassEquals(injectionPointType, bean.getSuperclass()))
+                {
+                    return true;
+                }
+
+                Class<?>[] interfaces = bean.getInterfaces();
+                if (interfaces == null || interfaces.length == 0)
+                {
+                    return false;
+                }
+
+                for (Class<?> clazz : interfaces)
+                {
+                    if (ClassUtil.isRawClassEquals(injectionPointType, clazz))
+                    {
+                        return true;
+                    }
+                }
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * 5.2.3 and 5.2.4
+     */
+    public static boolean isAssignableFrom(boolean isDelegateOrEvent, boolean isProducer, Type requiredType, Type beanType)
+    {
+        if (requiredType instanceof Class)
+        {
+            return isAssignableFrom(isDelegateOrEvent, (Class<?>)requiredType, beanType);
+        }
+        else if (requiredType instanceof ParameterizedType)
+        {
+            return isAssignableFrom(isDelegateOrEvent, isProducer, (ParameterizedType)requiredType, beanType);
+        }
+        else if (requiredType instanceof TypeVariable)
+        {
+            return isAssignableFrom(isDelegateOrEvent, (TypeVariable<?>)requiredType, beanType);
+        }
+        else if (requiredType instanceof GenericArrayType)
+        {
+            return Class.class.isInstance(beanType) && Class.class.cast(beanType).isArray()
+                    && isAssignableFrom(isDelegateOrEvent, (GenericArrayType)requiredType, beanType);
+        }
+        else if (requiredType instanceof WildcardType)
+        {
+            return isAssignableFrom(isDelegateOrEvent, (WildcardType)requiredType, beanType);
+        }
+        else
+        {
+            throw new IllegalArgumentException("Unsupported type " + requiredType.getClass());
+        }
+    }
+
+    private static boolean isAssignableFrom(boolean isDelegateOrEvent, Class<?> injectionPointType, Type beanType)
+    {
+        if (beanType instanceof Class)
+        {
+            return isAssignableFrom(injectionPointType, (Class<?>)beanType);
+        }
+        else if (beanType instanceof TypeVariable)
+        {
+            return isAssignableFrom(isDelegateOrEvent, injectionPointType, (TypeVariable<?>)beanType);
+        }
+        else if (beanType instanceof ParameterizedType)
+        {
+            return isAssignableFrom(isDelegateOrEvent, injectionPointType, (ParameterizedType)beanType);
+        }
+        else if (beanType instanceof GenericArrayType)
+        {
+            return isAssignableFrom(isDelegateOrEvent, injectionPointType, (GenericArrayType)beanType);
+        }
+        else if (beanType instanceof WildcardType)
+        {
+            return isAssignableFrom(isDelegateOrEvent, (Type)injectionPointType, (WildcardType)beanType);
+        }
+        else
+        {
+            throw new IllegalArgumentException("Unsupported type " + injectionPointType.getClass());
+        }
+    }
+
+    private static boolean isAssignableFrom(Class<?> injectionPointType, Class<?> beanType)
+    {
+        return ClassUtil.isClassAssignableFrom(injectionPointType, beanType);
+    }
+
+    private static boolean isAssignableFrom(boolean isDelegateOrEvent, Class<?> injectionPointType, TypeVariable<?> beanType)
+    {
+        for (Type bounds: beanType.getBounds())
+        {
+            if (isAssignableFrom(isDelegateOrEvent, injectionPointType, bounds))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * CDI Spec. 5.2.4: "A parameterized bean type is considered assignable to a raw required type
+     * if the raw generics are identical and all type parameters of the bean type are either unbounded type variables or java.lang.Object."
+     */
+    private static boolean isAssignableFrom(boolean isDelegateOrEvent, Class<?> injectionPointType, ParameterizedType beanType)
+    {
+        if (beanType.getRawType() != injectionPointType)
+        {
+            return false; //raw generics don't match
+        }
+
+        if (isDelegateOrEvent)
+        {
+            // for delegate and events we match 'in reverse' kind off
+            // @Observes ProcessInjectionPoint<?, Instance> does also match Instance<SomeBean>
+            return isAssignableFrom(true, injectionPointType, beanType.getRawType());
+        }
+
+        for (Type typeArgument: beanType.getActualTypeArguments())
+        {
+            if (typeArgument == Object.class)
+            {
+                continue;
+            }
+            if (!(typeArgument instanceof TypeVariable))
+            {
+                return false; //neither object nor type variable
+            }
+            TypeVariable<?> typeVariable = (TypeVariable<?>)typeArgument;
+            for (Type bounds: typeVariable.getBounds())
+            {
+                if (bounds != Object.class)
+                {
+                    return false; //bound type variable
+                }
+            }
+        }
+        return true;
+    }
+
+    private static boolean isAssignableFrom(boolean isDelegateOrEvent, Class<?> injectionPointType, GenericArrayType beanType)
+    {
+        return injectionPointType.isArray() && isAssignableFrom(isDelegateOrEvent, injectionPointType.getComponentType(), beanType.getGenericComponentType());
+    }
+    
+    private static boolean isAssignableFrom(boolean isDelegateOrEvent, Type injectionPointType, WildcardType beanType)
+    {
+        for (Type bounds: beanType.getLowerBounds())
+        {
+            if (!isAssignableFrom(isDelegateOrEvent, false, bounds, injectionPointType))
+            {
+                return false;
+            }
+        }
+        for (Type bounds: beanType.getUpperBounds())
+        {
+            if (isAssignableFrom(isDelegateOrEvent, false, injectionPointType, bounds))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static boolean isAssignableFrom(boolean isDelegateOrEvent, boolean isProducer, ParameterizedType injectionPointType, Type beanType)
+    {
+        if (beanType instanceof Class)
+        {
+            return isAssignableFrom(isDelegateOrEvent, isProducer, injectionPointType, (Class<?>)beanType);
+        }
+        else if (beanType instanceof TypeVariable)
+        {
+            return isAssignableFrom(isDelegateOrEvent, isProducer, injectionPointType, (TypeVariable<?>)beanType);
+        }
+        else if (beanType instanceof ParameterizedType)
+        {
+            return isAssignableFrom(isDelegateOrEvent, injectionPointType, (ParameterizedType)beanType);
+        }
+        else if (beanType instanceof WildcardType)
+        {
+            return isAssignableFrom(isDelegateOrEvent, injectionPointType, (WildcardType)beanType);
+        }
+        else if (beanType instanceof GenericArrayType)
+        {
+            return false;
+        }
+        else
+        {
+            throw new IllegalArgumentException("Unsupported type " + beanType.getClass());
+        }
+    }
+
+    private static boolean isAssignableFrom(boolean isDelegateOrEvent, boolean isProducer, ParameterizedType injectionPointType, Class<?> beanType)
+    {
+        Class<?> rawInjectionPointType = getRawType(injectionPointType);
+        if (rawInjectionPointType.equals(beanType))
+        {
+            if (isProducer)
+            {
+                for (final Type t : injectionPointType.getActualTypeArguments())
+                {
+                    if (!TypeVariable.class.isInstance(t) || !isNotBound(TypeVariable.class.cast(t).getBounds()))
+                    {
+                        if (!Class.class.isInstance(t) || Object.class != t)
+                        {
+                            return false;
+                        }
+                    }
+                }
+            }
+            return true;
+        }
+        if (!rawInjectionPointType.isAssignableFrom(beanType))
+        {
+            return false;
+        }
+        if (beanType.getSuperclass() != null && isAssignableFrom(isDelegateOrEvent, isProducer, injectionPointType, beanType.getGenericSuperclass()))
+        {
+            return true;
+        }
+        for (Type genericInterface: beanType.getGenericInterfaces())
+        {
+            if (isAssignableFrom(isDelegateOrEvent, isProducer, injectionPointType, genericInterface))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static boolean isAssignableFrom(boolean isDelegateOrEvent, boolean isProducer, ParameterizedType injectionPointType, TypeVariable<?> beanType)
+    {
+        final Type[] types = beanType.getBounds();
+        if (isNotBound(types))
+        {
+            return true;
+        }
+        for (final Type bounds: types)
+        {
+            if (isAssignableFrom(isDelegateOrEvent, isProducer, injectionPointType, bounds))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * CDI Spec. 5.2.4
+     */
+    private static boolean isAssignableFrom(boolean isDelegateOrEvent, ParameterizedType injectionPointType, ParameterizedType beanType)
+    {
+        if (injectionPointType.getRawType() != beanType.getRawType())
+        {
+            return false;
+        }
+        boolean swapParams = !isDelegateOrEvent;
+        Type[] injectionPointTypeArguments = injectionPointType.getActualTypeArguments();
+        Type[] beanTypeArguments = beanType.getActualTypeArguments();
+        for (int i = 0; i < injectionPointTypeArguments.length; i++)
+        {
+            Type injectionPointTypeArgument = injectionPointTypeArguments[i];
+            Type beanTypeArgument = beanTypeArguments[i];
+
+            // for this special case it's actually an 'assignable to', thus we swap the params, see CDI-389
+            // but this special rule does not apply to Delegate injection points...
+            if (swapParams &&
+                (injectionPointTypeArgument instanceof Class || injectionPointTypeArgument instanceof TypeVariable) &&
+                beanTypeArgument instanceof TypeVariable)
+            {
+                final Type[] bounds = ((TypeVariable<?>) beanTypeArgument).getBounds();
+                final boolean isNotBound = isNotBound(bounds);
+                if (!isNotBound)
+                {
+                    for (final Type upperBound : bounds)
+                    {
+                        if (!isAssignableFrom(true, false, upperBound, injectionPointTypeArgument))
+                        {
+                            return false;
+                        }
+                    }
+                }
+            }
+            else if (swapParams && injectionPointTypeArgument instanceof TypeVariable)
+            {
+                return false;
+            }
+            else if (isDelegateOrEvent && injectionPointTypeArgument instanceof Class && beanTypeArgument instanceof Class)
+            {
+                // if no wildcard type was given then we require a real exact match.
+                return injectionPointTypeArgument.equals(beanTypeArgument);
+
+            }
+            else if (!isAssignableFrom(isDelegateOrEvent, false, injectionPointTypeArgument, beanTypeArgument))
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private static boolean isNotBound(final Type... bounds)
+    {
+        return bounds == null || bounds.length == 0 || (bounds.length == 1 && Object.class == bounds[0]);
+    }
+
+    private static boolean isAssignableFrom(boolean isDelegateOrEvent, TypeVariable<?> injectionPointType, Type beanType)
+    {
+        for (Type bounds: injectionPointType.getBounds())
+        {
+            if (!isAssignableFrom(isDelegateOrEvent, false, bounds, beanType))
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    // rules are a bit different when in an array so we handle ParameterizedType manually (not reusing isAssignableFrom)
+    private static boolean isAssignableFrom(boolean isDelegateOrEvent, GenericArrayType injectionPointType, Type beanType)
+    {
+        final Type genericComponentType = injectionPointType.getGenericComponentType();
+        final Class componentType = Class.class.cast(beanType).getComponentType();
+        if (Class.class.isInstance(genericComponentType))
+        {
+            return Class.class.cast(genericComponentType).isAssignableFrom(componentType);
+        }
+        if (ParameterizedType.class.isInstance(genericComponentType))
+        {
+            return isAssignableFrom(isDelegateOrEvent, false, ParameterizedType.class.cast(genericComponentType).getRawType(), componentType);
+        }
+        return isAssignableFrom(isDelegateOrEvent, false, genericComponentType, componentType);
+    }
+
+    private static boolean isAssignableFrom(boolean isDelegateOrEvent, WildcardType injectionPointType, Type beanType)
+    {
+        if (beanType instanceof TypeVariable)
+        {
+            return isAssignableFrom(isDelegateOrEvent, injectionPointType, (TypeVariable<?>)beanType);
+        }
+        for (Type bounds: injectionPointType.getLowerBounds())
+        {
+            if (!isAssignableFrom(isDelegateOrEvent, false, beanType, bounds))
+            {
+                return false;
+            }
+        }
+        for (Type bounds: injectionPointType.getUpperBounds())
+        {
+            Set<Type> beanTypeClosure = getTypeClosure(beanType);
+            boolean isAssignable = false;
+            for (Type beanSupertype: beanTypeClosure)
+            {
+                if (isAssignableFrom(isDelegateOrEvent, false, bounds, beanSupertype)
+                    || (Class.class.isInstance(bounds)
+                        && ParameterizedType.class.isInstance(beanSupertype)
+                        && bounds == ParameterizedType.class.cast(beanSupertype).getRawType()))
+                {
+                    isAssignable = true;
+                    break;
+                }
+            }
+            if (!isAssignable)
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+    
+    /**
+     * CDI 1.1 Spec. 5.2.4, third bullet point
+     */
+    private static boolean isAssignableFrom(boolean isDelegateOrEvent, WildcardType injectionPointType, TypeVariable<?> beanType)
+    {
+        for (Type upperBound: injectionPointType.getUpperBounds())
+        {
+            for (Type bound: beanType.getBounds())
+            {
+                if (!isAssignableFrom(isDelegateOrEvent, false, upperBound, bound) && !isAssignableFrom(isDelegateOrEvent, false, bound, upperBound))
+                {
+                    return false;
+                }
+            }
+        }
+        for (Type lowerBound: injectionPointType.getLowerBounds())
+        {
+            for (Type bound: beanType.getBounds())
+            {
+                if (!isAssignableFrom(isDelegateOrEvent, false, bound, lowerBound))
+                {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+    
+    /**
+     * @return <tt>true</tt>, if the specified type declaration contains an unresolved type variable.
+     */
+    public static boolean containsTypeVariable(Type type)
+    {
+        if (type instanceof Class)
+        {
+            return false;
+        }
+        else if (type instanceof TypeVariable)
+        {
+            return true;
+        }
+        else if (type instanceof ParameterizedType)
+        {
+            ParameterizedType parameterizedType = (ParameterizedType)type;
+            return containTypeVariable(parameterizedType.getActualTypeArguments());
+        }
+        else if (type instanceof WildcardType)
+        {
+            WildcardType wildcardType = (WildcardType)type;
+            return containTypeVariable(wildcardType.getUpperBounds()) || containTypeVariable(wildcardType.getLowerBounds());
+        }
+        else if (type instanceof GenericArrayType)
+        {
+            GenericArrayType arrayType = (GenericArrayType)type;
+            return containsTypeVariable(arrayType.getGenericComponentType());
+        }
+        else
+        {
+            throw new IllegalArgumentException("Unsupported type " + type.getClass().getName());
+        }
+
+    }
+    
+    public static boolean containTypeVariable(Collection<? extends Type> types)
+    {
+        return containTypeVariable(types.toArray(new Type[types.size()]));
+    }
+    
+    public static boolean containTypeVariable(Type[] types)
+    {
+        for (Type type: types)
+        {
+            if (containsTypeVariable(type))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     *
+     * @param type to check
+     *
+     * @return {@code true} if the given type contains a {@link WildcardType}
+     *         {@code false} otherwise
+     */
+    public static boolean containsWildcardType(Type type)
+    {
+        if (!(type instanceof ParameterizedType))
+        {
+            return false;
+        }
+
+        for (Type typeArgument : getParameterizedType(type).getActualTypeArguments())
+        {
+            if (ClassUtil.isParametrizedType(typeArgument))
+            {
+                if (containsWildcardType(typeArgument))
+                {
+                    return true;
+                }
+            }
+            else
+            {
+                if (ClassUtil.isWildCardType(typeArgument))
+                {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+
+    /**
+     * Resolves the actual type of the specified field for the type hierarchy specified by the given subclass
+     */
+    public static Type resolveType(Class<?> subclass, Field field)
+    {
+        return resolveType(field.getGenericType(), subclass, newSeenList());
+    }
+
+    /**
+     * Resolves the actual return type of the specified method for the type hierarchy specified by the given subclass
+     */
+    public static Type resolveReturnType(Class<?> subclass, Method method)
+    {
+        return resolveType(method.getGenericReturnType(), subclass, newSeenList());
+    }
+
+    /**
+     * Resolves the actual parameter generics of the specified constructor for the type hierarchy specified by the given subclass
+     */
+    public static Type[] resolveParameterTypes(Class<?> subclass, Constructor<?> constructor)
+    {
+        return resolveTypes(constructor.getGenericParameterTypes(), subclass);
+    }
+
+    /**
+     * Resolves the actual parameter generics of the specified method for the type hierarchy specified by the given subclass
+     */
+    public static Type[] resolveParameterTypes(Class<?> subclass, Method method)
+    {
+        return resolveTypes(method.getGenericParameterTypes(), subclass);
+    }
+
+    /**
+     * Resolves the actual type of the specified type for the type hierarchy specified by the given subclass
+     */
+    public static Type resolveType(Type type, Class<?> subclass, Member member)
+    {
+        return resolveType(type, subclass, newSeenList());
+    }
+
+    public static Type resolveType(Type type, Class<?> subclass, Member member, Collection<TypeVariable<?>> seen)
+    {
+        return resolveType(type, subclass, seen);
+    }
+
+    public static Type resolveType(Type type, Type actualType, Collection<TypeVariable<?>> seen)
+    {
+        if (type instanceof Class)
+        {
+            return type;
+        }
+        else if (type instanceof ParameterizedType)
+        {
+            ParameterizedType parameterizedType = (ParameterizedType)type;
+
+            Type[] resolvedTypeArguments;
+            if (Enum.class.equals(parameterizedType.getRawType()))
+            {
+                // Enums derive from themselves, which would create an infinite loop
+                // we directly escape the loop if we detect this.
+                resolvedTypeArguments = new Type[]{new OwbWildcardTypeImpl(new Type[]{Enum.class}, ClassUtil.NO_TYPES)};
+            }
+            else
+            {
+                resolvedTypeArguments = resolveTypes(parameterizedType.getActualTypeArguments(), actualType, seen);
+
+            }
+
+            return new OwbParametrizedTypeImpl(parameterizedType.getOwnerType(), parameterizedType.getRawType(), resolvedTypeArguments);
+        }
+        else if (type instanceof TypeVariable)
+        {
+            TypeVariable<?> variable = (TypeVariable<?>)type;
+            return resolveTypeVariable(variable, actualType, seen);
+        }
+        else if (type instanceof WildcardType)
+        {
+            WildcardType wildcardType = (WildcardType)type;
+            Type[] upperBounds = resolveTypes(wildcardType.getUpperBounds(), actualType, seen);
+            Type[] lowerBounds = resolveTypes(wildcardType.getLowerBounds(), actualType, seen);
+            return new OwbWildcardTypeImpl(upperBounds, lowerBounds);
+        }
+        else if (type instanceof GenericArrayType)
+        {
+            GenericArrayType arrayType = (GenericArrayType)type;
+            return createArrayType(resolveType(arrayType.getGenericComponentType(), actualType, seen));
+        }
+        else
+        {
+            throw new IllegalArgumentException("Unsupported type " + type.getClass().getName());
+        }
+    }
+    
+    public static Type[] resolveTypes(Type[] types, Type actualType, Collection<TypeVariable<?>> seen)
+    {
+        Type[] resolvedTypeArguments = new Type[types.length];
+        for (int i = 0; i < types.length; i++)
+        {
+            final Type type = resolveType(types[i], actualType, seen);
+            if (type != null) // means a stackoverflow was avoided, just keep what we have
+            {
+                resolvedTypeArguments[i] = type;
+            }
+        }
+        return resolvedTypeArguments;
+    }
+
+    public static Type[] resolveTypes(Type[] types, Type actualType)
+    {
+        Type[] resolvedTypeArguments = new Type[types.length];
+        for (int i = 0; i < types.length; i++)
+        {
+            resolvedTypeArguments[i] = resolveType(types[i], actualType, newSeenList());
+        }
+        return resolvedTypeArguments;
+    }
+
+    public static Set<Type> getTypeClosure(Class<?> type)
+    {
+        return getTypeClosure(type, type);
+    }
+
+    public static Set<Type> getTypeClosure(Type actualType)
+    {
+        return getTypeClosure(actualType, actualType);
+    }
+
+    /**
+     * Returns the type closure for the specified parameters.
+     * <h3>Example 1:</h3>
+     * <p>
+     * Take the following classes:
+     * </p>
+     * <code>
+     * public class Foo<T> {
+     *   private T t;
+     * }
+     * public class Bar extends Foo<Number> {
+     * }
+     * </code>
+     * <p>
+     * To get the type closure of T in the context of Bar (which is {Number.class, Object.class}), you have to call this method like
+     * </p>
+     * <code>
+     * GenericUtil.getTypeClosure(Foo.class.getDeclaredField("t").getType(), Bar.class, Foo.class);
+     * </code>
+     * <h3>Example 2:</h3>
+     * <p>
+     * Take the following classes:
+     * </p>
+     * <code>
+     * public class Foo<T> {
+     *   private T t;
+     * }
+     * public class Bar<T> extends Foo<T> {
+     * }
+     * </code>
+     * <p>
+     * To get the type closure of Bar<T> in the context of Foo<Number> (which are besides Object.class the <tt>ParameterizedType</tt>s Bar<Number> and Foo<Number>),
+     * you have to call this method like
+     * </p>
+     * <code>
+     * GenericUtil.getTypeClosure(Foo.class, new TypeLiteral<Foo<Number>>() {}.getType(), Bar.class);
+     * </code>
+     * 
+     * @param type the type to get the closure for
+     * @param actualType the context to bind type variables
+     * @return the type closure
+     */
+    public static Set<Type> getTypeClosure(Type type, Type actualType)
+    {
+        Class<?> rawType = getRawType(type);
+        Class<?> actualRawType = getRawType(actualType);
+        if (rawType.isAssignableFrom(actualRawType) && rawType != actualRawType)
+        {
+            return getTypeClosure(actualType, type);
+        }
+        if (hasTypeParameters(type))
+        {
+            type = getParameterizedType(type);
+        }
+        return getDirectTypeClosure(type, actualType);
+    }
+
+    public static Set<Type> getDirectTypeClosure(final Type type, final Type actualType)
+    {
+        Set<Type> typeClosure = new HashSet<Type>();
+        typeClosure.add(Object.class);
+        fillTypeHierarchy(typeClosure, type, actualType);
+        return typeClosure;
+    }
+
+    private static void fillTypeHierarchy(Set<Type> set, Type type, Type actualType)
+    {
+        if (type == null)
+        {
+           return;
+        }
+        Type resolvedType = GenericsUtil.resolveType(type, actualType, newSeenList());
+        set.add(resolvedType);
+        Class<?> resolvedClass = GenericsUtil.getRawType(resolvedType, actualType);
+        if (resolvedClass.getSuperclass() != null)
+        {
+            fillTypeHierarchy(set, resolvedClass.getGenericSuperclass(), resolvedType);
+        }
+        for (Type interfaceType: resolvedClass.getGenericInterfaces())
+        {
+            fillTypeHierarchy(set, interfaceType, resolvedType);
+        }
+    }
+
+    private static Collection<TypeVariable<?>> newSeenList()
+    {
+        return new ArrayList<TypeVariable<?>>();
+    }
+
+    public static boolean hasTypeParameters(Type type)
+    {
+        if (type instanceof Class)
+        {
+            Class<?> classType = (Class<?>)type;
+            return classType.getTypeParameters().length > 0;
+        }
+        return false;
+    }
+
+    public static ParameterizedType getParameterizedType(Type type)
+    {
+        if (type instanceof ParameterizedType)
+        {
+            return (ParameterizedType)type;
+        }
+        else if (type instanceof Class)
+        {
+            Class<?> classType = (Class<?>)type;
+            return new OwbParametrizedTypeImpl(classType.getDeclaringClass(), classType, classType.getTypeParameters());
+        }
+        else
+        {
+            throw new IllegalArgumentException(type.getClass().getSimpleName() + " is not supported");
+        }
+    }
+
+    public static <T> Class<T> getRawType(Type type)
+    {
+        return getRawType(type, null);
+    }
+
+    static <T> Class<T> getRawType(Type type, Type actualType)
+    {
+        if (type instanceof Class)
+        {
+            return (Class<T>)type;
+        }
+        else if (type instanceof ParameterizedType)
+        {
+            ParameterizedType parameterizedType = (ParameterizedType)type;
+            return getRawType(parameterizedType.getRawType(), actualType);
+        }
+        else if (type instanceof TypeVariable)
+        {
+            TypeVariable<?> typeVariable = (TypeVariable<?>)type;
+            Type mostSpecificType = getMostSpecificType(getRawTypes(typeVariable.getBounds(), actualType), typeVariable.getBounds());
+            return getRawType(mostSpecificType, actualType);
+        }
+        else if (type instanceof WildcardType)
+        {
+            WildcardType wildcardType = (WildcardType)type;
+            Type mostSpecificType = getMostSpecificType(getRawTypes(wildcardType.getUpperBounds(), actualType), wildcardType.getUpperBounds());
+            return getRawType(mostSpecificType, actualType);
+        }
+        else if (type instanceof GenericArrayType)
+        {
+            GenericArrayType arrayType = (GenericArrayType)type;
+            return getRawType(createArrayType(getRawType(arrayType.getGenericComponentType(), actualType)), actualType);
+        }
+        else
+        {
+            throw new IllegalArgumentException("Unsupported type " + type.getClass().getName());
+        }
+    }
+
+    private static <T> Class<T>[] getRawTypes(Type[] types)
+    {
+        return getRawTypes(types, null);
+    }
+
+    private static <T> Class<T>[] getRawTypes(Type[] types, Type actualType)
+    {
+        Class<T>[] rawTypes = new Class[types.length];
+        for (int i = 0; i < types.length; i++)
+        {
+            rawTypes[i] = getRawType(types[i], actualType);
+        }
+        return rawTypes;
+    }
+
+    private static Type getMostSpecificType(Class<?>[] types, Type[] genericTypes)
+    {
+        Class<?> mostSpecificType = types[0];
+        int mostSpecificIndex = 0;
+        for (int i = 0; i < types.length; i++) 
+        {
+            if (mostSpecificType.isAssignableFrom(types[i]))
+            {
+                mostSpecificType = types[i];
+                mostSpecificIndex = i;
+            }
+        }
+        return genericTypes[mostSpecificIndex];
+    }
+
+    private static Class<?>[] getClassTypes(Class<?>[] rawTypes)
+    {
+        List<Class<?>> classTypes = new ArrayList<Class<?>>();
+        for (Class<?> rawType : rawTypes)
+        {
+            if (!rawType.isInterface())
+            {
+                classTypes.add(rawType);
+            }
+        }
+        return classTypes.toArray(new Class[classTypes.size()]);
+    }
+
+    private static Type resolveTypeVariable(TypeVariable<?> variable, Type actualType, Collection<TypeVariable<?>> seen)
+    {
+        if (actualType == null)
+        {
+            return variable;
+        }
+        Class<?> declaringClass = getDeclaringClass(variable.getGenericDeclaration());
+        Class<?> actualClass = getRawType(actualType);
+        if (actualClass == declaringClass)
+        {
+            return resolveTypeVariable(variable, variable.getGenericDeclaration(), getParameterizedType(actualType), seen);
+        }
+        else if (actualClass.isAssignableFrom(declaringClass))
+        {
+            Class<?> directSubclass = getDirectSubclass(declaringClass, actualClass);
+            Type[] typeArguments = resolveTypeArguments(directSubclass, actualType);
+            Type directSubtype = new OwbParametrizedTypeImpl(directSubclass.getDeclaringClass(), directSubclass, typeArguments);
+            return resolveTypeVariable(variable, directSubtype, seen);
+        }
+        else // if (declaringClass.isAssignableFrom(actualClass))
+        { 
+            Type genericSuperclass = getGenericSuperclass(actualClass, declaringClass);
+            if (genericSuperclass == null)
+            {
+                return variable;
+            }
+            else if (genericSuperclass instanceof Class)
+            {
+                // special handling for type erasure
+                Class<?> superclass = (Class<?>)genericSuperclass;
+                genericSuperclass = new OwbParametrizedTypeImpl(superclass.getDeclaringClass(), superclass, getRawTypes(superclass.getTypeParameters()));
+            }
+            else
+            {
+                ParameterizedType genericSupertype = getParameterizedType(genericSuperclass);
+                Type[] typeArguments = resolveTypeArguments(getParameterizedType(actualType), genericSupertype);
+                genericSuperclass = new OwbParametrizedTypeImpl(genericSupertype.getOwnerType(), genericSupertype.getRawType(), typeArguments);
+            }
+            Type resolvedType = resolveTypeVariable(variable, genericSuperclass, seen);
+            if (resolvedType instanceof TypeVariable)
+            {
+                TypeVariable<?> resolvedTypeVariable = (TypeVariable<?>)resolvedType;
+                TypeVariable<?>[] typeParameters = actualClass.getTypeParameters();
+                for (int i = 0; i < typeParameters.length; i++)
+                {
+                    if (typeParameters[i].getName().equals(resolvedTypeVariable.getName()))
+                    {
+                        resolvedType = getParameterizedType(actualType).getActualTypeArguments()[i];
+                        break;
+                    }
+                }
+            }
+            return resolvedType;
+        }
+    }
+
+    private static Class<?> getDeclaringClass(GenericDeclaration declaration)
+    {
+        if (declaration instanceof Class)
+        {
+            return (Class<?>)declaration;
+        }
+        else if (declaration instanceof Member)
+        {
+            return ((Member)declaration).getDeclaringClass();
+        }
+        else
+        {
+            throw new IllegalArgumentException("Unsupported type " + declaration.getClass());
+        }
+    }
+
+    private static Type resolveTypeVariable(TypeVariable<?> variable, GenericDeclaration declaration, ParameterizedType type,
+                                            Collection<TypeVariable<?>> seen)
+    {
+        int index = getIndex(declaration, variable);
+        if (declaration instanceof Class)
+        {
+            if (index >= 0)
+            {
+                return type.getActualTypeArguments()[index];
+            }
+            else
+            {
+                index = getIndex(type, variable);
+                if (index >= 0)
+                {
+                    return declaration.getTypeParameters()[index];
+                }
+            }
+        }
+        else
+        {
+            if (seen.contains(variable))
+            {
+                return null;
+            }
+            seen.add(variable);
+
+            Type[] resolvedBounds = resolveTypes(declaration.getTypeParameters()[index].getBounds(), type, seen);
+            return OwbTypeVariableImpl.createTypeVariable(variable, resolvedBounds);
+        }
+        return variable;
+    }
+    
+    private static int getIndex(GenericDeclaration declaration, TypeVariable<?> variable)
+    {
+        Type[] typeParameters = declaration.getTypeParameters();
+        for (int i = 0; i < typeParameters.length; i++)
+        {
+            if (typeParameters[i] instanceof TypeVariable)
+            {
+                TypeVariable<?> variableArgument = (TypeVariable<?>)typeParameters[i];
+                if (variableArgument.getName().equals(variable.getName()))
+                {
+                    return i;
+                }
+            }
+        }
+        return -1;
+    }
+    
+    private static int getIndex(ParameterizedType type, TypeVariable<?> variable)
+    {
+        Type[] actualTypeArguments = type.getActualTypeArguments();
+        for (int i = 0; i < actualTypeArguments.length; i++)
+        {
+            if (actualTypeArguments[i] instanceof TypeVariable)
+            {
+                TypeVariable<?> variableArgument = (TypeVariable<?>)actualTypeArguments[i];
+                if (variableArgument.getName().equals(variable.getName()))
+                {
+                    return i;
+                }
+            }
+        }
+        return -1;
+    }
+
+    private static Class<?> getDirectSubclass(Class<?> declaringClass, Class<?> actualClass)
+    {
+        if (actualClass.isInterface())
+        {
+            Class<?> subclass = declaringClass;
+            for (Class<?> iface: declaringClass.getInterfaces())
+            {
+                if (iface == actualClass)
+                {
+                    return subclass;
+                }
+                if (actualClass.isAssignableFrom(iface))
+                {
+                    subclass = iface;
+                }
+                else
+                {
+                    subclass = declaringClass.getSuperclass();
+                }
+            }
+            return getDirectSubclass(subclass, actualClass);
+        }
+        else
+        {
+            Class<?> directSubclass = declaringClass;
+            while (directSubclass.getSuperclass() != actualClass)
+            {
+                directSubclass = directSubclass.getSuperclass();
+            }
+            return directSubclass;
+        }
+    }
+
+    private static Type getGenericSuperclass(Class<?> subclass, Class<?> superclass)
+    {
+        if (!superclass.isInterface())
+        {
+            return subclass.getGenericSuperclass();
+        }
+        else
+        {
+            for (Type genericInterface: subclass.getGenericInterfaces())
+            {
+                if (getRawType(genericInterface) == superclass)
+                {
+                    return genericInterface;
+                }
+            }
+        }
+        return superclass;
+    }
+
+    private static Type[] resolveTypeArguments(Class<?> subclass, Type supertype)
+    {
+        if (supertype instanceof ParameterizedType)
+        {
+            ParameterizedType parameterizedSupertype = (ParameterizedType)supertype;
+            return resolveTypeArguments(subclass, parameterizedSupertype);
+        }
+        else
+        {
+            return subclass.getTypeParameters();
+        }
+    }
+
+    private static Type[] resolveTypeArguments(Class<?> subclass, ParameterizedType parameterizedSupertype)
+    {
+        Type genericSuperclass = getGenericSuperclass(subclass, getRawType(parameterizedSupertype));
+        if (!(genericSuperclass instanceof ParameterizedType))
+        {
+            return subclass.getTypeParameters();
+        }
+        ParameterizedType parameterizedSuperclass = (ParameterizedType)genericSuperclass;
+        Type[] typeParameters = subclass.getTypeParameters();
+        Type[] actualTypeArguments = parameterizedSupertype.getActualTypeArguments();
+        return resolveTypeArguments(parameterizedSuperclass, typeParameters, actualTypeArguments);
+    }
+
+    private static Type[] resolveTypeArguments(ParameterizedType subtype, ParameterizedType parameterizedSupertype)
+    {
+        return resolveTypeArguments(getParameterizedType(getRawType(subtype)), parameterizedSupertype.getActualTypeArguments(), subtype.getActualTypeArguments());
+    }
+
+    private static Type[] resolveTypeArguments(ParameterizedType parameterizedType, Type[] typeParameters, Type[] actualTypeArguments)
+    {
+        Type[] resolvedTypeArguments = new Type[typeParameters.length];
+        for (int i = 0; i < typeParameters.length; i++)
+        {
+            resolvedTypeArguments[i] = resolveTypeArgument(parameterizedType, typeParameters[i], actualTypeArguments);
+        }
+        return resolvedTypeArguments;
+    }
+
+    private static Type resolveTypeArgument(ParameterizedType parameterizedType, Type typeParameter, Type[] actualTypeArguments)
+    {
+        if (typeParameter instanceof TypeVariable)
+        {
+            TypeVariable<?> variable = (TypeVariable<?>)typeParameter;
+            int index = getIndex(parameterizedType, variable);
+            if (index == -1)
+            {
+                return typeParameter;
+            }
+            else
+            {
+                return actualTypeArguments[index];
+            }
+        }
+        else if (typeParameter instanceof GenericArrayType)
+        {
+            GenericArrayType array = (GenericArrayType)typeParameter;
+            return createArrayType(resolveTypeArgument(parameterizedType, array.getGenericComponentType(), actualTypeArguments));
+        }
+        else
+        {
+            return typeParameter;
+        }
+    }
+    
+    private static Type createArrayType(Type componentType)
+    {
+        if (componentType instanceof Class)
+        {
+            return Array.newInstance((Class<?>)componentType, 0).getClass();
+        }
+        else
+        {
+            return new OwbGenericArrayTypeImpl(componentType);
+        }
+    }
+
+    public static Type resolveType(ParameterizedType parameterizedType, Type metadataType)
+    {
+        return resolveType(parameterizedType, metadataType, newSeenList());
+    }
+}

Added: aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/utils/generics/OwbGenericArrayTypeImpl.java
URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/utils/generics/OwbGenericArrayTypeImpl.java?rev=1822706&view=auto
==============================================================================
--- aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/utils/generics/OwbGenericArrayTypeImpl.java (added)
+++ aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/utils/generics/OwbGenericArrayTypeImpl.java Tue Jan 30 22:05:17 2018
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.blueprint.utils.generics;
+
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.Type;
+
+
+public class OwbGenericArrayTypeImpl implements GenericArrayType
+{
+
+    private Type componentType;
+    
+    public OwbGenericArrayTypeImpl(Type componentType)
+    {
+        this.componentType = componentType;
+    }
+
+    @Override
+    public Type getGenericComponentType()
+    {
+        return componentType;
+    }
+    
+    /* (non-Javadoc)
+     * @see java.lang.Object#hashCode()
+     */
+    @Override
+    public int hashCode()
+    {
+       return componentType.hashCode();
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals(Object obj)
+    {
+       if (this == obj)
+       {
+          return true;
+       }
+       else if (obj instanceof GenericArrayType)
+       {
+           return ((GenericArrayType)obj).getGenericComponentType().equals(componentType);
+       }
+       else
+       {
+          return false;
+       }
+       
+    }
+
+    public String toString()
+    {
+        return componentType + "[]";
+    }
+}

Added: aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/utils/generics/OwbParametrizedTypeImpl.java
URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/utils/generics/OwbParametrizedTypeImpl.java?rev=1822706&view=auto
==============================================================================
--- aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/utils/generics/OwbParametrizedTypeImpl.java (added)
+++ aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/utils/generics/OwbParametrizedTypeImpl.java Tue Jan 30 22:05:17 2018
@@ -0,0 +1,138 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.blueprint.utils.generics;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.Arrays;
+
+/**
+ * Custom parametrized type implementation.
+ * @version $Rev: 1621935 $ $Date: 2014-09-02 09:07:32 +0200 (Tue, 02 Sep 2014) $
+ *
+ */
+public class OwbParametrizedTypeImpl implements ParameterizedType
+{
+    /**Owner type*/
+    private final Type owner;
+    
+    /**Raw type*/
+    private final Type rawType;
+    
+    /**Actual type arguments*/
+    private final Type[] types;
+
+    /**
+     * New instance.
+     * @param owner owner
+     * @param raw raw
+     */
+    public OwbParametrizedTypeImpl(Type owner, Type raw, Type... types)
+    {
+        this.owner = owner;
+        rawType = raw;
+        this.types = types;
+    }
+    
+    @Override
+    public Type[] getActualTypeArguments()
+    {
+        return types.clone();
+    }
+    
+    @Override
+    public Type getOwnerType()
+    {
+        return owner;
+    }
+
+    @Override
+    public Type getRawType()
+    {
+        return rawType;
+    }
+
+    
+    
+    /* (non-Javadoc)
+     * @see java.lang.Object#hashCode()
+     */
+    @Override
+    public int hashCode()
+    {
+       return Arrays.hashCode(types) ^ (owner == null ? 0 : owner.hashCode()) ^ (rawType == null ? 0 : rawType.hashCode());
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals(Object obj)
+    {
+       if (this == obj)
+       {
+          return true;
+       }
+       else if (obj instanceof ParameterizedType)
+       {
+          ParameterizedType that = (ParameterizedType) obj;
+          Type thatOwnerType = that.getOwnerType();
+          Type thatRawType = that.getRawType();
+          return (owner == null ? thatOwnerType == null : owner.equals(thatOwnerType))
+                  && (rawType == null ? thatRawType == null : rawType.equals(thatRawType))
+                  && Arrays.equals(types, that.getActualTypeArguments());
+       }
+       else
+       {
+          return false;
+       }
+       
+    }
+
+    public String toString()
+    {
+        StringBuilder buffer = new StringBuilder();
+        buffer.append(((Class<?>) rawType).getName());
+        Type[] actualTypes = getActualTypeArguments();
+        if(actualTypes.length > 0)
+        {
+            buffer.append("<");
+            int length = actualTypes.length;
+            for(int i=0;i<length;i++)
+            {
+                if (actualTypes[i] instanceof Class)
+                {
+                    buffer.append(((Class<?>)actualTypes[i]).getSimpleName());
+                }
+                else
+                {
+                    buffer.append(actualTypes[i].toString());
+                }
+                if(i != actualTypes.length-1)
+                {
+                    buffer.append(", ");
+                }
+            }
+            
+            buffer.append(">");
+        }
+        
+        return buffer.toString();
+    }
+}

Added: aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/utils/generics/OwbTypeVariableImpl.java
URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/utils/generics/OwbTypeVariableImpl.java?rev=1822706&view=auto
==============================================================================
--- aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/utils/generics/OwbTypeVariableImpl.java (added)
+++ aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/utils/generics/OwbTypeVariableImpl.java Tue Jan 30 22:05:17 2018
@@ -0,0 +1,177 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.blueprint.utils.generics;
+
+import java.lang.reflect.*;
+import java.util.Arrays;
+
+
+public class OwbTypeVariableImpl
+{
+    private static final Class<?>[] TYPE_VARIABLE_TYPES = new Class<?>[]{TypeVariable.class};
+
+    /**
+     * Java TypeVariable is different in various JDK versions. Thus it is not possible to e.g.
+     * write a custom TypeVariable which works in either Java7 and Java8 as they introduced
+     * new methods in Java8 which have return generics which only exist in Java8 :(
+     *
+     * As workaround we dynamically crate a proxy to wrap this and do the delegation manually.
+     * This is of course slower, but as we do not use it often it might not have much impact.
+     *
+     * @param typeVariable
+     * @param bounds
+     * @return the typeVariable with the defined bounds.
+     */
+    public static TypeVariable createTypeVariable(TypeVariable typeVariable, Type... bounds)
+    {
+        TypeVariable tv = (TypeVariable) Proxy.newProxyInstance(OwbTypeVariableImpl.class.getClassLoader(), TYPE_VARIABLE_TYPES,
+                new OwbTypeVariableInvocationHandler(typeVariable, bounds));
+
+        return tv;
+    }
+
+
+
+    public static class OwbTypeVariableInvocationHandler implements InvocationHandler
+    {
+
+        private String name;
+        private GenericDeclaration genericDeclaration;
+        private Type[] bounds;
+
+
+        public OwbTypeVariableInvocationHandler(TypeVariable typeVariable, Type... bounds)
+        {
+            name = typeVariable.getName();
+            genericDeclaration = typeVariable.getGenericDeclaration();
+            if (bounds == null || bounds.length == 0)
+            {
+                this.bounds = typeVariable.getBounds();
+            }
+            else
+            {
+                this.bounds = bounds;
+            }
+        }
+
+
+        @Override
+        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
+        {
+            String methodName = method.getName();
+            if ("equals".equals(methodName))
+            {
+                return typeVariableEquals(args[0]);
+            }
+            else if ("hashCode".equals(methodName))
+            {
+                return typeVariableHashCode();
+            }
+            else if ("toString".equals(methodName))
+            {
+                return typeVariableToString();
+            }
+            else if ("getName".equals(methodName))
+            {
+                return getName();
+            }
+            else if ("getGenericDeclaration".equals(methodName))
+            {
+                return getGenericDeclaration();
+            }
+            else if ("getBounds".equals(methodName))
+            {
+                return getBounds();
+            }
+
+
+            // new method from java8...
+            return null;
+        }
+
+        /** method from TypeVariable */
+        public String getName()
+        {
+            return name;
+        }
+
+        /** method from TypeVariable */
+        public GenericDeclaration getGenericDeclaration()
+        {
+            return genericDeclaration;
+        }
+
+        /** method from TypeVariable */
+        public Type[] getBounds()
+        {
+            return bounds.clone();
+        }
+
+        /** method from TypeVariable */
+        public int typeVariableHashCode()
+        {
+            return Arrays.hashCode(bounds) ^ name.hashCode() ^ genericDeclaration.hashCode();
+        }
+
+        /** method from TypeVariable */
+        public boolean typeVariableEquals(Object object)
+        {
+            if (this == object)
+            {
+                return true;
+            }
+            else if (object instanceof TypeVariable)
+            {
+                TypeVariable<?> that = (TypeVariable<?>)object;
+                return name.equals(that.getName()) && genericDeclaration.equals(that.getGenericDeclaration()) && Arrays.equals(bounds, that.getBounds());
+            }
+            else
+            {
+                return false;
+            }
+
+        }
+
+        /** method from TypeVariable */
+        public String typeVariableToString()
+        {
+            StringBuilder buffer = new StringBuilder();
+            buffer.append(name);
+            if (bounds.length > 0)
+            {
+                buffer.append(" extends ");
+                boolean first = true;
+                for (Type bound: bounds)
+                {
+                    if (first)
+                    {
+                        first = false;
+                    }
+                    else
+                    {
+                        buffer.append(',');
+                    }
+                    buffer.append(' ').append(bound);
+                }
+            }
+            return buffer.toString();
+        }
+
+    }
+}