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 }