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

commit 6bb927a1bd9885c46a76f508e6edd1c6d48f5784
Author: James Bognar <[email protected]>
AuthorDate: Wed Nov 19 13:57:41 2025 -0500

    org.apache.juneau.common.reflect API improvements
---
 .../juneau/common/reflect/AnnotationProvider.java  | 149 ---------------------
 .../java/org/apache/juneau/BeanPropertyMeta.java   |  10 +-
 .../main/java/org/apache/juneau/BeanRegistry.java  |   3 +-
 .../src/main/java/org/apache/juneau/ClassMeta.java |   4 +-
 .../rest/swagger/BasicSwaggerProviderSession.java  |  22 +--
 5 files changed, 22 insertions(+), 166 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 dddef37fbd..55b10cb9b6 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
@@ -17,9 +17,7 @@
 package org.apache.juneau.common.reflect;
 
 import static org.apache.juneau.common.utils.AssertionUtils.*;
-import static org.apache.juneau.common.utils.ClassUtils.*;
 import static org.apache.juneau.common.utils.CollectionUtils.*;
-import static org.apache.juneau.common.utils.PredicateUtils.*;
 import static org.apache.juneau.common.utils.ThrowableUtils.*;
 import static org.apache.juneau.common.utils.Utils.*;
 import static org.apache.juneau.common.reflect.AnnotationTraversal.*;
@@ -28,7 +26,6 @@ import static java.util.stream.Stream.*;
 import java.lang.annotation.*;
 import java.lang.reflect.*;
 import java.util.*;
-import java.util.function.*;
 import java.util.stream.*;
 
 import org.apache.juneau.common.collections.*;
@@ -405,7 +402,6 @@ public class AnnotationProvider {
        }
 
        // @formatter:off
-       private final Cache<Class<?>,List<AnnotationInfo<Annotation>>> 
classDeclaredAnnotations;
        private final Cache<Class<?>,List<AnnotationInfo<Annotation>>> 
classRuntimeAnnotations;
        private final Cache<Method,List<AnnotationInfo<Annotation>>> 
methodRuntimeAnnotations;
        private final Cache<Field,List<AnnotationInfo<Annotation>>> 
