Skip to content

Commit

Permalink
[LANG-1524] TypeUtils.toString(Type) StackOverflowError for an inner
Browse files Browse the repository at this point in the history
class in the inner class parameterized enclosing class #657
  • Loading branch information
garydgregory committed Apr 24, 2024
1 parent abdcd58 commit c4007c4
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 3 deletions.
1 change: 1 addition & 0 deletions src/changes/changes.xml
Expand Up @@ -119,6 +119,7 @@ The <action> type attribute can be add,update,fix,remove.
<action type="fix" dev="ggregory" due-to="Gary Gregory">Make ArrayUtils.removeAll() null-safe.</action>
<action type="fix" dev="ggregory" due-to="Philipp Trulson, Gary Gregory">Fix Java version in README.md #1170.</action>
<action type="fix" dev="ggregory" due-to="Stephan Peters, Gary Gregory, Bernd">StringUtils.stripAccents() should handle ligatures, UTF32 math blocks, etc. #1201.</action>
<action issue="LANG-1524" type="fix" dev="ggregory" due-to="kijong.youn, Aakash Gupta, Gary Gregory">TypeUtils.toString(Type) StackOverflowError for an inner class in the inner class parameterized enclosing class #657.</action>
<!-- UPDATE -->
<action type="update" dev="sebb" due-to="Dependabot">Bump commons-parent from 64 to 69 #1194.</action>
<action type="update" dev="ggregory" due-to="Dependabot">Bump org.codehaus.mojo:exec-maven-plugin from 3.1.1 to 3.2.0 #1175.</action>
Expand Down
25 changes: 22 additions & 3 deletions src/main/java/org/apache/commons/lang3/reflect/TypeUtils.java
Expand Up @@ -16,6 +16,7 @@
*/
package org.apache.commons.lang3.reflect;

import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.GenericDeclaration;
Expand Down Expand Up @@ -325,15 +326,15 @@ private static void appendRecursiveTypes(final StringBuilder builder, final int[
*
* @param cls {@link Class} to format
* @return String
* @since 3.2
*/
private static String classToString(final Class<?> cls) {
if (cls.isArray()) {
return toString(cls.getComponentType()) + "[]";
}

if (isCyclical(cls)) {
return cls.getSimpleName() + "(cycle)";
}
final StringBuilder buf = new StringBuilder();

if (cls.getEnclosingClass() != null) {
buf.append(classToString(cls.getEnclosingClass())).append('.').append(cls.getSimpleName());
} else {
Expand Down Expand Up @@ -1426,6 +1427,24 @@ private static boolean isAssignable(final Type type, final WildcardType toWildca
return true;
}

/**
* Tests whether the class contains a cyclical reference in the qualified name of a class. If any of the type parameters of A class is extending X class
* which is in scope of A class, then it forms cycle.
*
* @param cls the class to test.
* @return whether the class contains a cyclical reference.
*/
private static boolean isCyclical(final Class<?> cls) {
for (final TypeVariable<?> typeParameter : cls.getTypeParameters()) {
for (final AnnotatedType annotatedBound : typeParameter.getAnnotatedBounds()) {
if (annotatedBound.getType().getTypeName().contains(cls.getName())) {
return true;
}
}
}
return false;
}

/**
* Tests if the given value can be assigned to the target type
* following the Java generics rules.
Expand Down
17 changes: 17 additions & 0 deletions src/test/java/org/apache/commons/lang3/reflect/TypeUtilsTest.java
Expand Up @@ -56,6 +56,16 @@
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;

/**
* Test fixture for https://issues.apache.org/jira/browse/LANG-1524
*/
class AAAAClass<T extends AAAAClass.BBBBClass.CCCClass> {
public static class BBBBClass {
public static class CCCClass {
}
}
}

final class AAAClass extends AAClass<String> {
public class BBBClass extends BBClass<String> {
// empty
Expand Down Expand Up @@ -261,6 +271,13 @@ public void test_LANG_1348() throws NoSuchMethodException {
assertEquals("T extends java.lang.Enum<T>", TypeUtils.toString(method.getGenericReturnType()));
}

@Test
public void test_LANG_1524() {
assertEquals("AAAAClass(cycle).BBBBClass.CCCClass", TypeUtils.toString(AAAAClass.BBBBClass.CCCClass.class));
assertEquals("AAAAClass(cycle).BBBBClass", TypeUtils.toString(AAAAClass.BBBBClass.class));
assertEquals("AAAAClass(cycle)", TypeUtils.toString(AAAAClass.class));
}

/**
* <pre>{@code
* java.lang.StackOverflowError
Expand Down

0 comments on commit c4007c4

Please sign in to comment.