isaric opened a new pull request, #1548:
URL: https://github.com/apache/commons-lang/pull/1548

   ### Fix `TypeUtils.isAssignable` for `Class` parameterized types
   
   #### Summary
   This PR fixes a bug in `TypeUtils.isAssignable` where it incorrectly 
returned `true` for certain `ParameterizedType` assignments involving 
`java.lang.Class`. Specifically, it was allowing assignments like 
`Class<TestIF>` to `Class<? extends TestIF<?>>`, which are prohibited by the 
Java compiler due to the invariance of the `Class<T>` type.
   
   #### Problem
   In Java, `Class<T>` is invariant. This means that even if `TestImpl` extends 
`TestIF`, `Class<TestImpl>` is NOT assignable to `Class<TestIF>`. Furthermore, 
`Class<TestIF>` is not assignable to `Class<? extends TestIF<?>>` because the 
type argument of the latter is a wildcard that requires a specific capturing 
behavior that a raw-ish or differently parameterized `Class` does not satisfy 
in the same way.
   
   The previous implementation of `TypeUtils.isAssignable(Type, 
ParameterizedType, Map)` was too permissive when handling `Class.class` as the 
raw type, treating it like any other parameterized interface or class instead 
of enforcing the strict invariance required for `Class<T>`.
   
   #### Solution
   The fix introduces a specialized check within `isAssignable(Type, 
ParameterizedType, Map)` when the target raw type is `java.lang.Class`. 
   
   1.  It identifies if the target `ParameterizedType` represents a `Class<?>`.
   2.  It extracts the type argument from both the source and target.
   3.  It ensures that the source type argument matches the target type 
argument exactly, or correctly satisfies the target's wildcard bounds if 
applicable, adhering to the strict rules of the Java language for the `Class` 
class.
   
   #### Changes
   - **`org.apache.commons.lang3.reflect.TypeUtils`**: 
       - Added a logic block in `isAssignable(Type, ParameterizedType, Map)` 
specifically for `Class.class`.
       - Implemented strict comparison for `Class` type arguments using 
`unrollVariableAssignments` to resolve any type variables in the current 
context.
       - Ensures that even if the target is a wildcard (e.g., `Class<? extends 
Foo>`), the source must match the captured type exactly or satisfy the bound 
without violating invariance.
   - **`org.apache.commons.lang3.reflect.TypeUtilsTest`**: 
       - Added `testIsAssignable_ClassWithParameterizedType` which includes:
           - `Class<TestIF>` to `Class<? extends TestIF<?>>` (Expected: `false`)
           - `Class<TestImpl>` to `Class<? extends TestIF<?>>` (Expected: 
`false`)
           - `Class<TestImpl2>` to `Class<? extends TestIF<Number>>` (Expected: 
`false`)
       - Added helper internal interfaces and classes (`TestIF<T>`, 
`TestImpl<T>`, `TestImpl2<R>`) to support these test cases.
   
   Note: Used AI tools in the writing of this PR - JetBrains AI. There are no 
copyright issues with the submitted code.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to