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 c4007c4a2 [LANG-1524] TypeUtils.toString(Type) StackOverflowError for 
an inner class in the inner class parameterized enclosing class #657
c4007c4a2 is described below

commit c4007c4a24eafbed53109e4b0376b4fd0ba01b56
Author: Gary Gregory <[email protected]>
AuthorDate: Wed Apr 24 11:09:10 2024 -0400

    [LANG-1524] TypeUtils.toString(Type) StackOverflowError for an inner
    class in the inner class parameterized enclosing class #657
---
 src/changes/changes.xml                            |  1 +
 .../apache/commons/lang3/reflect/TypeUtils.java    | 25 +++++++++++++++++++---
 .../commons/lang3/reflect/TypeUtilsTest.java       | 17 +++++++++++++++
 3 files changed, 40 insertions(+), 3 deletions(-)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 7eba1df85..f56258941 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -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>
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 8533ea3be..cd0f437ae 100644
--- a/src/main/java/org/apache/commons/lang3/reflect/TypeUtils.java
+++ b/src/main/java/org/apache/commons/lang3/reflect/TypeUtils.java
@@ -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;
@@ -325,15 +326,15 @@ public class TypeUtils {
      *
      * @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 {
@@ -1426,6 +1427,24 @@ public class TypeUtils {
         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.
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 ce5051413..dca2096b5 100644
--- a/src/test/java/org/apache/commons/lang3/reflect/TypeUtilsTest.java
+++ b/src/test/java/org/apache/commons/lang3/reflect/TypeUtilsTest.java
@@ -56,6 +56,16 @@ import 
org.apache.commons.lang3.reflect.testbed.StringParameterizedChild;
 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
@@ -261,6 +271,13 @@ public class TypeUtilsTest<B> extends AbstractLangTest {
         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

Reply via email to