This is an automated email from the ASF dual-hosted git repository.
ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-lang.git
The following commit(s) were added to refs/heads/master by this push:
new bcad40a50 [LANG-1749] Add stricter type checks for parameterized
types in method (#1548)
bcad40a50 is described below
commit bcad40a502cd45b49a5e025938b9711d95c7bde7
Author: Ivan Šarić <[email protected]>
AuthorDate: Wed Dec 31 20:35:02 2025 +0100
[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]>
---
.../apache/commons/lang3/reflect/TypeUtils.java | 11 +++++++++
.../commons/lang3/reflect/TypeUtilsTest.java | 27 ++++++++++++++++++++++
2 files changed, 38 insertions(+)
diff --git a/src/main/java/org/apache/commons/lang3/reflect/TypeUtils.java
b/src/main/java/org/apache/commons/lang3/reflect/TypeUtils.java
index 3c721719a..f1fc44ae3 100644
--- a/src/main/java/org/apache/commons/lang3/reflect/TypeUtils.java
+++ b/src/main/java/org/apache/commons/lang3/reflect/TypeUtils.java
@@ -1080,6 +1080,17 @@ private static boolean isAssignable(final Type type,
final ParameterizedType toP
}
// get the target type's type arguments including owner type arguments
final Map<TypeVariable<?>, Type> toTypeVarAssigns =
getTypeArguments(toParameterizedType, toClass, typeVarAssigns);
+ // Class<T> is not assignable to Class<S> if T is not S (even if T
extends S)
+ if (toClass.equals(Class.class)) {
+ final TypeVariable<?>[] typeParams = toClass.getTypeParameters();
+ if (typeParams.length > 0) {
+ final Type toTypeArg =
unrollVariableAssignments(typeParams[0], toTypeVarAssigns);
+ final Type fromTypeArg =
unrollVariableAssignments(typeParams[0], fromTypeVarAssigns);
+ if (toTypeArg != null && (fromTypeArg == null ||
!toTypeArg.equals(fromTypeArg))) {
+ return false;
+ }
+ }
+ }
// now to check each type argument
for (final TypeVariable<?> var : toTypeVarAssigns.keySet()) {
final Type toTypeArg = unrollVariableAssignments(var,
toTypeVarAssigns);
diff --git a/src/test/java/org/apache/commons/lang3/reflect/TypeUtilsTest.java
b/src/test/java/org/apache/commons/lang3/reflect/TypeUtilsTest.java
index e9a6709d3..565a8d78a 100644
--- a/src/test/java/org/apache/commons/lang3/reflect/TypeUtilsTest.java
+++ b/src/test/java/org/apache/commons/lang3/reflect/TypeUtilsTest.java
@@ -773,6 +773,33 @@ void testIsAssignableGenericArrayTypeToWildcardType() {
() -> String.format("TypeUtils.isAssignable(%s, %s)",
testType, paramType));
}
+ @Test
+ void testIsAssignable_ClassWithParameterizedType() {
+ final ParameterizedType topre1 = TypeUtils.parameterize(TestIF.class,
TypeUtils.wildcardType().build());
+ final Type to1 = TypeUtils.parameterize(Class.class,
TypeUtils.wildcardType().withUpperBounds(topre1).build());
+ final Type from1 = TypeUtils.parameterize(Class.class, TestIF.class);
+ assertFalse(TypeUtils.isAssignable(from1, to1), "Class<TestIF> should
not be assignable to Class<? extends TestIF<?>>");
+
+ final ParameterizedType topre2 = TypeUtils.parameterize(TestIF.class,
TypeUtils.wildcardType().build());
+ final Type to2 = TypeUtils.parameterize(Class.class,
TypeUtils.wildcardType().withUpperBounds(topre2).build());
+ final Type from2 = TypeUtils.parameterize(Class.class, TestImpl.class);
+ assertFalse(TypeUtils.isAssignable(from2, to2), "Class<TestImpl>
should not be assignable to Class<? extends TestIF<?>>");
+
+ final ParameterizedType topre3 = TypeUtils.parameterize(TestIF.class,
Number.class);
+ final Type to3 = TypeUtils.parameterize(Class.class,
TypeUtils.wildcardType().withUpperBounds(topre3).build());
+ final Type from3 = TypeUtils.parameterize(Class.class,
TestImpl2.class);
+ assertFalse(TypeUtils.isAssignable(from3, to3), "Class<TestImpl2>
should not be assignable to Class<? extends TestIF<Number>>");
+ }
+
+ private interface TestIF<T> {
+ }
+
+ private static class TestImpl<T> implements TestIF<T> {
+ }
+
+ private static class TestImpl2<R> implements TestIF<Number> {
+ }
+
@Test
void testIsAssignableGenericClassHierarchy() throws NoSuchFieldException {
/*