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 {
         /*

Reply via email to