This is an automated email from the ASF dual-hosted git repository.
jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git
The following commit(s) were added to refs/heads/master by this push:
new 2d937bf555 org.apache.juneau.common.reflect API improvements
2d937bf555 is described below
commit 2d937bf55523f5cb128d59797d4b0a651de0348b
Author: James Bognar <[email protected]>
AuthorDate: Fri Nov 21 16:20:07 2025 -0500
org.apache.juneau.common.reflect API improvements
---
.../juneau/common/reflect/AnnotationProvider.java | 863 ++++++++-------------
.../apache/juneau/common/reflect/MethodInfo.java | 1 -
.../juneau/common/reflect/ReflectionMap.java | 4 +
.../apache/juneau/common/utils/SystemUtils.java | 2 +-
4 files changed, 316 insertions(+), 554 deletions(-)
diff --git
a/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/reflect/AnnotationProvider.java
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/reflect/AnnotationProvider.java
index fb8bc0826a..9838a13109 100644
---
a/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/reflect/AnnotationProvider.java
+++
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/reflect/AnnotationProvider.java
@@ -21,13 +21,10 @@ import static
org.apache.juneau.common.utils.CollectionUtils.*;
import static org.apache.juneau.common.utils.ThrowableUtils.*;
import static org.apache.juneau.common.utils.Utils.*;
import static org.apache.juneau.common.reflect.AnnotationTraversal.*;
-import static org.apache.juneau.common.collections.CacheMode.*;
-import static java.util.stream.Stream.*;
import java.lang.annotation.*;
import java.lang.reflect.*;
import java.util.*;
-import java.util.function.*;
import java.util.stream.*;
import org.apache.juneau.common.collections.*;
@@ -179,6 +176,7 @@ import org.apache.juneau.common.collections.*;
* <li class='jc'>{@link MethodInfo}
* </ul>
*/
+@SuppressWarnings({"unchecked", "rawtypes"})
public class AnnotationProvider {
//-----------------------------------------------------------------------------------------------------------------
@@ -209,70 +207,12 @@ public class AnnotationProvider {
* <br>Valid values: <c>TRUE</c>, <c>FALSE</c> (case-insensitive)
* <br>Default: <c>FALSE</c>
*/
- private static final boolean LOG_ON_EXIT =
b(System.getProperty("juneau.annotationProvider.caching.logOnExit"));
-
- /**
- * Enable performance instrumentation for tracking method call counts.
- *
- * <p>
- * System property: <c>juneau.annotationProvider.instrumentation</c>
- * <br>Valid values: <c>TRUE</c>, <c>FALSE</c> (case-insensitive)
- * <br>Default: <c>FALSE</c>
- */
- private static final boolean ENABLE_INSTRUMENTATION =
b(System.getProperty("juneau.annotationProvider.instrumentation"));
-
- /**
- * Enable new optimized code path for annotation lookups.
- *
- * <p>
- * System property: <c>juneau.annotationProvider.useNewCode</c>
- * <br>Valid values: <c>TRUE</c>, <c>FALSE</c> (case-insensitive)
- * <br>Default: <c>FALSE</c>
- */
- private static final boolean ENABLE_NEW_CODE = true;
+ private static final boolean LOG_ON_EXIT =
true;//b(System.getProperty("juneau.annotationProvider.caching.logOnExit"));
/**
* Default instance.
*/
- public static final AnnotationProvider INSTANCE = new
AnnotationProvider(create());
-
-
//-----------------------------------------------------------------------------------------------------------------
- // Performance instrumentation
-
//-----------------------------------------------------------------------------------------------------------------
-
- private static final Map<String, Long> methodCallCounts = new
java.util.concurrent.ConcurrentHashMap<>();
-
- static {
- if (ENABLE_INSTRUMENTATION) {
- Runtime.getRuntime().addShutdownHook(new Thread(() -> {
- try {
- java.io.PrintWriter pw = new
java.io.PrintWriter(new
java.io.FileWriter("/tmp/annotation-provider-stats.txt"));
- pw.println("\n=== AnnotationProvider
Method Call Statistics ===");
- pw.println(String.format("%-65s %12s",
"Method", "Calls"));
- pw.println("=".repeat(80));
-
- methodCallCounts.entrySet().stream()
- .sorted(Map.Entry.<String,
Long>comparingByValue().reversed())
- .forEach(e ->
pw.println(String.format("%-65s %,12d", e.getKey(), e.getValue())));
-
- long totalCalls =
methodCallCounts.values().stream().mapToLong(Long::longValue).sum();
- pw.println("=".repeat(80));
- pw.println(String.format("%-65s %,12d",
"TOTAL", totalCalls));
- pw.println("=== Total methods
instrumented: " + methodCallCounts.size() + " ===\n");
- pw.close();
- System.err.println("\n===
AnnotationProvider statistics written to /tmp/annotation-provider-stats.txt
===\n");
- } catch (Exception e) {
- e.printStackTrace();
- }
- }));
- }
- }
-
- private static void trackCall(String methodSignature) {
- if (ENABLE_INSTRUMENTATION) {
- methodCallCounts.merge(methodSignature, 1L, Long::sum);
- }
- }
+ public static final AnnotationProvider INSTANCE = new
AnnotationProvider(create().logOnExit());
//-----------------------------------------------------------------------------------------------------------------
// Builder
@@ -297,7 +237,7 @@ public class AnnotationProvider {
public static class Builder {
CacheMode cacheMode;
boolean logOnExit;
- ReflectionMap.Builder<Annotation> runtimeAnnotations =
ReflectionMap.create(Annotation.class);
+ ReflectionMap.Builder<Annotation> runtimeAnnotations;
Builder() {
cacheMode = CACHING_MODE;
@@ -310,6 +250,7 @@ public class AnnotationProvider {
* @return A new immutable {@link AnnotationProvider} instance.
*/
public AnnotationProvider build() {
+ if ((runtimeAnnotations == null ||
runtimeAnnotations.isEmpty()) && INSTANCE != null) return INSTANCE;
return new AnnotationProvider(this);
}
@@ -353,83 +294,84 @@ public class AnnotationProvider {
return this;
}
- /**
- * Adds runtime annotations to be applied to classes, methods, fields,
and constructors.
- *
- * <p>
- * Runtime annotations are concrete Java objects that implement
annotation interfaces (e.g., {@code @Bean}).
- * They allow you to dynamically apply annotations to code elements at
runtime without modifying source code.
- *
- * <p>
- * <b>How It Works:</b>
- * <ol>
- * <li>Create annotation objects using builder classes (e.g.,
{@code BeanAnnotation.create()})
- * <li>Specify targets using {@code on()} or {@code onClass()}
methods
- * <li>Set annotation properties (e.g., {@code typeName()}, {@code
properties()})
- * <li>Build the annotation object
- * <li>Add to the provider via this method
- * </ol>
- *
- * <p>
- * <b>Targeting Requirements:</b>
- * <ul>
- * <li>Annotations MUST define an {@code onClass()} method
returning {@code Class[]} for type-safe targeting
- * <li>OR an {@code on()} method returning {@code String[]} for
string-based targeting
- * <li>The {@code on()} method accepts fully-qualified names:
- * <ul>
- * <li>{@code "com.example.MyClass"} - targets a
class
- * <li>{@code "com.example.MyClass.myMethod"} -
targets a method
- * <li>{@code "com.example.MyClass.myField"} -
targets a field
- * </ul>
- * </ul>
- *
- * <p class='bjava'>
- * <jc>// Example 1: Target a specific class using type-safe
targeting</jc>
- * Bean <jv>beanAnnotation</jv> = BeanAnnotation
- * .<jsm>create</jsm>()
- * .onClass(MyClass.<jk>class</jk>) <jc>// Targets
MyClass</jc>
- * .typeName(<js>"MyType"</js>)
- * .properties(<js>"id,name"</js>)
- * .build();
- *
- * <jc>// Example 2: Target multiple classes</jc>
- * Bean <jv>multiAnnotation</jv> = BeanAnnotation
- * .<jsm>create</jsm>()
- * .onClass(MyClass.<jk>class</jk>,
OtherClass.<jk>class</jk>)
- * .sort(<jk>true</jk>)
- * .build();
- *
- * <jc>// Example 3: Target using string names (useful for
dynamic/reflection scenarios)</jc>
- * Bean <jv>stringAnnotation</jv> = BeanAnnotation
- * .<jsm>create</jsm>()
- * .on(<js>"com.example.MyClass"</js>)
- * .findFluentSetters(<jk>true</jk>)
- * .build();
- *
- * <jc>// Example 4: Target a specific method</jc>
- * Swap <jv>swapAnnotation</jv> = SwapAnnotation
- * .<jsm>create</jsm>()
- * .on(<js>"com.example.MyClass.getValue"</js>)
- * .value(MySwap.<jk>class</jk>)
- * .build();
- *
- * <jc>// Add all runtime annotations to the provider</jc>
- * AnnotationProvider <jv>provider</jv> = AnnotationProvider
- * .<jsm>create</jsm>()
- * .addRuntimeAnnotations(<jv>beanAnnotation</jv>,
<jv>multiAnnotation</jv>, <jv>stringAnnotation</jv>, <jv>swapAnnotation</jv>)
- * .build();
- * </p>
- *
- * <p>
- * <b>Priority:</b> Runtime annotations always take precedence over
declared annotations at the same level.
- * They are evaluated first when searching for annotations.
- *
- * @param annotations The list of runtime annotation objects to add.
- * @return This object for method chaining.
- * @throws BeanRuntimeException If any annotation is invalid (missing
{@code on()} or {@code onClass()} methods,
- * or if the methods return incorrect types).
- */
- public Builder addRuntimeAnnotations(List<Annotation> annotations) {
+ /**
+ * Adds runtime annotations to be applied to classes, methods,
fields, and constructors.
+ *
+ * <p>
+ * Runtime annotations are concrete Java objects that implement
annotation interfaces (e.g., {@code @Bean}).
+ * They allow you to dynamically apply annotations to code
elements at runtime without modifying source code.
+ *
+ * <p>
+ * <b>How It Works:</b>
+ * <ol>
+ * <li>Create annotation objects using builder classes
(e.g., {@code BeanAnnotation.create()})
+ * <li>Specify targets using {@code on()} or {@code
onClass()} methods
+ * <li>Set annotation properties (e.g., {@code
typeName()}, {@code properties()})
+ * <li>Build the annotation object
+ * <li>Add to the provider via this method
+ * </ol>
+ *
+ * <p>
+ * <b>Targeting Requirements:</b>
+ * <ul>
+ * <li>Annotations MUST define an {@code onClass()} method
returning {@code Class[]} for type-safe targeting
+ * <li>OR an {@code on()} method returning {@code
String[]} for string-based targeting
+ * <li>The {@code on()} method accepts fully-qualified
names:
+ * <ul>
+ * <li>{@code "com.example.MyClass"} -
targets a class
+ * <li>{@code
"com.example.MyClass.myMethod"} - targets a method
+ * <li>{@code
"com.example.MyClass.myField"} - targets a field
+ * </ul>
+ * </ul>
+ *
+ * <p class='bjava'>
+ * <jc>// Example 1: Target a specific class using
type-safe targeting</jc>
+ * Bean <jv>beanAnnotation</jv> = BeanAnnotation
+ * .<jsm>create</jsm>()
+ * .onClass(MyClass.<jk>class</jk>) <jc>//
Targets MyClass</jc>
+ * .typeName(<js>"MyType"</js>)
+ * .properties(<js>"id,name"</js>)
+ * .build();
+ *
+ * <jc>// Example 2: Target multiple classes</jc>
+ * Bean <jv>multiAnnotation</jv> = BeanAnnotation
+ * .<jsm>create</jsm>()
+ * .onClass(MyClass.<jk>class</jk>,
OtherClass.<jk>class</jk>)
+ * .sort(<jk>true</jk>)
+ * .build();
+ *
+ * <jc>// Example 3: Target using string names (useful for
dynamic/reflection scenarios)</jc>
+ * Bean <jv>stringAnnotation</jv> = BeanAnnotation
+ * .<jsm>create</jsm>()
+ * .on(<js>"com.example.MyClass"</js>)
+ * .findFluentSetters(<jk>true</jk>)
+ * .build();
+ *
+ * <jc>// Example 4: Target a specific method</jc>
+ * Swap <jv>swapAnnotation</jv> = SwapAnnotation
+ * .<jsm>create</jsm>()
+ * .on(<js>"com.example.MyClass.getValue"</js>)
+ * .value(MySwap.<jk>class</jk>)
+ * .build();
+ *
+ * <jc>// Add all runtime annotations to the provider</jc>
+ * AnnotationProvider <jv>provider</jv> =
AnnotationProvider
+ * .<jsm>create</jsm>()
+ * .addRuntimeAnnotations(<jv>beanAnnotation</jv>,
<jv>multiAnnotation</jv>, <jv>stringAnnotation</jv>, <jv>swapAnnotation</jv>)
+ * .build();
+ * </p>
+ *
+ * <p>
+ * <b>Priority:</b> Runtime annotations always take precedence
over declared annotations at the same level.
+ * They are evaluated first when searching for annotations.
+ *
+ * @param annotations The list of runtime annotation objects to
add.
+ * @return This object for method chaining.
+ * @throws BeanRuntimeException If any annotation is invalid
(missing {@code on()} or {@code onClass()} methods,
+ * or if the methods return incorrect types).
+ */
+ public Builder addRuntimeAnnotations(List<Annotation>
annotations) {
+ if (runtimeAnnotations == null) runtimeAnnotations =
ReflectionMap.create(Annotation.class);
for (var a : annotations) {
try {
@@ -504,10 +446,7 @@ public class AnnotationProvider {
return new Builder();
}
- private final Cache<Class<?>,List<AnnotationInfo<Annotation>>>
classRuntimeAnnotations;
- private final Cache<Method,List<AnnotationInfo<Annotation>>>
methodRuntimeAnnotations;
- private final Cache<Field,List<AnnotationInfo<Annotation>>>
fieldRuntimeAnnotations;
- private final Cache<Constructor<?>,List<AnnotationInfo<Annotation>>>
constructorRuntimeAnnotations;
+ private final Cache<Object,List<AnnotationInfo<Annotation>>>
runtimeCache;
private final Cache3<Class<?>,ElementInfo,AnnotationTraversal[],List>
cache;
private final ReflectionMap<Annotation> annotationMap;
@@ -517,66 +456,19 @@ public class AnnotationProvider {
* @param builder The builder containing configuration settings.
*/
protected AnnotationProvider(Builder builder) {
- var classCache =
Cache.<Class<?>,List<AnnotationInfo<Annotation>>>create()
- .supplier(this::findClassRuntimeAnnotations)
- .cacheMode(builder.cacheMode);
- if (builder.logOnExit)
-
classCache.logOnExit("AnnotationProvider.classRuntimeAnnotations");
- this.classRuntimeAnnotations = classCache.build();
-
- var methodCache =
Cache.<Method,List<AnnotationInfo<Annotation>>>create()
- .supplier(this::findMethodRuntimeAnnotations)
- .cacheMode(builder.cacheMode);
- if (builder.logOnExit)
-
methodCache.logOnExit("AnnotationProvider.methodRuntimeAnnotations");
- this.methodRuntimeAnnotations = methodCache.build();
-
- var fieldCache =
Cache.<Field,List<AnnotationInfo<Annotation>>>create()
- .supplier(this::findFieldRuntimeAnnotations)
- .cacheMode(builder.cacheMode);
- if (builder.logOnExit)
-
fieldCache.logOnExit("AnnotationProvider.fieldRuntimeAnnotations");
- this.fieldRuntimeAnnotations = fieldCache.build();
-
- var constructorCache =
Cache.<Constructor<?>,List<AnnotationInfo<Annotation>>>create()
- .supplier(this::findConstructorRuntimeAnnotations)
- .cacheMode(builder.cacheMode);
- if (builder.logOnExit)
-
constructorCache.logOnExit("AnnotationProvider.constructorRuntimeAnnotations");
- this.constructorRuntimeAnnotations = constructorCache.build();
-
- var cache3 =
Cache3.<Class<?>,ElementInfo,AnnotationTraversal[],List>create()
- .supplier(this::findCached)
- .cacheMode(builder.cacheMode);
- if (builder.logOnExit)
- cache3.logOnExit("AnnotationProvider.cache");
- this.cache = cache3.build();
-
- this.annotationMap = builder.runtimeAnnotations.build();
- }
-
-
//-----------------------------------------------------------------------------------------------------------------
- // Private implementation
-
//-----------------------------------------------------------------------------------------------------------------
-
- private List<AnnotationInfo<Annotation>>
findClassRuntimeAnnotations(Class<?> forClass) {
- var ci = ClassInfo.of(forClass);
- return annotationMap.find(forClass).map(a -> ai(ci,
a)).toList();
- }
-
- private List<AnnotationInfo<Annotation>>
findMethodRuntimeAnnotations(Method forMethod) {
- var mi = MethodInfo.of(forMethod);
- return annotationMap.find(forMethod).map(a -> ai(mi,
a)).toList();
- }
-
- private List<AnnotationInfo<Annotation>>
findFieldRuntimeAnnotations(Field forField) {
- var fi = FieldInfo.of(forField);
- return annotationMap.find(forField).map(a -> ai(fi,
a)).toList();
- }
-
- private List<AnnotationInfo<Annotation>>
findConstructorRuntimeAnnotations(Constructor<?> forConstructor) {
- var ci = ConstructorInfo.of(forConstructor);
- return annotationMap.find(forConstructor).map(a -> ai(ci,
a)).toList();
+ this.runtimeCache =
Cache.<Object,List<AnnotationInfo<Annotation>>>create()
+ .supplier(this::load)
+ .cacheMode(builder.cacheMode)
+ .logOnExit(builder.logOnExit,
"AnnotationProvider.runtimeAnnotations")
+ .build();
+
+ this.cache =
Cache3.<Class<?>,ElementInfo,AnnotationTraversal[],List>create()
+ .supplier(this::load)
+ .cacheMode(builder.cacheMode)
+ .logOnExit(builder.logOnExit,
"AnnotationProvider.cache")
+ .build();
+
+ this.annotationMap = opt(builder.runtimeAnnotations).map(x ->
x.build()).orElse(null);
}
//-----------------------------------------------------------------------------------------------------------------
@@ -607,87 +499,22 @@ public class AnnotationProvider {
*
* @param <A> The annotation type.
* @param type The annotation type to search for.
- * @param clazz The class to search.
+ * @param c The class to search.
* @param traversals The traversal options (what to search and order).
* @return A stream of {@link AnnotationInfo} objects. Never
<jk>null</jk>.
*/
- @SuppressWarnings("unchecked")
- public <A extends Annotation> Stream<AnnotationInfo<A>> find(Class<A>
type, ClassInfo clazz, AnnotationTraversal... traversals) {
- trackCall("find(Class, ClassInfo, AnnotationTraversal...)");
- if (ENABLE_NEW_CODE)
- return findNew(type, clazz, traversals).stream();
-
+ public <A extends Annotation> Stream<AnnotationInfo<A>> find(Class<A>
type, ClassInfo c, AnnotationTraversal... traversals) {
assertArgNotNull("type", type);
- assertArgNotNull("clazz", clazz);
- if (traversals.length == 0)
- traversals = a(PARENTS, PACKAGE);
-
- return Arrays.stream(traversals)
-
.sorted(Comparator.comparingInt(AnnotationTraversal::getOrder))
- .flatMap(traversal -> {
- if (traversal == SELF) {
- return concat(
-
classRuntimeAnnotations.get(clazz.inner()).stream(),
-
clazz.getDeclaredAnnotations().stream()
- )
- .filter(a -> a.isType(type)).map(a ->
(AnnotationInfo<A>)a);
- } else if (traversal == PARENTS) {
- return
clazz.getParentsAndInterfaces().stream().flatMap(x ->
- concat(
-
classRuntimeAnnotations.get(x.inner()).stream(),
-
x.getDeclaredAnnotations().stream()
- ).filter(a ->
a.isType(type)).map(a -> (AnnotationInfo<A>)a)
- );
- } else if (traversal == PACKAGE) {
- return opt(clazz.getPackage()).map(x ->
x.getAnnotations().stream().filter(a -> a.isType(type)).map(a ->
(AnnotationInfo<A>)a)).orElse(Stream.empty());
- }
- throw illegalArg("Invalid traversal type for
class annotations: {0}", traversal);
- });
- }
-
- /**
- * New optimized implementation of find(Class, ClassInfo,
AnnotationTraversal...).
- * Returns a List for better performance.
- * Enable with -Djuneau.annotationProvider.enableNewCode=true
- */
- @SuppressWarnings("unchecked")
- private <A extends Annotation> List<AnnotationInfo<A>> findNew(Class<A>
type, ClassInfo clazz, AnnotationTraversal... traversals) {
- return (List<AnnotationInfo<A>>)cache.get(type, clazz,
traversals);
+ assertArgNotNull("c", c);
+ return cache.get(type, c, traversals).stream();
}
- /**
- * Computes and caches the complete list of annotations for a given
type, class, and traversal combination.
- * This is the supplier function for the findCache.
- */
- @SuppressWarnings("unchecked")
- private List findCached(Class<?> type, ElementInfo element,
AnnotationTraversal[] traversals) {
- var l = new ArrayList();
- var filter = isType((Class<? extends Annotation>)type);
-
- if (element instanceof ClassInfo ci) {
- if (traversals.length == 0)
- traversals = a(PARENTS, PACKAGE);
- var t = Arrays.asList(traversals);
- if (t.contains(SELF)) {
-
classRuntimeAnnotations.get(ci.inner()).stream().filter(filter).forEach(l::add);
-
ci.getDeclaredAnnotations().stream().filter(filter).forEach(l::add);
- }
- if (t.contains(PARENTS)) {
- for (var p : ci.getParentsAndInterfaces()) {
-
classRuntimeAnnotations.get(p.inner()).stream().filter(filter).forEach(l::add);
-
p.getDeclaredAnnotations().stream().filter(filter).forEach(l::add);
- }
- }
- if (t.contains(PACKAGE)) {
- if (ci.getPackage() != null)
-
ci.getPackage().getAnnotations().stream().filter(filter).forEach(l::add);
- }
- }
-
- return l;
+ public <A extends Annotation> List<AnnotationInfo<A>> find2(Class<A>
type, ClassInfo c, AnnotationTraversal... traversals) {
+ assertArgNotNull("type", type);
+ assertArgNotNull("c", c);
+ return cache.get(type, c, traversals);
}
-
/**
* Streams all annotations from a class using configurable traversal
options, without filtering by annotation type.
*
@@ -706,40 +533,18 @@ public class AnnotationProvider {
* find(<jv>ci</jv>, SELF, PARENTS);
* </p>
*
- * @param clazz The class to search.
+ * @param c The class to search.
* @param traversals The traversal options (what to search and order).
* @return A stream of {@link AnnotationInfo} objects. Never
<jk>null</jk>.
*/
- @SuppressWarnings("unchecked")
- public Stream<AnnotationInfo<? extends Annotation>> find(ClassInfo
clazz, AnnotationTraversal... traversals) {
- trackCall("find(ClassInfo, AnnotationTraversal...)");
- if (ENABLE_NEW_CODE)
- return (Stream<AnnotationInfo<? extends
Annotation>>)(Stream<?>)findNew(null, clazz, traversals).stream();
-
- assertArgNotNull("clazz", clazz);
- if (traversals.length == 0)
- traversals = a(PARENTS, PACKAGE);
+ public Stream<AnnotationInfo<? extends Annotation>> find(ClassInfo c,
AnnotationTraversal... traversals) {
+ assertArgNotNull("c", c);
+ return cache.get(null, c, traversals).stream();
+ }
- return Arrays.stream(traversals)
-
.sorted(Comparator.comparingInt(AnnotationTraversal::getOrder))
- .flatMap(traversal -> {
- if (traversal == SELF) {
- return concat(
-
classRuntimeAnnotations.get(clazz.inner()).stream(),
-
clazz.getDeclaredAnnotations().stream().map(a -> (AnnotationInfo<Annotation>)a)
- );
- } else if (traversal == PARENTS) {
- return
clazz.getParentsAndInterfaces().stream().flatMap(x -> {
- return concat(
-
classRuntimeAnnotations.get(x.inner()).stream(),
-
x.getDeclaredAnnotations().stream().map(a -> (AnnotationInfo<Annotation>)a)
- );
- });
- } else if (traversal == PACKAGE) {
- return opt(clazz.getPackage()).map(x ->
x.getAnnotations().stream()).orElse(Stream.empty());
- }
- throw illegalArg("Invalid traversal type for
class annotations: {0}", traversal);
- });
+ public List<AnnotationInfo<? extends Annotation>> find2(ClassInfo c,
AnnotationTraversal... traversals) {
+ assertArgNotNull("c", c);
+ return cache.get(null, c, traversals);
}
/**
@@ -751,13 +556,14 @@ public class AnnotationProvider {
*
* @param <A> The annotation type.
* @param type The annotation type to search for.
- * @param clazz The class to search.
+ * @param c The class to search.
* @param traversals The traversal options (what to search and order).
* @return A stream of {@link AnnotationInfo} objects in parent-first
order. Never <jk>null</jk>.
*/
- public <A extends Annotation> Stream<AnnotationInfo<A>>
findTopDown(Class<A> type, ClassInfo clazz, AnnotationTraversal... traversals) {
- trackCall("findTopDown(Class, ClassInfo,
AnnotationTraversal...)");
- return rstream(find(type, clazz, traversals).toList());
+ public <A extends Annotation> Stream<AnnotationInfo<A>>
findTopDown(Class<A> type, ClassInfo c, AnnotationTraversal... traversals) {
+ assertArgNotNull("type", type);
+ assertArgNotNull("c", c);
+ return rstream(cache.get(type, c, traversals));
}
/**
@@ -767,13 +573,13 @@ public class AnnotationProvider {
* This is equivalent to calling {@link #find(ClassInfo,
AnnotationTraversal...)}
* and reversing the result.
*
- * @param clazz The class to search.
+ * @param c The class to search.
* @param traversals The traversal options (what to search and order).
* @return A stream of {@link AnnotationInfo} objects in parent-first
order. Never <jk>null</jk>.
*/
- public Stream<AnnotationInfo<? extends Annotation>>
findTopDown(ClassInfo clazz, AnnotationTraversal... traversals) {
- trackCall("findTopDown(ClassInfo, AnnotationTraversal...)");
- return rstream(find(clazz, traversals).toList());
+ public Stream<AnnotationInfo<? extends Annotation>>
findTopDown(ClassInfo c, AnnotationTraversal... traversals) {
+ assertArgNotNull("c", c);
+ return rstream(cache.get(null, c, traversals));
}
/**
@@ -807,15 +613,14 @@ public class AnnotationProvider {
*
* @param <A> The annotation type.
* @param type The annotation type to search for.
- * @param clazz The class to search.
+ * @param c The class to search.
* @param traversals
* The traversal options. If not specified, defaults to {@code
SELF, PARENTS, PACKAGE}.
* <br>Valid values: {@link AnnotationTraversal#SELF SELF}, {@link
AnnotationTraversal#PARENTS PARENTS}, {@link AnnotationTraversal#PACKAGE
PACKAGE}
* @return <jk>true</jk> if the annotation is found, <jk>false</jk>
otherwise.
*/
- public <A extends Annotation> boolean has(Class<A> type, ClassInfo
clazz, AnnotationTraversal... traversals) {
- trackCall("has(Class, ClassInfo, AnnotationTraversal...)");
- return find(type, clazz, traversals).findFirst().isPresent();
+ public <A extends Annotation> boolean has(Class<A> type, ClassInfo c,
AnnotationTraversal... traversals) {
+ return find(type, c, traversals).findFirst().isPresent();
}
/**
@@ -837,42 +642,14 @@ public class AnnotationProvider {
*
* @param <A> The annotation type.
* @param type The annotation type to search for.
- * @param method The method to search.
+ * @param m The method to search.
* @param traversals The traversal options.
* @return A stream of {@link AnnotationInfo} objects. Never
<jk>null</jk>.
*/
- @SuppressWarnings("unchecked")
- public <A extends Annotation> Stream<AnnotationInfo<A>> find(Class<A>
type, MethodInfo method, AnnotationTraversal... traversals) {
- trackCall("find(Class, MethodInfo, AnnotationTraversal...)");
+ public <A extends Annotation> Stream<AnnotationInfo<A>> find(Class<A>
type, MethodInfo m, AnnotationTraversal... traversals) {
assertArgNotNull("type", type);
- assertArgNotNull("method", method);
- if (traversals.length == 0)
- traversals = a(SELF, MATCHING_METHODS, DECLARING_CLASS,
RETURN_TYPE, PACKAGE);
-
- return Arrays.stream(traversals)
-
.sorted(Comparator.comparingInt(AnnotationTraversal::getOrder))
- .flatMap(traversal -> {
- if (traversal == SELF) {
- return concat(
-
methodRuntimeAnnotations.get(method.inner()).stream(),
-
method.getDeclaredAnnotations().stream()
- ).filter(a -> a.isType(type)).map(a ->
(AnnotationInfo<A>)a);
- } else if (traversal == MATCHING_METHODS) {
- return
method.getMatchingMethods().stream().skip(1).flatMap(m ->
- concat(
-
methodRuntimeAnnotations.get(m.inner()).stream(),
-
m.getDeclaredAnnotations().stream()
- ).filter(a ->
a.isType(type)).map(a -> (AnnotationInfo<A>)a)
- );
- } else if (traversal == DECLARING_CLASS) {
- return find(type,
method.getDeclaringClass(), PARENTS);
- } else if (traversal == RETURN_TYPE) {
- return find(type,
method.getReturnType().unwrap(Value.class, Optional.class), PARENTS);
- } else if (traversal == PACKAGE) {
- return
opt(method.getDeclaringClass().getPackage()).map(x ->
x.getAnnotations().stream().filter(a -> a.isType(type)).map(a ->
(AnnotationInfo<A>)a)).orElse(Stream.empty());
- }
- throw illegalArg("Invalid traversal type for
method annotations: {0}", traversal);
- });
+ assertArgNotNull("m", m);
+ return cache.get(type, m, traversals).stream();
}
/**
@@ -893,40 +670,13 @@ public class AnnotationProvider {
* find(<jv>mi</jv>, SELF, MATCHING_METHODS, RETURN_TYPE);
* </p>
*
- * @param method The method to search.
+ * @param m The method to search.
* @param traversals The traversal options.
* @return A stream of {@link AnnotationInfo} objects. Never
<jk>null</jk>.
*/
- public Stream<AnnotationInfo<? extends Annotation>> find(MethodInfo
method, AnnotationTraversal... traversals) {
- trackCall("find(MethodInfo, AnnotationTraversal...)");
- assertArgNotNull("method", method);
- if (traversals.length == 0)
- traversals = a(SELF, MATCHING_METHODS, DECLARING_CLASS,
RETURN_TYPE, PACKAGE);
-
- return Arrays.stream(traversals)
-
.sorted(Comparator.comparingInt(AnnotationTraversal::getOrder))
- .flatMap(traversal -> {
- if (traversal == SELF) {
- return concat(
-
methodRuntimeAnnotations.get(method.inner()).stream(),
-
method.getDeclaredAnnotations().stream()
- );
- } else if (traversal == MATCHING_METHODS) {
- return
method.getMatchingMethods().stream().skip(1).flatMap(m -> {
- return concat(
-
methodRuntimeAnnotations.get(m.inner()).stream(),
-
m.getDeclaredAnnotations().stream()
- );
- });
- } else if (traversal == DECLARING_CLASS) {
- return find(method.getDeclaringClass(),
PARENTS);
- } else if (traversal == RETURN_TYPE) {
- return
find(method.getReturnType().unwrap(Value.class, Optional.class), PARENTS);
- } else if (traversal == PACKAGE) {
- return
opt(method.getDeclaringClass().getPackage()).map(x ->
x.getAnnotations().stream()).orElse(Stream.empty());
- }
- throw illegalArg("Invalid traversal type for
method annotations: {0}", traversal);
- });
+ public Stream<AnnotationInfo<? extends Annotation>> find(MethodInfo m,
AnnotationTraversal... traversals) {
+ assertArgNotNull("m", m);
+ return cache.get(null, m, traversals).stream();
}
/**
@@ -938,13 +688,14 @@ public class AnnotationProvider {
*
* @param <A> The annotation type.
* @param type The annotation type to search for.
- * @param method The method to search.
+ * @param m The method to search.
* @param traversals The traversal options.
* @return A stream of {@link AnnotationInfo} objects in parent-first
order. Never <jk>null</jk>.
*/
- public <A extends Annotation> Stream<AnnotationInfo<A>>
findTopDown(Class<A> type, MethodInfo method, AnnotationTraversal...
traversals) {
- trackCall("findTopDown(Class, MethodInfo,
AnnotationTraversal...)");
- return rstream(find(type, method, traversals).toList());
+ public <A extends Annotation> Stream<AnnotationInfo<A>>
findTopDown(Class<A> type, MethodInfo m, AnnotationTraversal... traversals) {
+ assertArgNotNull("type", type);
+ assertArgNotNull("m", m);
+ return rstream(cache.get(type, m, traversals));
}
/**
@@ -954,13 +705,13 @@ public class AnnotationProvider {
* This is equivalent to calling {@link #find(MethodInfo,
AnnotationTraversal...)}
* and reversing the result.
*
- * @param method The method to search.
+ * @param m The method to search.
* @param traversals The traversal options.
* @return A stream of {@link AnnotationInfo} objects in parent-first
order. Never <jk>null</jk>.
*/
- public Stream<AnnotationInfo<? extends Annotation>>
findTopDown(MethodInfo method, AnnotationTraversal... traversals) {
- trackCall("findTopDown(MethodInfo, AnnotationTraversal...)");
- return rstream(find(method, traversals).toList());
+ public Stream<AnnotationInfo<? extends Annotation>>
findTopDown(MethodInfo m, AnnotationTraversal... traversals) {
+ assertArgNotNull("m", m);
+ return rstream(cache.get(null, m, traversals));
}
/**
@@ -994,15 +745,14 @@ public class AnnotationProvider {
*
* @param <A> The annotation type.
* @param type The annotation type to search for.
- * @param method The method to search.
+ * @param m The method to search.
* @param traversals
* The traversal options. If not specified, defaults to {@code
SELF, MATCHING_METHODS, RETURN_TYPE, PACKAGE}.
* <br>Valid values: {@link AnnotationTraversal#SELF SELF}, {@link
AnnotationTraversal#MATCHING_METHODS MATCHING_METHODS}, {@link
AnnotationTraversal#RETURN_TYPE RETURN_TYPE}, {@link
AnnotationTraversal#PACKAGE PACKAGE}
* @return <jk>true</jk> if the annotation is found, <jk>false</jk>
otherwise.
*/
- public <A extends Annotation> boolean has(Class<A> type, MethodInfo
method, AnnotationTraversal... traversals) {
- trackCall("has(Class, MethodInfo, AnnotationTraversal...)");
- return find(type, method, traversals).findFirst().isPresent();
+ public <A extends Annotation> boolean has(Class<A> type, MethodInfo m,
AnnotationTraversal... traversals) {
+ return find(type, m, traversals).findFirst().isPresent();
}
/**
@@ -1038,31 +788,16 @@ public class AnnotationProvider {
*
* @param <A> The annotation type.
* @param type The annotation type to search for.
- * @param parameter The parameter to search.
+ * @param p The parameter to search.
* @param traversals
* The traversal options. If not specified, defaults to {@code
SELF, MATCHING_PARAMETERS, PARAMETER_TYPE}.
* <br>Valid values: {@link AnnotationTraversal#SELF SELF}, {@link
AnnotationTraversal#MATCHING_PARAMETERS MATCHING_PARAMETERS}, {@link
AnnotationTraversal#PARAMETER_TYPE PARAMETER_TYPE}
* @return A stream of {@link AnnotationInfo} objects in
child-to-parent order. Never <jk>null</jk>.
*/
- public <A extends Annotation> Stream<AnnotationInfo<A>> find(Class<A>
type, ParameterInfo parameter, AnnotationTraversal... traversals) {
- trackCall("find(Class, ParameterInfo, AnnotationTraversal...)");
+ public <A extends Annotation> Stream<AnnotationInfo<A>> find(Class<A>
type, ParameterInfo p, AnnotationTraversal... traversals) {
assertArgNotNull("type", type);
- assertArgNotNull("parameter", parameter);
- if (traversals.length == 0)
- traversals = a(SELF, MATCHING_PARAMETERS,
PARAMETER_TYPE);
-
- return Arrays.stream(traversals)
-
.sorted(Comparator.comparingInt(AnnotationTraversal::getOrder))
- .flatMap(traversal -> {
- if (traversal == SELF) {
- return parameter.getAnnotations(type);
- } else if (traversal == MATCHING_PARAMETERS) {
- return
parameter.getMatchingParameters().stream().skip(1).flatMap(x ->
x.getAnnotations(type));
- } else if (traversal == PARAMETER_TYPE) {
- return find(type,
parameter.getParameterType().unwrap(Value.class, Optional.class), PARENTS,
PACKAGE);
- }
- throw illegalArg("Invalid traversal type for
parameter annotations: {0}", traversal);
- });
+ assertArgNotNull("p", p);
+ return cache.get(type, p, traversals).stream();
}
/**
@@ -1094,15 +829,16 @@ public class AnnotationProvider {
*
* @param <A> The annotation type.
* @param type The annotation type to search for.
- * @param parameter The parameter to search.
+ * @param p The parameter to search.
* @param traversals
* The traversal options. If not specified, defaults to {@code
SELF, MATCHING_PARAMETERS, PARAMETER_TYPE}.
* <br>Valid values: {@link AnnotationTraversal#SELF SELF}, {@link
AnnotationTraversal#MATCHING_PARAMETERS MATCHING_PARAMETERS}, {@link
AnnotationTraversal#PARAMETER_TYPE PARAMETER_TYPE}
* @return A stream of {@link AnnotationInfo} objects in
parent-to-child order. Never <jk>null</jk>.
*/
- public <A extends Annotation> Stream<AnnotationInfo<A>>
findTopDown(Class<A> type, ParameterInfo parameter, AnnotationTraversal...
traversals) {
- trackCall("findTopDown(Class, ParameterInfo,
AnnotationTraversal...)");
- return rstream(find(type, parameter, traversals).toList());
+ public <A extends Annotation> Stream<AnnotationInfo<A>>
findTopDown(Class<A> type, ParameterInfo p, AnnotationTraversal... traversals) {
+ assertArgNotNull("type", type);
+ assertArgNotNull("p", p);
+ return rstream(cache.get(type, p, traversals));
}
/**
@@ -1133,30 +869,15 @@ public class AnnotationProvider {
* find(<jv>pi</jv>, SELF);
* </p>
*
- * @param parameter The parameter to search.
+ * @param p The parameter to search.
* @param traversals
* The traversal options. If not specified, defaults to {@code
SELF, MATCHING_PARAMETERS, PARAMETER_TYPE}.
* <br>Valid values: {@link AnnotationTraversal#SELF SELF}, {@link
AnnotationTraversal#MATCHING_PARAMETERS MATCHING_PARAMETERS}, {@link
AnnotationTraversal#PARAMETER_TYPE PARAMETER_TYPE}
* @return A stream of {@link AnnotationInfo} objects in
child-to-parent order. Never <jk>null</jk>.
*/
- public Stream<AnnotationInfo<? extends Annotation>> find(ParameterInfo
parameter, AnnotationTraversal... traversals) {
- trackCall("find(ParameterInfo, AnnotationTraversal...)");
- assertArgNotNull("parameter", parameter);
- if (traversals.length == 0)
- traversals = a(SELF, MATCHING_PARAMETERS,
PARAMETER_TYPE);
-
- return Arrays.stream(traversals)
-
.sorted(Comparator.comparingInt(AnnotationTraversal::getOrder))
- .flatMap(traversal -> {
- if (traversal == SELF) {
- return
parameter.getAnnotations().stream();
- } else if (traversal == MATCHING_PARAMETERS) {
- return
parameter.getMatchingParameters().stream().skip(1).flatMap(x ->
x.getAnnotations().stream());
- } else if (traversal == PARAMETER_TYPE) {
- return
find(parameter.getParameterType().unwrap(Value.class, Optional.class), PARENTS,
PACKAGE);
- }
- throw illegalArg("Invalid traversal type for
parameter annotations: {0}", traversal);
- });
+ public Stream<AnnotationInfo<? extends Annotation>> find(ParameterInfo
p, AnnotationTraversal... traversals) {
+ assertArgNotNull("p", p);
+ return cache.get(null, p, traversals).stream();
}
/**
@@ -1166,15 +887,15 @@ public class AnnotationProvider {
* This is equivalent to calling {@link #find(ParameterInfo,
AnnotationTraversal...)}
* and reversing the result.
*
- * @param parameter The parameter to search.
+ * @param p The parameter to search.
* @param traversals
* The traversal options. If not specified, defaults to {@code
SELF, MATCHING_PARAMETERS, PARAMETER_TYPE}.
* <br>Valid values: {@link AnnotationTraversal#SELF SELF}, {@link
AnnotationTraversal#MATCHING_PARAMETERS MATCHING_PARAMETERS}, {@link
AnnotationTraversal#PARAMETER_TYPE PARAMETER_TYPE}
* @return A stream of {@link AnnotationInfo} objects in
parent-to-child order. Never <jk>null</jk>.
*/
- public Stream<AnnotationInfo<? extends Annotation>>
findTopDown(ParameterInfo parameter, AnnotationTraversal... traversals) {
- trackCall("findTopDown(ParameterInfo, AnnotationTraversal...)");
- return rstream(find(parameter, traversals).toList());
+ public Stream<AnnotationInfo<? extends Annotation>>
findTopDown(ParameterInfo p, AnnotationTraversal... traversals) {
+ assertArgNotNull("p", p);
+ return rstream(cache.get(null, p, traversals));
}
/**
@@ -1207,15 +928,14 @@ public class AnnotationProvider {
*
* @param <A> The annotation type.
* @param type The annotation type to search for.
- * @param parameter The parameter to search.
+ * @param p The parameter to search.
* @param traversals
* The traversal options. If not specified, defaults to {@code
SELF, MATCHING_PARAMETERS, PARAMETER_TYPE}.
* <br>Valid values: {@link AnnotationTraversal#SELF SELF}, {@link
AnnotationTraversal#MATCHING_PARAMETERS MATCHING_PARAMETERS}, {@link
AnnotationTraversal#PARAMETER_TYPE PARAMETER_TYPE}
* @return <jk>true</jk> if the annotation is found, <jk>false</jk>
otherwise.
*/
- public <A extends Annotation> boolean has(Class<A> type, ParameterInfo
parameter, AnnotationTraversal... traversals) {
- trackCall("has(Class, ParameterInfo, AnnotationTraversal...)");
- return find(type, parameter,
traversals).findFirst().isPresent();
+ public <A extends Annotation> boolean has(Class<A> type, ParameterInfo
p, AnnotationTraversal... traversals) {
+ return find(type, p, traversals).findFirst().isPresent();
}
/**
@@ -1233,29 +953,14 @@ public class AnnotationProvider {
*
* @param <A> The annotation type.
* @param type The annotation type to search for.
- * @param field The field to search.
+ * @param f The field to search.
* @param traversals The traversal options.
* @return A stream of {@link AnnotationInfo} objects. Never
<jk>null</jk>.
*/
- @SuppressWarnings("unchecked")
- public <A extends Annotation> Stream<AnnotationInfo<A>> find(Class<A>
type, FieldInfo field, AnnotationTraversal... traversals) {
- trackCall("find(Class, FieldInfo, AnnotationTraversal...)");
+ public <A extends Annotation> Stream<AnnotationInfo<A>> find(Class<A>
type, FieldInfo f, AnnotationTraversal... traversals) {
assertArgNotNull("type", type);
- assertArgNotNull("field", field);
- if (traversals.length == 0)
- traversals = a(SELF);
-
- return Arrays.stream(traversals)
-
.sorted(Comparator.comparingInt(AnnotationTraversal::getOrder))
- .flatMap(traversal -> {
- if (traversal == SELF) {
- return concat(
-
fieldRuntimeAnnotations.get(field.inner()).stream(),
- field.getAnnotations().stream()
- ).filter(a -> a.isType(type)).map(a ->
(AnnotationInfo<A>)a);
- }
- throw illegalArg("Invalid traversal type for
field annotations: {0}", traversal);
- });
+ assertArgNotNull("f", f);
+ return cache.get(type, f, traversals).stream();
}
/**
@@ -1272,27 +977,13 @@ public class AnnotationProvider {
* find(<jv>fi</jv>, SELF);
* </p>
*
- * @param field The field to search.
+ * @param f The field to search.
* @param traversals The traversal options.
* @return A stream of {@link AnnotationInfo} objects. Never
<jk>null</jk>.
*/
- public Stream<AnnotationInfo<? extends Annotation>> find(FieldInfo
field, AnnotationTraversal... traversals) {
- trackCall("find(FieldInfo, AnnotationTraversal...)");
- assertArgNotNull("field", field);
- if (traversals.length == 0)
- traversals = a(SELF);
-
- return Arrays.stream(traversals)
-
.sorted(Comparator.comparingInt(AnnotationTraversal::getOrder))
- .flatMap(traversal -> {
- if (traversal == SELF) {
- return concat(
-
fieldRuntimeAnnotations.get(field.inner()).stream(),
- field.getAnnotations().stream()
- );
- }
- throw illegalArg("Invalid traversal type for
field annotations: {0}", traversal);
- });
+ public Stream<AnnotationInfo<? extends Annotation>> find(FieldInfo f,
AnnotationTraversal... traversals) {
+ assertArgNotNull("f", f);
+ return cache.get(null, f, traversals).stream();
}
/**
@@ -1304,13 +995,14 @@ public class AnnotationProvider {
*
* @param <A> The annotation type.
* @param type The annotation type to search for.
- * @param field The field to search.
+ * @param f The field to search.
* @param traversals The traversal options.
* @return A stream of {@link AnnotationInfo} objects in parent-first
order. Never <jk>null</jk>.
*/
- public <A extends Annotation> Stream<AnnotationInfo<A>>
findTopDown(Class<A> type, FieldInfo field, AnnotationTraversal... traversals) {
- trackCall("findTopDown(Class, FieldInfo,
AnnotationTraversal...)");
- return rstream(find(type, field, traversals).toList());
+ public <A extends Annotation> Stream<AnnotationInfo<A>>
findTopDown(Class<A> type, FieldInfo f, AnnotationTraversal... traversals) {
+ assertArgNotNull("type", type);
+ assertArgNotNull("f", f);
+ return rstream(cache.get(type, f, traversals));
}
/**
@@ -1320,13 +1012,13 @@ public class AnnotationProvider {
* This is equivalent to calling {@link #find(FieldInfo,
AnnotationTraversal...)}
* and reversing the result.
*
- * @param field The field to search.
+ * @param f The field to search.
* @param traversals The traversal options.
* @return A stream of {@link AnnotationInfo} objects in parent-first
order. Never <jk>null</jk>.
*/
- public Stream<AnnotationInfo<? extends Annotation>>
findTopDown(FieldInfo field, AnnotationTraversal... traversals) {
- trackCall("findTopDown(FieldInfo, AnnotationTraversal...)");
- return rstream(find(field, traversals).toList());
+ public Stream<AnnotationInfo<? extends Annotation>>
findTopDown(FieldInfo f, AnnotationTraversal... traversals) {
+ assertArgNotNull("f", f);
+ return rstream(cache.get(null, f, traversals));
}
/**
@@ -1354,15 +1046,14 @@ public class AnnotationProvider {
*
* @param <A> The annotation type.
* @param type The annotation type to search for.
- * @param field The field to search.
+ * @param f The field to search.
* @param traversals
* The traversal options. If not specified, defaults to {@code
SELF}.
* <br>Valid values: {@link AnnotationTraversal#SELF SELF}
* @return <jk>true</jk> if the annotation is found, <jk>false</jk>
otherwise.
*/
- public <A extends Annotation> boolean has(Class<A> type, FieldInfo
field, AnnotationTraversal... traversals) {
- trackCall("has(Class, FieldInfo, AnnotationTraversal...)");
- return find(type, field, traversals).findFirst().isPresent();
+ public <A extends Annotation> boolean has(Class<A> type, FieldInfo f,
AnnotationTraversal... traversals) {
+ return find(type, f, traversals).findFirst().isPresent();
}
/**
@@ -1380,29 +1071,14 @@ public class AnnotationProvider {
*
* @param <A> The annotation type.
* @param type The annotation type to search for.
- * @param constructor The constructor to search.
+ * @param c The constructor to search.
* @param traversals The traversal options.
* @return A stream of {@link AnnotationInfo} objects. Never
<jk>null</jk>.
*/
- @SuppressWarnings("unchecked")
- public <A extends Annotation> Stream<AnnotationInfo<A>> find(Class<A>
type, ConstructorInfo constructor, AnnotationTraversal... traversals) {
- trackCall("find(Class, ConstructorInfo,
AnnotationTraversal...)");
+ public <A extends Annotation> Stream<AnnotationInfo<A>> find(Class<A>
type, ConstructorInfo c, AnnotationTraversal... traversals) {
assertArgNotNull("type", type);
- assertArgNotNull("constructor", constructor);
- if (traversals.length == 0)
- traversals = a(SELF);
-
- return Arrays.stream(traversals)
-
.sorted(Comparator.comparingInt(AnnotationTraversal::getOrder))
- .flatMap(traversal -> {
- if (traversal == SELF) {
- return concat(
-
constructorRuntimeAnnotations.get(constructor.inner()).stream(),
-
constructor.getDeclaredAnnotations().stream()
- ).filter(a -> a.isType(type)).map(a ->
(AnnotationInfo<A>)a);
- }
- throw illegalArg("Invalid traversal type for
constructor annotations: {0}", traversal);
- });
+ assertArgNotNull("c", c);
+ return cache.get(type, c, traversals).stream();
}
/**
@@ -1419,27 +1095,13 @@ public class AnnotationProvider {
* find(<jv>ci</jv>, SELF);
* </p>
*
- * @param constructor The constructor to search.
+ * @param c The constructor to search.
* @param traversals The traversal options.
* @return A stream of {@link AnnotationInfo} objects. Never
<jk>null</jk>.
*/
- public Stream<AnnotationInfo<? extends Annotation>>
find(ConstructorInfo constructor, AnnotationTraversal... traversals) {
- trackCall("find(ConstructorInfo, AnnotationTraversal...)");
- assertArgNotNull("constructor", constructor);
- if (traversals.length == 0)
- traversals = a(SELF);
-
- return Arrays.stream(traversals)
-
.sorted(Comparator.comparingInt(AnnotationTraversal::getOrder))
- .flatMap(traversal -> {
- if (traversal == SELF) {
- return concat(
-
constructorRuntimeAnnotations.get(constructor.inner()).stream(),
-
constructor.getDeclaredAnnotations().stream()
- );
- }
- throw illegalArg("Invalid traversal type for
constructor annotations: {0}", traversal);
- });
+ public Stream<AnnotationInfo<? extends Annotation>>
find(ConstructorInfo c, AnnotationTraversal... traversals) {
+ assertArgNotNull("c", c);
+ return cache.get(null, c, traversals).stream();
}
/**
@@ -1451,13 +1113,14 @@ public class AnnotationProvider {
*
* @param <A> The annotation type.
* @param type The annotation type to search for.
- * @param constructor The constructor to search.
+ * @param c The constructor to search.
* @param traversals The traversal options.
* @return A stream of {@link AnnotationInfo} objects in parent-first
order. Never <jk>null</jk>.
*/
- public <A extends Annotation> Stream<AnnotationInfo<A>>
findTopDown(Class<A> type, ConstructorInfo constructor, AnnotationTraversal...
traversals) {
- trackCall("findTopDown(Class, ConstructorInfo,
AnnotationTraversal...)");
- return rstream(find(type, constructor, traversals).toList());
+ public <A extends Annotation> Stream<AnnotationInfo<A>>
findTopDown(Class<A> type, ConstructorInfo c, AnnotationTraversal...
traversals) {
+ assertArgNotNull("type", type);
+ assertArgNotNull("c", c);
+ return rstream(cache.get(type, c, traversals));
}
/**
@@ -1467,13 +1130,13 @@ public class AnnotationProvider {
* This is equivalent to calling {@link #find(ConstructorInfo,
AnnotationTraversal...)}
* and reversing the result.
*
- * @param constructor The constructor to search.
+ * @param c The constructor to search.
* @param traversals The traversal options.
* @return A stream of {@link AnnotationInfo} objects in parent-first
order. Never <jk>null</jk>.
*/
- public Stream<AnnotationInfo<? extends Annotation>>
findTopDown(ConstructorInfo constructor, AnnotationTraversal... traversals) {
- trackCall("findTopDown(ConstructorInfo,
AnnotationTraversal...)");
- return rstream(find(constructor, traversals).toList());
+ public Stream<AnnotationInfo<? extends Annotation>>
findTopDown(ConstructorInfo c, AnnotationTraversal... traversals) {
+ assertArgNotNull("c", c);
+ return rstream(cache.get(null, c, traversals));
}
/**
@@ -1501,34 +1164,130 @@ public class AnnotationProvider {
*
* @param <A> The annotation type.
* @param type The annotation type to search for.
- * @param constructor The constructor to search.
+ * @param c The constructor to search.
* @param traversals
* The traversal options. If not specified, defaults to {@code
SELF}.
* <br>Valid values: {@link AnnotationTraversal#SELF SELF}
* @return <jk>true</jk> if the annotation is found, <jk>false</jk>
otherwise.
*/
- public <A extends Annotation> boolean has(Class<A> type,
ConstructorInfo constructor, AnnotationTraversal... traversals) {
- trackCall("has(Class, ConstructorInfo,
AnnotationTraversal...)");
- return find(type, constructor,
traversals).findFirst().isPresent();
+ public <A extends Annotation> boolean has(Class<A> type,
ConstructorInfo c, AnnotationTraversal... traversals) {
+ return find(type, c, traversals).findFirst().isPresent();
}
//-----------------------------------------------------------------------------------------------------------------
// Helper methods
//-----------------------------------------------------------------------------------------------------------------
+ private List load(Object o) {
+ if (o instanceof Class c) {
+ var ci = ClassInfo.of(c);
+ return annotationMap == null ? liste() :
annotationMap.find(ci.inner()).map(a -> ai(ci, a)).toList();
+ }
+ if (o instanceof Method m) {
+ var mi = MethodInfo.of(m);
+ return annotationMap == null ? liste() :
annotationMap.find(mi.inner()).map(a -> ai(mi, a)).toList();
+ }
+ if (o instanceof Field f) {
+ var fi = FieldInfo.of(f);
+ return annotationMap == null ? liste() :
annotationMap.find(fi.inner()).map(a -> ai(fi, a)).toList();
+ }
+ if (o instanceof Constructor c) {
+ var ci = ConstructorInfo.of(c);
+ return annotationMap == null ? liste() :
annotationMap.find(ci.inner()).map(a -> ai(ci, a)).toList();
+ }
+ throw unsupportedOp();
+ }
+
/**
- * Creates a predicate that filters annotations by type.
- * If type is null, all annotations pass; otherwise only annotations of
the specified type pass.
- *
- * @param type The annotation type to filter by, or null to accept all
annotations.
- * @return A predicate that tests if an annotation matches the type.
+ * Computes and caches the complete list of annotations for a given
type, class, and traversal combination.
+ * This is the supplier function for the findCache.
*/
- @SuppressWarnings({"unchecked", "rawtypes"})
- private static Predicate isType(Class<? extends Annotation> type) {
- return type == null ? x -> true : x ->
((AnnotationInfo)x).isType(type);
+ private List load(Class<?> type, ElementInfo element,
AnnotationTraversal[] traversals) {
+
+ if (type != null) {
+ return cache.get(null, element,
traversals).stream().filter(x -> ((AnnotationInfo)x).isType(type)).toList();
+ }
+
+ var l = new ArrayList();
+
+ List<AnnotationTraversal> t;
+ if (traversals.length > 0)
+ t = l(traversals);
+ else if (element instanceof ClassInfo)
+ t = l(a(PARENTS, PACKAGE));
+ else if (element instanceof MethodInfo)
+ t = l(a(SELF, MATCHING_METHODS, DECLARING_CLASS,
RETURN_TYPE, PACKAGE));
+ else if (element instanceof FieldInfo || element instanceof
ConstructorInfo)
+ t = l(a(SELF));
+ else if (element instanceof ParameterInfo)
+ t = l(a(SELF, MATCHING_PARAMETERS, PARAMETER_TYPE));
+ else
+ t = l(); // Never happens.
+
+ if (element instanceof ClassInfo ci) {
+ if (t.contains(SELF)) {
+ l.addAll(runtimeCache.get(ci.inner()));
+ l.addAll(ci.getDeclaredAnnotations());
+ }
+ if (t.contains(PARENTS)) {
+ for (var p : ci.getParentsAndInterfaces()) {
+ l.addAll(runtimeCache.get(p.inner()));
+ l.addAll(p.getDeclaredAnnotations());
+ }
+ }
+ if (t.contains(PACKAGE)) {
+ if (ci.getPackage() != null)
+
l.addAll(ci.getPackage().getAnnotations());
+ }
+ } else if (element instanceof MethodInfo mi) {
+ if (t.contains(SELF)) {
+ l.addAll(runtimeCache.get(mi.inner()));
+ l.addAll(mi.getDeclaredAnnotations());
+ }
+ if (t.contains(MATCHING_METHODS)) {
+ for (var m :
mi.getMatchingMethods().stream().skip(1).toList()) {
+ l.addAll(runtimeCache.get(m.inner()));
+ l.addAll(m.getDeclaredAnnotations());
+ }
+ }
+ if (t.contains(DECLARING_CLASS)) {
+ l.addAll(find2(mi.getDeclaringClass(),
a(PARENTS)));
+ }
+ if (t.contains(RETURN_TYPE)) {
+
l.addAll(find2(mi.getReturnType().unwrap(Value.class, Optional.class),
a(PARENTS)));
+ }
+ if (t.contains(PACKAGE)) {
+ if (mi.getDeclaringClass().getPackage() != null)
+
l.addAll(mi.getDeclaringClass().getPackage().getAnnotations());
+ }
+ } else if (element instanceof FieldInfo fi) {
+ if (t.contains(SELF)) {
+ l.addAll(runtimeCache.get(fi.inner()));
+ l.addAll(fi.getAnnotations());
+ }
+ } else if (element instanceof ConstructorInfo ci2) {
+ if (t.contains(SELF)) {
+ l.addAll(runtimeCache.get(ci2.inner()));
+ l.addAll(ci2.getDeclaredAnnotations());
+ }
+ } else if (element instanceof ParameterInfo pi) {
+ if (t.contains(SELF)) {
+ l.addAll(pi.getAnnotations());
+ }
+ if (t.contains(MATCHING_PARAMETERS)) {
+ for (var p :
pi.getMatchingParameters().stream().skip(1).toList()) {
+ l.addAll(p.getAnnotations());
+ }
+ }
+ if (t.contains(PARAMETER_TYPE)) {
+
l.addAll(find2(pi.getParameterType().unwrap(Value.class, Optional.class),
a(PARENTS, PACKAGE)));
+ }
+ }
+
+ return l;
}
- private <A extends Annotation> AnnotationInfo<A> ai(Annotatable on, A
value) {
+ private static <A extends Annotation> AnnotationInfo<A> ai(Annotatable
on, A value) {
return AnnotationInfo.of(on, value);
}
}
\ No newline at end of file
diff --git
a/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/reflect/MethodInfo.java
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/reflect/MethodInfo.java
index 9e236a3250..a2a19f99d7 100644
---
a/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/reflect/MethodInfo.java
+++
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/reflect/MethodInfo.java
@@ -27,7 +27,6 @@ import java.util.*;
import java.util.function.*;
import java.util.stream.*;
-import org.apache.juneau.common.collections.*;
import org.apache.juneau.common.utils.*;
/**
diff --git
a/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/reflect/ReflectionMap.java
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/reflect/ReflectionMap.java
index 4cf6cacc03..55cd108777 100644
---
a/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/reflect/ReflectionMap.java
+++
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/reflect/ReflectionMap.java
@@ -295,6 +295,10 @@ public class ReflectionMap<V> {
public ReflectionMap<V> build() {
return new ReflectionMap<>(this);
}
+
+ public boolean isEmpty() { // TODO Auto-generated method stub
+ return classEntries.isEmpty() &&
methodEntries.isEmpty() && fieldEntries.isEmpty() &&
constructorEntries.isEmpty();
+ }
}
private static class ClassEntry<V> {
diff --git
a/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/utils/SystemUtils.java
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/utils/SystemUtils.java
index 3eecb7d98b..c1d9278d12 100644
---
a/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/utils/SystemUtils.java
+++
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/utils/SystemUtils.java
@@ -31,7 +31,7 @@ public class SystemUtils {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
- if (Boolean.getBoolean("SystemUtils.verbose"))
+ if (!
Boolean.getBoolean("juneau.shutdown.quiet"))
SHUTDOWN_MESSAGES.forEach(x ->
System.out.println(x.get())); // NOSONAR - System.out.println is acceptable
here for shutdown messages.
}
});