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 5621703a6a org.apache.juneau.common.reflect API improvements
5621703a6a is described below

commit 5621703a6adc1d561045d41a284282b122080899
Author: James Bognar <[email protected]>
AuthorDate: Wed Nov 19 09:51:10 2025 -0500

    org.apache.juneau.common.reflect API improvements
---
 .../juneau/common/reflect/AnnotationProvider.java  | 180 ++++++----
 .../apache/juneau/common/reflect/FieldInfo.java    |  14 +-
 .../juneau/common/reflect/ParameterInfo.java       | 191 +----------
 .../apache/juneau/common/utils/StringUtils.java    | 120 +++++++
 .../main/java/org/apache/juneau/BeanFilter.java    |   8 +-
 .../juneau/http/annotation/FormDataAnnotation.java |  33 +-
 .../juneau/http/annotation/HeaderAnnotation.java   |  33 +-
 .../juneau/http/annotation/PathAnnotation.java     |  31 +-
 .../http/annotation/PathRemainderAnnotation.java   |  17 +-
 .../juneau/http/annotation/QueryAnnotation.java    |  33 +-
 .../juneau/httppart/bean/RequestBeanMeta.java      |   8 +-
 .../juneau/httppart/bean/ResponseBeanMeta.java     |  12 +-
 .../rest/client/remote/RemoteOperationArg.java     |  14 +-
 .../java/org/apache/juneau/rest/RestContext.java   |   4 +-
 .../org/apache/juneau/rest/arg/AttributeArg.java   |  20 +-
 .../org/apache/juneau/rest/arg/ContentArg.java     |   4 +-
 .../org/apache/juneau/rest/arg/FormDataArg.java    |  23 +-
 .../org/apache/juneau/rest/arg/HasFormDataArg.java |  24 +-
 .../org/apache/juneau/rest/arg/HasQueryArg.java    |  23 +-
 .../java/org/apache/juneau/rest/arg/HeaderArg.java |  36 +-
 .../java/org/apache/juneau/rest/arg/MethodArg.java |   4 +-
 .../java/org/apache/juneau/rest/arg/PathArg.java   |  55 ++--
 .../apache/juneau/rest/arg/PathRemainderArg.java   |  11 +-
 .../java/org/apache/juneau/rest/arg/QueryArg.java  |  39 +--
 .../org/apache/juneau/rest/arg/RequestBeanArg.java |   5 +-
 .../apache/juneau/rest/arg/ResponseBeanArg.java    |   7 +-
 .../apache/juneau/rest/arg/ResponseCodeArg.java    |   4 +-
 .../apache/juneau/rest/arg/ResponseHeaderArg.java  |  17 +-
 .../rest/swagger/BasicSwaggerProviderSession.java  |  56 ++--
 .../reflect/FieldInfo_AnnotationInfos_Test.java    |  22 +-
 .../juneau/common/reflect/ParamInfoTest.java       | 309 ++---------------
 .../org/apache/juneau/reflect/ParamInfoTest.java   | 364 ---------------------
 32 files changed, 564 insertions(+), 1157 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 87792a2024..7a6d3e5f23 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
@@ -514,67 +514,6 @@ public class AnnotationProvider {
                        .map(a -> (AnnotationInfo<A>)a);
        }
 
-       /**
-        * Finds all annotations of the specified type on the specified class 
in a bottom-up traversal order.
-        *
-        * <p>
-        * This method provides a very specific traversal order that searches 
annotations in the following sequence:
-        * <ol>
-        *      <li><b>This class</b>
-        *              <ul>
-        *                      <li>Runtime annotations
-        *                      <li>Declared annotations
-        *              </ul>
-        *      <li><b>Parent classes (child-to-parent order)</b>
-        *              <ul>
-        *                      <li>For each parent: runtime annotations, then 
declared annotations
-        *              </ul>
-        *      <li><b>Interfaces (for each class level, then their parent 
interfaces)</b>
-        *              <ul>
-        *                      <li>For each interface: runtime annotations, 
then declared annotations
-        *              </ul>
-        *      <li><b>Package of this class</b>
-        *              <ul>
-        *                      <li>Declared annotations (packages do not 
support runtime annotations)
-        *              </ul>
-        * </ol>
-        *
-        * <p>
-        * <b>Example traversal order</b> (given class {@code Child extends 
Parent implements I1, I2}):
-        * <ol>
-        *      <li>Child runtime annotations
-        *      <li>Child declared annotations
-        *      <li>Parent runtime annotations
-        *      <li>Parent declared annotations
-        *      <li>I1 runtime annotations (declared on Child)
-        *      <li>I1 declared annotations
-        *      <li>I2 runtime annotations (declared on Child)
-        *      <li>I2 declared annotations
-        *      <li>Parent interfaces and their parents...
-        *      <li>Package declared annotations
-        * </ol>
-        *
-        * <p>
-        * <b>Comparison with {@link #find(Class, Class)}:</b>
-        * <ul>
-        *      <li>{@link #find(Class, Class)} interleaves parent classes and 
interfaces at each level
-        *      <li>{@code findBottomUp} processes all parent classes first, 
then all interfaces, then package
-        *      <li>{@code findBottomUp} ensures runtime annotations always 
come before declared annotations at each level (except packages which don't 
support runtime annotations)
-        * </ul>
-        *
-        * @param <A> The annotation type to find.
-        * @param type The annotation type to find.
-        * @param onClass The class info to search on.
-        * @return A stream of {@link AnnotationInfo} objects in the specified 
bottom-up order. Never <jk>null</jk>.
-        */
-       @SuppressWarnings("unchecked")
-       public <A extends Annotation> Stream<AnnotationInfo<A>> 
findBottomUp(Class<A> type, ClassInfo onClass) {
-               assertArgNotNull("type", type);
-               assertArgNotNull("onClass", onClass);
-
-               return null;  // TODO
-       }
-
        /**
         * Finds annotations declared directly on the specified class, 
including runtime annotations.
         *
@@ -887,7 +826,7 @@ public class AnnotationProvider {
 
                FieldInfo fi = FieldInfo.of(forField);
                runtimeAnnotations.find(forField).forEach(a -> 
list.add(AnnotationInfo.of(fi, a)));
-               list.addAll(fi.getDeclaredAnnotations());
+               list.addAll(fi.getAnnotations());
 
                return u(list);
        }
@@ -1099,31 +1038,49 @@ public class AnnotationProvider {
        }
 
        /**
-        * Streams annotations from a parameter using configurable traversal 
options.
+        * Streams annotations from a parameter using configurable traversal 
options in child-to-parent order.
         *
         * <p>
         * This method provides a flexible, stream-based API for traversing 
parameter annotations without creating intermediate lists.
         *
+        * <h5 class='section'>Supported Traversal Types:</h5>
+        * <ul>
+        *      <li>{@link AnnotationTraversal#SELF SELF} - Annotations 
declared directly on this parameter
+        *      <li>{@link AnnotationTraversal#MATCHING_PARAMETERS 
MATCHING_PARAMETERS} - Matching parameters in parent methods/constructors 
(child-to-parent)
+        *      <li>{@link AnnotationTraversal#PARAMETER_TYPE PARAMETER_TYPE} - 
The parameter's type hierarchy (includes class parents and package)
+        * </ul>
+        *
+        * <p>
+        * <b>Default:</b> If no traversals are specified, defaults to: {@code 
SELF, MATCHING_PARAMETERS, PARAMETER_TYPE}
+        *
         * <h5 class='section'>Examples:</h5>
         * <p class='bjava'>
-        *      <jc>// Search parameter, matching parameters, and parameter 
type</jc>
+        *      <jc>// Search parameter, matching parameters, and parameter 
type (child-to-parent)</jc>
         *      Stream&lt;AnnotationInfo&lt;MyAnnotation&gt;&gt; <jv>s1</jv> =
-        *              findAnnotations(MyAnnotation.<jk>class</jk>, 
<jv>pi</jv>, SELF, MATCHING_PARAMETERS, PARAMETER_TYPE);
+        *              find(MyAnnotation.<jk>class</jk>, <jv>pi</jv>, SELF, 
MATCHING_PARAMETERS, PARAMETER_TYPE);
         *
-        *      <jc>// Search in parent-first order using 
findAnnotationsParentFirst</jc>
+        *      <jc>// Just search this parameter</jc>
         *      Stream&lt;AnnotationInfo&lt;MyAnnotation&gt;&gt; <jv>s2</jv> =
-        *              findAnnotationsParentFirst(MyAnnotation.<jk>class</jk>, 
<jv>pi</jv>, SELF, MATCHING_PARAMETERS, PARAMETER_TYPE);
+        *              find(MyAnnotation.<jk>class</jk>, <jv>pi</jv>, SELF);
+        *
+        *      <jc>// Search in parent-to-child order using findTopDown</jc>
+        *      Stream&lt;AnnotationInfo&lt;MyAnnotation&gt;&gt; <jv>s3</jv> =
+        *              findTopDown(MyAnnotation.<jk>class</jk>, <jv>pi</jv>, 
SELF, MATCHING_PARAMETERS, PARAMETER_TYPE);
         * </p>
         *
         * @param <A> The annotation type.
         * @param type The annotation type to search for.
         * @param parameter The parameter to search.
-        * @param traversals The traversal options.
-        * @return A stream of {@link AnnotationInfo} objects. Never 
<jk>null</jk>.
+        * @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>> 
findAnnotations(Class<A> type, ParameterInfo parameter, AnnotationTraversal... 
traversals) {
+       public <A extends Annotation> Stream<AnnotationInfo<A>> find(Class<A> 
type, ParameterInfo parameter, AnnotationTraversal... traversals) {
                assertArgNotNull("type", type);
                assertArgNotNull("parameter", parameter);
+               if (traversals.length == 0)
+                       traversals = new AnnotationTraversal[]{SELF, 
MATCHING_PARAMETERS, PARAMETER_TYPE};
 
                return Arrays.stream(traversals)
                        
.sorted(Comparator.comparingInt(AnnotationTraversal::getOrder))
@@ -1139,11 +1096,90 @@ public class AnnotationProvider {
                        });
        }
 
+       /**
+        * Streams annotations from a parameter using configurable traversal 
options in parent-to-child order.
+        *
+        * <p>
+        * This is equivalent to calling {@link #find(Class, ParameterInfo, 
AnnotationTraversal...)} and reversing the result.
+        * Use this when you need parent annotations to take precedence over 
child annotations.
+        *
+        * <h5 class='section'>Supported Traversal Types:</h5>
+        * <ul>
+        *      <li>{@link AnnotationTraversal#SELF SELF} - Annotations 
declared directly on this parameter
+        *      <li>{@link AnnotationTraversal#MATCHING_PARAMETERS 
MATCHING_PARAMETERS} - Matching parameters in parent methods/constructors 
(parent-to-child)
+        *      <li>{@link AnnotationTraversal#PARAMETER_TYPE PARAMETER_TYPE} - 
The parameter's type hierarchy (includes class parents and package)
+        * </ul>
+        *
+        * <p>
+        * <b>Default:</b> If no traversals are specified, defaults to: {@code 
SELF, MATCHING_PARAMETERS, PARAMETER_TYPE}
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bjava'>
+        *      <jc>// Search in parent-to-child order</jc>
+        *      Stream&lt;AnnotationInfo&lt;MyAnnotation&gt;&gt; <jv>s</jv> =
+        *              findTopDown(MyAnnotation.<jk>class</jk>, <jv>pi</jv>, 
SELF, MATCHING_PARAMETERS, PARAMETER_TYPE);
+        *
+        *      <jc>// Get first annotation (from parent)</jc>
+        *      Optional&lt;AnnotationInfo&lt;MyAnnotation&gt;&gt; 
<jv>first</jv> = <jv>s</jv>.findFirst();
+        * </p>
+        *
+        * @param <A> The annotation type.
+        * @param type The annotation type to search for.
+        * @param parameter 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) {
+               return rstream(find(type, parameter, traversals).toList());
+       }
+
+       /**
+        * Checks if a parameter has the specified annotation.
+        *
+        * <p>
+        * This is a convenience method equivalent to:
+        * <p class='bjava'>
+        *      find(<jv>type</jv>, <jv>parameter</jv>, 
<jv>traversals</jv>).findFirst().isPresent()
+        * </p>
+        *
+        * <h5 class='section'>Supported Traversal Types:</h5>
+        * <ul>
+        *      <li>{@link AnnotationTraversal#SELF SELF} - Annotations 
declared directly on this parameter
+        *      <li>{@link AnnotationTraversal#MATCHING_PARAMETERS 
MATCHING_PARAMETERS} - Matching parameters in parent methods/constructors 
(child-to-parent)
+        *      <li>{@link AnnotationTraversal#PARAMETER_TYPE PARAMETER_TYPE} - 
The parameter's type hierarchy (includes class parents and package)
+        * </ul>
+        *
+        * <p>
+        * <b>Default:</b> If no traversals are specified, defaults to: {@code 
SELF, MATCHING_PARAMETERS, PARAMETER_TYPE}
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bjava'>
+        *      <jc>// Check if parameter has @MyAnnotation anywhere in 
hierarchy</jc>
+        *      <jk>boolean</jk> <jv>hasIt</jv> = 
has(MyAnnotation.<jk>class</jk>, <jv>pi</jv>);
+        *
+        *      <jc>// Check only on the parameter itself</jc>
+        *      <jk>boolean</jk> <jv>hasIt2</jv> = 
has(MyAnnotation.<jk>class</jk>, <jv>pi</jv>, SELF);
+        * </p>
+        *
+        * @param <A> The annotation type.
+        * @param type The annotation type to search for.
+        * @param parameter 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) {
+               return find(type, parameter, 
traversals).findFirst().isPresent();
+       }
+
        /**
         * Streams annotations from a parameter using configurable traversal 
options in parent-first order.
         *
         * <p>
-        * This is equivalent to calling {@link #findAnnotations(Class, 
ParameterInfo, AnnotationTraversal...)}
+        * This is equivalent to calling {@link #find(Class, ParameterInfo, 
AnnotationTraversal...)}
         * and reversing the result.
         *
         * @param <A> The annotation type.
@@ -1153,7 +1189,7 @@ public class AnnotationProvider {
         * @return A stream of {@link AnnotationInfo} objects in parent-first 
order. Never <jk>null</jk>.
         */
        public <A extends Annotation> Stream<AnnotationInfo<A>> 
findAnnotationsParentFirst(Class<A> type, ParameterInfo parameter, 
AnnotationTraversal... traversals) {
-               return rstream(findAnnotations(type, parameter, 
traversals).toList());
+               return rstream(find(type, parameter, traversals).toList());
        }
 
        /**
diff --git 
a/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/reflect/FieldInfo.java
 
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/reflect/FieldInfo.java
index 44cdb6b39d..e25f0d20e8 100644
--- 
a/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/reflect/FieldInfo.java
+++ 
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/reflect/FieldInfo.java
@@ -65,7 +65,7 @@ public class FieldInfo extends AccessibleInfo implements 
Comparable<FieldInfo>,
        private final Field inner;
        private final ClassInfo declaringClass;
        private final Supplier<ClassInfo> type;
-       private final Supplier<List<AnnotationInfo<Annotation>>> 
declaredAnnotations;  // All annotations declared directly on this field.
+       private final Supplier<List<AnnotationInfo<Annotation>>> annotations;  
// All annotations declared directly on this field.
        private final Supplier<String> fullName;  // Fully qualified field name 
(declaring-class.field-name).
 
        /**
@@ -80,7 +80,7 @@ public class FieldInfo extends AccessibleInfo implements 
Comparable<FieldInfo>,
                this.declaringClass = declaringClass;
                this.inner = inner;
                this.type = memoize(() -> ClassInfo.of(inner.getType()));
-               this.declaredAnnotations = memoize(() -> 
stream(inner.getAnnotations()).flatMap(a -> streamRepeated(a)).map(a -> 
AnnotationInfo.of(this, a)).toList());
+               this.annotations = memoize(() -> 
stream(inner.getAnnotations()).flatMap(a -> streamRepeated(a)).map(a -> 
AnnotationInfo.of(this, a)).toList());
                this.fullName = memoize(this::findFullName);
        }
 
@@ -108,8 +108,8 @@ public class FieldInfo extends AccessibleInfo implements 
Comparable<FieldInfo>,
         *      An unmodifiable list of all annotations declared on this field.
         *      <br>Repeatable annotations are expanded into individual 
instances.
         */
