private boolean isAssignableFrom()

in commons/src/main/java/org/apache/tapestry5/commons/internal/services/GenericsResolverImpl.java [156:250]


    private boolean isAssignableFrom(Type suspectedSuperType, Type suspectedSubType)
    {
        final Class suspectedSuperClass = asClass(suspectedSuperType);
        final Class suspectedSubClass = asClass(suspectedSubType);

        // The raw types need to be compatible.
        if (!suspectedSuperClass.isAssignableFrom(suspectedSubClass))
        {
            return false;
        }

        // From this point we know that the raw types are assignable.
        // We need to figure out what the generic parameters in the targetClass are
        // as they pertain to the sourceType.

        if (suspectedSuperType instanceof WildcardType)
        {
            // ? extends Number
            // needs to match all the bounds (there will only be upper bounds or lower bounds
            for (Type t : ((WildcardType) suspectedSuperType).getUpperBounds())
            {
                if (!isAssignableFrom(t, suspectedSubType)) return false;
            }
            for (Type t : ((WildcardType) suspectedSuperType).getLowerBounds())
            {
                if (!isAssignableFrom(suspectedSubType, t)) return false;
            }
            return true;
        }

        Type curType = suspectedSubType;
        Class curClass;

        while (curType != null && !curType.equals(Object.class))
        {
            curClass = asClass(curType);

            if (curClass.equals(suspectedSuperClass))
            {
                final Type resolved = resolve(curType, suspectedSubType);

                if (suspectedSuperType instanceof Class)
                {
                    if ( resolved instanceof Class )
                        return suspectedSuperType.equals(resolved);

                    // They may represent the same class, but the suspectedSuperType is not parameterized. The parameter
                    // types default to Object so they must be a match.
                    // e.g. Pair p = new StringLongPair();
                    //      Pair p = new Pair<? extends Number, String>

                    return true;
                }

                if (suspectedSuperType instanceof ParameterizedType)
                {
                    if (resolved instanceof ParameterizedType)
                    {
                        final Type[] type1Arguments = ((ParameterizedType) suspectedSuperType).getActualTypeArguments();
                        final Type[] type2Arguments = ((ParameterizedType) resolved).getActualTypeArguments();
                        if (type1Arguments.length != type2Arguments.length) return false;

                        for (int i = 0; i < type1Arguments.length; ++i)
                        {
                            if (!isAssignableFrom(type1Arguments[i], type2Arguments[i])) return false;
                        }
                        return true;
                    }
                }
                else if (suspectedSuperType instanceof GenericArrayType)
                {
                    if (resolved instanceof GenericArrayType)
                    {
                        return isAssignableFrom(
                                ((GenericArrayType) suspectedSuperType).getGenericComponentType(),
                                ((GenericArrayType) resolved).getGenericComponentType()
                        );
                    }
                }

                return false;
            }

            final Type[] types = curClass.getGenericInterfaces();
            for (Type t : types)
            {
                final Type resolved = resolve(t, suspectedSubType);
                if (isAssignableFrom(suspectedSuperType, resolved))
                    return true;
            }

            curType = curClass.getGenericSuperclass();
        }
        return false;
    }