Alwaysgaurav1 opened a new pull request, #1789: URL: https://github.com/apache/commons-lang/pull/1789
## Problem `TypeUtils.toString(Type)` suffered from several interrelated issues when handling recursive generic types and type bounds: 1. **StackOverflowError on Recursive Generic Types**: Formatting recursive generic types like `class MySuperClass<T>`, `class MyClass<U extends MySuperClass<? super U>>`, or `class MultiBoundClass<U extends Number & Comparable<? super U>>` resulted in `StackOverflowError`. 2. **Stripping of Valid Interface Bounds**: A workaround previously introduced for `LANG-1698` unconditionally skipped bounds if the raw type was an interface. This stripped all valid interface bounds (e.g. `<T extends List<String>>` formatted as `"T"` instead of `"T extends java.util.List<java.lang.String>"`), while still failing with a `StackOverflowError` on class bounds. 3. **Corrupted Multi-Parameter Recursive Types**: Workaround methods `findRecursiveTypes` and `appendRecursiveTypes` corrupted type parameter formatting on multi-parameter recursive types (such as `TwoParams<T extends TwoParams<T, U>, U>`), outputting `<T><U><U>`. 4. **Incomplete Multi-Bound Wildcard Inspection**: `TypeUtils.containsTypeVariables(WildcardType)` only inspected the bound at index `0`, ignoring subsequent bounds for multi-bounded wildcards. ## Root Cause In Java grammar (JLS Chapter 4), a `TypeVariable` is a **declaration** only when declaring a type parameter (e.g. `<U extends Number>`). Everywhere else—such as inside type arguments (`List<U>`), wildcard bounds (`? extends U`, `? super U`), generic arrays (`U[]`), or other type variable bounds (`<S extends T>`)—it is a **type reference** (`ReferenceType`) and should be formatted only by its identifier name `U`. Treating embedded type variables as declarations led to recursive expansion of bounds. ## Solution 1. **Differentiate Type Declarations and References**: Added `toReferenceString(Type)` which formats `TypeVariable` instances by name only and delegates other types to `toString(Type)`. Configured `AMP_JOINER`, `TYPE_ARG_JOINER`, and `genericArrayTypeToString` to format embedded types as references. 2. **Preserve Interface Bounds**: Removed the interface-check workaround from `typeVariableToString`, properly preserving all interface bounds without recursion. 3. **Remove Workaround Heuristics**: Cleanly removed `findRecursiveTypes`, `appendRecursiveTypes`, and `containsVariableTypeSameParametrizedTypeBound`. 4. **Inspect All Wildcard Bounds**: Updated `containsTypeVariables(WildcardType)` to check all implicit upper and lower bounds. 5. **ThreadLocal Cycle Guard**: Added `VISITING` `ThreadLocal<Set<TypeVariable<?>>>` with guaranteed `VISITING.remove()` in `finally` to guard against arbitrary cyclical type graphs without leaking memory. ## Verification - All 430 tests in `TypeUtilsTest` passed (including 6 new tests covering recursive class bounds, multi-bounds, interface preservation, and multi-bound wildcards). - All 590 tests across `org.apache.commons.lang3.reflect.*` passed without regressions. -- 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]