-       public List<AnnotationInfo<Annotation>> getDeclaredAnnotations() {
-               return declaredAnnotations.get();
+       public List<AnnotationInfo<Annotation>> getAnnotations() {
+               return annotations.get();
        }
 
        /**
@@ -120,8 +120,8 @@ public class FieldInfo extends AccessibleInfo implements 
Comparable<FieldInfo>,
         * @return A stream of all matching annotations.
         */
        @SuppressWarnings("unchecked")
-       public <A extends Annotation> Stream<AnnotationInfo<A>> 
getDeclaredAnnotations(Class<A> type) {
-               return declaredAnnotations.get().stream()
+       public <A extends Annotation> Stream<AnnotationInfo<A>> 
getAnnotations(Class<A> type) {
+               return annotations.get().stream()
                        .filter(x -> type.isInstance(x.inner()))
                        .map(x -> (AnnotationInfo<A>)x);
        }
@@ -204,7 +204,7 @@ public class FieldInfo extends AccessibleInfo implements 
Comparable<FieldInfo>,
         * @return <jk>true</jk> if the specified annotation is present.
         */
        public <A extends Annotation> boolean hasAnnotation(Class<A> type) {
-               return inner.isAnnotationPresent(type);
+               return getAnnotations(type).findAny().isPresent();
        }
 
        /**
diff --git 
a/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/reflect/ParameterInfo.java
 
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/reflect/ParameterInfo.java
index 2ed7df9c94..1546b39119 100644
--- 
a/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/reflect/ParameterInfo.java
+++ 
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/reflect/ParameterInfo.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.function.ResettableSupplier;
 
 /**
@@ -58,10 +57,7 @@ public class ParameterInfo extends ElementInfo implements 
Annotatable {
        private final int index;
        private final ClassInfo type;
 
-       @SuppressWarnings({"rawtypes","unchecked"})
-       private final Cache<Class,List<AnnotationInfo<Annotation>>> 
allAnnotations = 
Cache.<Class,List<AnnotationInfo<Annotation>>>create().supplier((k) -> 
findAllAnnotationInfos(k)).build();
-
-       private final Supplier<List<AnnotationInfo<Annotation>>> 
declaredAnnotations;  // All annotations declared directly on this parameter.
+       private final Supplier<List<AnnotationInfo<Annotation>>> annotations;  
// All annotations declared directly on this parameter.
        private final Supplier<List<ParameterInfo>> matchingParameters;  // 
Matching parameters in parent methods.
        private final ResettableSupplier<String> resolvedName = 
memoizeResettable(this::findNameInternal);  // Resolved name from @Name 
annotation or bytecode.
        private final ResettableSupplier<String> resolvedQualifier = 
memoizeResettable(this::findQualifierInternal);  // Resolved qualifier from 
@Named annotation.
@@ -81,7 +77,7 @@ public class ParameterInfo extends ElementInfo implements 
Annotatable {
                this.inner = inner;
                this.index = index;
                this.type = type;
-               this.declaredAnnotations = memoize(() -> 
stream(inner.getAnnotations()).flatMap(a -> streamRepeated(a)).map(a -> 
AnnotationInfo.of(this, a)).toList());
+               this.annotations = memoize(() -> 
stream(inner.getAnnotations()).flatMap(a -> streamRepeated(a)).map(a -> 
AnnotationInfo.of(this, a)).toList());
                this.matchingParameters = memoize(this::findMatchingParameters);
        }
 
@@ -111,7 +107,7 @@ public class ParameterInfo extends ElementInfo implements 
Annotatable {
         *      <br>Repeatable annotations are expanded into individual 
instances.
         */
        public List<AnnotationInfo<Annotation>> getAnnotations() {
-               return declaredAnnotations.get();
+               return annotations.get();
        }
 
        /**
@@ -199,78 +195,6 @@ public class ParameterInfo extends ElementInfo implements 
Annotatable {
                return 
((MethodInfo)executable).getMatchingMethods().stream().map(m -> 
m.getParameter(index)).toList();
        }
 
-       /**
-        * Returns all annotation infos of the specified type defined on this 
parameter.
-        *
-        * <p>
-        * Performs a comprehensive search through the parameter hierarchy and 
parameter type hierarchy.
-        *
-        * <h5 class='section'>Search Order (child-to-parent):</h5>
-        * <ol>
-        *      <li><b>Matching parameters in hierarchy</b>
-        *              <ul>
-        *                      <li>For methods: This parameter → parent method 
parameters (via {@link #getMatchingParameters()})
-        *                      <li>For constructors: This parameter → parent 
constructor parameters (via {@link #getMatchingParameters()})
-        *              </ul>
-        *      <li><b>Parameter type hierarchy</b> (via {@link 
ClassInfo#getParentsAndInterfaces()})
-        *              <ul>
-        *                      <li>Parameter's class and its interfaces 
(interleaved)
-        *                      <li>Parameter's parent classes and their 
interfaces (interleaved)
-        *                      <li>Continues up to Object class
-        *              </ul>
-        *      <li><b>Package annotation</b> - Package of the parameter type
-        * </ol>
-        *
-        * <h5 class='section'>Example:</h5>
-        * <p class='bjava'>
-        *      <jc>// Given:</jc>
-        *      <jk>class</jk> Parent {
-        *              <jk>void</jk> method(@MyAnnotation String 
<jv>param</jv>) {}
-        *      }
-        *      <jk>class</jk> Child <jk>extends</jk> Parent {
-        *              <ja>@Override</ja>
-        *              <jk>void</jk> method(@MyAnnotation String 
<jv>param</jv>) {}
-        *      }
-        *
-        *      <jc>// Search order for Child.method parameter:</jc>
-        *      ParameterInfo <jv>pi</jv> = 
ClassInfo.<jsm>of</jsm>(Child.<jk>class</jk>).getMethod(<js>"method"</js>, 
String.<jk>class</jk>).getParameter(0);
-        *      List&lt;AnnotationInfo&lt;MyAnnotation&gt;&gt; 
<jv>annotations</jv> = 
<jv>pi</jv>.getAllAnnotations(MyAnnotation.<jk>class</jk>);
-        *      <jc>// Returns (in order):</jc>
-        *      <jc>//   1. @MyAnnotation on Child.method parameter</jc>
-        *      <jc>//   2. @MyAnnotation on Parent.method parameter</jc>
-        *      <jc>//   3. Any @MyAnnotation on String class hierarchy</jc>
-        *      <jc>//   4. Any @MyAnnotation on java.lang package</jc>
-        * </p>
-        *
-        * @param <A> The annotation type to look for.
-        * @param type The annotation type to look for.
-        * @return An unmodifiable list of annotation infos in child-to-parent 
order, or an empty list if none found.
-        */
-       @SuppressWarnings({ "unchecked", "rawtypes" })
-       public <A extends Annotation> List<AnnotationInfo<A>> 
getAllAnnotations(Class<A> type) {
-               return (List)allAnnotations.get(type);
-       }
-
-       /**
-        * Returns the first annotation info of the specified type defined on 
this parameter.
-        *
-        * <p>
-        * This is a convenience method that returns the first result from 
{@link #getAllAnnotations(Class)}.
-        *
-        * <p>
-        * Performs a comprehensive search through the parameter hierarchy and 
parameter type hierarchy
-        * in child-to-parent order, returning the first annotation found.
-        *
-        * @param <A> The annotation type to look for.
-        * @param type The annotation type to look for.
-        * @return The first annotation info if found (closest to this 
parameter), or <jk>null</jk> if not found.
-        * @see #getAllAnnotations(Class)
-        */
-       public <A extends Annotation> AnnotationInfo<A> 
getAllAnnotation(Class<A> type) {
-               var list = getAllAnnotations(type);
-               return list.isEmpty() ? null : list.get(0);
-       }
-
        /**
         * Returns the constructor that this parameter belongs to.
         *
@@ -278,21 +202,6 @@ public class ParameterInfo extends ElementInfo implements 
Annotatable {
         */
        public ConstructorInfo getConstructor() { return 
executable.isConstructor() ? (ConstructorInfo)executable : null; }
 
-       /**
-        * Returns the specified parameter annotation declared on this 
parameter.
-        *
-        * @param <A> The annotation type to look for.
-        * @param type The annotation type to look for.
-        * @return The specified parameter annotation declared on this 
parameter, or <jk>null</jk> if not found.
-        */
-       public <A extends Annotation> A getDeclaredAnnotation(Class<A> type) {
-               if (nn(type))
-                       for (var ai : getAnnotations())
-                               if (type.isInstance(ai.inner()))
-                                       return type.cast(ai.inner());
-               return null;
-       }
-
        /**
         * Returns the index position of this parameter.
         *
@@ -421,18 +330,6 @@ public class ParameterInfo extends ElementInfo implements 
Annotatable {
         */
        public ClassInfo getParameterType() { return type; }
 
-       /**
-        * Returns <jk>true</jk> if this parameter has the specified annotation.
-        *
-        * @param <A> The annotation type to look for.
-        * @param type The annotation type to look for.
-        * @return
-        *      The <jk>true</jk> if annotation if found.
-        */
-       public <A extends Annotation> boolean hasAnnotation(Class<A> type) {
-               return nn(getAllAnnotation(type));
-       }
-
        /**
         * Returns <jk>true</jk> if the parameter has a name.
         *
@@ -673,93 +570,11 @@ public class ParameterInfo extends ElementInfo implements 
Annotatable {
                return inner.getAnnotatedType();
        }
 
-       /**
-        * Returns annotations that are <em>directly present</em> on this 
parameter.
-        *
-        * <p>
-        * Same as calling {@link Parameter#getDeclaredAnnotations()}.
-        *
-        * <p>
-        * <b>Note:</b> This returns the simple array of declared annotations.
-        * For Juneau's enhanced annotation searching, use {@link 
#findAnnotations(Class, AnnotationTraversal...)} instead.
-        *
-        * <h5 class='section'>Example:</h5>
-        * <p class='bjava'>
-        *      <jc>// Get declared annotations on parameter</jc>
-        *      ParameterInfo <jv>pi</jv> = ...;
-        *      Annotation[] <jv>annotations</jv> = 
<jv>pi</jv>.getDeclaredAnnotations();
-        * </p>
-        *
-        * @return Annotations directly present on this parameter, or an empty 
array if there are none.
-        * @see Parameter#getDeclaredAnnotations()
-        */
-       public Annotation[] getDeclaredAnnotations() {
-               return inner.getDeclaredAnnotations();
-       }
-
-       /**
-        * Returns this element's declared annotations of the specified type 
(including repeated annotations).
-        *
-        * <p>
-        * Same as calling {@link 
Parameter#getDeclaredAnnotationsByType(Class)}.
-        *
-        * <p>
-        * This method handles repeatable annotations by "looking through" 
container annotations,
-        * but only examines annotations directly declared on this parameter 
(not inherited).
-        *
-        * <h5 class='section'>Example:</h5>
-        * <p class='bjava'>
-        *      <jc>// Get declared @Author annotations (including 
repeated)</jc>
-        *      ParameterInfo <jv>pi</jv> = ...;
-        *      Author[] <jv>authors</jv> = 
<jv>pi</jv>.getDeclaredAnnotationsByType(Author.<jk>class</jk>);
-        * </p>
-        *
-        * @param <A> The annotation type.
-        * @param annotationClass The Class object corresponding to the 
annotation type.
-        * @return All this element's declared annotations of the specified 
type, or an empty array if there are none.
-        * @see Parameter#getDeclaredAnnotationsByType(Class)
-        */
-       public <A extends Annotation> A[] getDeclaredAnnotationsByType(Class<A> 
annotationClass) {
-               return inner.getDeclaredAnnotationsByType(annotationClass);
-       }
-
        @Override
        public String toString() {
                return (executable.getSimpleName()) + "[" + index + "]";
        }
 
-       @SuppressWarnings("unchecked")
-       private <A extends Annotation> List<AnnotationInfo<A>> 
findAllAnnotationInfos(Class<A> type) {
-               var list = new ArrayList<AnnotationInfo<A>>();
-
-               // Search through matching parameters in hierarchy 
(child-to-parent order)
-               for (var mp : getMatchingParameters()) {
-                       mp.getAnnotations().stream()
-                               .filter(x -> x.isType(type))
-                               .map(x -> (AnnotationInfo<A>)x)
-                               .forEach(list::add);
-               }
-
-               // Search parameter type hierarchy in child-to-parent order 
(interleaved classes and interfaces)
-               var paramType = 
executable.getParameter(index).getParameterType().unwrap(Value.class, 
Optional.class);
-               
-               // Traverse parent classes and interfaces (child-to-parent, 
interleaved)
-               var parentsAndInterfaces = paramType.getParentsAndInterfaces();
-               for (int i = 0; i < parentsAndInterfaces.size(); i++) {
-                       
parentsAndInterfaces.get(i).getDeclaredAnnotations().stream()
-                               .filter(x -> x.isType(type))
-                               .map(x -> (AnnotationInfo<A>)x)
-                               .forEach(list::add);
-               }
-               
-               // Package annotation (last)
-               var packageAnn = paramType.getPackageAnnotation(type);
-               if (nn(packageAnn))
-                       list.add(AnnotationInfo.of(paramType, packageAnn));
-
-               return list;
-       }
-
        
//-----------------------------------------------------------------------------------------------------------------
        // Annotatable interface methods
        
//-----------------------------------------------------------------------------------------------------------------
diff --git 
a/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/utils/StringUtils.java
 
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/utils/StringUtils.java
index 8469c1014d..363d51c04a 100644
--- 
a/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/utils/StringUtils.java
+++ 
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/utils/StringUtils.java
@@ -1351,6 +1351,126 @@ public class StringUtils {
                return ! isBlank(str);
        }
 
+       /**
+        * Checks if any of the provided strings are not empty (not null and 
not zero-length).
+        *
+        * <p>
+        * Returns <jk>true</jk> if at least one string is not null and has a 
length greater than zero.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bjava'>
+        *      isAnyNotEmpty(<jk>null</jk>, <jk>null</jk>);             <jc>// 
false</jc>
+        *      isAnyNotEmpty(<js>""</js>, <js>""</js>);                 <jc>// 
false</jc>
+        *      isAnyNotEmpty(<jk>null</jk>, <js>"hello"</js>);          <jc>// 
true</jc>
+        *      isAnyNotEmpty(<js>""</js>, <js>"   "</js>);              <jc>// 
true</jc>
+        *      isAnyNotEmpty(<js>"hello"</js>, <js>"world"</js>);       <jc>// 
true</jc>
+        * </p>
+        *
+        * @param values The strings to check.
+        * @return <jk>true</jk> if at least one string is not null and not 
empty.
+        */
+       public static boolean isAnyNotEmpty(CharSequence...values) {
+               if (values == null)
+                       return false;
+               for (CharSequence value : values)
+                       if (value != null && !value.isEmpty())
+                               return true;
+               return false;
+       }
+
+       /**
+        * Checks if any of the provided strings are not blank (not null, not 
empty, and not whitespace only).
+        *
+        * <p>
+        * Returns <jk>true</jk> if at least one string is not null, not empty, 
and contains non-whitespace characters.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bjava'>
+        *      isAnyNotBlank(<jk>null</jk>, <jk>null</jk>);             <jc>// 
false</jc>
+        *      isAnyNotBlank(<js>""</js>, <js>""</js>);                 <jc>// 
false</jc>
+        *      isAnyNotBlank(<js>"   "</js>, <js>"   "</js>);           <jc>// 
false</jc>
+        *      isAnyNotBlank(<jk>null</jk>, <js>"hello"</js>);          <jc>// 
true</jc>
+        *      isAnyNotBlank(<js>""</js>, <js>"   "</js>, <js>"x"</js>);<jc>// 
true</jc>
+        *      isAnyNotBlank(<js>"hello"</js>, <js>"world"</js>);       <jc>// 
true</jc>
+        * </p>
+        *
+        * @param values The strings to check.
+        * @return <jk>true</jk> if at least one string is not null, not empty, 
and contains non-whitespace characters.
+        */
+       public static boolean isAnyNotBlank(CharSequence...values) {
+               if (values == null)
+                       return false;
+               for (CharSequence value : values)
+                       if (isNotBlank(value))
+                               return true;
+               return false;
+       }
+
+       /**
+        * Checks if all of the provided strings are not empty (not null and 
not zero-length).
+        *
+        * <p>
+        * Returns <jk>true</jk> only if all strings are not null and have a 
length greater than zero.
+        * Returns <jk>false</jk> if the array is null or empty, or if any 
string is null or empty.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bjava'>
+        *      isAllNotEmpty();                                     <jc>// 
false</jc>
+        *      isAllNotEmpty(<jk>null</jk>);                        <jc>// 
false</jc>
+        *      isAllNotEmpty(<jk>null</jk>, <jk>null</jk>);         <jc>// 
false</jc>
+        *      isAllNotEmpty(<js>""</js>, <js>""</js>);             <jc>// 
false</jc>
+        *      isAllNotEmpty(<jk>null</jk>, <js>"hello"</js>);      <jc>// 
false</jc>
+        *      isAllNotEmpty(<js>""</js>, <js>"   "</js>);          <jc>// 
false</jc>
+        *      isAllNotEmpty(<js>"hello"</js>);                     <jc>// 
true</jc>
+        *      isAllNotEmpty(<js>"hello"</js>, <js>"world"</js>);   <jc>// 
true</jc>
+        *      isAllNotEmpty(<js>"hello"</js>, <js>"   "</js>);     <jc>// 
true</jc>
+        * </p>
+        *
+        * @param values The strings to check.
+        * @return <jk>true</jk> if all strings are not null and not empty, 
<jk>false</jk> otherwise.
+        */
+       public static boolean isAllNotEmpty(CharSequence...values) {
+               if (values == null || values.length == 0)
+                       return false;
+               for (CharSequence value : values)
+                       if (value == null || value.isEmpty())
+                               return false;
+               return true;
+       }
+
+       /**
+        * Checks if all of the provided strings are not blank (not null, not 
empty, and not whitespace only).
+        *
+        * <p>
+        * Returns <jk>true</jk> only if all strings are not null, not empty, 
and contain non-whitespace characters.
+        * Returns <jk>false</jk> if the array is null or empty, or if any 
string is null, empty, or whitespace only.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bjava'>
+        *      isAllNotBlank();                                     <jc>// 
false</jc>
+        *      isAllNotBlank(<jk>null</jk>);                        <jc>// 
false</jc>
+        *      isAllNotBlank(<jk>null</jk>, <jk>null</jk>);         <jc>// 
false</jc>
+        *      isAllNotBlank(<js>""</js>, <js>""</js>);             <jc>// 
false</jc>
+        *      isAllNotBlank(<js>"   "</js>, <js>"   "</js>);       <jc>// 
false</jc>
+        *      isAllNotBlank(<jk>null</jk>, <js>"hello"</js>);      <jc>// 
false</jc>
+        *      isAllNotBlank(<js>""</js>, <js>"   "</js>);          <jc>// 
false</jc>
+        *      isAllNotBlank(<js>"hello"</js>, <js>"   "</js>);     <jc>// 
false</jc>
+        *      isAllNotBlank(<js>"hello"</js>);                     <jc>// 
true</jc>
+        *      isAllNotBlank(<js>"hello"</js>, <js>"world"</js>);   <jc>// 
true</jc>
+        * </p>
+        *
+        * @param values The strings to check.
+        * @return <jk>true</jk> if all strings are not null, not empty, and 
not whitespace only, <jk>false</jk> otherwise.
+        */
+       public static boolean isAllNotBlank(CharSequence...values) {
+               if (values == null || values.length == 0)
+                       return false;
+               for (CharSequence value : values)
+                       if (! isNotBlank(value))
+                               return false;
+               return true;
+       }
+
        /**
         * Returns <jk>true</jk> if the specified character is a valid number 
character.
         *
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanFilter.java 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanFilter.java
index a27419ca24..f426acf309 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanFilter.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanFilter.java
@@ -76,17 +76,17 @@ public class BeanFilter {
                public Builder applyAnnotations(List<Bean> annotations) {
 
                        annotations.forEach(x -> {
-                               if (isNotEmpty(x.properties()) || 
isNotEmpty(x.p()))
+                               if (isAnyNotEmpty(x.properties(), x.p()))
                                        properties(x.properties(), x.p());
                                if (x.sort())
                                        sortProperties(true);
                                if (x.findFluentSetters())
                                        findFluentSetters();
-                               if (isNotEmpty(x.excludeProperties()) || 
isNotEmpty(x.xp()))
+                               if (isAnyNotEmpty(x.excludeProperties(), 
x.xp()))
                                        
excludeProperties(x.excludeProperties(), x.xp());
-                               if (isNotEmpty(x.readOnlyProperties()) || 
isNotEmpty(x.ro()))
+                               if (isAnyNotEmpty(x.readOnlyProperties(), 
x.ro()))
                                        
readOnlyProperties(x.readOnlyProperties(), x.ro());
-                               if (isNotEmpty(x.writeOnlyProperties()) || 
isNotEmpty(x.wo()))
+                               if (isAnyNotEmpty(x.writeOnlyProperties(), 
x.wo()))
                                        
writeOnlyProperties(x.writeOnlyProperties(), x.wo());
                                if (isNotEmpty(x.typeName()))
                                        typeName(x.typeName());
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/FormDataAnnotation.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/FormDataAnnotation.java
index 1a646851c9..3b47907f17 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/FormDataAnnotation.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/FormDataAnnotation.java
@@ -19,13 +19,14 @@ package org.apache.juneau.http.annotation;
 import static java.lang.annotation.ElementType.*;
 import static java.lang.annotation.RetentionPolicy.*;
 import static org.apache.juneau.common.utils.CollectionUtils.*;
+import static org.apache.juneau.common.utils.StringUtils.*;
 import static org.apache.juneau.common.utils.Utils.*;
 
 import java.lang.annotation.*;
+import java.util.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
-import org.apache.juneau.common.collections.*;
 import org.apache.juneau.httppart.*;
 import org.apache.juneau.common.reflect.*;
 import org.apache.juneau.svl.*;
@@ -37,6 +38,9 @@ import org.apache.juneau.svl.*;
  * </ul>
  */
 public class FormDataAnnotation {
+
+       private static AnnotationProvider AP = AnnotationProvider.INSTANCE;
+
        /**
         * Applies targeted {@link FormData} annotations to a {@link 
org.apache.juneau.BeanContext.Builder}.
         */
@@ -53,7 +57,7 @@ public class FormDataAnnotation {
 
                @Override
                public void apply(AnnotationInfo<FormData> ai, 
BeanContext.Builder b) {
-                       FormData a = ai.inner();
+                       var a = ai.inner();
                        if (isEmptyArray(a.on()) && isEmptyArray(a.onClass()))
                                return;
                        b.annotations(a);
@@ -270,12 +274,14 @@ public class FormDataAnnotation {
         * Finds the default value from the specified list of annotations.
         *
         * @param pi The parameter.
-        * @return The last matching default value, or {@link Value#empty()} if 
not found.
+        * @return The last matching default value, or empty if not found.
         */
-       public static Value<String> findDef(ParameterInfo pi) {
-               Value<String> n = Value.empty();
-               
rstream(pi.getAllAnnotations(FormData.class)).map(AnnotationInfo::inner).filter(x
 -> isNotEmpty(x.def())).forEach(x -> n.set(x.def()));
-               return n;
+       public static Optional<String> findDef(ParameterInfo pi) {
+               return AP.find(FormData.class, pi)
+                       .map(AnnotationInfo::inner)
+                       .filter(x -> isNotEmpty(x.def()))
+                       .findFirst()
+                       .map(x -> x.def());
        }
 
        /**
@@ -285,12 +291,13 @@ public class FormDataAnnotation {
         * The last matching name found is returned.
         *
         * @param pi The parameter.
-        * @return The last matching name, or {@link Value#empty()} if not 
found.
+        * @return The last matching name, or empty if not found.
         */
-       public static Value<String> findName(ParameterInfo pi) {
-               Value<String> n = Value.empty();
-               
rstream(pi.getAllAnnotations(FormData.class)).map(AnnotationInfo::inner).filter(x
 -> isNotEmpty(x.value())).forEach(x -> n.set(x.value()));
-               
rstream(pi.getAllAnnotations(FormData.class)).map(AnnotationInfo::inner).filter(x
 -> isNotEmpty(x.name())).forEach(x -> n.set(x.name()));
-               return n;
+       public static Optional<String> findName(ParameterInfo pi) {
+               return AP.find(FormData.class, pi)
+                       .map(AnnotationInfo::inner)
+                       .filter(x -> isAnyNotBlank(x.value(), x.name()))
+                       .findFirst()
+                       .map(x -> firstNonBlank(x.name(), x.value()));
        }
 }
\ No newline at end of file
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/HeaderAnnotation.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/HeaderAnnotation.java
index 91d3daf29d..3a7af85219 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/HeaderAnnotation.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/HeaderAnnotation.java
@@ -19,13 +19,14 @@ package org.apache.juneau.http.annotation;
 import static java.lang.annotation.ElementType.*;
 import static java.lang.annotation.RetentionPolicy.*;
 import static org.apache.juneau.common.utils.CollectionUtils.*;
+import static org.apache.juneau.common.utils.StringUtils.*;
 import static org.apache.juneau.common.utils.Utils.*;
 
 import java.lang.annotation.*;
+import java.util.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
-import org.apache.juneau.common.collections.*;
 import org.apache.juneau.httppart.*;
 import org.apache.juneau.common.reflect.*;
 import org.apache.juneau.svl.*;
@@ -37,6 +38,9 @@ import org.apache.juneau.svl.*;
  * </ul>
  */
 public class HeaderAnnotation {
+
+       private static AnnotationProvider AP = AnnotationProvider.INSTANCE;
+
        /**
         * Applies targeted {@link Header} annotations to a {@link 
org.apache.juneau.BeanContext.Builder}.
         */
@@ -53,7 +57,7 @@ public class HeaderAnnotation {
 
                @Override
                public void apply(AnnotationInfo<Header> ai, 
BeanContext.Builder b) {
-                       Header a = ai.inner();
+                       var a = ai.inner();
                        if (isEmptyArray(a.on()) && isEmptyArray(a.onClass()))
                                return;
                        b.annotations(a);
@@ -270,12 +274,14 @@ public class HeaderAnnotation {
         * Finds the default value from the specified list of annotations.
         *
         * @param pi The parameter.
-        * @return The last matching default value, or {@link Value#empty()} if 
not found.
+        * @return The last matching default value, or empty if not found.
         */
-       public static Value<String> findDef(ParameterInfo pi) {
-               Value<String> n = Value.empty();
-               
rstream(pi.getAllAnnotations(Header.class)).map(AnnotationInfo::inner).filter(x 
-> isNotEmpty(x.def())).forEach(x -> n.set(x.def()));
-               return n;
+       public static Optional<String> findDef(ParameterInfo pi) {
+               return AP.find(Header.class, pi)
+                       .map(AnnotationInfo::inner)
+                       .filter(x -> isNotEmpty(x.def()))
+                       .findFirst()
+                       .map(x -> x.def());
        }
 
        /**
@@ -285,12 +291,13 @@ public class HeaderAnnotation {
         * The last matching name found is returned.
         *
         * @param pi The parameter.
-        * @return The last matching name, or {@link Value#empty()} if not 
found.
+        * @return The last matching name, or empty if not found.
         */
-       public static Value<String> findName(ParameterInfo pi) {
-               Value<String> n = Value.empty();
-               
rstream(pi.getAllAnnotations(Header.class)).map(AnnotationInfo::inner).filter(x 
-> isNotEmpty(x.value())).forEach(x -> n.set(x.value()));
-               
rstream(pi.getAllAnnotations(Header.class)).map(AnnotationInfo::inner).filter(x 
-> isNotEmpty(x.name())).forEach(x -> n.set(x.name()));
-               return n;
+       public static Optional<String> findName(ParameterInfo pi) {
+               return AP.find(Header.class, pi)
+                       .map(AnnotationInfo::inner)
+                       .filter(x -> isAnyNotBlank(x.value(), x.name()))
+                       .findFirst()
+                       .map(x -> firstNonBlank(x.name(), x.value()));
        }
 }
\ No newline at end of file
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/PathAnnotation.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/PathAnnotation.java
index 829ee71d1b..9f1f9e59c6 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/PathAnnotation.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/PathAnnotation.java
@@ -20,13 +20,14 @@ import static java.lang.annotation.ElementType.*;
 import static java.lang.annotation.RetentionPolicy.*;
 import static org.apache.juneau.Constants.*;
 import static org.apache.juneau.common.utils.CollectionUtils.*;
+import static org.apache.juneau.common.utils.StringUtils.*;
 import static org.apache.juneau.common.utils.Utils.*;
 
 import java.lang.annotation.*;
+import java.util.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
-import org.apache.juneau.common.collections.*;
 import org.apache.juneau.httppart.*;
 import org.apache.juneau.common.reflect.*;
 import org.apache.juneau.svl.*;
@@ -38,6 +39,9 @@ import org.apache.juneau.svl.*;
  * </ul>
  */
 public class PathAnnotation {
+
+       private static AnnotationProvider AP = AnnotationProvider.INSTANCE;
+
        /**
         * Applies targeted {@link Path} annotations to a {@link 
org.apache.juneau.BeanContext.Builder}.
         */
@@ -271,12 +275,14 @@ public class PathAnnotation {
         * Finds the default value from the specified list of annotations.
         *
         * @param pi The parameter.
-        * @return The last matching default value, or {@link Value#empty()} if 
not found.
+        * @return The last matching default value, or empty if not found.
         */
-       public static Value<String> findDef(ParameterInfo pi) {
-               Value<String> n = Value.empty();
-               
rstream(pi.getAllAnnotations(Path.class)).map(AnnotationInfo::inner).filter(x 
-> isNotEmpty(x.def()) && ne(NONE, x.def())).forEach(x -> n.set(x.def()));
-               return n;
+       public static Optional<String> findDef(ParameterInfo pi) {
+               return AP.find(Header.class, pi)
+                       .map(AnnotationInfo::inner)
+                       .filter(x -> isNotEmpty(x.def()) && ne(NONE, x.def()))
+                       .findFirst()
+                       .map(x -> x.def());
        }
 
        /**
@@ -286,12 +292,13 @@ public class PathAnnotation {
         * The last matching name found is returned.
         *
         * @param pi The parameter.
-        * @return The last matching name, or {@link Value#empty()} if not 
found.
+        * @return The last matching name, or empty if not found.
         */
-       public static Value<String> findName(ParameterInfo pi) {
-               Value<String> n = Value.empty();
-               
rstream(pi.getAllAnnotations(Path.class)).map(AnnotationInfo::inner).filter(x 
-> isNotEmpty(x.value())).forEach(x -> n.set(x.value()));
-               
rstream(pi.getAllAnnotations(Path.class)).map(AnnotationInfo::inner).filter(x 
-> isNotEmpty(x.name())).forEach(x -> n.set(x.name()));
-               return n;
+       public static Optional<String> findName(ParameterInfo pi) {
+               return AP.find(Path.class, pi)
+                       .map(AnnotationInfo::inner)
+                       .filter(x -> isAnyNotBlank(x.value(), x.name()))
+                       .findFirst()
+                       .map(x -> firstNonBlank(x.name(), x.value()));
        }
 }
\ No newline at end of file
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/PathRemainderAnnotation.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/PathRemainderAnnotation.java
index a7d49024b0..1f1de34044 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/PathRemainderAnnotation.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/PathRemainderAnnotation.java
@@ -22,10 +22,10 @@ import static 
org.apache.juneau.common.utils.CollectionUtils.*;
 import static org.apache.juneau.common.utils.Utils.*;
 
 import java.lang.annotation.*;
+import java.util.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
-import org.apache.juneau.common.collections.*;
 import org.apache.juneau.httppart.*;
 import org.apache.juneau.common.reflect.*;
 import org.apache.juneau.svl.*;
@@ -41,6 +41,9 @@ import org.apache.juneau.svl.*;
  * @since 9.2.0
  */
 public class PathRemainderAnnotation {
+
+       private static AnnotationProvider AP = AnnotationProvider.INSTANCE;
+
        /**
         * Applies targeted {@link PathRemainder} annotations to a {@link 
org.apache.juneau.BeanContext.Builder}.
         */
@@ -259,11 +262,13 @@ public class PathRemainderAnnotation {
         * Finds the default value from the specified list of annotations.
         *
         * @param pi The parameter.
-        * @return The last matching default value, or {@link Value#empty()} if 
not found.
+        * @return The last matching default value, or empty if not found.
         */
-       public static Value<String> findDef(ParameterInfo pi) {
-               Value<String> n = Value.empty();
-               
rstream(pi.getAllAnnotations(PathRemainder.class)).map(AnnotationInfo::inner).filter(x
 -> isNotEmpty(x.def())).forEach(x -> n.set(x.def()));
-               return n;
+       public static Optional<String> findDef(ParameterInfo pi) {
+               return AP.find(PathRemainder.class, pi)
+                       .map(AnnotationInfo::inner)
+                       .filter(x -> isNotEmpty(x.def()))
+                       .findFirst()
+                       .map(x -> x.def());
        }
 }
\ No newline at end of file
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/QueryAnnotation.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/QueryAnnotation.java
index 792f0d9c7e..58a31eda37 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/QueryAnnotation.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/QueryAnnotation.java
@@ -19,13 +19,14 @@ package org.apache.juneau.http.annotation;
 import static java.lang.annotation.ElementType.*;
 import static java.lang.annotation.RetentionPolicy.*;
 import static org.apache.juneau.common.utils.CollectionUtils.*;
+import static org.apache.juneau.common.utils.StringUtils.*;
 import static org.apache.juneau.common.utils.Utils.*;
 
 import java.lang.annotation.*;
+import java.util.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
-import org.apache.juneau.common.collections.*;
 import org.apache.juneau.httppart.*;
 import org.apache.juneau.common.reflect.*;
 import org.apache.juneau.svl.*;
@@ -37,6 +38,9 @@ import org.apache.juneau.svl.*;
  * </ul>
  */
 public class QueryAnnotation {
+
+       private static AnnotationProvider AP = AnnotationProvider.INSTANCE;
+
        /**
         * Applies targeted {@link Query} annotations to a {@link 
org.apache.juneau.BeanContext.Builder}.
         */
@@ -53,7 +57,7 @@ public class QueryAnnotation {
 
                @Override
                public void apply(AnnotationInfo<Query> ai, BeanContext.Builder 
b) {
-                       Query a = ai.inner();
+                       var a = ai.inner();
                        if (isEmptyArray(a.on()) && isEmptyArray(a.onClass()))
                                return;
                        b.annotations(a);
@@ -270,24 +274,27 @@ public class QueryAnnotation {
         * Finds the default value from the specified list of annotations.
         *
         * @param pi The parameter.
-        * @return The last matching default value, or {@link Value#empty()} if 
not found.
+        * @return The last matching default value, or empty if not found.
         */
-       public static Value<String> findDef(ParameterInfo pi) {
-               Value<String> n = Value.empty();
-               
rstream(pi.getAllAnnotations(Query.class)).map(AnnotationInfo::inner).filter(x 
-> isNotEmpty(x.def())).forEach(x -> n.set(x.def()));
-               return n;
+       public static Optional<String> findDef(ParameterInfo pi) {
+               return AP.find(Query.class, pi)
+                       .map(AnnotationInfo::inner)
+                       .filter(x -> isNotEmpty(x.def()))
+                       .findFirst()
+                       .map(x -> x.def());
        }
 
        /**
         * Finds the name from the specified list of annotations.
         *
         * @param pi The parameter.
-        * @return The last matching name, or {@link Value#empty()} if not 
found.
+        * @return The last matching name, or empty if not found.
         */
-       public static Value<String> findName(ParameterInfo pi) {
-               Value<String> n = Value.empty();
-               
rstream(pi.getAllAnnotations(Query.class)).map(AnnotationInfo::inner).filter(x 
-> isNotEmpty(x.value())).forEach(x -> n.set(x.value()));
-               
rstream(pi.getAllAnnotations(Query.class)).map(AnnotationInfo::inner).filter(x 
-> isNotEmpty(x.name())).forEach(x -> n.set(x.name()));
-               return n;
+       public static Optional<String> findName(ParameterInfo pi) {
+               return AP.find(Query.class, pi)
+                       .map(AnnotationInfo::inner)
+                       .filter(x -> isAnyNotBlank(x.value(), x.name()))
+                       .findFirst()
+                       .map(x -> firstNonBlank(x.name(), x.value()));
        }
 }
\ No newline at end of file
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/bean/RequestBeanMeta.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/bean/RequestBeanMeta.java
index 5d8e418d97..7d6aee1e72 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/bean/RequestBeanMeta.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/bean/RequestBeanMeta.java
@@ -39,6 +39,8 @@ import org.apache.juneau.common.reflect.*;
  */
 public class RequestBeanMeta {
 
+       private static AnnotationProvider AP = AnnotationProvider.INSTANCE;
+
        static class Builder {
                ClassMeta<?> cm;
                AnnotationWorkList annotations;
@@ -54,7 +56,7 @@ public class RequestBeanMeta {
                        this.cm = BeanContext.DEFAULT.getClassMeta(c);
                        apply(cm.getLastAnnotation(Request.class));
                        cm.getInfo().getPublicMethods().stream().forEach(x -> {
-                               String n = x.getSimpleName();
+                               var n = x.getSimpleName();
                                if (x.hasAnnotation(Header.class)) {
                                        assertNoArgs(x, Header.class);
                                        assertReturnNotVoid(x, Header.class);
@@ -81,7 +83,7 @@ public class RequestBeanMeta {
                }
 
                Builder apply(ParameterInfo mpi) {
-                       return 
apply(mpi.getParameterType().inner()).apply(opt(mpi.getAllAnnotation(Request.class)).map(x
 -> x.inner()).orElse(null));
+                       return 
apply(mpi.getParameterType().inner()).apply(AP.find(Request.class, 
mpi).findFirst().map(x -> x.inner()).orElse(null));
                }
 
                Builder apply(Request a) {
@@ -121,7 +123,7 @@ public class RequestBeanMeta {
         * @return Metadata about the parameter, or <jk>null</jk> if parameter 
or parameter type not annotated with {@link Request}.
         */
        public static RequestBeanMeta create(ParameterInfo mpi, 
AnnotationWorkList annotations) {
-               if (! mpi.hasAnnotation(Request.class))
+               if (! AP.has(Request.class, mpi))
                        return null;
                return new 
RequestBeanMeta.Builder(annotations).apply(mpi).build();
        }
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/bean/ResponseBeanMeta.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/bean/ResponseBeanMeta.java
index a67b9c18f1..8a4e54f6c8 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/bean/ResponseBeanMeta.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/bean/ResponseBeanMeta.java
@@ -42,6 +42,8 @@ import org.apache.juneau.common.reflect.*;
  */
 public class ResponseBeanMeta {
 
+       private static AnnotationProvider AP = AnnotationProvider.INSTANCE;
+
        static class Builder {
                ClassMeta<?> cm;
                int code;
@@ -78,9 +80,9 @@ public class ResponseBeanMeta {
                }
 
                Builder apply(Type t) {
-                       Class<?> c = toClass(t);
+                       var c = toClass(t);
                        this.cm = BeanContext.DEFAULT.getClassMeta(c);
-                       ClassInfo ci = cm.getInfo();
+                       var ci = cm.getInfo();
                        ci.getPublicMethods().stream().forEach(x -> {
                                assertNoInvalidAnnotations(x, Query.class, 
FormData.class);
                                if (x.hasAnnotation(Header.class)) {
@@ -138,12 +140,12 @@ public class ResponseBeanMeta {
         * @return Metadata about the class, or <jk>null</jk> if class not 
annotated with {@link Response}.
         */
        public static ResponseBeanMeta create(ParameterInfo mpi, 
AnnotationWorkList annotations) {
-               if (! mpi.hasAnnotation(Response.class))
+               if (! AP.has(Response.class, mpi))
                        return null;
                var b = new Builder(annotations);
                b.apply(mpi.getParameterType().unwrap(Value.class, 
Optional.class).innerType());
-               
rstream(mpi.getAllAnnotations(Response.class)).map(AnnotationInfo::inner).forEach(x
 -> b.apply(x));
-               
rstream(mpi.getAllAnnotations(StatusCode.class)).map(AnnotationInfo::inner).forEach(x
 -> b.apply(x));
+               AP.findTopDown(Response.class, 
mpi).map(AnnotationInfo::inner).forEach(x -> b.apply(x));
+               AP.findTopDown(StatusCode.class, 
mpi).map(AnnotationInfo::inner).forEach(x -> b.apply(x));
                return b.build();
        }
 
diff --git 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteOperationArg.java
 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteOperationArg.java
index b43dda6ce4..1571515acc 100644
--- 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteOperationArg.java
+++ 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteOperationArg.java
@@ -35,22 +35,24 @@ import org.apache.juneau.common.reflect.*;
  */
 public class RemoteOperationArg {
 
+       private static AnnotationProvider AP = AnnotationProvider.INSTANCE;
+
        static RemoteOperationArg create(ParameterInfo mpi) {
                int i = mpi.getIndex();
-               if (mpi.hasAnnotation(Header.class)) {
+               if (AP.has(Header.class, mpi)) {
                        return new RemoteOperationArg(i, HEADER, 
HttpPartSchema.create(Header.class, mpi));
-               } else if (mpi.hasAnnotation(Query.class)) {
+               } else if (AP.has(Query.class, mpi)) {
                        return new RemoteOperationArg(i, QUERY, 
HttpPartSchema.create(Query.class, mpi));
-               } else if (mpi.hasAnnotation(FormData.class)) {
+               } else if (AP.has(FormData.class, mpi)) {
                        return new RemoteOperationArg(i, FORMDATA, 
HttpPartSchema.create(FormData.class, mpi));
-               } else if (mpi.hasAnnotation(PathRemainder.class)) {
+               } else if (AP.has(PathRemainder.class, mpi)) {
                        // PathRemainder is equivalent to @Path("/*")
                        // Create with schema properties but override name to 
"/*"
                        var schema = HttpPartSchema.create(PathRemainder.class, 
mpi);
                        return new RemoteOperationArg(i, PATH, schema, "/*");
-               } else if (mpi.hasAnnotation(Path.class)) {
+               } else if (AP.has(Path.class, mpi)) {
                        return new RemoteOperationArg(i, PATH, 
HttpPartSchema.create(Path.class, mpi));
-               } else if (mpi.hasAnnotation(Content.class)) {
+               } else if (AP.has(Content.class, mpi)) {
                        return new RemoteOperationArg(i, BODY, 
HttpPartSchema.create(Content.class, mpi));
                }
                return null;
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
index cb8631a7e9..bdce59ca4d 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
@@ -1767,7 +1767,7 @@ public class RestContext extends Context {
                                        y -> beanStore.add(
                                                x.getFieldType().inner(),
                                                y,
-                                               
RestInjectAnnotation.name(x.getDeclaredAnnotations(RestInject.class).findFirst().map(AnnotationInfo::inner).orElse(null))
+                                               
RestInjectAnnotation.name(x.getAnnotations(RestInject.class).findFirst().map(AnnotationInfo::inner).orElse(null))
                                        )
                                ));
                        // @formatter:on
@@ -1804,7 +1804,7 @@ public class RestContext extends Context {
                                resource.get(),
                                beanStore.getBean(
                                        x.getFieldType().inner(),
-                                       
RestInjectAnnotation.name(x.getDeclaredAnnotations(RestInject.class).findFirst().map(AnnotationInfo::inner).orElse(null))
+                                       
RestInjectAnnotation.name(x.getAnnotations(RestInject.class).findFirst().map(AnnotationInfo::inner).orElse(null))
                                        ).orElse(null)
                                ));
                // @formatter:on
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/AttributeArg.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/AttributeArg.java
index adc1034ae3..108395d811 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/AttributeArg.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/AttributeArg.java
@@ -16,10 +16,8 @@
  */
 package org.apache.juneau.rest.arg;
 
-import static org.apache.juneau.common.utils.CollectionUtils.*;
-import static org.apache.juneau.common.utils.Utils.*;
+import static org.apache.juneau.common.utils.StringUtils.*;
 
-import org.apache.juneau.common.collections.*;
 import org.apache.juneau.common.reflect.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
@@ -44,6 +42,8 @@ import org.apache.juneau.rest.httppart.*;
  */
 public class AttributeArg implements RestOpArg {
 
+       private static AnnotationProvider AP = AnnotationProvider.INSTANCE;
+
        /**
         * Static creator.
         *
@@ -51,7 +51,7 @@ public class AttributeArg implements RestOpArg {
         * @return A new {@link AttributeArg}, or <jk>null</jk> if the 
parameter is not annotated with {@link Attr}.
         */
        public static AttributeArg create(ParameterInfo paramInfo) {
-               if (paramInfo.hasAnnotation(Attr.class) || 
paramInfo.getParameterType().hasAnnotation(Attr.class))
+               if (AP.has(Attr.class, paramInfo))
                        return new AttributeArg(paramInfo);
                return null;
        }
@@ -76,11 +76,11 @@ public class AttributeArg implements RestOpArg {
        }
 
        private static String getName(ParameterInfo paramInfo) {
-               Value<String> n = Value.empty();
-               
rstream(paramInfo.getAllAnnotations(Attr.class)).map(AnnotationInfo::inner).filter(x
 -> isNotEmpty(x.name())).forEach(x -> n.set(x.name()));
-               
rstream(paramInfo.getAllAnnotations(Attr.class)).map(AnnotationInfo::inner).filter(x
 -> isNotEmpty(x.value())).forEach(x -> n.set(x.value()));
-               if (n.isEmpty())
-                       throw new ArgException(paramInfo, "@Attr used without 
name or value");
-               return n.get();
+               return AP.find(Attr.class, paramInfo)
+                       .map(AnnotationInfo::inner)
+                       .filter(x -> isAnyNotBlank(x.value(), x.name()))
+                       .findFirst()
+                       .map(x -> firstNonBlank(x.name(), x.value()))
+                       .orElseThrow(() -> new ArgException(paramInfo, "@Attr 
used without name or value"));
        }
 }
\ No newline at end of file
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/ContentArg.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/ContentArg.java
index f04688caa5..6579ded7c8 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/ContentArg.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/ContentArg.java
@@ -47,6 +47,8 @@ import org.apache.juneau.rest.httppart.*;
  */
 public class ContentArg implements RestOpArg {
 
+       private static AnnotationProvider AP = AnnotationProvider.INSTANCE;
+
        /**
         * Static creator.
         *
@@ -54,7 +56,7 @@ public class ContentArg implements RestOpArg {
         * @return A new {@link ContentArg}, or <jk>null</jk> if the parameter 
is not annotated with {@link Content}.
         */
        public static ContentArg create(ParameterInfo paramInfo) {
-               if (paramInfo.hasAnnotation(Content.class) || 
paramInfo.getParameterType().hasAnnotation(Content.class))
+               if (AP.has(Content.class, paramInfo))
                        return new ContentArg(paramInfo);
                return null;
        }
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/FormDataArg.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/FormDataArg.java
index 25f44d0164..44762188fa 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/FormDataArg.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/FormDataArg.java
@@ -57,6 +57,9 @@ import org.apache.juneau.rest.httppart.*;
  * </ul>
  */
 public class FormDataArg implements RestOpArg {
+
+       private static AnnotationProvider AP = AnnotationProvider.INSTANCE;
+
        /**
         * Static creator.
         *
@@ -65,7 +68,7 @@ public class FormDataArg implements RestOpArg {
         * @return A new {@link FormDataArg}, or <jk>null</jk> if the parameter 
is not annotated with {@link FormData}.
         */
        public static FormDataArg create(ParameterInfo paramInfo, 
AnnotationWorkList annotations) {
-               if (paramInfo.hasAnnotation(FormData.class) || 
paramInfo.getParameterType().hasAnnotation(FormData.class))
+               if (AP.has(FormData.class, paramInfo))
                        return new FormDataArg(paramInfo, annotations);
                return null;
        }
@@ -79,32 +82,30 @@ public class FormDataArg implements RestOpArg {
         */
        private static FormData getMergedFormData(ParameterInfo pi, String 
paramName) {
                // Get the declaring class
-               ClassInfo declaringClass = pi.getMethod().getDeclaringClass();
+               var declaringClass = pi.getMethod().getDeclaringClass();
                if (declaringClass == null)
                        return null;
 
                // Find @Rest annotation on the class
-               Rest restAnnotation = 
declaringClass.getAnnotations(Rest.class).findFirst().map(AnnotationInfo::inner).orElse(null);
+               var restAnnotation = 
declaringClass.getAnnotations(Rest.class).findFirst().map(AnnotationInfo::inner).orElse(null);
                if (restAnnotation == null)
                        return null;
 
                // Find matching @FormData from class-level formDataParams array
                FormData classLevelFormData = null;
                for (var f : restAnnotation.formDataParams()) {
-                       String fName = firstNonEmpty(f.name(), f.value());
-                       if (paramName.equals(fName)) {
+                       var fName = firstNonEmpty(f.name(), f.value());
+                       if (eq(paramName, fName)) {
                                classLevelFormData = f;
                                break;
                        }
                }
 
-       if (classLevelFormData == null)
-               return null;
+               if (classLevelFormData == null)
+                       return null;
 
-       // Get parameter-level @FormData
-       FormData paramFormData = opt(pi.getAllAnnotation(FormData.class)).map(x 
-> x.inner()).orElse(null);
-       if (paramFormData == null)
-               paramFormData = 
pi.getParameterType().getAnnotations(FormData.class).findFirst().map(AnnotationInfo::inner).orElse(null);
+               // Get parameter-level @FormData
+               var paramFormData = AP.find(FormData.class, 
pi).findFirst().map(x -> x.inner()).orElse(null);
 
                if (paramFormData == null) {
                        // No parameter-level @FormData, use class-level as-is
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/HasFormDataArg.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/HasFormDataArg.java
index 8fa4daac1e..48584f9a9e 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/HasFormDataArg.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/HasFormDataArg.java
@@ -16,14 +16,10 @@
  */
 package org.apache.juneau.rest.arg;
 
-import static org.apache.juneau.common.utils.CollectionUtils.*;
 import static org.apache.juneau.common.utils.StringUtils.*;
-import static org.apache.juneau.common.utils.Utils.*;
 
 import java.lang.reflect.*;
 
-import org.apache.juneau.*;
-import org.apache.juneau.common.collections.*;
 import org.apache.juneau.http.annotation.*;
 import org.apache.juneau.common.reflect.*;
 import org.apache.juneau.rest.*;
@@ -51,6 +47,8 @@ import org.apache.juneau.rest.httppart.*;
  */
 public class HasFormDataArg implements RestOpArg {
 
+       private static AnnotationProvider AP = AnnotationProvider.INSTANCE;
+
        /**
         * Static creator.
         *
@@ -58,7 +56,7 @@ public class HasFormDataArg implements RestOpArg {
         * @return A new {@link HasFormDataArg}, or <jk>null</jk> if the 
parameter is not annotated with {@link HasFormData}.
         */
        public static HasFormDataArg create(ParameterInfo paramInfo) {
-               if (paramInfo.hasAnnotation(HasFormData.class))
+               if (AP.has(HasFormData.class, paramInfo))
                        return new HasFormDataArg(paramInfo);
                return null;
        }
@@ -68,11 +66,10 @@ public class HasFormDataArg implements RestOpArg {
        }
 
        private static boolean hasName(HasFormData x) {
-               return isNotEmpty(x.name()) || isNotEmpty(x.value());
+               return isAnyNotBlank(x.name(), x.value());
        }
 
        private final String name;
-
        private final Type type;
 
        /**
@@ -81,16 +78,19 @@ public class HasFormDataArg implements RestOpArg {
         * @param pi The Java method parameter being resolved.
         */
        protected HasFormDataArg(ParameterInfo pi) {
-               Value<String> _name = Value.empty();
-               
rstream(pi.getAllAnnotations(HasFormData.class)).map(AnnotationInfo::inner).filter(HasFormDataArg::hasName).forEach(x
 -> _name.set(getName(x)));
-               this.name = _name.orElseThrow(() -> new ArgException(pi, 
"@HasFormData used without name or value"));
+               this.name = AP.find(HasFormData.class, pi)
+                       .map(AnnotationInfo::inner)
+                       .filter(HasFormDataArg::hasName)
+                       .findFirst()
+                       .map(HasFormDataArg::getName)
+                       .orElseThrow(() -> new ArgException(pi, "@HasFormData 
used without name or value"));
                this.type = pi.getParameterType().innerType();
        }
 
        @Override /* Overridden from RestOpArg */
        public Object resolve(RestOpSession opSession) throws Exception {
-               RestRequest req = opSession.getRequest();
-               BeanSession bs = req.getBeanSession();
+               var req = opSession.getRequest();
+               var bs = req.getBeanSession();
                return bs.convertToType(req.getFormParams().contains(name), 
bs.getClassMeta(type));
        }
 }
\ No newline at end of file
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/HasQueryArg.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/HasQueryArg.java
index b639cc253c..2b650c4ba0 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/HasQueryArg.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/HasQueryArg.java
@@ -16,14 +16,10 @@
  */
 package org.apache.juneau.rest.arg;
 
-import static org.apache.juneau.common.utils.CollectionUtils.*;
 import static org.apache.juneau.common.utils.StringUtils.*;
-import static org.apache.juneau.common.utils.Utils.*;
 
 import java.lang.reflect.*;
 
-import org.apache.juneau.*;
-import org.apache.juneau.common.collections.*;
 import org.apache.juneau.http.annotation.*;
 import org.apache.juneau.common.reflect.*;
 import org.apache.juneau.rest.*;
@@ -51,6 +47,8 @@ import org.apache.juneau.rest.httppart.*;
  */
 public class HasQueryArg implements RestOpArg {
 
+       private static AnnotationProvider AP = AnnotationProvider.INSTANCE;
+
        /**
         * Static creator.
         *
@@ -58,7 +56,7 @@ public class HasQueryArg implements RestOpArg {
         * @return A new {@link HasQueryArg}, or <jk>null</jk> if the parameter 
is not annotated with {@link HasQuery}.
         */
        public static HasQueryArg create(ParameterInfo paramInfo) {
-               if (paramInfo.hasAnnotation(HasQuery.class))
+               if (AP.has(HasQuery.class, paramInfo))
                        return new HasQueryArg(paramInfo);
                return null;
        }
@@ -68,7 +66,7 @@ public class HasQueryArg implements RestOpArg {
        }
 
        private static boolean hasName(HasQuery x) {
-               return isNotEmpty(x.name()) || isNotEmpty(x.value());
+               return isAnyNotBlank(x.name(), x.value());
        }
 
        private final String name;
@@ -81,16 +79,19 @@ public class HasQueryArg implements RestOpArg {
         * @param pi The Java method parameter being resolved.
         */
        protected HasQueryArg(ParameterInfo pi) {
-               Value<String> _name = Value.empty();
-               
rstream(pi.getAllAnnotations(HasQuery.class)).map(AnnotationInfo::inner).filter(HasQueryArg::hasName).forEach(x
 -> _name.set(getName(x)));
-               this.name = _name.orElseThrow(() -> new ArgException(pi, 
"@HasQuery used without name or value"));
+               this.name = AP.find(HasQuery.class, pi)
+                       .map(AnnotationInfo::inner)
+                       .filter(HasQueryArg::hasName)
+                       .findFirst()
+                       .map(HasQueryArg::getName)
+                       .orElseThrow(() -> new ArgException(pi, "@HasQuery used 
without name or value"));
                this.type = pi.getParameterType().innerType();
        }
 
        @Override /* Overridden from RestOpArg */
        public Object resolve(RestOpSession opSession) throws Exception {
-               RestRequest req = opSession.getRequest();
-               BeanSession bs = req.getBeanSession();
+               var req = opSession.getRequest();
+               var bs = req.getBeanSession();
                return bs.convertToType(req.getQueryParams().contains(name), 
bs.getClassMeta(type));
        }
 }
\ No newline at end of file
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/HeaderArg.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/HeaderArg.java
index 7df32c7b47..53f5e01407 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/HeaderArg.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/HeaderArg.java
@@ -33,7 +33,6 @@ import org.apache.juneau.httppart.*;
 import org.apache.juneau.common.reflect.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.httppart.*;
 
 /**
  * Resolves method parameters and parameter types annotated with {@link 
Header} on {@link RestOp}-annotated Java methods.
@@ -99,6 +98,9 @@ import org.apache.juneau.rest.httppart.*;
  * </ul>
  */
 public class HeaderArg implements RestOpArg {
+
+       private static AnnotationProvider AP = AnnotationProvider.INSTANCE;
+
        /**
         * Static creator.
         *
@@ -107,7 +109,7 @@ public class HeaderArg implements RestOpArg {
         * @return A new {@link HeaderArg}, or <jk>null</jk> if the parameter 
is not annotated with {@link Header}.
         */
        public static HeaderArg create(ParameterInfo paramInfo, 
AnnotationWorkList annotations) {
-               if ((! paramInfo.getParameterType().is(Value.class)) && 
(paramInfo.hasAnnotation(Header.class) || 
paramInfo.getParameterType().hasAnnotation(Header.class)))
+               if ((! paramInfo.getParameterType().is(Value.class)) && 
AP.has(Header.class, paramInfo))
                        return new HeaderArg(paramInfo, annotations);
                return null;
        }
@@ -121,12 +123,12 @@ public class HeaderArg implements RestOpArg {
         */
        private static Header getMergedHeader(ParameterInfo pi, String 
paramName) {
                // Get the declaring class
-               ClassInfo declaringClass = pi.getMethod().getDeclaringClass();
+               var declaringClass = pi.getMethod().getDeclaringClass();
                if (declaringClass == null)
                        return null;
 
                // Find @Rest annotation on the class
-               Rest restAnnotation = 
declaringClass.getAnnotations(Rest.class).findFirst().map(AnnotationInfo::inner).orElse(null);
+               var restAnnotation = 
declaringClass.getAnnotations(Rest.class).findFirst().map(AnnotationInfo::inner).orElse(null);
                if (restAnnotation == null)
                        return null;
 
@@ -140,13 +142,11 @@ public class HeaderArg implements RestOpArg {
                        }
                }
 
-       if (classLevelHeader == null)
-               return null;
+               if (classLevelHeader == null)
+                       return null;
 
-       // Get parameter-level @Header
-       Header paramHeader = opt(pi.getAllAnnotation(Header.class)).map(x -> 
x.inner()).orElse(null);
-       if (paramHeader == null)
-               paramHeader = 
pi.getParameterType().getAnnotations(Header.class).findFirst().map(AnnotationInfo::inner).orElse(null);
+               // Get parameter-level @Header
+               var paramHeader = 
AnnotationProvider.INSTANCE.find(Header.class, pi).findFirst().map(x -> 
x.inner()).orElse(null);
 
                if (paramHeader == null) {
                        // No parameter-level @Header, use class-level as-is
@@ -213,13 +213,13 @@ public class HeaderArg implements RestOpArg {
                this.name = findName(pi).orElseThrow(() -> new ArgException(pi, 
"@Header used without name or value"));
 
                // Check for class-level defaults and merge if found
-               Header mergedHeader = getMergedHeader(pi, name);
+               var mergedHeader = getMergedHeader(pi, name);
 
                // Use merged header annotation for all lookups
                this.def = nn(mergedHeader) && ! mergedHeader.def().isEmpty() ? 
mergedHeader.def() : findDef(pi).orElse(null);
                this.type = pi.getParameterType();
                this.schema = nn(mergedHeader) ? 
HttpPartSchema.create(mergedHeader) : HttpPartSchema.create(Header.class, pi);
-               Class<? extends HttpPartParser> pp = schema.getParser();
+               var pp = schema.getParser();
                this.partParser = nn(pp) ? 
HttpPartParser.creator().type(pp).apply(annotations).create() : null;
                this.multi = schema.getCollectionFormat() == 
HttpPartCollectionFormat.MULTI;
 
@@ -230,14 +230,14 @@ public class HeaderArg implements RestOpArg {
        @SuppressWarnings({ "rawtypes", "unchecked" })
        @Override /* Overridden from RestOpArg */
        public Object resolve(RestOpSession opSession) throws Exception {
-               RestRequest req = opSession.getRequest();
-               HttpPartParserSession ps = partParser == null ? 
req.getPartParserSession() : partParser.getPartSession();
-               RequestHeaders rh = req.getHeaders();
-               BeanSession bs = req.getBeanSession();
-               ClassMeta<?> cm = bs.getClassMeta(type.innerType());
+               var req = opSession.getRequest();
+               var ps = partParser == null ? req.getPartParserSession() : 
partParser.getPartSession();
+               var rh = req.getHeaders();
+               var bs = req.getBeanSession();
+               var cm = bs.getClassMeta(type.innerType());
 
                if (multi) {
-                       Collection c = cm.isArray() ? list() : 
(Collection)(cm.canCreateNewInstance() ? cm.newInstance() : new JsonList());
+                       var c = cm.isArray() ? list() : 
(Collection)(cm.canCreateNewInstance() ? cm.newInstance() : new JsonList());
                        rh.stream(name).map(x -> 
x.parser(ps).schema(schema).as(cm.getElementType()).orElse(null)).forEach(x -> 
c.add(x));
                        return cm.isArray() ? toArray(c, 
cm.getElementType().getInnerClass()) : c;
                }
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/MethodArg.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/MethodArg.java
index 5d4ee3a2ae..9d11298405 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/MethodArg.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/MethodArg.java
@@ -40,6 +40,8 @@ import org.apache.juneau.rest.annotation.*;
  */
 public class MethodArg implements RestOpArg {
 
+       private static AnnotationProvider AP = AnnotationProvider.INSTANCE;
+
        /**
         * Static creator.
         *
@@ -47,7 +49,7 @@ public class MethodArg implements RestOpArg {
         * @return A new {@link MethodArg}, or <jk>null</jk> if the parameter 
isn't annotated with {@link Method}.
         */
        public static MethodArg create(ParameterInfo paramInfo) {
-               if (paramInfo.hasAnnotation(Method.class))
+               if (AP.has(Method.class, paramInfo))
                        return new MethodArg();
                return null;
        }
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/PathArg.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/PathArg.java
index fed7eab5f2..c002ee49a8 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/PathArg.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/PathArg.java
@@ -26,7 +26,6 @@ import java.lang.reflect.*;
 import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
 import org.apache.juneau.collections.*;
-import org.apache.juneau.common.utils.*;
 import org.apache.juneau.http.annotation.*;
 import org.apache.juneau.httppart.*;
 import org.apache.juneau.common.reflect.*;
@@ -56,6 +55,9 @@ import org.apache.juneau.rest.util.*;
  * </ul>
  */
 public class PathArg implements RestOpArg {
+
+       private static AnnotationProvider AP = AnnotationProvider.INSTANCE;
+
        /**
         * Static creator.
         *
@@ -65,7 +67,7 @@ public class PathArg implements RestOpArg {
         * @return A new {@link PathArg}, or <jk>null</jk> if the parameter is 
not annotated with {@link Path}.
         */
        public static PathArg create(ParameterInfo paramInfo, 
AnnotationWorkList annotations, UrlPathMatcher pathMatcher) {
-               if (paramInfo.hasAnnotation(Path.class) || 
paramInfo.getParameterType().hasAnnotation(Path.class))
+               if (AP.has(Path.class, paramInfo))
                        return new PathArg(paramInfo, annotations, pathMatcher);
                return null;
        }
@@ -79,12 +81,12 @@ public class PathArg implements RestOpArg {
         */
        private static Path getMergedPath(ParameterInfo pi, String paramName) {
                // Get the declaring class
-               ClassInfo declaringClass = pi.getMethod().getDeclaringClass();
+               var declaringClass = pi.getMethod().getDeclaringClass();
                if (declaringClass == null)
                        return null;
 
                // Find @Rest annotation on the class
-               Rest restAnnotation = 
declaringClass.getAnnotations(Rest.class).findFirst().map(AnnotationInfo::inner).orElse(null);
+               var restAnnotation = 
declaringClass.getAnnotations(Rest.class).findFirst().map(AnnotationInfo::inner).orElse(null);
                if (restAnnotation == null)
                        return null;
 
@@ -98,13 +100,11 @@ public class PathArg implements RestOpArg {
                        }
                }
 
-       if (classLevelPath == null)
-               return null;
+               if (classLevelPath == null)
+                       return null;
 
-       // Get parameter-level @Path
-       Path paramPath = opt(pi.getAllAnnotation(Path.class)).map(x -> 
x.inner()).orElse(null);
-       if (paramPath == null)
-               paramPath = 
pi.getParameterType().getAnnotations(Path.class).findFirst().map(AnnotationInfo::inner).orElse(null);
+               // Get parameter-level @Path
+               var paramPath = AP.find(Path.class, pi).findFirst().map(x -> 
x.inner()).orElse(null);
 
                if (paramPath == null) {
                        // No parameter-level @Path, use class-level as-is
@@ -151,11 +151,8 @@ public class PathArg implements RestOpArg {
        }
 
        private final HttpPartParser partParser;
-
        private final HttpPartSchema schema;
-
        private final String name, def;
-
        private final Type type;
 
        /**
@@ -170,50 +167,52 @@ public class PathArg implements RestOpArg {
                this.name = getName(paramInfo, pathMatcher);
 
                // Check for class-level defaults and merge if found
-               Path mergedPath = getMergedPath(paramInfo, name);
+               var mergedPath = getMergedPath(paramInfo, name);
 
                // Use merged path annotation for all lookups
-               String pathDef = nn(mergedPath) ? mergedPath.def() : null;
+               var pathDef = nn(mergedPath) ? mergedPath.def() : null;
                this.def = nn(pathDef) && ne(NONE, pathDef) ? pathDef : 
findDef(paramInfo).orElse(null);
                this.type = paramInfo.getParameterType().innerType();
                this.schema = nn(mergedPath) ? 
HttpPartSchema.create(mergedPath) : HttpPartSchema.create(Path.class, 
paramInfo);
-               Class<? extends HttpPartParser> pp = schema.getParser();
+               var pp = schema.getParser();
                this.partParser = nn(pp) ? 
HttpPartParser.creator().type(pp).apply(annotations).create() : null;
        }
 
        @Override /* Overridden from RestOpArg */
        public Object resolve(RestOpSession opSession) throws Exception {
-               RestRequest req = opSession.getRequest();
+               var req = opSession.getRequest();
                if (name.equals("*")) {
                        var m = new JsonMap();
                        req.getPathParams().stream().forEach(x -> 
m.put(x.getName(), x.getValue()));
                        return req.getBeanSession().convertToType(m, type);
                }
-               HttpPartParserSession ps = partParser == null ? 
req.getPartParserSession() : partParser.getPartSession();
+               var ps = partParser == null ? req.getPartParserSession() : 
partParser.getPartSession();
                return 
req.getPathParams().get(name).parser(ps).schema(schema).def(def).as(type).orElse(null);
        }
 
        private static String getName(ParameterInfo pi, UrlPathMatcher 
pathMatcher) {
-               String p = findName(pi).orElse(null);
+               var p = findName(pi).orElse(null);
                if (nn(p))
                        return p;
                if (nn(pathMatcher)) {
-               int idx = 0;
-               int i = pi.getIndex();
-               MethodInfo mi = pi.getMethod();
-
-               for (int j = 0; j < i; j++)
-                       if (nn(mi.getParameter(j).getAllAnnotation(Path.class)))
-                               idx++;
+                       int idx = 0;
+                       int i = pi.getIndex();
+                       var mi = pi.getMethod();
+
+                       for (int j = 0; j < i; j++) {
+                               var hasAnnotation = 
AnnotationProvider.INSTANCE.find(Path.class, 
mi.getParameter(j)).findAny().isPresent();
+                               if (hasAnnotation)
+                                       idx++;
+                       }
 
-                       String[] vars = pathMatcher.getVars();
+                       var vars = pathMatcher.getVars();
                        if (vars.length <= idx)
                                throw new ArgException(pi, "Number of attribute 
parameters exceeds the number of URL pattern variables.  vars.length={0}, 
idx={1}", vars.length, idx);
 
                        // Check for {#} variables.
                        var idxs = String.valueOf(idx);
                        for (var var : vars)
-                               if (StringUtils.isNumeric(var) && 
var.equals(idxs))
+                               if (isNumeric(var) && var.equals(idxs))
                                        return var;
 
                        return pathMatcher.getVars()[idx];
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/PathRemainderArg.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/PathRemainderArg.java
index d79d204049..ea51522e53 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/PathRemainderArg.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/PathRemainderArg.java
@@ -59,6 +59,9 @@ import org.apache.juneau.rest.util.*;
  * @since 9.2.0
  */
 public class PathRemainderArg implements RestOpArg {
+
+       private static AnnotationProvider AP = AnnotationProvider.INSTANCE;
+
        /**
         * Static creator.
         *
@@ -68,7 +71,7 @@ public class PathRemainderArg implements RestOpArg {
         * @return A new {@link PathRemainderArg}, or <jk>null</jk> if the 
parameter is not annotated with {@link PathRemainder}.
         */
        public static PathRemainderArg create(ParameterInfo paramInfo, 
AnnotationWorkList annotations, UrlPathMatcher pathMatcher) {
-               if (paramInfo.hasAnnotation(PathRemainder.class) || 
paramInfo.getParameterType().hasAnnotation(PathRemainder.class))
+               if (AP.has(PathRemainder.class, paramInfo))
                        return new PathRemainderArg(paramInfo, annotations);
                return null;
        }
@@ -89,14 +92,14 @@ public class PathRemainderArg implements RestOpArg {
                this.def = findDef(paramInfo).orElse(null);
                this.type = paramInfo.getParameterType().innerType();
                this.schema = HttpPartSchema.create(PathRemainder.class, 
paramInfo);
-               Class<? extends HttpPartParser> pp = schema.getParser();
+               var pp = schema.getParser();
                this.partParser = nn(pp) ? 
HttpPartParser.creator().type(pp).apply(annotations).create() : null;
        }
 
        @Override /* Overridden from RestOpArg */
        public Object resolve(RestOpSession opSession) throws Exception {
-               RestRequest req = opSession.getRequest();
-               HttpPartParserSession ps = partParser == null ? 
req.getPartParserSession() : partParser.getPartSession();
+               var req = opSession.getRequest();
+               var ps = partParser == null ? req.getPartParserSession() : 
partParser.getPartSession();
                // The path remainder is stored under the name "/*"
                return 
req.getPathParams().get("/*").parser(ps).schema(schema).def(def).as(type).orElse(null);
        }
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/QueryArg.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/QueryArg.java
index 2f76c8f1d8..d00a01fb08 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/QueryArg.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/QueryArg.java
@@ -57,6 +57,9 @@ import org.apache.juneau.rest.httppart.*;
  * </ul>
  */
 public class QueryArg implements RestOpArg {
+
+       private static AnnotationProvider AP = AnnotationProvider.INSTANCE;
+
        /**
         * Static creator.
         *
@@ -65,7 +68,7 @@ public class QueryArg implements RestOpArg {
         * @return A new {@link QueryArg}, or <jk>null</jk> if the parameter is 
not annotated with {@link Query}.
         */
        public static QueryArg create(ParameterInfo paramInfo, 
AnnotationWorkList annotations) {
-               if (paramInfo.hasAnnotation(Query.class) || 
paramInfo.getParameterType().hasAnnotation(Query.class))
+               if (AP.has(Query.class, paramInfo))
                        return new QueryArg(paramInfo, annotations);
                return null;
        }
@@ -79,12 +82,12 @@ public class QueryArg implements RestOpArg {
         */
        private static Query getMergedQuery(ParameterInfo pi, String paramName) 
{
                // Get the declaring class
-               ClassInfo declaringClass = pi.getMethod().getDeclaringClass();
+               var declaringClass = pi.getMethod().getDeclaringClass();
                if (declaringClass == null)
                        return null;
 
                // Find @Rest annotation on the class
-               Rest restAnnotation = 
declaringClass.getAnnotations(Rest.class).findFirst().map(AnnotationInfo::inner).orElse(null);
+               var restAnnotation = 
declaringClass.getAnnotations(Rest.class).findFirst().map(AnnotationInfo::inner).orElse(null);
                if (restAnnotation == null)
                        return null;
 
@@ -98,13 +101,11 @@ public class QueryArg implements RestOpArg {
                        }
                }
 
-       if (classLevelQuery == null)
-               return null;
+               if (classLevelQuery == null)
+                       return null;
 
-       // Get parameter-level @Query
-       Query paramQuery = opt(pi.getAllAnnotation(Query.class)).map(x -> 
x.inner()).orElse(null);
-       if (paramQuery == null)
-               paramQuery = 
pi.getParameterType().getAnnotations(Query.class).findFirst().map(AnnotationInfo::inner).orElse(null);
+               // Get parameter-level @Query
+               var paramQuery = AP.find(Query.class, pi).findFirst().map(x -> 
x.inner()).orElse(null);
 
                if (paramQuery == null) {
                        // No parameter-level @Query, use class-level as-is
@@ -151,13 +152,9 @@ public class QueryArg implements RestOpArg {
        }
 
        private final boolean multi;
-
        private final HttpPartParser partParser;
-
        private final HttpPartSchema schema;
-
        private final String name, def;
-
        private final ClassInfo type;
 
        /**
@@ -171,13 +168,13 @@ public class QueryArg implements RestOpArg {
                this.name = findName(pi).orElseThrow(() -> new ArgException(pi, 
"@Query used without name or value"));
 
                // Check for class-level defaults and merge if found
-               Query mergedQuery = getMergedQuery(pi, name);
+               var mergedQuery = getMergedQuery(pi, name);
 
                // Use merged query annotation for all lookups
                this.def = nn(mergedQuery) && ! mergedQuery.def().isEmpty() ? 
mergedQuery.def() : findDef(pi).orElse(null);
                this.type = pi.getParameterType();
                this.schema = nn(mergedQuery) ? 
HttpPartSchema.create(mergedQuery) : HttpPartSchema.create(Query.class, pi);
-               Class<? extends HttpPartParser> pp = schema.getParser();
+               var pp = schema.getParser();
                this.partParser = nn(pp) ? 
HttpPartParser.creator().type(pp).apply(annotations).create() : null;
                this.multi = schema.getCollectionFormat() == 
HttpPartCollectionFormat.MULTI;
 
@@ -188,14 +185,14 @@ public class QueryArg implements RestOpArg {
        @SuppressWarnings({ "rawtypes", "unchecked" })
        @Override /* Overridden from RestOpArg */
        public Object resolve(RestOpSession opSession) throws Exception {
-               RestRequest req = opSession.getRequest();
-               HttpPartParserSession ps = partParser == null ? 
req.getPartParserSession() : partParser.getPartSession();
-               RequestQueryParams rh = req.getQueryParams();
-               BeanSession bs = req.getBeanSession();
-               ClassMeta<?> cm = bs.getClassMeta(type.innerType());
+               var req = opSession.getRequest();
+               var ps = partParser == null ? req.getPartParserSession() : 
partParser.getPartSession();
+               var rh = req.getQueryParams();
+               var bs = req.getBeanSession();
+               var cm = bs.getClassMeta(type.innerType());
 
                if (multi) {
-                       Collection c = cm.isArray() ? list() : 
(Collection)(cm.canCreateNewInstance() ? cm.newInstance() : new JsonList());
+                       var c = cm.isArray() ? list() : 
(Collection)(cm.canCreateNewInstance() ? cm.newInstance() : new JsonList());
                        rh.getAll(name).stream().map(x -> 
x.parser(ps).schema(schema).as(cm.getElementType()).orElse(null)).forEach(x -> 
c.add(x));
                        return cm.isArray() ? toArray(c, 
cm.getElementType().getInnerClass()) : c;
                }
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/RequestBeanArg.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/RequestBeanArg.java
index b39ac1c4fe..b14966f58c 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/RequestBeanArg.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/RequestBeanArg.java
@@ -42,6 +42,9 @@ import org.apache.juneau.rest.annotation.*;
  * </ul>
  */
 public class RequestBeanArg implements RestOpArg {
+
+       private static AnnotationProvider AP = AnnotationProvider.INSTANCE;
+
        /**
         * Static creator.
         *
@@ -50,7 +53,7 @@ public class RequestBeanArg implements RestOpArg {
         * @return A new {@link RequestBeanArg}, or <jk>null</jk> if the 
parameter is not annotated with {@link Request}.
         */
        public static RequestBeanArg create(ParameterInfo paramInfo, 
AnnotationWorkList annotations) {
-               if (paramInfo.hasAnnotation(Request.class))
+               if (AP.has(Request.class, paramInfo))
                        return new RequestBeanArg(paramInfo, annotations);
                return null;
        }
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/ResponseBeanArg.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/ResponseBeanArg.java
index 855eed42d9..d50e8b51ee 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/ResponseBeanArg.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/ResponseBeanArg.java
@@ -42,6 +42,9 @@ import org.apache.juneau.rest.annotation.*;
  * </ul>
  */
 public class ResponseBeanArg implements RestOpArg {
+
+       private static AnnotationProvider AP = AnnotationProvider.INSTANCE;
+
        /**
         * Static creator.
         *
@@ -50,7 +53,7 @@ public class ResponseBeanArg implements RestOpArg {
         * @return A new {@link ResponseBeanArg}, or <jk>null</jk> if the 
parameter is not annotated with {@link Response}.
         */
        public static ResponseBeanArg create(ParameterInfo paramInfo, 
AnnotationWorkList annotations) {
-               if (paramInfo.hasAnnotation(Response.class) || 
paramInfo.getParameterType().hasAnnotation(Response.class))
+               if (AP.has(Response.class, paramInfo))
                        return new ResponseBeanArg(paramInfo, annotations);
                return null;
        }
@@ -68,7 +71,7 @@ public class ResponseBeanArg implements RestOpArg {
        protected ResponseBeanArg(ParameterInfo paramInfo, AnnotationWorkList 
annotations) {
                this.type = paramInfo.getParameterType().innerType();
                this.meta = ResponseBeanMeta.create(paramInfo, annotations);
-               Class<?> c = type instanceof Class ? (Class<?>)type : type 
instanceof ParameterizedType ? (Class<?>)((ParameterizedType)type).getRawType() 
: null;
+               var c = type instanceof Class ? (Class<?>)type : type 
instanceof ParameterizedType ? (Class<?>)((ParameterizedType)type).getRawType() 
: null;
                if (c != Value.class)
                        throw new ArgException(paramInfo, "Type must be 
Value<?> on parameter annotated with @Response annotation");
        }
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/ResponseCodeArg.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/ResponseCodeArg.java
index 4b75077be1..0f7c4b90f1 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/ResponseCodeArg.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/ResponseCodeArg.java
@@ -35,6 +35,8 @@ import org.apache.juneau.rest.annotation.*;
  */
 public class ResponseCodeArg implements RestOpArg {
 
+       private static AnnotationProvider AP = AnnotationProvider.INSTANCE;
+
        /**
         * Static creator.
         *
@@ -42,7 +44,7 @@ public class ResponseCodeArg implements RestOpArg {
         * @return A new {@link ResponseCodeArg}, or <jk>null</jk> if the 
parameter is not annotated with {@link StatusCode}.
         */
        public static ResponseCodeArg create(ParameterInfo paramInfo) {
-               if (paramInfo.hasAnnotation(StatusCode.class) || 
paramInfo.getParameterType().hasAnnotation(StatusCode.class))
+               if (AP.has(StatusCode.class, paramInfo))
                        return new ResponseCodeArg(paramInfo);
                return null;
        }
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/ResponseHeaderArg.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/ResponseHeaderArg.java
index 95a495b835..6003a9cf97 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/ResponseHeaderArg.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/ResponseHeaderArg.java
@@ -48,6 +48,9 @@ import org.apache.juneau.rest.httppart.*;
  * </ul>
  */
 public class ResponseHeaderArg implements RestOpArg {
+
+       private static AnnotationProvider AP = AnnotationProvider.INSTANCE;
+
        /**
         * Static creator.
         *
@@ -56,7 +59,7 @@ public class ResponseHeaderArg implements RestOpArg {
         * @return A new {@link ResponseHeaderArg}, or <jk>null</jk> if the 
parameter is not annotated with {@link Header}.
         */
        public static ResponseHeaderArg create(ParameterInfo paramInfo, 
AnnotationWorkList annotations) {
-               if (paramInfo.getParameterType().is(Value.class) && 
(paramInfo.hasAnnotation(Header.class) || 
paramInfo.getParameterType().hasAnnotation(Header.class)))
+               if (paramInfo.getParameterType().is(Value.class) && 
AP.has(Header.class, paramInfo))
                        return new ResponseHeaderArg(paramInfo, annotations);
                return null;
        }
@@ -77,10 +80,10 @@ public class ResponseHeaderArg implements RestOpArg {
                this.type = pi.getParameterType().innerType();
                var schema = HttpPartSchema.create(Header.class, pi);
 
-               Class<? extends HttpPartSerializer> ps = schema.getSerializer();
+               var ps = schema.getSerializer();
                this.meta = new ResponsePartMeta(HttpPartType.HEADER, schema, 
nn(ps) ? HttpPartSerializer.creator().type(ps).apply(annotations).create() : 
null);
 
-               Class<?> c = type instanceof Class ? (Class<?>)type : type 
instanceof ParameterizedType ? (Class<?>)((ParameterizedType)type).getRawType() 
: null;
+               var c = type instanceof Class ? (Class<?>)type : type 
instanceof ParameterizedType ? (Class<?>)((ParameterizedType)type).getRawType() 
: null;
                if (c != Value.class)
                        throw new ArgException(pi, "Type must be Value<?> on 
parameter annotated with @Header annotation");
        }
@@ -90,12 +93,12 @@ public class ResponseHeaderArg implements RestOpArg {
        public Object resolve(final RestOpSession opSession) throws Exception {
                Value<Object> v = new Value();
                v.listener(o -> {
-                       RestRequest req = opSession.getRequest();
-                       RestResponse res = opSession.getResponse();
-                       ResponsePartMeta rpm = 
req.getOpContext().getResponseHeaderMeta(o);
+                       var req = opSession.getRequest();
+                       var res = opSession.getResponse();
+                       var rpm = req.getOpContext().getResponseHeaderMeta(o);
                        if (rpm == null)
                                rpm = ResponseHeaderArg.this.meta;
-                       HttpPartSerializerSession pss = rpm.getSerializer() == 
null ? req.getPartSerializerSession() : rpm.getSerializer().getPartSession();
+                       var pss = rpm.getSerializer() == null ? 
req.getPartSerializerSession() : rpm.getSerializer().getPartSession();
                        res.setHeader(new SerializedHeader(name, o, pss, 
rpm.getSchema(), false));
                });
                return v;
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/swagger/BasicSwaggerProviderSession.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/swagger/BasicSwaggerProviderSession.java
index 542af9b730..c49862aa88 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/swagger/BasicSwaggerProviderSession.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/swagger/BasicSwaggerProviderSession.java
@@ -146,6 +146,8 @@ public class BasicSwaggerProviderSession {
 
                InputStream is = ff.getStream(rci.getNameSimple() + ".json", 
locale).orElse(null);
 
+               var ap = this.context.getBeanContext().getAnnotationProvider();
+
                Predicate<String> ne = Utils::isNotEmpty;
                Predicate<Collection<?>> nec = Utils::isNotEmpty;
                Predicate<Map<?,?>> nem = Utils::isNotEmpty;
@@ -159,7 +161,7 @@ public class BasicSwaggerProviderSession {
                List<Rest> restAnnotations = list();
                
context.getAnnotationProvider().forEachClassAnnotation(Rest.class, rci, x -> 
true, x -> restAnnotations.add(x));
                for (var rr : restAnnotations) {
-       
+
                        JsonMap sInfo = omSwagger.getMap("info", true);
 
                        sInfo
@@ -382,45 +384,45 @@ public class BasicSwaggerProviderSession {
                                ClassInfo pt = mpi.getParameterType();
                                Type type = pt.innerType();
 
-                               if (mpi.hasAnnotation(Content.class) || 
pt.hasAnnotation(Content.class)) {
+                               if (ap.has(Content.class, mpi)) {
                                        JsonMap param = paramMap.getMap(BODY + 
".body", true).append("in", BODY);
                                        JsonMap schema = 
getSchema(param.getMap("schema"), type, bs);
-                                       
rstream(mpi.getAllAnnotations(Schema.class)).map(AnnotationInfo::inner).forEach(x
 -> merge(schema, x));
-                                       
rstream(mpi.getAllAnnotations(Content.class)).map(AnnotationInfo::inner).forEach(x
 -> merge(schema, x.schema()));
+                                       ap.findTopDown(Schema.class, 
mpi).map(AnnotationInfo::inner).forEach(x -> merge(schema, x));
+                                       ap.findTopDown(Content.class, 
mpi).map(AnnotationInfo::inner).forEach(x -> merge(schema, x.schema()));
                                        pushupSchemaFields(BODY, param, schema);
                                        param.appendIf(nem, "schema", schema);
                                        param.putIfAbsent("required", true);
                                        addBodyExamples(sm, param, false, type, 
locale);
 
-                               } else if (mpi.hasAnnotation(Query.class) || 
pt.hasAnnotation(Query.class)) {
+                               } else if (ap.has(Query.class, mpi)) {
                                        String name = 
QueryAnnotation.findName(mpi).orElse(null);
                                        JsonMap param = paramMap.getMap(QUERY + 
"." + name, true).append("name", name).append("in", QUERY);
-                                       
rstream(mpi.getAllAnnotations(Schema.class)).map(AnnotationInfo::inner).forEach(x
 -> merge(param, x));
-                                       
rstream(mpi.getAllAnnotations(Query.class)).map(AnnotationInfo::inner).forEach(x
 -> merge(param, x.schema()));
+                                       ap.findTopDown(Schema.class, 
mpi).map(AnnotationInfo::inner).forEach(x -> merge(param, x));
+                                       ap.findTopDown(Query.class, 
mpi).map(AnnotationInfo::inner).forEach(x -> merge(param, x.schema()));
                                        pushupSchemaFields(QUERY, param, 
getSchema(param.getMap("schema"), type, bs));
                                        addParamExample(sm, param, QUERY, type);
 
-                               } else if (mpi.hasAnnotation(FormData.class) || 
pt.hasAnnotation(FormData.class)) {
+                               } else if (ap.has(FormData.class, mpi)) {
                                        String name = 
FormDataAnnotation.findName(mpi).orElse(null);
                                        JsonMap param = 
paramMap.getMap(FORM_DATA + "." + name, true).append("name", name).append("in", 
FORM_DATA);
-                                       
rstream(mpi.getAllAnnotations(Schema.class)).map(AnnotationInfo::inner).forEach(x
 -> merge(param, x));
-                                       
rstream(mpi.getAllAnnotations(FormData.class)).map(AnnotationInfo::inner).forEach(x
 -> merge(param, x.schema()));
+                                       ap.findTopDown(Schema.class, 
mpi).map(AnnotationInfo::inner).forEach(x -> merge(param, x));
+                                       ap.findTopDown(FormData.class, 
mpi).map(AnnotationInfo::inner).forEach(x -> merge(param, x.schema()));
                                        pushupSchemaFields(FORM_DATA, param, 
getSchema(param.getMap("schema"), type, bs));
                                        addParamExample(sm, param, FORM_DATA, 
type);
 
-                               } else if (mpi.hasAnnotation(Header.class) || 
pt.hasAnnotation(Header.class)) {
+                               } else if (ap.has(Header.class, mpi)) {
                                        String name = 
HeaderAnnotation.findName(mpi).orElse(null);
                                        JsonMap param = paramMap.getMap(HEADER 
+ "." + name, true).append("name", name).append("in", HEADER);
-                                       
rstream(mpi.getAllAnnotations(Schema.class)).map(AnnotationInfo::inner).forEach(x
 -> merge(param, x));
-                                       
rstream(mpi.getAllAnnotations(Header.class)).map(AnnotationInfo::inner).forEach(x
 -> merge(param, x.schema()));
+                                       ap.findTopDown(Schema.class, 
mpi).map(AnnotationInfo::inner).forEach(x -> merge(param, x));
+                                       ap.findTopDown(Header.class, 
mpi).map(AnnotationInfo::inner).forEach(x -> merge(param, x.schema()));
                                        pushupSchemaFields(HEADER, param, 
getSchema(param.getMap("schema"), type, bs));
                                        addParamExample(sm, param, HEADER, 
type);
 
-                               } else if (mpi.hasAnnotation(Path.class) || 
pt.hasAnnotation(Path.class)) {
+                               } else if (ap.has(Path.class, mpi)) {
                                        String name = 
PathAnnotation.findName(mpi).orElse(null);
                                        JsonMap param = paramMap.getMap(PATH + 
"." + name, true).append("name", name).append("in", PATH);
-                                       
rstream(mpi.getAllAnnotations(Schema.class)).map(AnnotationInfo::inner).forEach(x
 -> merge(param, x));
-                                       
rstream(mpi.getAllAnnotations(Path.class)).map(AnnotationInfo::inner).forEach(x 
-> merge(param, x.schema()));
+                                       ap.findTopDown(Schema.class, 
mpi).map(AnnotationInfo::inner).forEach(x -> merge(param, x));
+                                       ap.findTopDown(Path.class, 
mpi).map(AnnotationInfo::inner).forEach(x -> merge(param, x.schema()));
                                        pushupSchemaFields(PATH, param, 
getSchema(param.getMap("schema"), type, bs));
                                        addParamExample(sm, param, PATH, type);
                                        param.putIfAbsent("required", true);
@@ -519,13 +521,11 @@ public class BasicSwaggerProviderSession {
 
                                ClassInfo pt = mpi.getParameterType();
 
-                               if (pt.is(Value.class) && 
(mpi.hasAnnotation(Header.class) || pt.hasAnnotation(Header.class))) {
+                               if (pt.is(Value.class) && (ap.has(Header.class, 
mpi))) {
                                        List<Header> la = list();
-                                       
rstream(mpi.getAllAnnotations(Header.class)).map(AnnotationInfo::inner).forEach(x
 -> la.add(x));
-                                       rstream(pt.getAnnotations()).map(x -> 
x.cast(Header.class)).filter(Objects::nonNull).map(AnnotationInfo::inner).forEach(x
 -> la.add(x));
+                                       ap.findTopDown(Header.class, 
mpi).map(AnnotationInfo::inner).forEach(x -> la.add(x));
                                        List<StatusCode> la2 = list();
-                                       
rstream(mpi.getAllAnnotations(StatusCode.class)).map(AnnotationInfo::inner).forEach(x
 -> la2.add(x));
-                                       rstream(pt.getAnnotations()).map(x -> 
x.cast(StatusCode.class)).filter(Objects::nonNull).map(AnnotationInfo::inner).forEach(x
 -> la2.add(x));
+                                       ap.findTopDown(StatusCode.class, 
mpi).map(AnnotationInfo::inner).forEach(x -> la2.add(x));
                                        Set<Integer> codes = getCodes(la2, 200);
                                        String name = 
HeaderAnnotation.findName(mpi).orElse(null);
                                        Type type = 
Value.unwrap(mpi.getParameterType().innerType());
@@ -533,20 +533,18 @@ public class BasicSwaggerProviderSession {
                                                if (! isMulti(a)) {
                                                        for (var code : codes) {
                                                                JsonMap header 
= responses.getMap(String.valueOf(code), true).getMap("headers", 
true).getMap(name, true);
-                                                               
rstream(mpi.getAllAnnotations(Schema.class)).map(AnnotationInfo::inner).forEach(x
 -> merge(header, x));
+                                                               
ap.findTopDown(Schema.class, mpi).map(AnnotationInfo::inner).forEach(x -> 
merge(header, x));
                                                                merge(header, 
a.schema());
                                                                
pushupSchemaFields(RESPONSE_HEADER, header, getSchema(header, type, bs));
                                                        }
                                                }
                                        }
-       
-                               } else if (mpi.hasAnnotation(Response.class) || 
pt.hasAnnotation(Response.class)) {
+
+                               } else if (ap.has(Response.class, mpi)) {
                                        List<Response> la = list();
-                                       
rstream(mpi.getAllAnnotations(Response.class)).map(AnnotationInfo::inner).forEach(x
 -> la.add(x));
-                                       rstream(pt.getAnnotations()).map(x -> 
x.cast(Response.class)).filter(Objects::nonNull).map(AnnotationInfo::inner).forEach(x
 -> la.add(x));
+                                       ap.findTopDown(Response.class, 
mpi).map(AnnotationInfo::inner).forEach(x -> la.add(x));
                                        List<StatusCode> la2 = list();
-                                       
rstream(mpi.getAllAnnotations(StatusCode.class)).map(AnnotationInfo::inner).forEach(x
 -> la2.add(x));
-                                       rstream(pt.getAnnotations()).map(x -> 
x.cast(StatusCode.class)).filter(Objects::nonNull).map(AnnotationInfo::inner).forEach(x
 -> la2.add(x));
+                                       ap.findTopDown(StatusCode.class, 
mpi).map(AnnotationInfo::inner).forEach(x -> la2.add(x));
                                        Set<Integer> codes = getCodes(la2, 200);
                                        Type type = 
Value.unwrap(mpi.getParameterType().innerType());
                                        for (var a : la) {
@@ -554,7 +552,7 @@ public class BasicSwaggerProviderSession {
                                                        JsonMap om = 
responses.getMap(String.valueOf(code), true);
                                                        merge(om, a);
                                                        JsonMap schema = 
getSchema(om.getMap("schema"), type, bs);
-                                                       
rstream(mpi.getAllAnnotations(Schema.class)).map(AnnotationInfo::inner).forEach(x
 -> merge(schema, x));
+                                                       
ap.findTopDown(Schema.class, mpi).map(AnnotationInfo::inner).forEach(x -> 
merge(schema, x));
                                                        la.forEach(x -> 
merge(schema, x.schema()));
                                                        
pushupSchemaFields(RESPONSE, om, schema);
                                                        om.appendIf(nem, 
"schema", schema);
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/common/reflect/FieldInfo_AnnotationInfos_Test.java
 
b/juneau-utest/src/test/java/org/apache/juneau/common/reflect/FieldInfo_AnnotationInfos_Test.java
index 7dfec97350..3a47c4d5ec 100644
--- 
a/juneau-utest/src/test/java/org/apache/juneau/common/reflect/FieldInfo_AnnotationInfos_Test.java
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/common/reflect/FieldInfo_AnnotationInfos_Test.java
@@ -19,7 +19,7 @@ import java.lang.annotation.*;
 import org.junit.jupiter.api.*;
 
 /**
- * Tests for {@link FieldInfo#getDeclaredAnnotations()} methods.
+ * Tests for {@link FieldInfo#getAnnotations()} methods.
  */
 public class FieldInfo_AnnotationInfos_Test {
 
@@ -60,18 +60,18 @@ public class FieldInfo_AnnotationInfos_Test {
                var field3 = ci.getPublicField(x -> 
x.getName().equals("field3")).get();
 
                // field1 has 2 annotations
-               var annotations1 = field1.getDeclaredAnnotations();
+               var annotations1 = field1.getAnnotations();
                assertEquals(2, annotations1.size());
                assertTrue(annotations1.stream().anyMatch(a -> 
a.hasSimpleName("TestAnnotation1")));
                assertTrue(annotations1.stream().anyMatch(a -> 
a.hasSimpleName("TestAnnotation2")));
 
                // field2 has 1 annotation
-               var annotations2 = field2.getDeclaredAnnotations();
+               var annotations2 = field2.getAnnotations();
                assertEquals(1, annotations2.size());
                assertTrue(annotations2.stream().anyMatch(a -> 
a.hasSimpleName("TestAnnotation1")));
 
                // field3 has no annotations
-               var annotations3 = field3.getDeclaredAnnotations();
+               var annotations3 = field3.getAnnotations();
                assertEquals(0, annotations3.size());
        }
 
@@ -82,24 +82,24 @@ public class FieldInfo_AnnotationInfos_Test {
                var field2 = ci.getPublicField(x -> 
x.getName().equals("field2")).get();
 
                // Test filtering by type for field1
-               var ann1_type1 = 
field1.getDeclaredAnnotations(TestAnnotation1.class).toList();
+               var ann1_type1 = 
field1.getAnnotations(TestAnnotation1.class).toList();
                assertEquals(1, ann1_type1.size());
                assertEquals("test1", ann1_type1.get(0).getValue().get());
 
-               var ann1_type2 = 
field1.getDeclaredAnnotations(TestAnnotation2.class).toList();
+               var ann1_type2 = 
field1.getAnnotations(TestAnnotation2.class).toList();
                assertEquals(1, ann1_type2.size());
                assertEquals(42, ann1_type2.get(0).getInt("value").get());
 
                // Test filtering by type that doesn't exist
-               var ann1_type3 = 
field1.getDeclaredAnnotations(TestAnnotation3.class).toList();
+               var ann1_type3 = 
field1.getAnnotations(TestAnnotation3.class).toList();
                assertEquals(0, ann1_type3.size());
 
                // Test filtering for field2
-               var ann2_type1 = 
field2.getDeclaredAnnotations(TestAnnotation1.class).toList();
+               var ann2_type1 = 
field2.getAnnotations(TestAnnotation1.class).toList();
                assertEquals(1, ann2_type1.size());
                assertEquals("test2", ann2_type1.get(0).getValue().get());
 
-               var ann2_type2 = 
field2.getDeclaredAnnotations(TestAnnotation2.class).toList();
+               var ann2_type2 = 
field2.getAnnotations(TestAnnotation2.class).toList();
                assertEquals(0, ann2_type2.size());
        }
 
@@ -109,8 +109,8 @@ public class FieldInfo_AnnotationInfos_Test {
                var field1 = ci.getPublicField(x -> 
x.getName().equals("field1")).get();
 
                // Calling getDeclaredAnnotationInfos() multiple times should 
return the same list instance
-               var annotations1 = field1.getDeclaredAnnotations();
-               var annotations2 = field1.getDeclaredAnnotations();
+               var annotations1 = field1.getAnnotations();
+               var annotations2 = field1.getAnnotations();
                assertSame(annotations1, annotations2);
        }
 }
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/common/reflect/ParamInfoTest.java
 
b/juneau-utest/src/test/java/org/apache/juneau/common/reflect/ParamInfoTest.java
index c90fbbebf5..3d505e776c 100644
--- 
a/juneau-utest/src/test/java/org/apache/juneau/common/reflect/ParamInfoTest.java
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/common/reflect/ParamInfoTest.java
@@ -43,7 +43,7 @@ class ParamInfoTest extends TestBase {
        public static void beforeAll() {
                // Save original system property value
                originalDisableParamNameDetection = 
System.getProperty("juneau.disableParamNameDetection");
-               
+
                // Set to true to ensure consistent behavior regardless of JVM 
compiler settings
                System.setProperty("juneau.disableParamNameDetection", "true");
                ParameterInfo.reset();
@@ -212,96 +212,25 @@ class ParamInfoTest extends TestBase {
                return pi.getAnnotations(type).map(x -> x.inner()).toList();
        }
 
-       @Test void getDeclaredAnnotation() {
-               check("@CA(5)", cb_a1.getDeclaredAnnotation(CA.class));
-               check("@CA(5)", cb_a2.getDeclaredAnnotation(CA.class));
-               check(null, cc_a1.getDeclaredAnnotation(CA.class));
-               check("@CA(6)", cc_a2.getDeclaredAnnotation(CA.class));
-       }
-
-       @Test void getDeclaredAnnotation_constructor() {
-               check("@CA(9)", cc_cc.getDeclaredAnnotation(CA.class));
-       }
-
-       @Test void getDeclaredAnnotation_notFound() {
-               check(null, cb_a1.getDeclaredAnnotation(DA.class));
-       }
-
-       @Test void getDeclaredAnnotation_notFound_constructor() {
-               check(null, cc_cc.getDeclaredAnnotation(DA.class));
-       }
-
-       @Test void getDeclaredAnnotation_null() {
-               check(null, cb_a1.getDeclaredAnnotation(null));
-       }
-
-       @Test void getDeclaredAnnotation_null_constructor() {
-               check(null, cc_cc.getDeclaredAnnotation(null));
-       }
-
-       @Test void getAnnotationsParentFirst() {
-               check("@CA(4),@CA(3),@CA(2),@CA(1),@CA(5)", annotations(cb_a1, 
CA.class));
-               check("@CA(4),@CA(3),@CA(2),@CA(1),@CA(5)", annotations(cb_a2, 
CA.class));
-               check("@CA(4),@CA(3),@CA(2),@CA(1),@CA(5)", annotations(cc_a1, 
CA.class));
-               check("@CA(4),@CA(3),@CA(2),@CA(1),@CA(5),@CA(6)", 
annotations(cc_a2, CA.class));
-       }
-
-       @Test void getAnnotationsParentFirst_notFound() {
-               check("", annotations(cb_a1, DA.class));
-       }
-
-       @Test void getAnnotationsParentFirst_constructor() {
-               check("@CA(4),@CA(3),@CA(2),@CA(1),@CA(9)", annotations(cc_cc, 
CA.class));
-       }
-
-       @Test void getAnnotationsParentFirst_notFound_constructor() {
-               check("", annotations(cc_cc, DA.class));
-       }
-
-       @Test void getAllAnnotationInfo() {
-               check("@CA(5)", cb_a1.getAllAnnotation(CA.class).inner());
-               check("@CA(5)", cb_a2.getAllAnnotation(CA.class).inner());
-               check("@CA(5)", cc_a1.getAllAnnotation(CA.class).inner());
-               check("@CA(6)", cc_a2.getAllAnnotation(CA.class).inner());
-       }
-
-       @Test void getAllAnnotationInfo_notFound() {
-               var ai = cb_a1.getAllAnnotation(DA.class);
-               check(null, ai == null ? null : ai.inner());
-       }
-
-       @Test void getAllAnnotationInfo_constructor() {
-               check("@CA(9)", cc_cc.getAllAnnotation(CA.class).inner());
-       }
-
-       @Test void getAllAnnotationInfo_notFound_constructor() {
-               var ai = cc_cc.getAllAnnotation(DA.class);
-               check(null, ai == null ? null : ai.inner());
-       }
-
-       @Test void getAllAnnotationInfo_twice() {
-               check("@CA(5)", cb_a1.getAllAnnotation(CA.class).inner());
-               check("@CA(5)", cb_a1.getAllAnnotation(CA.class).inner());
-       }
-
-       @Test void getAllAnnotationInfo_twice_constructor() {
-               check("@CA(9)", cc_cc.getAllAnnotation(CA.class).inner());
-               check("@CA(9)", cc_cc.getAllAnnotation(CA.class).inner());
-       }
-
-       @Test void hasAnnotation() {
-               assertTrue(cb_a1.hasAnnotation(CA.class));
-               assertTrue(cb_a2.hasAnnotation(CA.class));
-               assertTrue(cc_a1.hasAnnotation(CA.class));
-               assertTrue(cc_a2.hasAnnotation(CA.class));
-               assertFalse(cb_a1.hasAnnotation(DA.class));
-       }
-
-       @Test void hasAnnotation_constructor() {
-               assertTrue(cc_cc.hasAnnotation(CA.class));
-               assertFalse(cc_cc.hasAnnotation(DA.class));
-       }
-
+//     @Test void getAnnotationsParentFirst() {
+//             check("@CA(4),@CA(3),@CA(2),@CA(1),@CA(5)", annotations(cb_a1, 
CA.class));
+//             check("@CA(4),@CA(3),@CA(2),@CA(1),@CA(5)", annotations(cb_a2, 
CA.class));
+//             check("@CA(4),@CA(3),@CA(2),@CA(1),@CA(5)", annotations(cc_a1, 
CA.class));
+//             check("@CA(4),@CA(3),@CA(2),@CA(1),@CA(5),@CA(6)", 
annotations(cc_a2, CA.class));
+//     }
+//
+//     @Test void getAnnotationsParentFirst_notFound() {
+//             check("", annotations(cb_a1, DA.class));
+//     }
+//
+//     @Test void getAnnotationsParentFirst_constructor() {
+//             check("@CA(4),@CA(3),@CA(2),@CA(1),@CA(9)", annotations(cc_cc, 
CA.class));
+//     }
+//
+//     @Test void getAnnotationsParentFirst_notFound_constructor() {
+//             check("", annotations(cc_cc, DA.class));
+//     }
+//
        @Target({PARAMETER,TYPE})
        @Retention(RUNTIME)
        @Inherited
@@ -328,24 +257,14 @@ class ParamInfoTest extends TestBase {
                db_a1 = db.getMethod(x -> 
x.hasName("a1")).get().getParameter(0),  // NOSONAR
                dc_a1 = dc.getMethod(x -> 
x.hasName("a1")).get().getParameter(0);  // NOSONAR
 
-       @Test void getAnnotationsParentFirst_inherited() {
-               check("@DA(4),@DA(3),@DA(2),@DA(1),@DA(0)", annotations(db_a1, 
DA.class));
-               check("@DA(4),@DA(3),@DA(2),@DA(1),@DA(0),@DA(5)", 
annotations(dc_a1, DA.class));
-       }
-
-       @Test void getAnnotationsParentFirst_inherited_notFound() {
-               check("", annotations(db_a1, CA.class));
-       }
-
-       @Test void getAllAnnotationInfo_inherited() {
-               check("@DA(0)", db_a1.getAllAnnotation(DA.class).inner());
-               check("@DA(5)", dc_a1.getAllAnnotation(DA.class).inner());
-       }
-
-       @Test void getAllAnnotationInfo_inherited_notFound() {
-               var ai = db_a1.getAllAnnotation(CA.class);
-               check(null, ai == null ? null : ai.inner());
-       }
+//     @Test void getAnnotationsParentFirst_inherited() {
+//             check("@DA(4),@DA(3),@DA(2),@DA(1),@DA(0)", annotations(db_a1, 
DA.class));
+//             check("@DA(4),@DA(3),@DA(2),@DA(1),@DA(0),@DA(5)", 
annotations(dc_a1, DA.class));
+//     }
+//
+//     @Test void getAnnotationsParentFirst_inherited_notFound() {
+//             check("", annotations(db_a1, CA.class));
+//     }
 
        
//-----------------------------------------------------------------------------------------------------------------
        // Other methods.
@@ -649,176 +568,4 @@ class ParamInfoTest extends TestBase {
                        assertEquals("param1", matching.get(1).getName());
                }
        }
-
-       
//-----------------------------------------------------------------------------------------------------------------
-       // getAllAnnotations() / getAllAnnotation()
-       
//-----------------------------------------------------------------------------------------------------------------
-
-       @Nested
-       class FindAnnotationsTests {
-
-               // Annotations for testing
-               @Documented
-               @Target({PARAMETER, TYPE})
-               @Retention(RUNTIME)
-               public @interface FA1 {
-                       int value();
-               }
-
-               @Documented
-               @Target({PARAMETER, TYPE})
-               @Retention(RUNTIME)
-               public @interface FA2 {
-                       String value();
-               }
-
-               // Test finding annotation on parameter itself
-               public static class F1 {
-                       public void test(@FA1(1) String x) {}  // NOSONAR
-               }
-
-               @Test void findOnParameter() throws Exception {
-                       var mi = MethodInfo.of(F1.class.getMethod("test", 
String.class));
-                       var pi = mi.getParameter(0);
-                       var infos = pi.getAllAnnotations(FA1.class);
-                       assertEquals(1, infos.size());
-                       assertEquals(1, infos.get(0).inner().value());
-               }
-
-               @Test void findOnParameter_single() throws Exception {
-                       var mi = MethodInfo.of(F1.class.getMethod("test", 
String.class));
-                       var pi = mi.getParameter(0);
-                       var info = pi.getAllAnnotation(FA1.class);
-                       assertNotNull(info);
-                       assertEquals(1, info.inner().value());
-               }
-
-               // Test finding annotation from matching method parameters
-               public interface F2 {
-                       void test(@FA1(2) String x);
-               }
-
-               public static class F3 implements F2 {
-                       @Override public void test(String x) {}  // NOSONAR
-               }
-
-               @Test void findFromMatchingMethod() throws Exception {
-                       var mi = MethodInfo.of(F3.class.getMethod("test", 
String.class));
-                       var pi = mi.getParameter(0);
-                       var infos = pi.getAllAnnotations(FA1.class);
-                       assertEquals(1, infos.size());
-                       assertEquals(2, infos.get(0).inner().value());
-               }
-
-               // Test finding annotation from parameter type
-               @FA1(3)
-               public static class F4Type {}
-
-               public static class F5 {
-                       public void test(F4Type x) {}  // NOSONAR
-               }
-
-               @Test void findFromParameterType() throws Exception {
-                       var mi = MethodInfo.of(F5.class.getMethod("test", 
F4Type.class));
-                       var pi = mi.getParameter(0);
-                       var infos = pi.getAllAnnotations(FA1.class);
-                       assertEquals(1, infos.size());
-                       assertEquals(3, infos.get(0).inner().value());
-               }
-
-               // Test finding multiple annotations from hierarchy
-               public interface F6 {
-                       void test(@FA1(4) String x);
-               }
-
-               public static class F7 {
-                       public void test(@FA1(5) String x) {}  // NOSONAR
-               }
-
-               public static class F8 extends F7 implements F6 {
-                       @Override public void test(@FA1(6) String x) {}  // 
NOSONAR
-               }
-
-               @Test void findMultipleFromHierarchy() throws Exception {
-                       var mi = MethodInfo.of(F8.class.getMethod("test", 
String.class));
-                       var pi = mi.getParameter(0);
-                       var infos = pi.getAllAnnotations(FA1.class);
-                       assertEquals(3, infos.size());
-                       assertEquals(6, infos.get(0).inner().value()); // F8
-                       assertEquals(4, infos.get(1).inner().value()); // F6
-                       assertEquals(5, infos.get(2).inner().value()); // F7
-               }
-
-               @Test void findMultipleFromHierarchy_single() throws Exception {
-                       var mi = MethodInfo.of(F8.class.getMethod("test", 
String.class));
-                       var pi = mi.getParameter(0);
-                       var info = pi.getAllAnnotation(FA1.class);
-                       assertNotNull(info);
-                       assertEquals(6, info.inner().value()); // Returns first 
(F8)
-               }
-
-               // Test finding annotation from constructor parameters
-               public static class F9 {
-                       public F9(@FA1(7) String x) {}  // NOSONAR
-               }
-
-               public static class F10 extends F9 {
-                       public F10(@FA1(8) String x) { super(x); }  // NOSONAR
-               }
-
-               @Test void findFromMatchingConstructor() throws Exception {
-                       var ci = 
ConstructorInfo.of(F10.class.getConstructor(String.class));
-                       var pi = ci.getParameter(0);
-                       var infos = pi.getAllAnnotations(FA1.class);
-                       assertEquals(2, infos.size());
-                       assertEquals(8, infos.get(0).inner().value()); // F10
-                       assertEquals(7, infos.get(1).inner().value()); // F9
-               }
-
-               // Test not found
-               public static class F11 {
-                       public void test(String x) {}  // NOSONAR
-               }
-
-               @Test void notFound() throws Exception {
-                       var mi = MethodInfo.of(F11.class.getMethod("test", 
String.class));
-                       var pi = mi.getParameter(0);
-                       var infos = pi.getAllAnnotations(FA1.class);
-                       assertEquals(0, infos.size());
-               }
-
-               @Test void notFound_single() throws Exception {
-                       var mi = MethodInfo.of(F11.class.getMethod("test", 
String.class));
-                       var pi = mi.getParameter(0);
-                       var info = pi.getAllAnnotation(FA1.class);
-                       assertNull(info);
-               }
-
-               // Test parameter annotation takes precedence over type 
annotation
-               @FA1(9)
-               public static class F12Type {}
-
-               public static class F13 {
-                       public void test(@FA1(10) F12Type x) {}  // NOSONAR
-               }
-
-               @Test void parameterAnnotationBeforeTypeAnnotation() throws 
Exception {
-                       var mi = MethodInfo.of(F13.class.getMethod("test", 
F12Type.class));
-                       var pi = mi.getParameter(0);
-                       var infos = pi.getAllAnnotations(FA1.class);
-                       assertEquals(2, infos.size());
-                       assertEquals(10, infos.get(0).inner().value()); // 
Parameter annotation first
-                       assertEquals(9, infos.get(1).inner().value());  // Type 
annotation second
-               }
-       }
-
-       
//-----------------------------------------------------------------------------------------------------------------
-       // Helpers
-       
//-----------------------------------------------------------------------------------------------------------------
-
-       private static <T extends Annotation> List<T> annotations(ParameterInfo 
pi, Class<T> a) {
-               List<T> l = list();
-               
rstream(pi.getAllAnnotations(a)).map(AnnotationInfo::inner).forEach(l::add);
-               return l;
-       }
 }
\ No newline at end of file
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/reflect/ParamInfoTest.java 
b/juneau-utest/src/test/java/org/apache/juneau/reflect/ParamInfoTest.java
deleted file mode 100644
index eb3cd7420c..0000000000
--- a/juneau-utest/src/test/java/org/apache/juneau/reflect/ParamInfoTest.java
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.juneau.reflect;
-
-import static java.lang.annotation.ElementType.*;
-import static java.lang.annotation.RetentionPolicy.*;
-import static org.apache.juneau.common.utils.CollectionUtils.*;
-import static org.apache.juneau.common.utils.Utils.*;
-import static org.junit.jupiter.api.Assertions.*;
-
-import java.lang.annotation.*;
-import java.util.*;
-import java.util.function.*;
-import java.util.stream.*;
-
-import org.apache.juneau.*;
-import org.apache.juneau.annotation.*;
-import org.apache.juneau.common.reflect.*;
-import org.junit.jupiter.api.*;
-
-/**
- * ParamInfo tests.
- */
-class ParamInfoTest extends TestBase {
-
-       @Documented
-       @Target(METHOD)
-       @Retention(RUNTIME)
-       @Inherited
-       public static @interface A {
-               String value();
-       }
-
-       @Documented
-       @Target(METHOD)
-       @Retention(RUNTIME)
-       @Inherited
-       public static @interface AX {
-               String value();
-       }
-
-       private static void check(String expected, Object o) {
-               assertEquals(expected, TO_STRING.apply(o));
-       }
-
-       private static final Function<Object,String> TO_STRING = new 
Function<>() {
-               @Override
-               public String apply(Object t) {
-                       if (t == null)
-                               return null;
-                       if (t instanceof List)
-                               return 
((List<?>)t).stream().map(this).collect(Collectors.joining(","));
-                       if (isArray(t))
-                               return StreamSupport.stream(toList(t, 
Object.class).spliterator(), false).map(this).collect(Collectors.joining(","));
-                       if (t instanceof MethodInfo)
-                               return 
((MethodInfo)t).getDeclaringClass().getNameSimple() + '.' + 
((MethodInfo)t).getShortName();
-                       if (t instanceof CA)
-                               return "@CA(" + ((CA)t).value() + ")";
-                       if (t instanceof DA)
-                               return "@DA(" + ((DA)t).value() + ")";
-                       if (t instanceof ClassInfo)
-                               return ((ClassInfo)t).getNameSimple();
-                       return t.toString();
-               }
-       };
-
-       
//-----------------------------------------------------------------------------------------------------------------
-       // Instantiation.
-       
//-----------------------------------------------------------------------------------------------------------------
-
-       static class B {
-               public B(int a, String b) {}
-               public void a1(int a, String b) {}  // NOSONAR
-               void a2(int a, String b) {}  // NOSONAR
-       }
-
-       static ClassInfo b = ClassInfo.of(B.class);
-       static ParameterInfo
-               b_b_a = b.getPublicConstructor(x -> 
x.hasParameterTypes(int.class, String.class)).get().getParameter(0),  // NOSONAR
-               b_b_b = b.getPublicConstructor(x -> 
x.hasParameterTypes(int.class, String.class)).get().getParameter(1),  // NOSONAR
-               b_a1_a = b.getMethod(x -> 
x.hasName("a1")).get().getParameter(0),  // NOSONAR
-               b_a1_b = b.getMethod(x -> 
x.hasName("a1")).get().getParameter(1),  // NOSONAR
-               b_a2_a = b.getMethod(x -> 
x.hasName("a2")).get().getParameter(0),  // NOSONAR
-               b_a2_b = b.getMethod(x -> 
x.hasName("a2")).get().getParameter(1);  // NOSONAR
-
-       @Test void getIndex() {
-               assertEquals(0, b_b_a.getIndex());
-               assertEquals(1, b_b_b.getIndex());
-               assertEquals(0, b_a1_a.getIndex());
-               assertEquals(1, b_a1_b.getIndex());
-               assertEquals(0, b_a2_a.getIndex());
-               assertEquals(1, b_a2_b.getIndex());
-       }
-
-       @Test void getMethod() {
-               check("B.a1(int,String)", b_a1_a.getMethod());
-               check("B.a1(int,String)", b_a1_b.getMethod());
-               check("B.a2(int,String)", b_a2_a.getMethod());
-               check("B.a2(int,String)", b_a2_b.getMethod());
-       }
-
-       @Test void getMethod_onConstrutor() {
-               check(null, b_b_a.getMethod());
-               check(null, b_b_b.getMethod());
-       }
-
-       @Test void getConstructor() {
-               check("B(int,String)", b_b_a.getConstructor());
-               check("B(int,String)", b_b_b.getConstructor());
-       }
-
-       @Test void getConstructor_onMethod() {
-               check(null, b_a1_a.getConstructor());
-               check(null, b_a1_b.getConstructor());
-               check(null, b_a2_a.getConstructor());
-               check(null, b_a2_b.getConstructor());
-       }
-
-       @Test void getParameterType() {
-               check("int", b_b_a.getParameterType());
-               check("String", b_b_b.getParameterType());
-               check("int", b_a1_a.getParameterType());
-               check("String", b_a1_b.getParameterType());
-               check("int", b_a2_a.getParameterType());
-               check("String", b_a2_b.getParameterType());
-
-       }
-
-       
//-----------------------------------------------------------------------------------------------------------------
-       // Annotations.
-       
//-----------------------------------------------------------------------------------------------------------------
-
-       @Target({PARAMETER,TYPE})
-       @Retention(RUNTIME)
-       public static @interface CA {
-               public String value();
-       }
-       @CA("1") public static class C1 extends C2 {}
-       @CA("2") public static class C2 implements C3, C4 {}
-       @CA("3") public interface C3 {}
-       @CA("4") public interface C4 {}
-
-       public interface CB {
-               void a1(@CA("5") C1 x);
-               void a2(@CA("5") C1 x);
-       }
-       public static class CC implements CB {
-               public CC(@CA("9") C1 x) {}
-               @Override
-               public void a1(C1 x) {}  // NOSONAR
-               @Override
-               public void a2(@CA("6") C1 x) {}  // NOSONAR
-       }
-       static ClassInfo
-               cb = ClassInfo.of(CB.class),
-               cc = ClassInfo.of(CC.class);
-       static ParameterInfo
-               cc_cc = cc.getPublicConstructor(x -> 
x.hasParameterTypes(C1.class)).get().getParameter(0),  // NOSONAR
-               cb_a1 = cb.getMethod(x -> 
x.hasName("a1")).get().getParameter(0),  // NOSONAR
-               cb_a2 = cb.getMethod(x -> 
x.hasName("a2")).get().getParameter(0),  // NOSONAR
-               cc_a1 = cc.getMethod(x -> 
x.hasName("a1")).get().getParameter(0),  // NOSONAR
-               cc_a2 = cc.getMethod(x -> 
x.hasName("a2")).get().getParameter(0);  // NOSONAR
-
-       @Test void getDeclaredAnnotations() {
-               check("@CA(5)", declaredAnnotations(cb_a1, CA.class));
-               check("@CA(5)", declaredAnnotations(cb_a2, CA.class));
-               check("", declaredAnnotations(cc_a1, CA.class));
-               check("@CA(6)", declaredAnnotations(cc_a2, CA.class));
-       }
-
-       @Test void getDeclaredAnnotations_constructor() {
-               check("@CA(9)", declaredAnnotations(cc_cc, CA.class));
-       }
-
-       private static <T extends Annotation> List<T> 
declaredAnnotations(ParameterInfo pi, Class<T> type) {
-               return pi.getAnnotations(type).map(x -> x.inner()).toList();
-       }
-
-       @Test void getDeclaredAnnotation() {
-               check("@CA(5)", cb_a1.getDeclaredAnnotation(CA.class));
-               check("@CA(5)", cb_a2.getDeclaredAnnotation(CA.class));
-               check(null, cc_a1.getDeclaredAnnotation(CA.class));
-               check("@CA(6)", cc_a2.getDeclaredAnnotation(CA.class));
-       }
-
-       @Test void getDeclaredAnnotation_constructor() {
-               check("@CA(9)", cc_cc.getDeclaredAnnotation(CA.class));
-       }
-
-       @Test void getDeclaredAnnotation_notFound() {
-               check(null, cb_a1.getDeclaredAnnotation(DA.class));
-       }
-
-       @Test void getDeclaredAnnotation_notFound_constructor() {
-               check(null, cc_cc.getDeclaredAnnotation(DA.class));
-       }
-
-       @Test void getDeclaredAnnotation_null() {
-               check(null, cb_a1.getDeclaredAnnotation(null));
-       }
-
-       @Test void getDeclaredAnnotation_null_constructor() {
-               check(null, cc_cc.getDeclaredAnnotation(null));
-       }
-
-       @Test void getAnnotationsParentFirst() {
-               check("@CA(4),@CA(3),@CA(2),@CA(1),@CA(5)", annotations(cb_a1, 
CA.class));
-               check("@CA(4),@CA(3),@CA(2),@CA(1),@CA(5)", annotations(cb_a2, 
CA.class));
-               check("@CA(4),@CA(3),@CA(2),@CA(1),@CA(5)", annotations(cc_a1, 
CA.class));
-               check("@CA(4),@CA(3),@CA(2),@CA(1),@CA(5),@CA(6)", 
annotations(cc_a2, CA.class));
-       }
-
-       @Test void getAnnotationsParentFirst_notFound() {
-               check("", annotations(cb_a1, DA.class));
-       }
-
-       @Test void getAnnotationsParentFirst_constructor() {
-               check("@CA(4),@CA(3),@CA(2),@CA(1),@CA(9)", annotations(cc_cc, 
CA.class));
-       }
-
-       @Test void getAnnotationsParentFirst_notFound_constructor() {
-               check("", annotations(cc_cc, DA.class));
-       }
-
-       @Test void getAllAnnotationInfo() {
-               check("@CA(5)", cb_a1.getAllAnnotation(CA.class).inner());
-               check("@CA(5)", cb_a2.getAllAnnotation(CA.class).inner());
-               check("@CA(5)", cc_a1.getAllAnnotation(CA.class).inner());
-               check("@CA(6)", cc_a2.getAllAnnotation(CA.class).inner());
-       }
-
-       @Test void getAllAnnotationInfo_notFound() {
-               var ai = cb_a1.getAllAnnotation(DA.class);
-               check(null, ai == null ? null : ai.inner());
-       }
-
-       @Test void getAllAnnotationInfo_constructor() {
-               check("@CA(9)", cc_cc.getAllAnnotation(CA.class).inner());
-       }
-
-       @Test void getAllAnnotationInfo_notFound_constructor() {
-               var ai = cc_cc.getAllAnnotation(DA.class);
-               check(null, ai == null ? null : ai.inner());
-       }
-
-       @Test void getAllAnnotationInfo_twice() {
-               check("@CA(5)", cb_a1.getAllAnnotation(CA.class).inner());
-               check("@CA(5)", cb_a1.getAllAnnotation(CA.class).inner());
-       }
-
-       @Test void getAllAnnotationInfo_twice_constructor() {
-               check("@CA(9)", cc_cc.getAllAnnotation(CA.class).inner());
-               check("@CA(9)", cc_cc.getAllAnnotation(CA.class).inner());
-       }
-
-       @Test void hasAnnotation() {
-               assertTrue(cb_a1.hasAnnotation(CA.class));
-               assertTrue(cb_a2.hasAnnotation(CA.class));
-               assertTrue(cc_a1.hasAnnotation(CA.class));
-               assertTrue(cc_a2.hasAnnotation(CA.class));
-               assertFalse(cb_a1.hasAnnotation(DA.class));
-       }
-
-       @Test void hasAnnotation_constructor() {
-               assertTrue(cc_cc.hasAnnotation(CA.class));
-               assertFalse(cc_cc.hasAnnotation(DA.class));
-       }
-
-       @Target({PARAMETER,TYPE})
-       @Retention(RUNTIME)
-       @Inherited
-       public static @interface DA {
-               public String value();
-       }
-       @DA("1") public static class D1 extends D2 {}
-       @DA("2") public static class D2 implements D3, D4 {}
-       @DA("3") public interface D3 {}
-       @DA("4") public interface D4 {}
-
-       public interface DB {
-               void a1(@DA("0") D1 x);
-       }
-       public static class DC implements DB {
-               @Override
-               public void a1(@DA("5") D1 x) {}  // NOSONAR
-       }
-
-       static ClassInfo
-               db = ClassInfo.of(DB.class),
-               dc = ClassInfo.of(DC.class);
-       static ParameterInfo
-               db_a1 = db.getMethod(x -> 
x.hasName("a1")).get().getParameter(0),  // NOSONAR
-               dc_a1 = dc.getMethod(x -> 
x.hasName("a1")).get().getParameter(0);  // NOSONAR
-
-       @Test void getAnnotationsParentFirst_inherited() {
-               check("@DA(4),@DA(3),@DA(2),@DA(1),@DA(0)", annotations(db_a1, 
DA.class));
-               check("@DA(4),@DA(3),@DA(2),@DA(1),@DA(0),@DA(5)", 
annotations(dc_a1, DA.class));
-       }
-
-       @Test void getAnnotationsParentFirst_inherited_notFound() {
-               check("", annotations(db_a1, CA.class));
-       }
-
-       @Test void getAllAnnotationInfo_inherited() {
-               check("@DA(0)", db_a1.getAllAnnotation(DA.class).inner());
-               check("@DA(5)", dc_a1.getAllAnnotation(DA.class).inner());
-       }
-
-       @Test void getAllAnnotationInfo_inherited_notFound() {
-               var ai = db_a1.getAllAnnotation(CA.class);
-               check(null, ai == null ? null : ai.inner());
-       }
-
-       
//-----------------------------------------------------------------------------------------------------------------
-       // Other methods.
-       
//-----------------------------------------------------------------------------------------------------------------
-
-       static class E {
-               public void a1(int a, @Name("b") int b) {}  // NOSONAR
-       }
-
-       static ClassInfo e = ClassInfo.of(E.class);
-       static ParameterInfo
-               e_a1_a = e.getMethod(x -> 
x.hasName("a1")).get().getParameter(0),  // NOSONAR
-               e_a1_b = e.getMethod(x -> 
x.hasName("a1")).get().getParameter(1);  // NOSONAR
-
-       @Test void hasName() {
-               e_a1_a.hasName();  // This might be true or false based on the 
JVM compiler used.
-               assertTrue(e_a1_b.hasName());
-       }
-
-       @Test void getName() {
-               e_a1_a.getName();  // This might be null or a value based on 
the JVM compiler used.
-               assertEquals("b", e_a1_b.getName());
-       }
-
-       @Test void toString2() {
-               assertEquals("a1[1]", e_a1_b.toString());
-       }
-
-       
//-----------------------------------------------------------------------------------------------------------------
-       // Helpers
-       
//-----------------------------------------------------------------------------------------------------------------
-
-       private static <T extends Annotation> List<T> annotations(ParameterInfo 
pi, Class<T> a) {
-               List<T> l = list();
-               
rstream(pi.getAllAnnotations(a)).map(AnnotationInfo::inner).forEach(l::add);
-               return l;
-       }
-}
\ No newline at end of file

Reply via email to