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;
}