Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 21 additions & 9 deletions spring-core/src/main/java/org/springframework/util/ClassUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
* @author Sam Brannen
* @author Sebastien Deleuze
* @author Sungbin Yang
* @author Chengang Guan
* @since 1.1
* @see TypeUtils
* @see ReflectionUtils
Expand Down Expand Up @@ -308,16 +309,27 @@ public static Class<?> forName(String name, @Nullable ClassLoader classLoader)
return Class.forName(name, false, clToUse);
}
catch (ClassNotFoundException ex) {
int lastDotIndex = name.lastIndexOf(PACKAGE_SEPARATOR);
int previousDotIndex = name.lastIndexOf(PACKAGE_SEPARATOR, lastDotIndex - 1);
if (lastDotIndex != -1 && previousDotIndex != -1 && Character.isUpperCase(name.charAt(previousDotIndex + 1))) {
String nestedClassName =
name.substring(0, lastDotIndex) + NESTED_CLASS_SEPARATOR + name.substring(lastDotIndex + 1);
try {
return Class.forName(nestedClassName, false, clToUse);
if (name.lastIndexOf(NESTED_CLASS_SEPARATOR) > 0) {
// not java source style
throw ex;
}
String curName = name;
for (;;) {
int lastDotIndex = curName.lastIndexOf(PACKAGE_SEPARATOR);
int previousDotIndex = curName.lastIndexOf(PACKAGE_SEPARATOR, lastDotIndex - 1);
if (lastDotIndex != -1 && previousDotIndex != -1 &&
Character.isUpperCase(curName.charAt(previousDotIndex + 1))) {
curName = curName.substring(0, lastDotIndex) + NESTED_CLASS_SEPARATOR +
curName.substring(lastDotIndex + 1);
try {
return Class.forName(curName, false, clToUse);
}
catch (ClassNotFoundException ex2) {
// Swallow - let original exception get through
}
}
catch (ClassNotFoundException ex2) {
// Swallow - let original exception get through
else {
break;
}
}
throw ex;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import org.springframework.tests.sample.objects.TestObject;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

/**
* Tests for {@link ClassUtils}.
Expand All @@ -63,6 +64,7 @@
* @author Rob Harrop
* @author Rick Evans
* @author Sam Brannen
* @author Chengang Guan
*/
class ClassUtilsTests {

Expand Down Expand Up @@ -101,6 +103,20 @@ void forNameWithNestedType() throws ClassNotFoundException {
assertThat(ClassUtils.forName("a.ClassHavingNestedClass.NestedClass", classLoader)).isEqualTo(ClassHavingNestedClass.NestedClass.class);
}

@Test
void forNamesWithDeepNestingTypes() throws ClassNotFoundException {
assertThat(ClassUtils.forName("org.springframework.util.ClassUtilsTests.NestedClass.NestedClassLevel1", classLoader))
.isEqualTo(NestedClass.NestedClassLevel1.class);
assertThat(ClassUtils.forName("org.springframework.util.ClassUtilsTests.NestedClass.NestedClassLevel1.NestedClassLevel2", classLoader))
.isEqualTo(NestedClass.NestedClassLevel1.NestedClassLevel2.class);
assertThat(ClassUtils.forName("org.springframework.util.ClassUtilsTests$NestedClass$NestedClassLevel1$NestedClassLevel2", classLoader))
.isEqualTo(NestedClass.NestedClassLevel1.NestedClassLevel2.class);
assertThatThrownBy(() -> ClassUtils.forName("org.springframework.util.ClassUtilsTests.NestedClass$NestedClassLevel1", classLoader))
.isInstanceOf(ClassNotFoundException.class);
assertThatThrownBy(() -> ClassUtils.forName("org.springframework.util.ClassUtilsTests$NestedClass.NestedClassLevel1", classLoader))
.isInstanceOf(ClassNotFoundException.class);
}

@Test
void forNameWithPrimitiveClasses() throws ClassNotFoundException {
assertThat(ClassUtils.forName("boolean", classLoader)).isEqualTo(boolean.class);
Expand Down Expand Up @@ -980,6 +996,12 @@ private static void assertStatic(Member member) {

public static class NestedClass {

public static class NestedClassLevel1 {

public static class NestedClassLevel2 {
}
}

static boolean noArgCalled;
static boolean argCalled;
static boolean overloadedCalled;
Expand Down
Loading