Skip to content

Commit

Permalink
Add Stream counterparts to ReflectionSupport utility methods retu…
Browse files Browse the repository at this point in the history
…rning `List` (#3084)

Resolves #2779
  • Loading branch information
Ndione24 committed Dec 16, 2022
1 parent b3827e2 commit 16de26f
Show file tree
Hide file tree
Showing 5 changed files with 244 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ repository on GitHub.

==== New Features and Improvements

* ❓

* All utility methods from `ReflectionSupport` now have counterparts returning `Stream` instead of `List`

[[release-notes-5.10.0-M1-junit-jupiter]]
=== JUnit Jupiter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
import static org.junit.platform.commons.util.AnnotationUtils.findRepeatableAnnotations;
import static org.junit.platform.commons.util.AnnotationUtils.isAnnotated;
import static org.junit.platform.commons.util.ReflectionUtils.HierarchyTraversalMode.TOP_DOWN;
import static org.junit.platform.commons.util.ReflectionUtils.findFields;
import static org.junit.platform.commons.util.ReflectionUtils.getDeclaredConstructor;
import static org.junit.platform.commons.util.ReflectionUtils.streamFields;
import static org.junit.platform.commons.util.ReflectionUtils.tryToReadFieldValue;

import java.lang.reflect.AnnotatedElement;
Expand Down Expand Up @@ -93,7 +93,7 @@ static void registerExtensionsFromFields(ExtensionRegistrar registrar, Class<?>

Predicate<Field> predicate = (instance == null ? ReflectionUtils::isStatic : ReflectionUtils::isNotStatic);

findFields(clazz, predicate, TOP_DOWN).stream()//
streamFields(clazz, predicate, TOP_DOWN)//
.sorted(orderComparator)//
.forEach(field -> {
List<Class<? extends Extension>> extensionTypes = streamExtensionTypes(field).collect(toList());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import static java.util.function.Predicate.isEqual;
import static java.util.stream.Collectors.toCollection;
import static org.junit.jupiter.engine.discovery.predicates.IsTestClassWithTests.isTestOrTestFactoryOrTestTemplateMethod;
import static org.junit.platform.commons.support.ReflectionSupport.findNestedClasses;
import static org.junit.platform.commons.support.ReflectionSupport.streamNestedClasses;
import static org.junit.platform.commons.util.FunctionUtils.where;
import static org.junit.platform.commons.util.ReflectionUtils.findMethods;
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectUniqueId;
Expand Down Expand Up @@ -135,7 +135,7 @@ private Resolution toResolution(Optional<? extends ClassBasedTestDescriptor> tes
return Resolution.match(Match.exact(it, () -> {
Stream<DiscoverySelector> methods = findMethods(testClass, isTestOrTestFactoryOrTestTemplateMethod).stream()
.map(method -> selectMethod(testClasses, method));
Stream<NestedClassSelector> nestedClasses = findNestedClasses(testClass, isNestedTestClass).stream()
Stream<NestedClassSelector> nestedClasses = streamNestedClasses(testClass, isNestedTestClass)
.map(nestedClass -> DiscoverySelectors.selectNestedClass(testClasses, nestedClass));
return Stream.concat(methods, nestedClasses).collect(toCollection((Supplier<Set<DiscoverySelector>>) LinkedHashSet::new));
}));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.util.List;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Stream;

import org.apiguardian.api.API;
import org.junit.platform.commons.JUnitException;
Expand Down Expand Up @@ -114,6 +115,31 @@ public static List<Class<?>> findAllClassesInClasspathRoot(URI root, Predicate<C
return ReflectionUtils.findAllClassesInClasspathRoot(root, classFilter, classNameFilter);
}

/**
* Find all {@linkplain Class classes} in the supplied classpath {@code root}
* that match the specified {@code classFilter} and {@code classNameFilter}
* predicates.
*
* <p>The classpath scanning algorithm searches recursively in subpackages
* beginning with the root of the classpath.
*
* @param root the URI for the classpath root in which to scan; never
* {@code null}
* @param classFilter the class type filter; never {@code null}
* @param classNameFilter the class name filter; never {@code null}
* @return a stream of all such classes found; never {@code null}
* but potentially empty
* @since 1.10
* @see #findAllClassesInPackage(String, Predicate, Predicate)
* @see #findAllClassesInModule(String, Predicate, Predicate)
*/
@API(status = MAINTAINED, since = "1.10")
public static Stream<Class<?>> streamAllClassesInClasspathRoot(URI root, Predicate<Class<?>> classFilter,
Predicate<String> classNameFilter) {

return ReflectionUtils.streamAllClassesInClasspathRoot(root, classFilter, classNameFilter);
}

/**
* Find all {@linkplain Class classes} in the supplied {@code basePackageName}
* that match the specified {@code classFilter} and {@code classNameFilter}
Expand All @@ -138,6 +164,32 @@ public static List<Class<?>> findAllClassesInPackage(String basePackageName, Pre
return ReflectionUtils.findAllClassesInPackage(basePackageName, classFilter, classNameFilter);
}

/**
* Find all {@linkplain Class classes} in the supplied {@code basePackageName}
* that match the specified {@code classFilter} and {@code classNameFilter}
* predicates.
*
* <p>The classpath scanning algorithm searches recursively in subpackages
* beginning within the supplied base package.
*
* @param basePackageName the name of the base package in which to start
* scanning; must not be {@code null} and must be valid in terms of Java
* syntax
* @param classFilter the class type filter; never {@code null}
* @param classNameFilter the class name filter; never {@code null}
* @return a stream of all such classes found; never {@code null}
* but potentially empty
* @since 1.10
* @see #findAllClassesInClasspathRoot(URI, Predicate, Predicate)
* @see #findAllClassesInModule(String, Predicate, Predicate)
*/
@API(status = MAINTAINED, since = "1.10")
public static Stream<Class<?>> streamAllClassesInPackage(String basePackageName, Predicate<Class<?>> classFilter,
Predicate<String> classNameFilter) {

return ReflectionUtils.streamAllClassesInPackage(basePackageName, classFilter, classNameFilter);
}

/**
* Find all {@linkplain Class classes} in the supplied {@code moduleName}
* that match the specified {@code classFilter} and {@code classNameFilter}
Expand All @@ -162,6 +214,31 @@ public static List<Class<?>> findAllClassesInModule(String moduleName, Predicate
return ReflectionUtils.findAllClassesInModule(moduleName, classFilter, classNameFilter);
}

/**
* Find all {@linkplain Class classes} in the supplied {@code moduleName}
* that match the specified {@code classFilter} and {@code classNameFilter}
* predicates.
*
* <p>The module-path scanning algorithm searches recursively in all
* packages contained in the module.
*
* @param moduleName the name of the module to scan; never {@code null} or
* <em>empty</em>
* @param classFilter the class type filter; never {@code null}
* @param classNameFilter the class name filter; never {@code null}
* @return a stream of all such classes found; never {@code null}
* but potentially empty
* @since 1.10
* @see #findAllClassesInClasspathRoot(URI, Predicate, Predicate)
* @see #findAllClassesInPackage(String, Predicate, Predicate)
*/
@API(status = MAINTAINED, since = "1.10")
public static Stream<Class<?>> streamAllClassesInModule(String moduleName, Predicate<Class<?>> classFilter,
Predicate<String> classNameFilter) {

return ReflectionUtils.streamAllClassesInModule(moduleName, classFilter, classNameFilter);
}

/**
* Create a new instance of the specified {@link Class} by invoking
* the constructor whose argument list matches the types of the supplied
Expand Down Expand Up @@ -225,6 +302,31 @@ public static List<Field> findFields(Class<?> clazz, Predicate<Field> predicate,
ReflectionUtils.HierarchyTraversalMode.valueOf(traversalMode.name()));
}

/**
* Find all {@linkplain Field fields} of the supplied class or interface
* that match the specified {@code predicate}.
*
* <p>Fields declared in the same class or interface will be ordered using
* an algorithm that is deterministic but intentionally nonobvious.
*
* <p>The results will not contain fields that are <em>hidden</em> or
* {@linkplain Field#isSynthetic() synthetic}.
*
* @param clazz the class or interface in which to find the fields; never {@code null}
* @param predicate the field filter; never {@code null}
* @param traversalMode the hierarchy traversal mode; never {@code null}
* @return a stream of all such fields found; never {@code null}
* but potentially empty
* @since 1.10
*/
@API(status = MAINTAINED, since = "1.10")
public static Stream<Field> streamFields(Class<?> clazz, Predicate<Field> predicate,
HierarchyTraversalMode traversalMode) {
Preconditions.notNull(traversalMode, "HierarchyTraversalMode must not be null");
return ReflectionUtils.streamFields(clazz, predicate,
ReflectionUtils.HierarchyTraversalMode.valueOf(traversalMode.name()));
}

/**
* Try to read the value of a potentially inaccessible field.
*
Expand Down Expand Up @@ -307,6 +409,34 @@ public static List<Method> findMethods(Class<?> clazz, Predicate<Method> predica
ReflectionUtils.HierarchyTraversalMode.valueOf(traversalMode.name()));
}

/**
* Find all distinct {@linkplain Method methods} of the supplied class or
* interface that match the specified {@code predicate}.
*
* <p>The results will not contain instance methods that are <em>overridden</em>
* or {@code static} methods that are <em>hidden</em>.
*
* <p>If you're are looking for methods annotated with a certain annotation
* type, consider using
* {@link AnnotationSupport#findAnnotatedMethods(Class, Class, HierarchyTraversalMode)}.
*
* @param clazz the class or interface in which to find the methods; never {@code null}
* @param predicate the method filter; never {@code null}
* @param traversalMode the hierarchy traversal mode; never {@code null}
* @return a stream of all such methods found; never {@code null}
* @since 1.10
* but potentially empty
*/
@API(status = MAINTAINED, since = "1.10")
public static Stream<Method> streamMethods(Class<?> clazz, Predicate<Method> predicate,
HierarchyTraversalMode traversalMode) {

Preconditions.notNull(traversalMode, "HierarchyTraversalMode must not be null");

return ReflectionUtils.streamMethods(clazz, predicate,
ReflectionUtils.HierarchyTraversalMode.valueOf(traversalMode.name()));
}

/**
* Find all nested classes within the supplied class, or inherited by the
* supplied class, that conform to the supplied predicate.
Expand All @@ -333,4 +463,32 @@ public static List<Class<?>> findNestedClasses(Class<?> clazz, Predicate<Class<?
return ReflectionUtils.findNestedClasses(clazz, predicate);
}

/**
* Find all nested classes within the supplied class, or inherited by the
* supplied class, that conform to the supplied predicate.
*
* <p>This method does <strong>not</strong> search for nested classes
* recursively.
*
* <p>As of JUnit Platform 1.6, this method detects cycles in <em>inner</em>
* class hierarchies &mdash; from the supplied class up to the outermost
* enclosing class &mdash; and throws a {@link JUnitException} if such a cycle
* is detected. Cycles within inner class hierarchies <em>below</em> the
* supplied class are not detected by this method.
*
* @param clazz the class to be searched; never {@code null}
* @param predicate the predicate against which the list of nested classes is
* checked; never {@code null}
* @return a stream of all such classes found; never {@code null}
* but potentially empty
* @throws JUnitException if a cycle is detected within an inner class hierarchy
* @since 1.10
*/
@API(status = MAINTAINED, since = "1.10")
public static Stream<Class<?>> streamNestedClasses(Class<?> clazz, Predicate<Class<?>> predicate)
throws JUnitException {

return ReflectionUtils.streamNestedClasses(clazz, predicate);
}

}
Loading

0 comments on commit 16de26f

Please sign in to comment.