Skip to content

Commit bcad40a

Browse files
isaricgarydgregory
andauthored
[LANG-1749] Add stricter type checks for parameterized types in method (#1548)
* [LANG-1749] Add stricter type checks for parameterized types in method * Remove extra blank lines --------- Co-authored-by: Gary Gregory <[email protected]>
1 parent 5e9736a commit bcad40a

File tree

2 files changed

+38
-0
lines changed

2 files changed

+38
-0
lines changed

src/main/java/org/apache/commons/lang3/reflect/TypeUtils.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,6 +1080,17 @@ private static boolean isAssignable(final Type type, final ParameterizedType toP
10801080
}
10811081
// get the target type's type arguments including owner type arguments
10821082
final Map<TypeVariable<?>, Type> toTypeVarAssigns = getTypeArguments(toParameterizedType, toClass, typeVarAssigns);
1083+
// Class<T> is not assignable to Class<S> if T is not S (even if T extends S)
1084+
if (toClass.equals(Class.class)) {
1085+
final TypeVariable<?>[] typeParams = toClass.getTypeParameters();
1086+
if (typeParams.length > 0) {
1087+
final Type toTypeArg = unrollVariableAssignments(typeParams[0], toTypeVarAssigns);
1088+
final Type fromTypeArg = unrollVariableAssignments(typeParams[0], fromTypeVarAssigns);
1089+
if (toTypeArg != null && (fromTypeArg == null || !toTypeArg.equals(fromTypeArg))) {
1090+
return false;
1091+
}
1092+
}
1093+
}
10831094
// now to check each type argument
10841095
for (final TypeVariable<?> var : toTypeVarAssigns.keySet()) {
10851096
final Type toTypeArg = unrollVariableAssignments(var, toTypeVarAssigns);

src/test/java/org/apache/commons/lang3/reflect/TypeUtilsTest.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -773,6 +773,33 @@ void testIsAssignableGenericArrayTypeToWildcardType() {
773773
() -> String.format("TypeUtils.isAssignable(%s, %s)", testType, paramType));
774774
}
775775

776+
@Test
777+
void testIsAssignable_ClassWithParameterizedType() {
778+
final ParameterizedType topre1 = TypeUtils.parameterize(TestIF.class, TypeUtils.wildcardType().build());
779+
final Type to1 = TypeUtils.parameterize(Class.class, TypeUtils.wildcardType().withUpperBounds(topre1).build());
780+
final Type from1 = TypeUtils.parameterize(Class.class, TestIF.class);
781+
assertFalse(TypeUtils.isAssignable(from1, to1), "Class<TestIF> should not be assignable to Class<? extends TestIF<?>>");
782+
783+
final ParameterizedType topre2 = TypeUtils.parameterize(TestIF.class, TypeUtils.wildcardType().build());
784+
final Type to2 = TypeUtils.parameterize(Class.class, TypeUtils.wildcardType().withUpperBounds(topre2).build());
785+
final Type from2 = TypeUtils.parameterize(Class.class, TestImpl.class);
786+
assertFalse(TypeUtils.isAssignable(from2, to2), "Class<TestImpl> should not be assignable to Class<? extends TestIF<?>>");
787+
788+
final ParameterizedType topre3 = TypeUtils.parameterize(TestIF.class, Number.class);
789+
final Type to3 = TypeUtils.parameterize(Class.class, TypeUtils.wildcardType().withUpperBounds(topre3).build());
790+
final Type from3 = TypeUtils.parameterize(Class.class, TestImpl2.class);
791+
assertFalse(TypeUtils.isAssignable(from3, to3), "Class<TestImpl2> should not be assignable to Class<? extends TestIF<Number>>");
792+
}
793+
794+
private interface TestIF<T> {
795+
}
796+
797+
private static class TestImpl<T> implements TestIF<T> {
798+
}
799+
800+
private static class TestImpl2<R> implements TestIF<Number> {
801+
}
802+
776803
@Test
777804
void testIsAssignableGenericClassHierarchy() throws NoSuchFieldException {
778805
/*

0 commit comments

Comments
 (0)