This commit is contained in:
Looly 2023-05-29 00:24:53 +08:00
parent 9c4d71d36a
commit 6260734304
2 changed files with 62 additions and 61 deletions

View File

@ -781,7 +781,7 @@ public class ClassUtil {
if (clazz == null) { if (clazz == null) {
return Collections.emptyList(); return Collections.emptyList();
} }
List<Class<?>> superclasses = new ArrayList<>(); final List<Class<?>> superclasses = new ArrayList<>();
traverseTypeHierarchy(clazz, t -> !t.isInterface(), superclasses::add, false); traverseTypeHierarchy(clazz, t -> !t.isInterface(), superclasses::add, false);
return superclasses; return superclasses;
} }
@ -797,7 +797,7 @@ public class ClassUtil {
if (cls == null) { if (cls == null) {
return Collections.emptyList(); return Collections.emptyList();
} }
List<Class<?>> interfaces = new ArrayList<>(); final List<Class<?>> interfaces = new ArrayList<>();
traverseTypeHierarchy(cls, t -> true, t -> { traverseTypeHierarchy(cls, t -> true, t -> {
if (t.isInterface()) { if (t.isInterface()) {
interfaces.add(t); interfaces.add(t);
@ -813,7 +813,7 @@ public class ClassUtil {
* @param terminator 对遍历到的每个类与接口执行的校验若为{@code false}则立刻中断遍历 * @param terminator 对遍历到的每个类与接口执行的校验若为{@code false}则立刻中断遍历
*/ */
public static void traverseTypeHierarchyWhile( public static void traverseTypeHierarchyWhile(
final Class<?> root, Predicate<Class<?>> terminator) { final Class<?> root, final Predicate<Class<?>> terminator) {
traverseTypeHierarchyWhile(root, t -> true, terminator); traverseTypeHierarchyWhile(root, t -> true, terminator);
} }
@ -847,11 +847,11 @@ public class ClassUtil {
* @param includeRoot 是否包括根类 * @param includeRoot 是否包括根类
*/ */
public static void traverseTypeHierarchy( public static void traverseTypeHierarchy(
final Class<?> root, final Predicate<Class<?>> filter, final Consumer<Class<?>> consumer, boolean includeRoot) { final Class<?> root, final Predicate<Class<?>> filter, final Consumer<Class<?>> consumer, final boolean includeRoot) {
Objects.requireNonNull(root); Objects.requireNonNull(root);
Objects.requireNonNull(filter); Objects.requireNonNull(filter);
Objects.requireNonNull(consumer); Objects.requireNonNull(consumer);
Function<Class<?>, Collection<Class<?>>> function = t -> { final Function<Class<?>, Collection<Class<?>>> function = t -> {
if (includeRoot || !root.equals(t)) { if (includeRoot || !root.equals(t)) {
consumer.accept(t); consumer.accept(t);
} }
@ -860,9 +860,9 @@ public class ClassUtil {
HierarchyUtil.traverseByBreadthFirst(root, filter, HierarchyIteratorUtil.scan(function)); HierarchyUtil.traverseByBreadthFirst(root, filter, HierarchyIteratorUtil.scan(function));
} }
private static Set<Class<?>> getNextTypeHierarchies(Class<?> t) { private static Set<Class<?>> getNextTypeHierarchies(final Class<?> t) {
Set<Class<?>> next = new LinkedHashSet<>(); final Set<Class<?>> next = new LinkedHashSet<>();
Class<?> superclass = t.getSuperclass(); final Class<?> superclass = t.getSuperclass();
if (Objects.nonNull(superclass)) { if (Objects.nonNull(superclass)) {
next.add(superclass); next.add(superclass);
} }

View File

@ -1,6 +1,7 @@
package org.dromara.hutool.core.reflect.method; package org.dromara.hutool.core.reflect.method;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import org.dromara.hutool.core.annotation.Alias;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -23,27 +24,27 @@ class MethodScannerTest {
@Test @Test
void testGetMethods() { void testGetMethods() {
Assertions.assertEquals(0, MethodScanner.getMethods(null).length); Assertions.assertEquals(0, MethodScanner.getMethods(null).length);
Method[] actual = MethodScanner.getMethods(Child.class); final Method[] actual = MethodScanner.getMethods(Child.class);
Assertions.assertSame(actual, MethodScanner.getMethods(Child.class)); Assertions.assertSame(actual, MethodScanner.getMethods(Child.class));
Method[] expected = Child.class.getMethods(); final Method[] expected = Child.class.getMethods();
Assertions.assertArrayEquals(expected, actual); Assertions.assertArrayEquals(expected, actual);
} }
@Test @Test
void testGetDeclaredMethods() { void testGetDeclaredMethods() {
Assertions.assertEquals(0, MethodScanner.getDeclaredMethods(null).length); Assertions.assertEquals(0, MethodScanner.getDeclaredMethods(null).length);
Method[] actual = MethodScanner.getDeclaredMethods(Child.class); final Method[] actual = MethodScanner.getDeclaredMethods(Child.class);
Assertions.assertSame(actual, MethodScanner.getDeclaredMethods(Child.class)); Assertions.assertSame(actual, MethodScanner.getDeclaredMethods(Child.class));
Method[] expected = Child.class.getDeclaredMethods(); final Method[] expected = Child.class.getDeclaredMethods();
Assertions.assertArrayEquals(expected, actual); Assertions.assertArrayEquals(expected, actual);
} }
@Test @Test
void testGetAllMethods() { void testGetAllMethods() {
Assertions.assertEquals(0, MethodScanner.getAllMethods(null).length); Assertions.assertEquals(0, MethodScanner.getAllMethods(null).length);
Method[] actual = MethodScanner.getAllMethods(Child.class); final Method[] actual = MethodScanner.getAllMethods(Child.class);
// get declared method from childparentgrandparent // get declared method from childparentgrandparent
Method[] expected = Stream.of(Child.class, Parent.class, Interface.class, Object.class) final Method[] expected = Stream.of(Child.class, Parent.class, Interface.class, Object.class)
.flatMap(c -> Stream.of(MethodScanner.getDeclaredMethods(c))) .flatMap(c -> Stream.of(MethodScanner.getDeclaredMethods(c)))
.toArray(Method[]::new); .toArray(Method[]::new);
Assertions.assertArrayEquals(expected, actual); Assertions.assertArrayEquals(expected, actual);
@ -51,9 +52,9 @@ class MethodScannerTest {
@Test @Test
void testClearCaches() { void testClearCaches() {
Method[] declaredMethods = MethodScanner.getDeclaredMethods(Child.class); final Method[] declaredMethods = MethodScanner.getDeclaredMethods(Child.class);
Assertions.assertSame(declaredMethods, MethodScanner.getDeclaredMethods(Child.class)); Assertions.assertSame(declaredMethods, MethodScanner.getDeclaredMethods(Child.class));
Method[] methods = MethodScanner.getMethods(Child.class); final Method[] methods = MethodScanner.getMethods(Child.class);
Assertions.assertSame(methods, MethodScanner.getMethods(Child.class)); Assertions.assertSame(methods, MethodScanner.getMethods(Child.class));
// clear method cache // clear method cache
@ -66,28 +67,28 @@ class MethodScannerTest {
@Test @Test
void testFindWithMetadataFromSpecificMethods() { void testFindWithMetadataFromSpecificMethods() {
Assertions.assertTrue(MethodScanner.findWithMetadataFromSpecificMethods(null, m -> m.getAnnotation(Annotation.class)).isEmpty()); Assertions.assertTrue(MethodScanner.findWithMetadataFromSpecificMethods(null, m -> m.getAnnotation(Annotation.class)).isEmpty());
Method[] methods = MethodScanner.getMethods(Child.class); final Method[] methods = MethodScanner.getMethods(Child.class);
Map<Method, Annotation> actual = MethodScanner.findWithMetadataFromSpecificMethods(methods, m -> m.getAnnotation(Annotation.class)); final Map<Method, Annotation> actual = MethodScanner.findWithMetadataFromSpecificMethods(methods, m -> m.getAnnotation(Annotation.class));
Assertions.assertEquals(1, actual.size()); Assertions.assertEquals(1, actual.size());
// check method // check method
Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class); final Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class);
Assertions.assertTrue(actual.containsKey(expectedMethod)); Assertions.assertTrue(actual.containsKey(expectedMethod));
// check annotation // check annotation
Annotation expectedAnnotation = expectedMethod.getAnnotation(Annotation.class); final Annotation expectedAnnotation = expectedMethod.getAnnotation(Annotation.class);
Assertions.assertEquals(expectedAnnotation, actual.get(expectedMethod)); Assertions.assertEquals(expectedAnnotation, actual.get(expectedMethod));
} }
@SneakyThrows @SneakyThrows
@Test @Test
void testFindFromSpecificMethods() { void testFindFromSpecificMethods() {
Method[] methods = MethodScanner.getMethods(Child.class); final Method[] methods = MethodScanner.getMethods(Child.class);
Set<Method> actual = MethodScanner.findFromSpecificMethods(methods, m -> m.getAnnotation(Annotation.class)); final Set<Method> actual = MethodScanner.findFromSpecificMethods(methods, m -> m.getAnnotation(Annotation.class));
Assertions.assertEquals(1, actual.size()); Assertions.assertEquals(1, actual.size());
// check method // check method
Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class); final Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class);
Assertions.assertTrue(actual.contains(expectedMethod)); Assertions.assertTrue(actual.contains(expectedMethod));
} }
@ -95,10 +96,10 @@ class MethodScannerTest {
@Test @Test
void testGetWithMetadataFromSpecificMethods() { void testGetWithMetadataFromSpecificMethods() {
// find first oneArgMethod method // find first oneArgMethod method
Method[] methods = MethodScanner.getMethods(Child.class); final Method[] methods = MethodScanner.getMethods(Child.class);
Map.Entry<Method, Boolean> actual = MethodScanner.getWithMetadataFromSpecificMethods(methods, MethodMatcherUtil.forName("oneArgMethod")); final Map.Entry<Method, Boolean> actual = MethodScanner.getWithMetadataFromSpecificMethods(methods, MethodMatcherUtil.forName("oneArgMethod"));
Assertions.assertNotNull(actual); Assertions.assertNotNull(actual);
Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class); final Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class);
Assertions.assertEquals(expectedMethod, actual.getKey()); Assertions.assertEquals(expectedMethod, actual.getKey());
Assertions.assertTrue(actual.getValue()); Assertions.assertTrue(actual.getValue());
} }
@ -107,145 +108,145 @@ class MethodScannerTest {
@Test @Test
void testGetFromSpecificMethods() { void testGetFromSpecificMethods() {
// find first oneArgMethod method // find first oneArgMethod method
Method[] methods = MethodScanner.getMethods(Child.class); final Method[] methods = MethodScanner.getMethods(Child.class);
Method actual = MethodScanner.getFromSpecificMethods(methods, MethodMatcherUtil.forName("oneArgMethod")); final Method actual = MethodScanner.getFromSpecificMethods(methods, MethodMatcherUtil.forName("oneArgMethod"));
Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class); final Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class);
Assertions.assertEquals(expectedMethod, actual); Assertions.assertEquals(expectedMethod, actual);
} }
@SneakyThrows @SneakyThrows
@Test @Test
void testFindWithMetadataFromMethods() { void testFindWithMetadataFromMethods() {
Map<Method, Annotation> actual = MethodScanner.findWithMetadataFromMethods(Child.class, m -> m.getAnnotation(Annotation.class)); final Map<Method, Annotation> actual = MethodScanner.findWithMetadataFromMethods(Child.class, m -> m.getAnnotation(Annotation.class));
Assertions.assertEquals(1, actual.size()); Assertions.assertEquals(1, actual.size());
// check method // check method
Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class); final Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class);
Assertions.assertTrue(actual.containsKey(expectedMethod)); Assertions.assertTrue(actual.containsKey(expectedMethod));
// check annotation // check annotation
Annotation expectedAnnotation = expectedMethod.getAnnotation(Annotation.class); final Annotation expectedAnnotation = expectedMethod.getAnnotation(Annotation.class);
Assertions.assertEquals(expectedAnnotation, actual.get(expectedMethod)); Assertions.assertEquals(expectedAnnotation, actual.get(expectedMethod));
} }
@SneakyThrows @SneakyThrows
@Test @Test
void testFindFromMethods() { void testFindFromMethods() {
Set<Method> actual = MethodScanner.findFromMethods(Child.class, m -> m.getAnnotation(Annotation.class)); final Set<Method> actual = MethodScanner.findFromMethods(Child.class, m -> m.getAnnotation(Annotation.class));
Assertions.assertEquals(1, actual.size()); Assertions.assertEquals(1, actual.size());
// check method // check method
Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class); final Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class);
Assertions.assertTrue(actual.contains(expectedMethod)); Assertions.assertTrue(actual.contains(expectedMethod));
} }
@SneakyThrows @SneakyThrows
@Test @Test
void testGetWithMetadataFromMethods() { void testGetWithMetadataFromMethods() {
Map.Entry<Method, Annotation> actual = MethodScanner.getWithMetadataFromMethods(Child.class, m -> m.getAnnotation(Annotation.class)); final Map.Entry<Method, Annotation> actual = MethodScanner.getWithMetadataFromMethods(Child.class, m -> m.getAnnotation(Annotation.class));
Assertions.assertNotNull(actual); Assertions.assertNotNull(actual);
Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class); final Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class);
Assertions.assertEquals(expectedMethod, actual.getKey()); Assertions.assertEquals(expectedMethod, actual.getKey());
Annotation expectedAnnotation = expectedMethod.getAnnotation(Annotation.class); final Annotation expectedAnnotation = expectedMethod.getAnnotation(Annotation.class);
Assertions.assertEquals(expectedAnnotation, actual.getValue()); Assertions.assertEquals(expectedAnnotation, actual.getValue());
} }
@SneakyThrows @SneakyThrows
@Test @Test
void testGetFromMethods() { void testGetFromMethods() {
Method actual = MethodScanner.getFromMethods(Child.class, m -> m.getAnnotation(Annotation.class)); final Method actual = MethodScanner.getFromMethods(Child.class, m -> m.getAnnotation(Annotation.class));
Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class); final Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class);
Assertions.assertEquals(expectedMethod, actual); Assertions.assertEquals(expectedMethod, actual);
} }
@SneakyThrows @SneakyThrows
@Test @Test
void testFindWithMetadataFromDeclaredMethods() { void testFindWithMetadataFromDeclaredMethods() {
Map<Method, Annotation> actual = MethodScanner.findWithMetadataFromDeclaredMethods(Parent.class, m -> m.getAnnotation(Annotation.class)); final Map<Method, Annotation> actual = MethodScanner.findWithMetadataFromDeclaredMethods(Parent.class, m -> m.getAnnotation(Annotation.class));
Assertions.assertEquals(1, actual.size()); Assertions.assertEquals(1, actual.size());
// check method // check method
Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class); final Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class);
Assertions.assertTrue(actual.containsKey(expectedMethod)); Assertions.assertTrue(actual.containsKey(expectedMethod));
// check annotation // check annotation
Annotation expectedAnnotation = expectedMethod.getAnnotation(Annotation.class); final Annotation expectedAnnotation = expectedMethod.getAnnotation(Annotation.class);
Assertions.assertEquals(expectedAnnotation, actual.get(expectedMethod)); Assertions.assertEquals(expectedAnnotation, actual.get(expectedMethod));
} }
@SneakyThrows @SneakyThrows
@Test @Test
void testFindFromDeclaredMethods() { void testFindFromDeclaredMethods() {
Set<Method> actual = MethodScanner.findFromDeclaredMethods(Parent.class, m -> m.getAnnotation(Annotation.class)); final Set<Method> actual = MethodScanner.findFromDeclaredMethods(Parent.class, m -> m.getAnnotation(Annotation.class));
Assertions.assertEquals(1, actual.size()); Assertions.assertEquals(1, actual.size());
// check method // check method
Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class); final Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class);
Assertions.assertTrue(actual.contains(expectedMethod)); Assertions.assertTrue(actual.contains(expectedMethod));
} }
@SneakyThrows @SneakyThrows
@Test @Test
void testGetWithMetadataFromDeclaredMethods() { void testGetWithMetadataFromDeclaredMethods() {
Map.Entry<Method, Annotation> actual = MethodScanner.getWithMetadataFromDeclaredMethods(Parent.class, m -> m.getAnnotation(Annotation.class)); final Map.Entry<Method, Annotation> actual = MethodScanner.getWithMetadataFromDeclaredMethods(Parent.class, m -> m.getAnnotation(Annotation.class));
Assertions.assertNotNull(actual); Assertions.assertNotNull(actual);
Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class); final Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class);
Assertions.assertEquals(expectedMethod, actual.getKey()); Assertions.assertEquals(expectedMethod, actual.getKey());
Annotation expectedAnnotation = expectedMethod.getAnnotation(Annotation.class); final Annotation expectedAnnotation = expectedMethod.getAnnotation(Annotation.class);
Assertions.assertEquals(expectedAnnotation, actual.getValue()); Assertions.assertEquals(expectedAnnotation, actual.getValue());
} }
@SneakyThrows @SneakyThrows
@Test @Test
void testGetFromDeclaredMethods() { void testGetFromDeclaredMethods() {
Method actual = MethodScanner.getFromDeclaredMethods(Parent.class, m -> m.getAnnotation(Annotation.class)); final Method actual = MethodScanner.getFromDeclaredMethods(Parent.class, m -> m.getAnnotation(Annotation.class));
Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class); final Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class);
Assertions.assertEquals(expectedMethod, actual); Assertions.assertEquals(expectedMethod, actual);
} }
@SneakyThrows @SneakyThrows
@Test @Test
void testFindWithMetadataFromAllMethods() { void testFindWithMetadataFromAllMethods() {
Map<Method, Annotation> actual = MethodScanner.findWithMetadataFromAllMethods(Child.class, m -> m.getAnnotation(Annotation.class)); final Map<Method, Annotation> actual = MethodScanner.findWithMetadataFromAllMethods(Child.class, m -> m.getAnnotation(Annotation.class));
Assertions.assertEquals(1, actual.size()); Assertions.assertEquals(1, actual.size());
// check method // check method
Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class); final Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class);
Assertions.assertTrue(actual.containsKey(expectedMethod)); Assertions.assertTrue(actual.containsKey(expectedMethod));
// check annotation // check annotation
Annotation expectedAnnotation = expectedMethod.getAnnotation(Annotation.class); final Annotation expectedAnnotation = expectedMethod.getAnnotation(Annotation.class);
Assertions.assertEquals(expectedAnnotation, actual.get(expectedMethod)); Assertions.assertEquals(expectedAnnotation, actual.get(expectedMethod));
} }
@SneakyThrows @SneakyThrows
@Test @Test
void testFindFromAllMethods() { void testFindFromAllMethods() {
Set<Method> actual = MethodScanner.findFromAllMethods(Child.class, m -> m.getAnnotation(Annotation.class)); final Set<Method> actual = MethodScanner.findFromAllMethods(Child.class, m -> m.getAnnotation(Annotation.class));
Assertions.assertEquals(1, actual.size()); Assertions.assertEquals(1, actual.size());
// check method // check method
Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class); final Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class);
Assertions.assertTrue(actual.contains(expectedMethod)); Assertions.assertTrue(actual.contains(expectedMethod));
} }
@SneakyThrows @SneakyThrows
@Test @Test
void testGetWithMetadataFromAllMethods() { void testGetWithMetadataFromAllMethods() {
Assertions.assertNull(MethodScanner.getWithMetadataFromAllMethods(Child.class, m -> m.getAnnotation(Deprecated.class))); Assertions.assertNull(MethodScanner.getWithMetadataFromAllMethods(Child.class, m -> m.getAnnotation(Alias.class)));
Map.Entry<Method, Annotation> actual = MethodScanner.getWithMetadataFromAllMethods(Child.class, m -> m.getAnnotation(Annotation.class)); final Map.Entry<Method, Annotation> actual = MethodScanner.getWithMetadataFromAllMethods(Child.class, m -> m.getAnnotation(Annotation.class));
Assertions.assertNotNull(actual); Assertions.assertNotNull(actual);
Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class); final Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class);
Assertions.assertEquals(expectedMethod, actual.getKey()); Assertions.assertEquals(expectedMethod, actual.getKey());
Annotation expectedAnnotation = expectedMethod.getAnnotation(Annotation.class); final Annotation expectedAnnotation = expectedMethod.getAnnotation(Annotation.class);
Assertions.assertEquals(expectedAnnotation, actual.getValue()); Assertions.assertEquals(expectedAnnotation, actual.getValue());
} }
@SneakyThrows @SneakyThrows
@Test @Test
void testGetFromAllMethods() { void testGetFromAllMethods() {
Method actual = MethodScanner.getFromAllMethods(Child.class, m -> m.getAnnotation(Annotation.class)); final Method actual = MethodScanner.getFromAllMethods(Child.class, m -> m.getAnnotation(Annotation.class));
Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class); final Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class);
Assertions.assertEquals(expectedMethod, actual); Assertions.assertEquals(expectedMethod, actual);
} }
@ -270,7 +271,7 @@ class MethodScannerTest {
@Annotation("oneArgMethod") @Annotation("oneArgMethod")
@Override @Override
public void oneArgMethod(String arg) { } public void oneArgMethod(final String arg) { }
} }
public static class Child extends Parent implements Interface { public static class Child extends Parent implements Interface {