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 }