This is an automated email from the ASF dual-hosted git repository.
garydgregory 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 45f08d9e3 Fix TypeUtils.toString() recursion and bound handling on
recursive generic types (#1789).
45f08d9e3 is described below
commit 45f08d9e3b03177e12559878fc95cf3266b65052
Author: Gary Gregory <[email protected]>
AuthorDate: Sun Sep 13 15:26:35 2026 -0700
Fix TypeUtils.toString() recursion and bound handling on recursive
generic types (#1789).
Sort members.
---
src/changes/changes.xml | 1 +
.../apache/commons/lang3/reflect/TypeUtils.java | 66 +--
.../commons/lang3/reflect/TypeUtilsTest.java | 640 ++++++++++-----------
3 files changed, 354 insertions(+), 353 deletions(-)
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 3801cfd96..22a98d042 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -284,6 +284,7 @@ java.lang.NullPointerException: Cannot invoke
<action type="fix" dev="ggregory" due-to="Jeff Lenamon,
Gary Gregory">Fix MethodUtils.invokeMethod on instances of non-public classes
(#1783).</action>
<action type="fix" dev="ggregory" due-to="Jeff Lenamon,
Gary Gregory">Fraction.add and subtract return the reduced form when an operand
is zero (#1787).</action>
<action type="fix" dev="ggregory" due-to="alhuda, Gary
Gregory">Return null for out-of-range offset in FastTimeZone.getGmtTimeZone
(#1788).</action>
+ <action type="fix" dev="ggregory" due-to="gaurav kumar
pandey, Gary Gregory">Fix TypeUtils.toString() recursion and bound handling on
recursive generic types (#1789).</action>
<!-- ADD -->
<action type="add" dev="ggregory" due-to="Gary
Gregory">Add JavaVersion.JAVA_27.</action>
<action type="add" dev="ggregory" due-to="Gary
Gregory">Add SystemUtils.IS_JAVA_27.</action>
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 4c8491efd..f36a6ccf2 100644
--- a/src/main/java/org/apache/commons/lang3/reflect/TypeUtils.java
+++ b/src/main/java/org/apache/commons/lang3/reflect/TypeUtils.java
@@ -336,23 +336,12 @@ public String toString() {
*/
public static final WildcardType WILDCARD_ALL =
wildcardType().withUpperBounds(Object.class).build();
+ private static final ThreadLocal<Set<Type>> VISITING =
ThreadLocal.withInitial(() -> Collections.newSetFromMap(new
IdentityHashMap<>()));
+
private static <T> String anyToString(final T object) {
return object instanceof Type ? toString((Type) object) :
object.toString();
}
- /**
- * Formats a {@link Type} as a type reference string (type variables are
formatted by name only without bounds).
- *
- * @param type The type to format.
- * @return String.
- */
- private static String toReferenceString(final Type type) {
- if (type instanceof TypeVariable<?>) {
- return ((TypeVariable<?>) type).getName();
- }
- return toString(type);
- }
-
/**
* Formats a {@link Class} as a {@link String}.
@@ -1531,6 +1520,28 @@ private static Type substituteTypeVariables(final Type
type, final Map<TypeVaria
return type;
}
+ private static String toCyclicString(final Type type) {
+ if (type instanceof Class<?>) {
+ return ((Class<?>) type).getSimpleName() + "(cycle)";
+ }
+ if (type instanceof TypeVariable<?>) {
+ return ((TypeVariable<?>) type).getName() + "(cycle)";
+ }
+ if (type instanceof WildcardType) {
+ return "? (cycle)";
+ }
+ if (type instanceof ParameterizedType) {
+ final ParameterizedType pt = (ParameterizedType) type;
+ final Type raw = pt.getRawType();
+ final String rawName = raw instanceof Class<?> ? ((Class<?>)
raw).getSimpleName() : raw.getTypeName();
+ return rawName + "(cycle)";
+ }
+ if (type instanceof GenericArrayType) {
+ return "(cycle)";
+ }
+ return ObjectUtils.identityToString(type) + "(cycle)";
+ }
+
/**
* Formats a {@link TypeVariable} including its {@link GenericDeclaration}.
*
@@ -1561,28 +1572,17 @@ public static String toLongString(final TypeVariable<?>
typeVariable) {
return buf.append(':').append(toString(typeVariable)).toString();
}
- private static final ThreadLocal<Set<Type>> VISITING =
ThreadLocal.withInitial(() -> Collections.newSetFromMap(new
IdentityHashMap<>()));
-
- private static String toCyclicString(final Type type) {
- if (type instanceof Class<?>) {
- return ((Class<?>) type).getSimpleName() + "(cycle)";
- }
+ /**
+ * Formats a {@link Type} as a type reference string (type variables are
formatted by name only without bounds).
+ *
+ * @param type The type to format.
+ * @return String.
+ */
+ private static String toReferenceString(final Type type) {
if (type instanceof TypeVariable<?>) {
- return ((TypeVariable<?>) type).getName() + "(cycle)";
- }
- if (type instanceof WildcardType) {
- return "? (cycle)";
- }
- if (type instanceof ParameterizedType) {
- final ParameterizedType pt = (ParameterizedType) type;
- final Type raw = pt.getRawType();
- final String rawName = raw instanceof Class<?> ? ((Class<?>)
raw).getSimpleName() : raw.getTypeName();
- return rawName + "(cycle)";
- }
- if (type instanceof GenericArrayType) {
- return "(cycle)";
+ return ((TypeVariable<?>) type).getName();
}
- return ObjectUtils.identityToString(type) + "(cycle)";
+ return toString(type);
}
/**
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 6c00f8204..291cfd45d 100644
--- a/src/test/java/org/apache/commons/lang3/reflect/TypeUtilsTest.java
+++ b/src/test/java/org/apache/commons/lang3/reflect/TypeUtilsTest.java
@@ -153,33 +153,11 @@ public class GClass<T extends BClass<? extends T> &
AInterface<AInterface<? supe
enclosingInstance.super();
}
}
-@SuppressWarnings("rawtypes")
-abstract class Test1<G> {
- public abstract Object m0();
- public abstract String[] m1();
- public abstract <K, V> Map<? extends K, V[]> m10();
- public abstract <K, V> Map<? extends K, List<V[]>> m11();
- public abstract List m12();
- public abstract Map m13();
- public abstract Properties m14();
- public abstract G m15();
- public abstract List<G> m16();
- public abstract Enum m17();
- public abstract <E> E[] m2();
- public abstract <E> List<? extends E> m3();
- public abstract <E extends Enum<E>> List<? extends Enum<E>> m4();
- public abstract List<? extends Enum<?>> m5();
- public abstract List<? super Enum<?>> m6();
- public abstract List<?> m7();
- public abstract Map<? extends Enum<?>, ? super Enum<?>> m8();
- public abstract <K, V> Map<? extends K, ? super V[]> m9();
-}
-
-class MySuperClass<T> {
+class DependentBounds<T extends Number, S extends T> {
// empty
}
-class MyClass<U extends MySuperClass<? super U>> {
+class InterfaceBound<T extends List<String>> {
// empty
}
@@ -187,15 +165,11 @@ class MultiBoundClass<U extends Number & Comparable<?
super U>> {
// empty
}
-class TwoParams<T extends TwoParams<T, U>, U> {
- // empty
-}
-
-class InterfaceBound<T extends List<String>> {
+class MyClass<U extends MySuperClass<? super U>> {
// empty
}
-class DependentBounds<T extends Number, S extends T> {
+class MySuperClass<T> {
// empty
}
@@ -209,6 +183,32 @@ public NonGenericInner getInner() {
}
}
+@SuppressWarnings("rawtypes")
+abstract class Test1<G> {
+ public abstract Object m0();
+ public abstract String[] m1();
+ public abstract <K, V> Map<? extends K, V[]> m10();
+ public abstract <K, V> Map<? extends K, List<V[]>> m11();
+ public abstract List m12();
+ public abstract Map m13();
+ public abstract Properties m14();
+ public abstract G m15();
+ public abstract List<G> m16();
+ public abstract Enum m17();
+ public abstract <E> E[] m2();
+ public abstract <E> List<? extends E> m3();
+ public abstract <E extends Enum<E>> List<? extends Enum<E>> m4();
+ public abstract List<? extends Enum<?>> m5();
+ public abstract List<? super Enum<?>> m6();
+ public abstract List<?> m7();
+ public abstract Map<? extends Enum<?>, ? super Enum<?>> m8();
+ public abstract <K, V> Map<? extends K, ? super V[]> m9();
+}
+
+class TwoParams<T extends TwoParams<T, U>, U> {
+ // empty
+}
+
/**
* Tests {@link TypeUtils}.
*
@@ -450,6 +450,20 @@ void test_LANG_1702() throws NoSuchMethodException,
SecurityException {
final Type unrolledType = TypeUtils.unrollVariables(typeArguments,
type);
}
+ @Test
+ void testBoundedGenericArrayTypeToString() {
+ final TypeVariable<?> t = DependentBounds.class.getTypeParameters()[0];
+ final GenericArrayType gat = TypeUtils.genericArrayType(t);
+ assertEquals("T[]", TypeUtils.toString(gat));
+ }
+
+ @Test
+ void testBoundedParameterizedTypeArgumentToString() {
+ final TypeVariable<?> t = DependentBounds.class.getTypeParameters()[0];
+ final ParameterizedType pt = TypeUtils.parameterize(List.class, t);
+ assertEquals("java.util.List<T>", TypeUtils.toString(pt));
+ }
+
@Test
void testContainsTypeVariables() throws NoSuchMethodException {
assertFalse(TypeUtils.containsTypeVariables(Test1.class.getMethod("m0").getGenericReturnType()));
@@ -472,6 +486,17 @@ void testContainsTypeVariables() throws
NoSuchMethodException {
assertTrue(TypeUtils.containsTypeVariables(Test1.class.getMethod("m17").getGenericReturnType()));
}
+ @Test
+ void testContainsTypeVariablesMultiBoundWildcard() {
+ final TypeVariable<?> t = getClass().getTypeParameters()[0];
+ final WildcardType wtUpper =
TypeUtils.wildcardType().withUpperBounds(Integer.class, t).build();
+ assertTrue(TypeUtils.containsTypeVariables(wtUpper));
+ final WildcardType wtLower =
TypeUtils.wildcardType().withLowerBounds(Integer.class, t).build();
+ assertTrue(TypeUtils.containsTypeVariables(wtLower));
+ final WildcardType wtNone =
TypeUtils.wildcardType().withUpperBounds(Integer.class, String.class).build();
+ assertFalse(TypeUtils.containsTypeVariables(wtNone));
+ }
+
@Test
void testContainsTypeVariablesPr437() throws Exception {
abstract class Test2<G> {
@@ -515,6 +540,126 @@ abstract class Test2<G> {
assertTrue(TypeUtils.containsTypeVariables(Test2.class.getMethod("m17").getGenericReturnType()));
}
+ @Test
+ void testCyclicGenericArrayTypeToString() {
+ final GenericArrayType[] holder = new GenericArrayType[1];
+ final GenericArrayType cyclicType = () -> holder[0];
+ holder[0] = cyclicType;
+ assertEquals("(cycle)[]", TypeUtils.toString(cyclicType));
+ }
+
+ @Test
+ void testCyclicOwnerParameterizedTypeToString() {
+ final ParameterizedType[] holder = new ParameterizedType[1];
+ final ParameterizedType cyclicOwnerType = new ParameterizedType() {
+ @Override
+ public Type[] getActualTypeArguments() {
+ return ArrayUtils.EMPTY_TYPE_ARRAY;
+ }
+
+ @Override
+ public Type getOwnerType() {
+ return holder[0];
+ }
+
+ @Override
+ public Type getRawType() {
+ return List.class;
+ }
+ };
+ holder[0] = cyclicOwnerType;
+ assertEquals("List(cycle).List", TypeUtils.toString(cyclicOwnerType));
+
+ final ParameterizedType[] holderA = new ParameterizedType[1];
+ final ParameterizedType[] holderB = new ParameterizedType[1];
+ final ParameterizedType typeA = new ParameterizedType() {
+ @Override
+ public Type[] getActualTypeArguments() {
+ return ArrayUtils.EMPTY_TYPE_ARRAY;
+ }
+
+ @Override
+ public Type getOwnerType() {
+ return holderB[0];
+ }
+
+ @Override
+ public Type getRawType() {
+ return Map.class;
+ }
+ };
+ final ParameterizedType typeB = new ParameterizedType() {
+ @Override
+ public Type[] getActualTypeArguments() {
+ return ArrayUtils.EMPTY_TYPE_ARRAY;
+ }
+
+ @Override
+ public Type getOwnerType() {
+ return holderA[0];
+ }
+
+ @Override
+ public Type getRawType() {
+ return Set.class;
+ }
+ };
+ holderA[0] = typeA;
+ holderB[0] = typeB;
+ assertEquals("Map(cycle).Set.Map", TypeUtils.toString(typeA));
+ }
+
+ @Test
+ void testCyclicParameterizedTypeToString() {
+ final ParameterizedType[] holder = new ParameterizedType[1];
+ final ParameterizedType cyclicType = new ParameterizedType() {
+ @Override
+ public Type[] getActualTypeArguments() {
+ return new Type[] { holder[0] };
+ }
+
+ @Override
+ public Type getOwnerType() {
+ return null;
+ }
+
+ @Override
+ public Type getRawType() {
+ return List.class;
+ }
+ };
+ holder[0] = cyclicType;
+ assertEquals("java.util.List<List(cycle)>",
TypeUtils.toString(cyclicType));
+ }
+
+ @Test
+ void testCyclicWildcardTypeToString() {
+ final WildcardType[] holder = new WildcardType[1];
+ final WildcardType cyclicWildcard = new WildcardType() {
+ @Override
+ public Type[] getLowerBounds() {
+ return ArrayUtils.EMPTY_TYPE_ARRAY;
+ }
+
+ @Override
+ public Type[] getUpperBounds() {
+ return new Type[] { holder[0] };
+ }
+ };
+ holder[0] = cyclicWildcard;
+ assertEquals("? extends ? (cycle)",
TypeUtils.toString(cyclicWildcard));
+ }
+
+ @Test
+ void testDependentBoundsClassAndTypeParametersToString() {
+ assertEquals("org.apache.commons.lang3.reflect.DependentBounds<T
extends java.lang.Number, S extends T>",
+ TypeUtils.toString(DependentBounds.class));
+ assertEquals("T extends java.lang.Number",
+
TypeUtils.toString(DependentBounds.class.getTypeParameters()[0]));
+ assertEquals("S extends T",
+
TypeUtils.toString(DependentBounds.class.getTypeParameters()[1]));
+ }
+
@Test
void testDeprecatedConstructor() {
assertNotNull(new TypeUtils().toString());
@@ -545,6 +690,13 @@ void testEquals() throws NoSuchFieldException {
assertFalse(TypeUtils.equals(null, gat1));
}
+ @Test
+ void testGClassToString() {
+ assertEquals("org.apache.commons.lang3.reflect.AClass.GClass<T extends
org.apache.commons.lang3.reflect.AClass.BClass<? extends T> "
+ + "&
org.apache.commons.lang3.reflect.AClass.AInterface<org.apache.commons.lang3.reflect.AClass.AInterface<?
super T>>>",
+ TypeUtils.toString(AClass.GClass.class));
+ }
+
@SuppressWarnings("unlikely-arg-type")
@Test
void testGenericArrayType() throws NoSuchFieldException {
@@ -695,6 +847,12 @@ void testGetTypeArguments() {
assertEquals(getClass().getTypeParameters()[0],
typeVarAssigns.get(Other.class.getTypeParameters()[0]));
}
+ @Test
+ void testInterfaceBoundPreserved() {
+ assertEquals("T extends java.util.List<java.lang.String>",
+
TypeUtils.toString(InterfaceBound.class.getTypeParameters()[0]));
+ }
+
@Test
void testIsArrayGenericTypes() throws NoSuchFieldException {
final Type rawListType =
GenericTypeHolder.class.getDeclaredField("rawList").getGenericType();
@@ -1155,6 +1313,21 @@ void testLowerBoundedWildcardType() {
assertEquals(String.format("? super %s", iterableT0.getName()),
lowerTypeVariable.toString());
}
+ @Test
+ void testMultiBoundRecursiveType() {
+ assertEquals("org.apache.commons.lang3.reflect.MultiBoundClass<U
extends java.lang.Number & java.lang.Comparable<? super U>>",
+ TypeUtils.toString(MultiBoundClass.class));
+ assertEquals("U extends java.lang.Number & java.lang.Comparable<?
super U>",
+
TypeUtils.toString(MultiBoundClass.class.getTypeParameters()[0]));
+ }
+
+ @Test
+ void testMultiParamRecursiveType() {
+ final ParameterizedType parameterizedType =
TypeUtils.parameterize(TwoParams.class, TwoParams.class.getTypeParameters());
+ assertEquals("org.apache.commons.lang3.reflect.TwoParams<T, U>",
+ TypeUtils.toString(parameterizedType));
+ }
+
@Test
void testNormalizeUpperBounds() {
final Type[] typeArray = { Collection.class, List.class };
@@ -1169,6 +1342,18 @@ void testNormalizeUpperBounds_LANG_820() {
assertArrayEquals(expectedArray,
TypeUtils.normalizeUpperBounds(typeArray));
}
+ @Test
+ void testParameterizedOwnerWithNonGenericInnerClassToString() throws
NoSuchMethodException {
+ final ParameterizedType owner =
TypeUtils.parameterize(ParameterizedOwner.class, String.class);
+ final ParameterizedType nonGenericInner =
TypeUtils.parameterizeWithOwner(owner,
ParameterizedOwner.NonGenericInner.class);
+
assertEquals("org.apache.commons.lang3.reflect.ParameterizedOwner<java.lang.String>.NonGenericInner",
+ TypeUtils.toString(nonGenericInner));
+
+ final Type methodReturnType =
ParameterizedOwner.class.getMethod("getInner").getGenericReturnType();
+
assertEquals("org.apache.commons.lang3.reflect.ParameterizedOwner<T>.NonGenericInner",
+ TypeUtils.toString(methodReturnType));
+ }
+
@Test
void testParameterizeMapArg() throws NoSuchFieldException {
final Map<TypeVariable<?>, Type> typeVariableMap = new HashMap<>();
@@ -1245,17 +1430,107 @@ void
testParameterizeWithOwnerVarArgsNullPointerException() {
}
@Test
- void testToLongString() {
- assertNullPointerException(() -> TypeUtils.toLongString(null));
- assertEquals(getClass().getName() + ":B",
TypeUtils.toLongString(getClass().getTypeParameters()[0]));
- assertEquals(getClass().getName() + ".MyInnerClass:T",
TypeUtils.toLongString(MyInnerClass.class.getTypeParameters()[0]));
- assertEquals(getClass().getName() + ".That:K",
TypeUtils.toLongString(That.class.getTypeParameters()[0]));
- assertEquals(getClass().getName() + ".The:K",
TypeUtils.toLongString(The.class.getTypeParameters()[0]));
- assertEquals(getClass().getName() + ".MyInnerClass.MyInnerClass2:X",
TypeUtils.toLongString(MyInnerClass.MyInnerClass2.class.getTypeParameters()[0]));
- }
-
- @Test
- void testToString() {
+ void testRecursiveTypeWildcardBoundClass() {
+ assertEquals("org.apache.commons.lang3.reflect.MyClass<U extends
org.apache.commons.lang3.reflect.MySuperClass<? super U>>",
+ TypeUtils.toString(MyClass.class));
+ assertEquals("U extends
org.apache.commons.lang3.reflect.MySuperClass<? super U>",
+ TypeUtils.toString(MyClass.class.getTypeParameters()[0]));
+ }
+
+ @Test
+ void testRepeatedSiblingReferencesToString() {
+ final ParameterizedType listString =
TypeUtils.parameterize(List.class, String.class);
+ final ParameterizedType mapType = TypeUtils.parameterize(Map.class,
listString, listString);
+ assertEquals("java.util.Map<java.util.List<java.lang.String>,
java.util.List<java.lang.String>>",
+ TypeUtils.toString(mapType));
+
+ final TypeVariable<?> t = DependentBounds.class.getTypeParameters()[0];
+ final ParameterizedType biFunctionType =
TypeUtils.parameterize(BiFunction.class, t, t, t);
+ assertEquals("java.util.function.BiFunction<T, T, T>",
TypeUtils.toString(biFunctionType));
+
+ final WildcardType wildcard =
TypeUtils.wildcardType().withUpperBounds(listString).build();
+ final ParameterizedType mapWildcards =
TypeUtils.parameterize(Map.class, wildcard, wildcard);
+ assertEquals("java.util.Map<? extends
java.util.List<java.lang.String>, ? extends java.util.List<java.lang.String>>",
+ TypeUtils.toString(mapWildcards));
+ }
+
+ @Test
+ void testThreadLocalCleanupAfterException() {
+ final Type unsupportedType = new Type() {
+ @Override
+ public String getTypeName() {
+ return "Unsupported";
+ }
+ };
+ assertThrows(IllegalArgumentException.class, () ->
TypeUtils.toString(unsupportedType));
+ assertEquals("java.lang.String", TypeUtils.toString(String.class));
+
+ final Type faultyType = new ParameterizedType() {
+ @Override
+ public Type[] getActualTypeArguments() {
+ throw new IllegalStateException("Simulated failure in
getActualTypeArguments");
+ }
+
+ @Override
+ public Type getOwnerType() {
+ return null;
+ }
+
+ @Override
+ public Type getRawType() {
+ return List.class;
+ }
+ };
+ assertThrows(IllegalStateException.class, () ->
TypeUtils.toString(faultyType));
+ assertEquals("java.lang.String", TypeUtils.toString(String.class));
+
+ final ParameterizedType wrapper = new ParameterizedType() {
+ @Override
+ public Type[] getActualTypeArguments() {
+ return new Type[] { faultyType };
+ }
+
+ @Override
+ public Type getOwnerType() {
+ return null;
+ }
+
+ @Override
+ public Type getRawType() {
+ return Set.class;
+ }
+ };
+ assertThrows(IllegalStateException.class, () ->
TypeUtils.toString(wrapper));
+ assertEquals("java.util.List<java.lang.String>",
+ TypeUtils.toString(TypeUtils.parameterize(List.class,
String.class)));
+ }
+
+ @Test
+ void testToLongString() {
+ assertNullPointerException(() -> TypeUtils.toLongString(null));
+ assertEquals(getClass().getName() + ":B",
TypeUtils.toLongString(getClass().getTypeParameters()[0]));
+ assertEquals(getClass().getName() + ".MyInnerClass:T",
TypeUtils.toLongString(MyInnerClass.class.getTypeParameters()[0]));
+ assertEquals(getClass().getName() + ".That:K",
TypeUtils.toLongString(That.class.getTypeParameters()[0]));
+ assertEquals(getClass().getName() + ".The:K",
TypeUtils.toLongString(The.class.getTypeParameters()[0]));
+ assertEquals(getClass().getName() + ".MyInnerClass.MyInnerClass2:X",
TypeUtils.toLongString(MyInnerClass.MyInnerClass2.class.getTypeParameters()[0]));
+ }
+
+ @Test
+ void testToLongStringBoundedTypeVariable() {
+ assertEquals("org.apache.commons.lang3.reflect.DependentBounds:T
extends java.lang.Number",
+
TypeUtils.toLongString(DependentBounds.class.getTypeParameters()[0]));
+ assertEquals("org.apache.commons.lang3.reflect.DependentBounds:S
extends T",
+
TypeUtils.toLongString(DependentBounds.class.getTypeParameters()[1]));
+ assertEquals("org.apache.commons.lang3.reflect.MultiBoundClass:U
extends java.lang.Number & java.lang.Comparable<? super U>",
+
TypeUtils.toLongString(MultiBoundClass.class.getTypeParameters()[0]));
+ assertEquals("org.apache.commons.lang3.reflect.InterfaceBound:T
extends java.util.List<java.lang.String>",
+
TypeUtils.toLongString(InterfaceBound.class.getTypeParameters()[0]));
+ assertEquals("org.apache.commons.lang3.reflect.MyClass:U extends
org.apache.commons.lang3.reflect.MySuperClass<? super U>",
+ TypeUtils.toLongString(MyClass.class.getTypeParameters()[0]));
+ }
+
+ @Test
+ void testToString() {
assertNullPointerException(() -> TypeUtils.toString(null));
assertIllegalArgumentException(() -> TypeUtils.toString(new Type() {
// empty
@@ -1327,60 +1602,6 @@ void testWildcardType() throws NoSuchFieldException {
assertFalse(simpleWildcard.equals(TypeUtils.genericArrayType(String.class)));
}
- @Test
- void testWrap() {
- final Type t = getClass().getTypeParameters()[0];
- assertTrue(TypeUtils.equals(t, TypeUtils.wrap(t).getType()));
- assertEquals(String.class, TypeUtils.wrap(String.class).getType());
- }
-
- @Test
- void testRecursiveTypeWildcardBoundClass() {
- assertEquals("org.apache.commons.lang3.reflect.MyClass<U extends
org.apache.commons.lang3.reflect.MySuperClass<? super U>>",
- TypeUtils.toString(MyClass.class));
- assertEquals("U extends
org.apache.commons.lang3.reflect.MySuperClass<? super U>",
- TypeUtils.toString(MyClass.class.getTypeParameters()[0]));
- }
-
- @Test
- void testMultiBoundRecursiveType() {
- assertEquals("org.apache.commons.lang3.reflect.MultiBoundClass<U
extends java.lang.Number & java.lang.Comparable<? super U>>",
- TypeUtils.toString(MultiBoundClass.class));
- assertEquals("U extends java.lang.Number & java.lang.Comparable<?
super U>",
-
TypeUtils.toString(MultiBoundClass.class.getTypeParameters()[0]));
- }
-
- @Test
- void testInterfaceBoundPreserved() {
- assertEquals("T extends java.util.List<java.lang.String>",
-
TypeUtils.toString(InterfaceBound.class.getTypeParameters()[0]));
- }
-
- @Test
- void testMultiParamRecursiveType() {
- final ParameterizedType parameterizedType =
TypeUtils.parameterize(TwoParams.class, TwoParams.class.getTypeParameters());
- assertEquals("org.apache.commons.lang3.reflect.TwoParams<T, U>",
- TypeUtils.toString(parameterizedType));
- }
-
- @Test
- void testGClassToString() {
- assertEquals("org.apache.commons.lang3.reflect.AClass.GClass<T extends
org.apache.commons.lang3.reflect.AClass.BClass<? extends T> "
- + "&
org.apache.commons.lang3.reflect.AClass.AInterface<org.apache.commons.lang3.reflect.AClass.AInterface<?
super T>>>",
- TypeUtils.toString(AClass.GClass.class));
- }
-
- @Test
- void testContainsTypeVariablesMultiBoundWildcard() {
- final TypeVariable<?> t = getClass().getTypeParameters()[0];
- final WildcardType wtUpper =
TypeUtils.wildcardType().withUpperBounds(Integer.class, t).build();
- assertTrue(TypeUtils.containsTypeVariables(wtUpper));
- final WildcardType wtLower =
TypeUtils.wildcardType().withLowerBounds(Integer.class, t).build();
- assertTrue(TypeUtils.containsTypeVariables(wtLower));
- final WildcardType wtNone =
TypeUtils.wildcardType().withUpperBounds(Integer.class, String.class).build();
- assertFalse(TypeUtils.containsTypeVariables(wtNone));
- }
-
@Test
void testWildcardTypeBuilderDefensiveCopy() {
// Upper bounds defensive copying on input array and getter
@@ -1401,231 +1622,10 @@ void testWildcardTypeBuilderDefensiveCopy() {
}
@Test
- void testBoundedGenericArrayTypeToString() {
- final TypeVariable<?> t = DependentBounds.class.getTypeParameters()[0];
- final GenericArrayType gat = TypeUtils.genericArrayType(t);
- assertEquals("T[]", TypeUtils.toString(gat));
- }
-
- @Test
- void testBoundedParameterizedTypeArgumentToString() {
- final TypeVariable<?> t = DependentBounds.class.getTypeParameters()[0];
- final ParameterizedType pt = TypeUtils.parameterize(List.class, t);
- assertEquals("java.util.List<T>", TypeUtils.toString(pt));
- }
-
- @Test
- void testDependentBoundsClassAndTypeParametersToString() {
- assertEquals("org.apache.commons.lang3.reflect.DependentBounds<T
extends java.lang.Number, S extends T>",
- TypeUtils.toString(DependentBounds.class));
- assertEquals("T extends java.lang.Number",
-
TypeUtils.toString(DependentBounds.class.getTypeParameters()[0]));
- assertEquals("S extends T",
-
TypeUtils.toString(DependentBounds.class.getTypeParameters()[1]));
- }
-
- @Test
- void testToLongStringBoundedTypeVariable() {
- assertEquals("org.apache.commons.lang3.reflect.DependentBounds:T
extends java.lang.Number",
-
TypeUtils.toLongString(DependentBounds.class.getTypeParameters()[0]));
- assertEquals("org.apache.commons.lang3.reflect.DependentBounds:S
extends T",
-
TypeUtils.toLongString(DependentBounds.class.getTypeParameters()[1]));
- assertEquals("org.apache.commons.lang3.reflect.MultiBoundClass:U
extends java.lang.Number & java.lang.Comparable<? super U>",
-
TypeUtils.toLongString(MultiBoundClass.class.getTypeParameters()[0]));
- assertEquals("org.apache.commons.lang3.reflect.InterfaceBound:T
extends java.util.List<java.lang.String>",
-
TypeUtils.toLongString(InterfaceBound.class.getTypeParameters()[0]));
- assertEquals("org.apache.commons.lang3.reflect.MyClass:U extends
org.apache.commons.lang3.reflect.MySuperClass<? super U>",
- TypeUtils.toLongString(MyClass.class.getTypeParameters()[0]));
- }
-
- @Test
- void testParameterizedOwnerWithNonGenericInnerClassToString() throws
NoSuchMethodException {
- final ParameterizedType owner =
TypeUtils.parameterize(ParameterizedOwner.class, String.class);
- final ParameterizedType nonGenericInner =
TypeUtils.parameterizeWithOwner(owner,
ParameterizedOwner.NonGenericInner.class);
-
assertEquals("org.apache.commons.lang3.reflect.ParameterizedOwner<java.lang.String>.NonGenericInner",
- TypeUtils.toString(nonGenericInner));
-
- final Type methodReturnType =
ParameterizedOwner.class.getMethod("getInner").getGenericReturnType();
-
assertEquals("org.apache.commons.lang3.reflect.ParameterizedOwner<T>.NonGenericInner",
- TypeUtils.toString(methodReturnType));
- }
-
- @Test
- void testCyclicOwnerParameterizedTypeToString() {
- final ParameterizedType[] holder = new ParameterizedType[1];
- final ParameterizedType cyclicOwnerType = new ParameterizedType() {
- @Override
- public Type[] getActualTypeArguments() {
- return ArrayUtils.EMPTY_TYPE_ARRAY;
- }
-
- @Override
- public Type getRawType() {
- return List.class;
- }
-
- @Override
- public Type getOwnerType() {
- return holder[0];
- }
- };
- holder[0] = cyclicOwnerType;
- assertEquals("List(cycle).List", TypeUtils.toString(cyclicOwnerType));
-
- final ParameterizedType[] holderA = new ParameterizedType[1];
- final ParameterizedType[] holderB = new ParameterizedType[1];
- final ParameterizedType typeA = new ParameterizedType() {
- @Override
- public Type[] getActualTypeArguments() {
- return ArrayUtils.EMPTY_TYPE_ARRAY;
- }
-
- @Override
- public Type getRawType() {
- return Map.class;
- }
-
- @Override
- public Type getOwnerType() {
- return holderB[0];
- }
- };
- final ParameterizedType typeB = new ParameterizedType() {
- @Override
- public Type[] getActualTypeArguments() {
- return ArrayUtils.EMPTY_TYPE_ARRAY;
- }
-
- @Override
- public Type getRawType() {
- return Set.class;
- }
-
- @Override
- public Type getOwnerType() {
- return holderA[0];
- }
- };
- holderA[0] = typeA;
- holderB[0] = typeB;
- assertEquals("Map(cycle).Set.Map", TypeUtils.toString(typeA));
- }
-
- @Test
- void testRepeatedSiblingReferencesToString() {
- final ParameterizedType listString =
TypeUtils.parameterize(List.class, String.class);
- final ParameterizedType mapType = TypeUtils.parameterize(Map.class,
listString, listString);
- assertEquals("java.util.Map<java.util.List<java.lang.String>,
java.util.List<java.lang.String>>",
- TypeUtils.toString(mapType));
-
- final TypeVariable<?> t = DependentBounds.class.getTypeParameters()[0];
- final ParameterizedType biFunctionType =
TypeUtils.parameterize(BiFunction.class, t, t, t);
- assertEquals("java.util.function.BiFunction<T, T, T>",
TypeUtils.toString(biFunctionType));
-
- final WildcardType wildcard =
TypeUtils.wildcardType().withUpperBounds(listString).build();
- final ParameterizedType mapWildcards =
TypeUtils.parameterize(Map.class, wildcard, wildcard);
- assertEquals("java.util.Map<? extends
java.util.List<java.lang.String>, ? extends java.util.List<java.lang.String>>",
- TypeUtils.toString(mapWildcards));
- }
-
- @Test
- void testThreadLocalCleanupAfterException() {
- final Type unsupportedType = new Type() {
- @Override
- public String getTypeName() {
- return "Unsupported";
- }
- };
- assertThrows(IllegalArgumentException.class, () ->
TypeUtils.toString(unsupportedType));
- assertEquals("java.lang.String", TypeUtils.toString(String.class));
-
- final Type faultyType = new ParameterizedType() {
- @Override
- public Type[] getActualTypeArguments() {
- throw new IllegalStateException("Simulated failure in
getActualTypeArguments");
- }
-
- @Override
- public Type getRawType() {
- return List.class;
- }
-
- @Override
- public Type getOwnerType() {
- return null;
- }
- };
- assertThrows(IllegalStateException.class, () ->
TypeUtils.toString(faultyType));
- assertEquals("java.lang.String", TypeUtils.toString(String.class));
-
- final ParameterizedType wrapper = new ParameterizedType() {
- @Override
- public Type[] getActualTypeArguments() {
- return new Type[] { faultyType };
- }
-
- @Override
- public Type getRawType() {
- return Set.class;
- }
-
- @Override
- public Type getOwnerType() {
- return null;
- }
- };
- assertThrows(IllegalStateException.class, () ->
TypeUtils.toString(wrapper));
- assertEquals("java.util.List<java.lang.String>",
- TypeUtils.toString(TypeUtils.parameterize(List.class,
String.class)));
- }
-
- @Test
- void testCyclicWildcardTypeToString() {
- final WildcardType[] holder = new WildcardType[1];
- final WildcardType cyclicWildcard = new WildcardType() {
- @Override
- public Type[] getUpperBounds() {
- return new Type[] { holder[0] };
- }
-
- @Override
- public Type[] getLowerBounds() {
- return ArrayUtils.EMPTY_TYPE_ARRAY;
- }
- };
- holder[0] = cyclicWildcard;
- assertEquals("? extends ? (cycle)",
TypeUtils.toString(cyclicWildcard));
- }
-
- @Test
- void testCyclicParameterizedTypeToString() {
- final ParameterizedType[] holder = new ParameterizedType[1];
- final ParameterizedType cyclicType = new ParameterizedType() {
- @Override
- public Type[] getActualTypeArguments() {
- return new Type[] { holder[0] };
- }
-
- @Override
- public Type getRawType() {
- return List.class;
- }
-
- @Override
- public Type getOwnerType() {
- return null;
- }
- };
- holder[0] = cyclicType;
- assertEquals("java.util.List<List(cycle)>",
TypeUtils.toString(cyclicType));
- }
-
- @Test
- void testCyclicGenericArrayTypeToString() {
- final GenericArrayType[] holder = new GenericArrayType[1];
- final GenericArrayType cyclicType = () -> holder[0];
- holder[0] = cyclicType;
- assertEquals("(cycle)[]", TypeUtils.toString(cyclicType));
+ void testWrap() {
+ final Type t = getClass().getTypeParameters()[0];
+ assertTrue(TypeUtils.equals(t, TypeUtils.wrap(t).getType()));
+ assertEquals(String.class, TypeUtils.wrap(String.class).getType());
}
}