fieldRuntimeAnnotations;
@@ -419,10 +415,6 @@ public class AnnotationProvider {
         * @param builder The builder containing configuration settings.
         */
        protected AnnotationProvider(Builder builder) {
-               this.classDeclaredAnnotations = 
Cache.<Class<?>,List<AnnotationInfo<Annotation>>>create()
-                       .supplier(this::findClassDeclaredAnnotations)
-                       .disableCaching(builder.disableCaching)
-                       .build();
                this.classRuntimeAnnotations = 
Cache.<Class<?>,List<AnnotationInfo<Annotation>>>create()
                        .supplier(this::findClassRuntimeAnnotations)
                        .disableCaching(builder.disableCaching)
@@ -442,77 +434,10 @@ public class AnnotationProvider {
                this.runtimeAnnotations = builder.runtimeAnnotations.build();
        }
 
-
-       
//-----------------------------------------------------------------------------------------------------------------
-       // Public API
-       
//-----------------------------------------------------------------------------------------------------------------
-
-       /**
-        * Finds all declared annotations on the specified class in 
parent-to-child order (reversed).
-        *
-        * <p>
-        * This method returns annotations in the opposite order from {@link 
#xfindDeclared(Class)}.
-        * Returns annotations in <b>parent-to-child</b> order with declared 
annotations coming before
-        * runtime annotations at each level.
-        *
-        * <p>
-        * <b>Order of precedence</b>:
-        * <ol>
-        *      <li>Declared annotations on this class (lowest priority)
-        *      <li>Runtime annotations on this class (highest priority)
-        * </ol>
-        *
-        * <p>
-        * This is useful when you want to process multiple annotation values 
where runtime annotations
-        * can override values from declared annotations.
-        *
-        * @param onClass The class to search on.
-        * @return A stream of {@link AnnotationInfo} objects in 
parent-to-child order.
-        * @deprecated Use {@link #findTopDown(ClassInfo, 
AnnotationTraversal...)} with {@link AnnotationTraversal#SELF SELF} instead.
-        */
-       @Deprecated
-       public Stream<AnnotationInfo<Annotation>> 
xfindDeclaredParentFirst(Class<?> onClass) {
-               assertArgNotNull("onClass", onClass);
-               var list = classDeclaredAnnotations.get(onClass);
-               // Iterate backwards to get parent-to-child order
-               return rstream(list);
-       }
-
-       /**
-        * Finds all declared annotations of the specified type on the 
specified class in parent-to-child order (reversed).
-        *
-        * <p>
-        * This method returns annotations in the opposite order from {@link 
#xfindDeclared(Class, Class)}.
-        *
-        * @param <A> The annotation type to find.
-        * @param type The annotation type to find.
-        * @param onClass The class to search on.
-        * @return A stream of {@link AnnotationInfo} objects in 
parent-to-child order.
-        * @deprecated Use {@link #findTopDown(Class, ClassInfo, 
AnnotationTraversal...)} with {@link AnnotationTraversal#SELF SELF} instead.
-        */
-       @Deprecated
-       @SuppressWarnings("unchecked")
-       public <A extends Annotation> Stream<AnnotationInfo<A>> 
xfindDeclaredParentFirst(Class<A> type, Class<?> onClass) {
-               assertArgNotNull("type", type);
-               assertArgNotNull("onClass", onClass);
-               return xfindDeclaredParentFirst(onClass)
-                       .filter(a -> a.isType(type))
-                       .map(a -> (AnnotationInfo<A>)a);
-       }
-
        
//-----------------------------------------------------------------------------------------------------------------
        // Private implementation
        
//-----------------------------------------------------------------------------------------------------------------
 
-       private List<AnnotationInfo<Annotation>> 
findClassDeclaredAnnotations(Class<?> forClass) {
-               var list = new ArrayList<AnnotationInfo<Annotation>>();
-
-               // On this class
-               findDeclaredAnnotations(list, forClass);
-
-               return u(list);
-       }
-
        private List<AnnotationInfo<Annotation>> 
findClassRuntimeAnnotations(Class<?> forClass) {
                ClassInfo ci = ClassInfo.of(forClass);
                return runtimeAnnotations.find(forClass).map(a -> 
AnnotationInfo.of(ci, a)).toList();
@@ -533,80 +458,6 @@ public class AnnotationProvider {
                return runtimeAnnotations.find(forConstructor).map(a -> 
AnnotationInfo.of(ci, a)).toList();
        }
 
-       /**
-        * Finds all declared annotations on the specified class and appends 
them to the list.
-        *
-        * @param appendTo The list to append to.
-        * @param forClass The class to find declared annotations on.
-        */
-       private void findDeclaredAnnotations(List<AnnotationInfo<Annotation>> 
appendTo, Class<?> forClass) {
-               var ci = ClassInfo.of(forClass);
-               runtimeAnnotations.find(forClass).forEach(x -> 
appendTo.add(AnnotationInfo.of(ClassInfo.of(forClass), x)));
-               for (var a : forClass.getDeclaredAnnotations())
-                       streamRepeated(a).forEach(a2 -> 
appendTo.add(AnnotationInfo.of(ci, a2)));
-       }
-
-       /**
-        * Iterates through annotations on a method, its declaring class 
hierarchy, and return type hierarchy.
-        *
-        * <p>
-        * This traverses annotations in parent-first order from:
-        * <ol>
-        *      <li>Declaring class hierarchy (via this AnnotationProvider)
-        *      <li>Method hierarchy (parent-first, declared annotations only)
-        *      <li>Return type hierarchy (via this AnnotationProvider)
-        * </ol>
-        *
-        * @param <A> The annotation type.
-        * @param type The annotation type to search for.
-        * @param mi The method info to traverse.
-        * @param filter Optional filter to apply to annotations. Can be 
<jk>null</jk>.
-        * @param action The action to perform on each matching annotation.
-        * @deprecated Use {@link #findTopDown(Class, MethodInfo, 
AnnotationTraversal...)} instead.
-        */
-       @Deprecated
-       public <A extends Annotation> void xforEachMethodAnnotation(Class<A> 
type, MethodInfo mi, Predicate<A> filter, Consumer<A> action) {
-               xforEachClassAnnotation(type, mi.getDeclaringClass(), filter, 
action);
-               rstream(mi.getMatchingMethods())
-                       .flatMap(m -> m.getDeclaredAnnotations().stream())
-                       .map(AnnotationInfo::inner)
-                       .filter(type::isInstance)
-                       .map(type::cast)
-                       .forEach(a -> consumeIf(filter, action, a));
-               xforEachClassAnnotation(type, 
mi.getReturnType().unwrap(Value.class, Optional.class), filter, action);
-       }
-
-       /**
-        * Iterates through annotations on a class hierarchy.
-        *
-        * <p>
-        * This traverses annotations in parent-first order from:
-        * <ol>
-        *      <li>Package annotations
-        *      <li>Interface hierarchy (parent-first)
-        *      <li>Class hierarchy (parent-first)
-        * </ol>
-        *
-        * @param <A> The annotation type.
-        * @param type The annotation type to search for.
-        * @param ci The class info to traverse.
-        * @param filter Optional filter to apply to annotations. Can be 
<jk>null</jk>.
-        * @param action The action to perform on each matching annotation.
-        * @deprecated Use {@link #findTopDown(Class, ClassInfo, 
AnnotationTraversal...)} instead.
-        */
-       @Deprecated
-       public <A extends Annotation> void xforEachClassAnnotation(Class<A> 
type, ClassInfo ci, Predicate<A> filter, Consumer<A> action) {
-               A t2 = ci.getPackageAnnotation(type);
-               if (nn(t2))
-                       consumeIf(filter, action, t2);
-               var interfaces2 = ci.getInterfaces();
-               for (int i = interfaces2.size() - 1; i >= 0; i--)
-                       xfindDeclaredParentFirst(type, 
interfaces2.get(i).inner()).map(x -> x.inner()).filter(x -> filter == null || 
filter.test(x)).forEach(x -> action.accept(x));
-               var parents2 = ci.getParents();
-               for (int i = parents2.size() - 1; i >= 0; i--)
-                       xfindDeclaredParentFirst(type, 
parents2.get(i).inner()).map(x -> x.inner()).filter(x -> filter == null || 
filter.test(x)).forEach(x -> action.accept(x));
-       }
-
        
//-----------------------------------------------------------------------------------------------------------------
        // Stream-based traversal methods
        
//-----------------------------------------------------------------------------------------------------------------
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java
index b32e96ff05..6803a1a637 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java
@@ -688,10 +688,10 @@ public class BeanPropertyMeta implements 
Comparable<BeanPropertyMeta> {
                var si = setter == null ? null : MethodInfo.of(setter);
                if (a == null)
                        return l;
-               ap.xforEachClassAnnotation(a, 
getBeanMeta().getClassMeta().getInfo(), x -> true, x -> l.add(x));
+               ap.findTopDown(a, getBeanMeta().getClassMeta().getInfo()).map(x 
-> x.inner()).forEach(x -> l.add(x));
                if (nn(field)) {
                        ap.find(a, fi).map(x -> x.inner()).forEach(x -> 
l.add(x));
-                       ap.xforEachClassAnnotation(a, 
ClassInfo.of(field.getType()), x -> true, x -> l.add(x));
+                       ap.findTopDown(a, ClassInfo.of(field.getType())).map(x 
-> x.inner()).forEach(x -> l.add(x));
                }
                if (nn(gi)) {
                        // Walk up the inheritance hierarchy for the getter 
method
@@ -699,7 +699,7 @@ public class BeanPropertyMeta implements 
Comparable<BeanPropertyMeta> {
                                ap.find(a, MethodInfo.of(parentGetter)).map(x 
-> x.inner()).forEach(x -> l.add(x));
                        });
                        ap.find(a, gi).map(x -> x.inner()).forEach(x -> 
l.add(x));
-                       ap.xforEachClassAnnotation(a, gi.getReturnType(), x -> 
true, x -> l.add(x));
+                       ap.findTopDown(a, gi.getReturnType()).map(x -> 
x.inner()).forEach(x -> l.add(x));
                }
                if (nn(setter)) {
                        // Walk up the inheritance hierarchy for the setter 
method
@@ -707,7 +707,7 @@ public class BeanPropertyMeta implements 
Comparable<BeanPropertyMeta> {
                                ap.find(a, MethodInfo.of(parentSetter)).map(x 
-> x.inner()).forEach(x -> l.add(x));
                        });
                        ap.find(a, si).map(x -> x.inner()).forEach(x -> 
l.add(x));
-                       ap.xforEachClassAnnotation(a, 
ClassInfo.of(setter.getReturnType()), x -> true, x -> l.add(x));
+                       ap.findTopDown(a, 
ClassInfo.of(setter.getReturnType())).map(x -> x.inner()).forEach(x -> 
l.add(x));
                }
                if (nn(extraKeys)) {
                        MethodInfo eki = MethodInfo.of(extraKeys);
@@ -716,7 +716,7 @@ public class BeanPropertyMeta implements 
Comparable<BeanPropertyMeta> {
                                ap.find(a, 
MethodInfo.of(parentExtraKeys)).map(x -> x.inner()).forEach(x -> l.add(x));
                        });
                        ap.find(a, eki).map(x -> x.inner()).filter(x -> 
true).forEach(x -> l.add(x));
-                       ap.xforEachClassAnnotation(a, 
ClassInfo.of(extraKeys.getReturnType()), x -> true, x -> l.add(x));
+                       ap.findTopDown(a, 
ClassInfo.of(extraKeys.getReturnType())).map(x -> x.inner()).forEach(x -> 
l.add(x));
                }
 
                return l;
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanRegistry.java 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanRegistry.java
index 8296be7fb7..bc3b90f21f 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanRegistry.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanRegistry.java
@@ -150,7 +150,8 @@ public class BeanRegistry {
                                        });
                                } else {
                                        Value<String> typeName = Value.empty();
-                                       
beanContext.getAnnotationProvider().xforEachClassAnnotation(Bean.class, ci, x 
-> isNotEmpty(x.typeName()), x -> typeName.set(x.typeName()));
+                                       
//beanContext.getAnnotationProvider().xforEachClassAnnotation(Bean.class, ci, x 
-> isNotEmpty(x.typeName()), x -> typeName.set(x.typeName()));
+                                       
beanContext.getAnnotationProvider().findTopDown(Bean.class, ci).map(x -> 
x.inner().typeName()).filter(x -> isNotEmpty(x)).forEach(x -> typeName.set(x));
                                        addToMap(typeName.orElseThrow(() -> new 
BeanRuntimeException("Class ''{0}'' was passed to BeanRegistry but it doesn't 
have a @Bean(typeName) annotation defined.", cn(c))),
                                                beanContext.getClassMeta(c));
                                }
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
index 0a38265bc5..d54b571470 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
@@ -467,7 +467,7 @@ public class ClassMeta<T> implements Type {
                private BeanFilter findBeanFilter(BeanContext bc) {
                        try {
                                List<Bean> ba = list();
-                               
bc.getAnnotationProvider().xforEachClassAnnotation(Bean.class, info, x -> true, 
x -> ba.add(x));
+                               
bc.getAnnotationProvider().findTopDown(Bean.class, info).map(x -> 
x.inner()).forEach(x -> ba.add(x));
                                if (! ba.isEmpty())
                                        return 
BeanFilter.create(innerClass).applyAnnotations(ba).build();
                        } catch (Exception e) {
@@ -483,7 +483,7 @@ public class ClassMeta<T> implements Type {
                private MarshalledFilter findMarshalledFilter(BeanContext bc) {
                        try {
                                List<Marshalled> ba = list();
-                               
bc.getAnnotationProvider().xforEachClassAnnotation(Marshalled.class, info, x -> 
true, x -> ba.add(x));
+                               
bc.getAnnotationProvider().findTopDown(Marshalled.class, info).map(x -> 
x.inner()).forEach(x -> ba.add(x));
                                if (! ba.isEmpty())
                                        return 
MarshalledFilter.create(innerClass).applyAnnotations(ba).build();
                        } catch (Exception e) {
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 46b75c7099..1d99a31c48 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
@@ -33,7 +33,6 @@ import java.util.stream.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
-import org.apache.juneau.annotation.Items;
 import org.apache.juneau.bean.swagger.Swagger;
 import org.apache.juneau.collections.*;
 import org.apache.juneau.common.collections.*;
@@ -159,7 +158,7 @@ public class BasicSwaggerProviderSession {
 
                // Combine it with @Rest(swagger)
                List<Rest> restAnnotations = list();
-               
context.getAnnotationProvider().xforEachClassAnnotation(Rest.class, rci, x -> 
true, x -> restAnnotations.add(x));
+               ap.findTopDown(Rest.class, rci).map(x -> x.inner()).forEach(x 
-> restAnnotations.add(x));
                for (var rr : restAnnotations) {
 
                        JsonMap sInfo = omSwagger.getMap("info", true);
@@ -437,9 +436,9 @@ public class BasicSwaggerProviderSession {
                        for (var eci : mi.getExceptionTypes()) {
                                if (eci.hasAnnotation(Response.class)) {
                                        List<Response> la = list();
-                                       
context.getAnnotationProvider().xforEachClassAnnotation(Response.class, eci, x 
-> true, x -> la.add(x));
+                                       ap.findTopDown(Response.class, 
eci).map(x -> x.inner()).forEach(x -> la.add(x));
                                        List<StatusCode> la2 = list();
-                                       
context.getAnnotationProvider().xforEachClassAnnotation(StatusCode.class, eci, 
x -> true, x -> la2.add(x));
+                                       ap.findTopDown(StatusCode.class, 
eci).map(x -> x.inner()).forEach(x -> la2.add(x));
                                        Set<Integer> codes = getCodes(la2, 500);
                                        for (var a : la) {
                                                for (var code : codes) {
@@ -461,7 +460,8 @@ public class BasicSwaggerProviderSession {
                                                        String ha = a.name();
                                                        for (var code : codes) {
                                                                JsonMap header 
= responses.getMap(String.valueOf(code), true).getMap("headers", 
true).getMap(ha, true);
-                                                               
context.getAnnotationProvider().xforEachMethodAnnotation(Schema.class, ecmi, x 
-> true, x -> merge(header, x));
+                                                               
ap.findTopDown(Schema.class, ecmi).map(x -> x.inner()).forEach(x -> 
merge(header, x));
+                                                       //      
context.getAnnotationProvider().xforEachMethodAnnotation(Schema.class, ecmi, x 
-> true, x -> merge(header, x));
                                                                
rstream(ecmi.getReturnType().unwrap(Value.class, 
Optional.class).getAnnotations()).map(x -> 
x.cast(Schema.class)).filter(Objects::nonNull).map(AnnotationInfo::inner).forEach(x
 -> merge(header, x));
                                                                
pushupSchemaFields(RESPONSE_HEADER, header, getSchema(header.getMap("schema"), 
ecmi.getReturnType().unwrap(Value.class, Optional.class).innerType(), bs));
                                                        }
@@ -472,16 +472,19 @@ public class BasicSwaggerProviderSession {
 
                        if (mi.hasAnnotation(Response.class) || 
mi.getReturnType().unwrap(Value.class, 
Optional.class).hasAnnotation(Response.class)) {
                                List<Response> la = list();
-                               
context.getAnnotationProvider().xforEachMethodAnnotation(Response.class, mi, x 
-> true, x -> la.add(x));
+                               ap.findTopDown(Response.class, mi).map(x -> 
x.inner()).forEach(x -> la.add(x));
+                               
//context.getAnnotationProvider().xforEachMethodAnnotation(Response.class, mi, 
x -> true, x -> la.add(x));
                                List<StatusCode> la2 = list();
-                               
context.getAnnotationProvider().xforEachMethodAnnotation(StatusCode.class, mi, 
x -> true, x -> la2.add(x));
+                               
//context.getAnnotationProvider().xforEachMethodAnnotation(StatusCode.class, 
mi, x -> true, x -> la2.add(x));
+                               ap.findTopDown(StatusCode.class, mi).map(x -> 
x.inner()).forEach(x -> la2.add(x));
                                Set<Integer> codes = getCodes(la2, 200);
                                for (var a : la) {
                                        for (var code : codes) {
                                                JsonMap om = 
responses.getMap(String.valueOf(code), true);
                                                merge(om, a);
                                                JsonMap schema = 
getSchema(om.getMap("schema"), m.getGenericReturnType(), bs);
-                                               
context.getAnnotationProvider().xforEachMethodAnnotation(Schema.class, mi, x -> 
true, x -> merge(schema, x));
+                                               ap.findTopDown(Schema.class, 
mi).map(x -> x.inner()).forEach(x -> merge(schema, x));
+                                               
//context.getAnnotationProvider().xforEachMethodAnnotation(Schema.class, mi, x 
-> true, x -> merge(schema, x));
                                                pushupSchemaFields(RESPONSE, 
om, schema);
                                                om.appendIf(nem, "schema", 
schema);
                                                addBodyExamples(sm, om, true, 
m.getGenericReturnType(), locale);
@@ -497,7 +500,8 @@ public class BasicSwaggerProviderSession {
                                                        if (! isMulti(a)) {
                                                                for (var code : 
codes) {
                                                                        JsonMap 
header = responses.getMap(String.valueOf(code), true).getMap("headers", 
true).getMap(ha, true);
-                                                                       
context.getAnnotationProvider().xforEachMethodAnnotation(Schema.class, ecmi, x 
-> true, x -> merge(header, x));
+                                                                       
//context.getAnnotationProvider().xforEachMethodAnnotation(Schema.class, ecmi, 
x -> true, x -> merge(header, x));
+                                                                       
ap.findTopDown(Schema.class, ecmi).map(x -> x.inner()).forEach(x -> 
merge(header, x));
                                                                        
rstream(ecmi.getReturnType().unwrap(Value.class, 
Optional.class).getAnnotations()).map(x -> 
x.cast(Schema.class)).filter(Objects::nonNull).map(AnnotationInfo::inner).forEach(x
 -> merge(header, x));
                                                                        
merge(header, a.schema());
                                                                        
pushupSchemaFields(RESPONSE_HEADER, header, getSchema(header, 
ecmi.getReturnType().innerType(), bs));

Reply via email to