Skip to content

Commit 566ff54

Browse files
committed
Polishing
See gh-26540
1 parent 77b7e49 commit 566ff54

File tree

4 files changed

+69
-61
lines changed

4 files changed

+69
-61
lines changed

spring-core/src/main/java/org/springframework/util/ClassUtils.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -74,8 +74,8 @@ public abstract class ClassUtils {
7474
/** The path separator character: {@code '/'}. */
7575
private static final char PATH_SEPARATOR = '/';
7676

77-
/** The inner class separator character: {@code '$'}. */
78-
private static final char INNER_CLASS_SEPARATOR = '$';
77+
/** The nested class separator character: {@code '$'}. */
78+
private static final char NESTED_CLASS_SEPARATOR = '$';
7979

8080
/** The CGLIB class separator: {@code "$$"}. */
8181
public static final String CGLIB_CLASS_SEPARATOR = "$$";
@@ -232,7 +232,7 @@ public static ClassLoader overrideThreadContextClassLoader(@Nullable ClassLoader
232232
/**
233233
* Replacement for {@code Class.forName()} that also returns Class instances
234234
* for primitives (e.g. "int") and array class names (e.g. "String[]").
235-
* Furthermore, it is also capable of resolving inner class names in Java source
235+
* Furthermore, it is also capable of resolving nested class names in Java source
236236
* style (e.g. "java.lang.Thread.State" instead of "java.lang.Thread$State").
237237
* @param name the name of the Class
238238
* @param classLoader the class loader to use
@@ -286,10 +286,10 @@ public static Class<?> forName(String name, @Nullable ClassLoader classLoader)
286286
catch (ClassNotFoundException ex) {
287287
int lastDotIndex = name.lastIndexOf(PACKAGE_SEPARATOR);
288288
if (lastDotIndex != -1) {
289-
String innerClassName =
290-
name.substring(0, lastDotIndex) + INNER_CLASS_SEPARATOR + name.substring(lastDotIndex + 1);
289+
String nestedClassName =
290+
name.substring(0, lastDotIndex) + NESTED_CLASS_SEPARATOR + name.substring(lastDotIndex + 1);
291291
try {
292-
return Class.forName(innerClassName, false, clToUse);
292+
return Class.forName(nestedClassName, false, clToUse);
293293
}
294294
catch (ClassNotFoundException ex2) {
295295
// Swallow - let original exception get through
@@ -953,7 +953,7 @@ public static String getShortName(String className) {
953953
nameEndIndex = className.length();
954954
}
955955
String shortName = className.substring(lastDotIndex + 1, nameEndIndex);
956-
shortName = shortName.replace(INNER_CLASS_SEPARATOR, PACKAGE_SEPARATOR);
956+
shortName = shortName.replace(NESTED_CLASS_SEPARATOR, PACKAGE_SEPARATOR);
957957
return shortName;
958958
}
959959

@@ -968,7 +968,7 @@ public static String getShortName(Class<?> clazz) {
968968

969969
/**
970970
* Return the short string name of a Java class in uncapitalized JavaBeans
971-
* property format. Strips the outer class name in case of an inner class.
971+
* property format. Strips the outer class name in case of a nested class.
972972
* @param clazz the class
973973
* @return the short name rendered in a standard JavaBeans property format
974974
* @see java.beans.Introspector#decapitalize(String)

spring-core/src/test/java/org/springframework/tests/sample/objects/TestObject.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,4 @@ public int compareTo(Object o) {
7575
return 1;
7676
}
7777
}
78-
79-
public static class NestedObject {
80-
}
8178
}

spring-core/src/test/java/org/springframework/util/ClassUtilsTests.java

Lines changed: 51 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -33,6 +33,7 @@
3333
import java.util.Set;
3434

3535
import org.junit.jupiter.api.BeforeEach;
36+
import org.junit.jupiter.api.Nested;
3637
import org.junit.jupiter.api.Test;
3738
import org.junit.jupiter.params.ParameterizedTest;
3839
import org.junit.jupiter.params.provider.CsvSource;
@@ -59,14 +60,6 @@ class ClassUtilsTests {
5960
private final ClassLoader classLoader = getClass().getClassLoader();
6061

6162

62-
@BeforeEach
63-
void clearStatics() {
64-
InnerClass.noArgCalled = false;
65-
InnerClass.argCalled = false;
66-
InnerClass.overloadedCalled = false;
67-
}
68-
69-
7063
@Test
7164
void isPresent() {
7265
assertThat(ClassUtils.isPresent("java.lang.String", classLoader)).isTrue();
@@ -86,8 +79,12 @@ void forName() throws ClassNotFoundException {
8679
assertThat(ClassUtils.forName("org.springframework.tests.sample.objects.TestObject[][]", classLoader)).isEqualTo(TestObject[][].class);
8780
assertThat(ClassUtils.forName(TestObject[][].class.getName(), classLoader)).isEqualTo(TestObject[][].class);
8881
assertThat(ClassUtils.forName("[[[S", classLoader)).isEqualTo(short[][][].class);
89-
assertThat(ClassUtils.forName("org.springframework.tests.sample.objects.TestObject$NestedObject", classLoader)).isEqualTo(TestObject.NestedObject.class);
90-
assertThat(ClassUtils.forName("org.springframework.tests.sample.objects.TestObject.NestedObject", classLoader)).isEqualTo(TestObject.NestedObject.class);
82+
}
83+
84+
@Test
85+
void forNameWithNestedType() throws ClassNotFoundException {
86+
assertThat(ClassUtils.forName("org.springframework.util.ClassUtilsTests$NestedClass", classLoader)).isEqualTo(NestedClass.class);
87+
assertThat(ClassUtils.forName("org.springframework.util.ClassUtilsTests.NestedClass", classLoader)).isEqualTo(NestedClass.class);
9188
}
9289

9390
@Test
@@ -145,11 +142,11 @@ public Class<?> loadClass(String name) throws ClassNotFoundException {
145142
assertThat(ClassUtils.isCacheSafe(String.class, childLoader1)).isTrue();
146143
assertThat(ClassUtils.isCacheSafe(String.class, childLoader2)).isTrue();
147144
assertThat(ClassUtils.isCacheSafe(String.class, childLoader3)).isTrue();
148-
assertThat(ClassUtils.isCacheSafe(InnerClass.class, null)).isFalse();
149-
assertThat(ClassUtils.isCacheSafe(InnerClass.class, classLoader)).isTrue();
150-
assertThat(ClassUtils.isCacheSafe(InnerClass.class, childLoader1)).isTrue();
151-
assertThat(ClassUtils.isCacheSafe(InnerClass.class, childLoader2)).isTrue();
152-
assertThat(ClassUtils.isCacheSafe(InnerClass.class, childLoader3)).isTrue();
145+
assertThat(ClassUtils.isCacheSafe(NestedClass.class, null)).isFalse();
146+
assertThat(ClassUtils.isCacheSafe(NestedClass.class, classLoader)).isTrue();
147+
assertThat(ClassUtils.isCacheSafe(NestedClass.class, childLoader1)).isTrue();
148+
assertThat(ClassUtils.isCacheSafe(NestedClass.class, childLoader2)).isTrue();
149+
assertThat(ClassUtils.isCacheSafe(NestedClass.class, childLoader3)).isTrue();
153150
assertThat(ClassUtils.isCacheSafe(composite, null)).isFalse();
154151
assertThat(ClassUtils.isCacheSafe(composite, classLoader)).isFalse();
155152
assertThat(ClassUtils.isCacheSafe(composite, childLoader1)).isTrue();
@@ -211,9 +208,9 @@ void getShortNameForMultiDimensionalPrimitiveArrayClass() {
211208
}
212209

213210
@Test
214-
void getShortNameForInnerClass() {
215-
String className = ClassUtils.getShortName(InnerClass.class);
216-
assertThat(className).as("Class name did not match").isEqualTo("ClassUtilsTests.InnerClass");
211+
void getShortNameForNestedClass() {
212+
String className = ClassUtils.getShortName(NestedClass.class);
213+
assertThat(className).as("Class name did not match").isEqualTo("ClassUtilsTests.NestedClass");
217214
}
218215

219216
@Test
@@ -301,27 +298,6 @@ void countOverloadedMethods() {
301298
assertThat(ClassUtils.hasAtLeastOneMethodWithName(TestObject.class, "setAge")).isTrue();
302299
}
303300

304-
@Test
305-
void noArgsStaticMethod() throws IllegalAccessException, InvocationTargetException {
306-
Method method = ClassUtils.getStaticMethod(InnerClass.class, "staticMethod");
307-
method.invoke(null, (Object[]) null);
308-
assertThat(InnerClass.noArgCalled).as("no argument method was not invoked.").isTrue();
309-
}
310-
311-
@Test
312-
void argsStaticMethod() throws IllegalAccessException, InvocationTargetException {
313-
Method method = ClassUtils.getStaticMethod(InnerClass.class, "argStaticMethod", String.class);
314-
method.invoke(null, "test");
315-
assertThat(InnerClass.argCalled).as("argument method was not invoked.").isTrue();
316-
}
317-
318-
@Test
319-
void overloadedStaticMethod() throws IllegalAccessException, InvocationTargetException {
320-
Method method = ClassUtils.getStaticMethod(InnerClass.class, "staticMethod", String.class);
321-
method.invoke(null, "test");
322-
assertThat(InnerClass.overloadedCalled).as("argument method was not invoked.").isTrue();
323-
}
324-
325301
@Test
326302
void isAssignable() {
327303
assertThat(ClassUtils.isAssignable(Object.class, Object.class)).isTrue();
@@ -433,6 +409,40 @@ void isPrimitiveOrWrapperWithWrapper(Class<?> type) {
433409
}
434410

435411

412+
@Nested
413+
class GetStaticMethodTests {
414+
415+
@BeforeEach
416+
void clearStatics() {
417+
NestedClass.noArgCalled = false;
418+
NestedClass.argCalled = false;
419+
NestedClass.overloadedCalled = false;
420+
}
421+
422+
@Test
423+
void noArgsStaticMethod() throws IllegalAccessException, InvocationTargetException {
424+
Method method = ClassUtils.getStaticMethod(NestedClass.class, "staticMethod");
425+
method.invoke(null, (Object[]) null);
426+
assertThat(NestedClass.noArgCalled).as("no argument method was not invoked.").isTrue();
427+
}
428+
429+
@Test
430+
void argsStaticMethod() throws IllegalAccessException, InvocationTargetException {
431+
Method method = ClassUtils.getStaticMethod(NestedClass.class, "argStaticMethod", String.class);
432+
method.invoke(null, "test");
433+
assertThat(NestedClass.argCalled).as("argument method was not invoked.").isTrue();
434+
}
435+
436+
@Test
437+
void overloadedStaticMethod() throws IllegalAccessException, InvocationTargetException {
438+
Method method = ClassUtils.getStaticMethod(NestedClass.class, "staticMethod", String.class);
439+
method.invoke(null, "test");
440+
assertThat(NestedClass.overloadedCalled).as("argument method was not invoked.").isTrue();
441+
}
442+
443+
}
444+
445+
436446
@Target(ElementType.METHOD)
437447
@Retention(RetentionPolicy.RUNTIME)
438448
@ValueSource(classes = { Boolean.class, Character.class, Byte.class, Short.class,
@@ -447,7 +457,7 @@ void isPrimitiveOrWrapperWithWrapper(Class<?> type) {
447457
@interface PrimitiveTypes {
448458
}
449459

450-
public static class InnerClass {
460+
public static class NestedClass {
451461

452462
static boolean noArgCalled;
453463
static boolean argCalled;

src/docs/asciidoc/core/core-beans.adoc

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -639,15 +639,16 @@ You can use the `Class` property in one of two ways:
639639
from the invocation of the `static` factory method may be the same class or another
640640
class entirely.
641641

642+
.Nested class names
642643
****
643-
.Inner class names
644-
If you want to configure a bean definition for a `static` nested class, you may use
645-
either binary name of the nested class or separate it with dot.
646-
647-
For example, if you have a class called `SomeThing` in the `com.example` package, and this
648-
`SomeThing` class has a `static` nested class called `OtherThing`, they can be separated
649-
by a dollar (`$`) or dot (`.`). So the value of the `class` attribute on a bean definition
650-
would be `com.example.SomeThing$OtherThing` or `com.example.SomeThing.OtherThing`.
644+
If you want to configure a bean definition for a nested class, you may use either the
645+
binary name or the source name of the nested class.
646+
647+
For example, if you have a class called `SomeThing` in the `com.example` package, and
648+
this `SomeThing` class has a `static` nested class called `OtherThing`, they can be
649+
separated by a dollar sign (`$`) or a dot (`.`). So the value of the `class` attribute in
650+
a bean definition would be `com.example.SomeThing$OtherThing` or
651+
`com.example.SomeThing.OtherThing`.
651652
****
652653

653654

0 commit comments

Comments
 (0)