View Javadoc
1   /*
2    * Copyright 2022 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.bremersee.apiclient.webflux;
18  
19  import static org.springframework.core.annotation.AnnotationUtils.findAnnotation;
20  
21  import java.lang.annotation.Annotation;
22  import java.lang.reflect.AnnotatedElement;
23  import java.lang.reflect.Method;
24  import java.lang.reflect.Parameter;
25  import java.util.ArrayList;
26  import java.util.Arrays;
27  import java.util.List;
28  import java.util.Optional;
29  import java.util.function.Function;
30  import java.util.function.Predicate;
31  import java.util.stream.Stream;
32  import lombok.AllArgsConstructor;
33  import lombok.EqualsAndHashCode;
34  import lombok.Getter;
35  import lombok.NonNull;
36  import org.springframework.util.Assert;
37  
38  /**
39   * The invocation.
40   *
41   * @author Christian Bremer
42   */
43  @SuppressWarnings("SameNameButDifferent")
44  @Getter
45  @EqualsAndHashCode
46  @AllArgsConstructor
47  public class Invocation {
48  
49    @NonNull
50    private final Class<?> targetClass;
51  
52    @NonNull
53    private final Method method;
54  
55    private final Object[] args;
56  
57    /**
58     * To method parameter stream.
59     *
60     * @return the stream
61     */
62    public Stream<InvocationParameter> toMethodParameterStream() {
63      List<InvocationParameter> invocationParameters = new ArrayList<>();
64      Parameter[] parameters = method.getParameters();
65      for (int i = 0; i < parameters.length; i++) {
66        invocationParameters.add(new InvocationParameter(this, parameters[i], args[i], i));
67      }
68      return invocationParameters.stream();
69    }
70  
71    @Override
72    public String toString() {
73      return "Invocation{"
74          + "targetClass=" + targetClass.getName()
75          + ", method=" + method.getName()
76          + ", args=" + Arrays.toString(args)
77          + '}';
78    }
79  
80    /**
81     * Find annotation value on target class.
82     *
83     * @param <T> the type parameter
84     * @param <A> the type parameter
85     * @param annotationType the annotation type
86     * @param condition the condition
87     * @param mapper the mapper
88     * @return the optional
89     */
90    public <T, A extends Annotation> Optional<T> findAnnotationValueOnTargetClass(
91        Class<A> annotationType,
92        Predicate<A> condition,
93        Function<A, T> mapper) {
94      return findAnnotationValue(targetClass, annotationType, condition, mapper);
95    }
96  
97    /**
98     * Find annotation value on method.
99     *
100    * @param <T> the type parameter
101    * @param <A> the type parameter
102    * @param annotationType the annotation type
103    * @param condition the condition
104    * @param mapper the mapper
105    * @return the optional
106    */
107   public <T, A extends Annotation> Optional<T> findAnnotationValueOnMethod(
108       Class<A> annotationType,
109       Predicate<A> condition,
110       Function<A, T> mapper) {
111     return findAnnotationValue(method, annotationType, condition, mapper);
112   }
113 
114   /**
115    * Find annotation value on parameter.
116    *
117    * @param <T> the type parameter
118    * @param <A> the type parameter
119    * @param parameterIndex the parameter index
120    * @param annotationType the annotation type
121    * @param condition the condition
122    * @param mapper the mapper
123    * @return the optional
124    */
125   public <T, A extends Annotation> Optional<T> findAnnotationValueOnParameter(
126       int parameterIndex,
127       Class<A> annotationType,
128       Predicate<A> condition,
129       Function<A, T> mapper) {
130     Parameter[] parameters = method.getParameters();
131     if (parameterIndex >= 0 && parameterIndex < parameters.length) {
132       return findAnnotationValue(parameters[parameterIndex], annotationType, condition, mapper);
133     }
134     return Optional.empty();
135   }
136 
137   /**
138    * Find annotation value.
139    *
140    * @param <T> the type parameter
141    * @param <A> the type parameter
142    * @param annotatedElement the annotated element
143    * @param annotationType the annotation type
144    * @param condition the condition
145    * @param mapper the mapper
146    * @return the optional
147    */
148   private static <T, A extends Annotation> Optional<T> findAnnotationValue(
149       AnnotatedElement annotatedElement,
150       Class<A> annotationType,
151       Predicate<A> condition,
152       Function<A, T> mapper) {
153 
154     Assert.notNull(annotatedElement, "Annotated element must be present.");
155     Assert.notNull(annotationType, "Annotation type must be present.");
156     Assert.notNull(condition, "Condition must be present.");
157     Assert.notNull(mapper, "Mapper must be present.");
158 
159     return Optional.of(annotatedElement)
160         .map(m -> findAnnotation(m, annotationType))
161         .filter(condition)
162         .map(mapper);
163   }
164 
165 }