From 625614a4d257cb220898fa4ef528750bb7aac96f Mon Sep 17 00:00:00 2001 From: Sam Brannen <104798+sbrannen@users.noreply.github.com> Date: Sun, 29 Sep 2024 15:34:40 +0200 Subject: [PATCH] Stop "collecting" annotations in MockitoAnnotationDetector There is no need to collect/track the actual annotations. Rather, we only need to know if there is at least once such annotation present. --- .../mockito/MockitoTestExecutionListener.java | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/spring-test/src/main/java/org/springframework/test/context/bean/override/mockito/MockitoTestExecutionListener.java b/spring-test/src/main/java/org/springframework/test/context/bean/override/mockito/MockitoTestExecutionListener.java index aca1a6aaff11..abc005180994 100644 --- a/spring-test/src/main/java/org/springframework/test/context/bean/override/mockito/MockitoTestExecutionListener.java +++ b/spring-test/src/main/java/org/springframework/test/context/bean/override/mockito/MockitoTestExecutionListener.java @@ -19,8 +19,7 @@ import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Predicate; import org.mockito.Mockito; @@ -146,16 +145,23 @@ private static class MockitoAnnotationDetector { }; static boolean hasMockitoAnnotations(Class testClass) { - Set annotations = new HashSet<>(); - collect(testClass, annotations); - ReflectionUtils.doWithFields(testClass, field -> collect(field, annotations)); - return !annotations.isEmpty(); + if (isAnnotated(testClass)) { + return true; + } + // TODO Ideally we should short-circuit the search once we've found a Mockito annotation, + // since there's no need to continue searching additional fields or further up the class + // hierarchy; however, that is not possible with ReflectionUtils#doWithFields. Plus, the + // previous invocation of isAnnotated(testClass) only finds annotations declared directly + // on the test class. So, we'll likely need a completely different approach that combines + // the "test class/interface is annotated?" and "field is annotated?" checks in a single + // search algorithm. + AtomicBoolean found = new AtomicBoolean(); + ReflectionUtils.doWithFields(testClass, field -> found.set(true), MockitoAnnotationDetector::isAnnotated); + return found.get(); } - static void collect(AnnotatedElement annotatedElement, Set annotations) { - Arrays.stream(annotatedElement.getAnnotations()) - .filter(isMockitoAnnotation) - .forEach(annotations::add); + private static boolean isAnnotated(AnnotatedElement annotatedElement) { + return Arrays.stream(annotatedElement.getAnnotations()).anyMatch(isMockitoAnnotation); } }