View Javadoc
1   /*
2    * Copyright (C) 2015 Sven von Pluto - javanarior (a) gmail dot com
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  package de.javanarior.utils.lang.reflect;
17  
18  import static de.javanarior.utils.lang.reflect.Invoke.invokeAnnotation;
19  
20  import java.lang.annotation.Annotation;
21  import java.lang.reflect.Method;
22  import java.util.ArrayList;
23  import java.util.List;
24  
25  /**
26   * Retrieve values from Java Elements e.g. {@link Annotation}s.
27   */
28  public final class Retrieve {
29  
30      private Retrieve() {
31      }
32  
33      /**
34       * Retrieve the value of an {@linkplain Annotation} attribute/method on a
35       * Class.
36       * To be more precise returns the value of {@code attributeName} from
37       * {@code annationClass} on {@code annotatedClass}.
38       * In case of error a {@linkplain ReflectionException} is thrown.
39       *
40       * @param annotationClass
41       *            - the class of the Annotation
42       * @param <T>
43       *            - a annotation class
44       * @param attributeName
45       *            - name of the attribute
46       * @param annotatedClass
47       *            - the class with the Annotation
48       * @return value of the annotation attribute
49       */
50      public static <T extends Annotation> Object annotationValueOnClass(Class<T> annotationClass, String attributeName,
51                      Class<?> annotatedClass) {
52          try {
53              T annotation = annotatedClass.getAnnotation(annotationClass);
54              if (annotation == null) {
55                  throw new ReflectionException("Annotation '" + annotationClass + "' not found in Class '"
56                                  + annotatedClass.getCanonicalName() + "'");
57              }
58              return invokeAnnotation(annotation, attributeName);
59          } catch (SecurityException exception) {
60              throw new ReflectionException(exception);
61          }
62      }
63  
64      /**
65       * Retrieve the value of an {@linkplain Annotation} on a Class. The
66       * Attribute/Method
67       * 'value' is assumed as default.
68       * To be more precise returns the value of {@code value} from
69       * {@code annationClass} on {@code annotatedClass}.
70       * In case of error a {@linkplain ReflectionException} is thrown.
71       *
72       * @param annotationClass
73       *            - the class of the Annotation
74       * @param <T>
75       *            - a annotation class
76       * @param annotatedClass
77       *            - the class with the Annotation
78       * @return value of the annotation attribute
79       */
80      public static <T extends Annotation> Object annotationValueOnClass(Class<T> annotationClass, Class<?> annotatedClass) {
81          return annotationValueOnClass(annotationClass, "value", annotatedClass);
82      }
83  
84      /**
85       * Retrieve the value of an {@linkplain Annotation} on a Method.
86       * To be more precise returns the value of {@code attributeName} from
87       * {@code annationClass} on {@code methodWithAnnotation}.
88       * In case of error a {@linkplain ReflectionException} is thrown.
89       *
90       * @param annotationClass
91       *            - the class of the Annotation
92       * @param <T>
93       *            - a annotation class
94       * @param methodWithAnnotation
95       *            - method with annotation
96       * @param attributeName
97       *            - name of the attribute
98       * @return value of the annotation attribute
99       */
100     public static <T extends Annotation> Object annotationValueOnMethod(Class<T> annotationClass,
101                     Method methodWithAnnotation, String attributeName) {
102         try {
103             T annotation = methodWithAnnotation.getAnnotation(annotationClass);
104             if (annotation == null) {
105                 throw new ReflectionException("Annotation '" + annotationClass + "' not found on Method '"
106                                 + methodWithAnnotation + "'");
107             }
108             return invokeAnnotation(annotation, attributeName);
109         } catch (SecurityException exception) {
110             throw new ReflectionException(exception);
111         }
112     }
113 
114     /**
115      * Retrieve the value of an {@linkplain Annotation} on a Method.
116      * To be more precise returns the value of {@code attributeName} of
117      * {@code annotationClass} from {@code methodName} of
118      * {@code classWithMethod}.
119      * In case of error a {@linkplain ReflectionException} is thrown.
120      *
121      * @param annotationClass
122      *            - the class of the Annotation
123      * @param <T>
124      *            - a annotation class
125      * @param attributeName
126      *            - name of the attribute
127      * @param classWithMethod
128      *            - class with the method
129      * @param methodName
130      *            - name of method with the annotation
131      * @param parameterTypes
132      *            - parameter types of {@code methodName}
133      * @return value of the annotation attribute
134      */
135     public static <T extends Annotation> Object annotationValueOnMethod(Class<T> annotationClass, String attributeName,
136                     Class<?> classWithMethod, String methodName, Class<?>... parameterTypes) {
137         return annotationValueOnMethod(annotationClass, findMethod(classWithMethod, methodName, parameterTypes),
138                         attributeName);
139     }
140 
141     /**
142      * Retrieve the value of an {@linkplain Annotation} on a Method. The
143      * Attribute/Method 'value' is assumed as default.
144      * To be more precise returns the value of {@code value} from
145      * {@code annationClass} on {@code method}.
146      * In case of error a {@linkplain ReflectionException} is thrown.
147      *
148      * @param annotationClass
149      *            - the class of the Annotation
150      * @param <T>
151      *            - a annotation class
152      * @param method
153      *            - the method with the Annotation
154      * @return value of the annotation attribute
155      */
156     public static <T extends Annotation> Object annotationValueOnMethod(Class<T> annotationClass, Method method) {
157         return annotationValueOnMethod(annotationClass, method, "value");
158     }
159 
160     /**
161      * Retrieve the value of an {@linkplain Annotation} on a Method. The
162      * Attribute/Method 'value' is assumed as default.
163      * To be more precise returns the value of {@code value} from
164      * {@code annationClass} of {@code methodName} of {@code annotatedClass}.
165      * In case of error a {@linkplain ReflectionException} is thrown.
166      *
167      * @param annotationClass
168      *            - the class of the Annotation
169      * @param <T>
170      *            - a annotation class
171      * @param classWithMethod
172      *            - class with method
173      * @param methodName
174      *            - name of method with annotation
175      * @param parameterTypes
176      *            - parameter types of {@code methodName}
177      * @return value of the annotation attribute
178      */
179     public static <T extends Annotation> Object annotationValueOnMethod(Class<T> annotationClass,
180                     Class<?> classWithMethod, String methodName, Class<?>... parameterTypes) {
181         try {
182             return annotationValueOnMethod(annotationClass, findMethod(classWithMethod, methodName, parameterTypes));
183         } catch (SecurityException exception) {
184             throw new ReflectionException(exception);
185         }
186     }
187 
188     /**
189      * Retrieve the value of an {@linkplain Annotation} on a method parameter.
190      * Returns the value of {@code attributeName} from {@code annotationClass}
191      * The Annotation is expected at the Method {@code methodNameWithParameter}
192      * in the class {@code classWithMethod}. If the Method is polymorphic
193      * overriden,
194      * the Signature can be provided with {@code parameterTypes}.
195      *
196      * @param <T>
197      *            - the annotation class
198      * @param annotationClass
199      *            - class of the annotation
200      * @param attributeName
201      *            - name of the attribute
202      * @param classWithMethod
203      *            - class of the method
204      * @param methodNameWithParameter
205      *            - the method name
206      * @param parameterName
207      *            - name of the parameter
208      * @param parameterTypes
209      *            - Types of the method
210      * @return value of the annotation attribute
211      */
212     // CHECKSTYLE:OFF
213     public static <T extends Annotation> Object annotationValueOnParameter(Class<T> annotationClass,
214                     String attributeName, Class<?> classWithMethod, String methodNameWithParameter,
215                     String parameterName, Class<?>... parameterTypes) {
216         // CHECKSTYLE:ON
217         Method method = findMethod(classWithMethod, methodNameWithParameter, parameterTypes);
218         for (Annotation[] annotations : method.getParameterAnnotations()) {
219             for (Annotation annotation : annotations) {
220                 if (annotation.annotationType().isAssignableFrom(annotationClass)) {
221                     return invokeAnnotation(annotation, attributeName);
222                 }
223             }
224         }
225         throw new ReflectionException("Annotation '" + annotationClass.getCanonicalName()
226                         + "' not found in Parameter list of Method '" + method + "'");
227     }
228 
229     /**
230      * Retrieve the value of an {@linkplain Annotation} on a method parameter.
231      * The
232      * Attribute/Method 'value' is assumed as default.
233      * Returns the value of 'value' from {@code annotationClass} The Annotation
234      * is expected at the Method {@code methodNameWithParameter} in the class
235      * {@code classWithMethod}. If the Method is polymorphic overridden,
236      * the Signature can be provided with {@code parameterTypes}.
237      *
238      * @param <T>
239      *            - the annotation class
240      * @param annotationClass
241      *            - class of the annotation
242      * @param classWithMethod
243      *            - class of the method
244      * @param methodNameWithParameter
245      *            - the method name
246      * @param parameterName
247      *            - name of the parameter
248      * @param parameterTypes
249      *            - Types of the method parameter
250      * @return value of the annotation attribute
251      */
252     public static <T extends Annotation> Object annotationValueOnParameter(Class<T> annotationClass,
253                     Class<?> classWithMethod, String methodNameWithParameter, String parameterName,
254                     Class<?>... parameterTypes) {
255         return annotationValueOnParameter(annotationClass, "value", classWithMethod, methodNameWithParameter,
256                         parameterName, parameterTypes);
257     }
258 
259 
260 
261     private static Method findMethod(Class<?> annotatedClass, String methodName, Class<?>... parameterTypes) {
262         try {
263             return annotatedClass.getMethod(methodName, parameterTypes);
264         } catch (NoSuchMethodException exception) {
265             if (parameterTypes == null || parameterTypes.length == 0) {
266                 List<Method> possibleMatches = findMethods(annotatedClass.getDeclaredMethods(), methodName);
267                 if (possibleMatches.size() == 1) {
268                     return possibleMatches.get(0);
269                 }
270             }
271             throw new ReflectionException("Method name '" + methodName + "' not found in Class '"
272                             + annotatedClass.getCanonicalName() + "'", exception);
273         }
274     }
275 
276     private static List<Method> findMethods(Method[] methods, String methodName) {
277         List<Method> matchingMethods = new ArrayList<>();
278         for (Method method : methods) {
279             if (method.getName().equals(methodName)) {
280                 matchingMethods.add(method);
281             }
282         }
283         return matchingMethods;
284     }
285 
286 }