AnnotationUtils.java 22.5 KB
Newer Older
A
Arjen Poutsma 已提交
1
/*
S
Sam Brannen 已提交
2
 * Copyright 2002-2013 the original author or authors.
A
Arjen Poutsma 已提交
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.core.annotation;

import java.lang.annotation.Annotation;
20
import java.lang.reflect.AnnotatedElement;
A
Arjen Poutsma 已提交
21
import java.lang.reflect.Method;
S
Sam Brannen 已提交
22

23
import java.util.List;
A
Arjen Poutsma 已提交
24
import java.util.Map;
25
import java.util.WeakHashMap;
A
Arjen Poutsma 已提交
26 27 28 29 30

import org.springframework.core.BridgeMethodResolver;
import org.springframework.util.Assert;

/**
J
Juergen Hoeller 已提交
31 32 33
 * General utility methods for working with annotations, handling bridge methods (which the compiler
 * generates for generic declarations) as well as super methods (for optional "annotation inheritance").
 * Note that none of this is provided by the JDK's introspection facilities themselves.
A
Arjen Poutsma 已提交
34
 *
J
Juergen Hoeller 已提交
35 36 37 38 39 40
 * <p>As a general rule for runtime-retained annotations (e.g. for transaction control, authorization or service
 * exposure), always use the lookup methods on this class (e.g., {@link #findAnnotation(Method, Class)}, {@link
 * #getAnnotation(Method, Class)}, and {@link #getAnnotations(Method)}) instead of the plain annotation lookup
 * methods in the JDK. You can still explicitly choose between lookup on the given class level only ({@link
 * #getAnnotation(Method, Class)}) and lookup in the entire inheritance hierarchy of the given method ({@link
 * #findAnnotation(Method, Class)}).
A
Arjen Poutsma 已提交
41 42 43 44 45
 *
 * @author Rob Harrop
 * @author Juergen Hoeller
 * @author Sam Brannen
 * @author Mark Fisher
C
Chris Beams 已提交
46
 * @author Chris Beams
A
Arjen Poutsma 已提交
47 48 49 50 51 52 53
 * @since 2.0
 * @see java.lang.reflect.Method#getAnnotations()
 * @see java.lang.reflect.Method#getAnnotation(Class)
 */
public abstract class AnnotationUtils {

	/** The attribute name for annotations with a single element */
J
Juergen Hoeller 已提交
54
	static final String VALUE = "value";
A
Arjen Poutsma 已提交
55

56
	private static final Map<Class<?>, Boolean> annotatedInterfaceCache = new WeakHashMap<Class<?>, Boolean>();
57

J
Juergen Hoeller 已提交
58

59
	/**
C
Chris Beams 已提交
60 61 62 63 64 65 66
	 * Get a single {@link Annotation} of {@code annotationType} from the supplied
	 * Method, Constructor or Field. Meta-annotations will be searched if the annotation
	 * is not declared locally on the supplied element.
	 * @param ae the Method, Constructor or Field from which to get the annotation
	 * @param annotationType the annotation class to look for, both locally and as a meta-annotation
	 * @return the matching annotation or {@code null} if not found
	 * @since 3.1
67 68 69 70 71 72 73 74 75 76 77 78 79 80
	 */
	public static <T extends Annotation> T getAnnotation(AnnotatedElement ae, Class<T> annotationType) {
		T ann = ae.getAnnotation(annotationType);
		if (ann == null) {
			for (Annotation metaAnn : ae.getAnnotations()) {
				ann = metaAnn.annotationType().getAnnotation(annotationType);
				if (ann != null) {
					break;
				}
			}
		}
		return ann;
	}

A
Arjen Poutsma 已提交
81 82 83 84 85 86 87 88 89 90 91 92
	/**
	 * Get all {@link Annotation Annotations} from the supplied {@link Method}.
	 * <p>Correctly handles bridge {@link Method Methods} generated by the compiler.
	 * @param method the method to look for annotations on
	 * @return the annotations found
	 * @see org.springframework.core.BridgeMethodResolver#findBridgedMethod(Method)
	 */
	public static Annotation[] getAnnotations(Method method) {
		return BridgeMethodResolver.findBridgedMethod(method).getAnnotations();
	}

	/**
93
	 * Get a single {@link Annotation} of {@code annotationType} from the supplied {@link Method}.
A
Arjen Poutsma 已提交
94 95 96 97 98 99 100
	 * <p>Correctly handles bridge {@link Method Methods} generated by the compiler.
	 * @param method the method to look for annotations on
	 * @param annotationType the annotation class to look for
	 * @return the annotations found
	 * @see org.springframework.core.BridgeMethodResolver#findBridgedMethod(Method)
	 */
	public static <A extends Annotation> A getAnnotation(Method method, Class<A> annotationType) {
101 102 103 104 105 106 107 108 109 110 111
		Method resolvedMethod = BridgeMethodResolver.findBridgedMethod(method);
		A ann = resolvedMethod.getAnnotation(annotationType);
		if (ann == null) {
			for (Annotation metaAnn : resolvedMethod.getAnnotations()) {
				ann = metaAnn.annotationType().getAnnotation(annotationType);
				if (ann != null) {
					break;
				}
			}
		}
		return ann;
A
Arjen Poutsma 已提交
112 113 114
	}

	/**
115
	 * Get a single {@link Annotation} of {@code annotationType} from the supplied {@link Method},
J
Juergen Hoeller 已提交
116 117
	 * traversing its super methods if no annotation can be found on the given method itself.
	 * <p>Annotations on methods are not inherited by default, so we need to handle this explicitly.
A
Arjen Poutsma 已提交
118 119
	 * @param method the method to look for annotations on
	 * @param annotationType the annotation class to look for
120
	 * @return the annotation found, or {@code null} if none found
A
Arjen Poutsma 已提交
121 122 123 124
	 */
	public static <A extends Annotation> A findAnnotation(Method method, Class<A> annotationType) {
		A annotation = getAnnotation(method, annotationType);
		Class<?> cl = method.getDeclaringClass();
J
Juergen Hoeller 已提交
125 126
		if (annotation == null) {
			annotation = searchOnInterfaces(method, annotationType, cl.getInterfaces());
127
		}
A
Arjen Poutsma 已提交
128 129 130 131 132 133 134 135 136 137
		while (annotation == null) {
			cl = cl.getSuperclass();
			if (cl == null || cl == Object.class) {
				break;
			}
			try {
				Method equivalentMethod = cl.getDeclaredMethod(method.getName(), method.getParameterTypes());
				annotation = getAnnotation(equivalentMethod, annotationType);
			}
			catch (NoSuchMethodException ex) {
138 139 140 141
				// No equivalent method found
			}
			if (annotation == null) {
				annotation = searchOnInterfaces(method, annotationType, cl.getInterfaces());
A
Arjen Poutsma 已提交
142 143 144 145 146
			}
		}
		return annotation;
	}

147
	private static <A extends Annotation> A searchOnInterfaces(Method method, Class<A> annotationType, Class<?>[] ifcs) {
148
		A annotation = null;
J
Juergen Hoeller 已提交
149
		for (Class<?> iface : ifcs) {
150 151 152 153 154 155 156 157 158 159 160
			if (isInterfaceWithAnnotatedMethods(iface)) {
				try {
					Method equivalentMethod = iface.getMethod(method.getName(), method.getParameterTypes());
					annotation = getAnnotation(equivalentMethod, annotationType);
				}
				catch (NoSuchMethodException ex) {
					// Skip this interface - it doesn't have the method...
				}
				if (annotation != null) {
					break;
				}
161
			}
162 163 164 165 166 167 168 169 170
		}
		return annotation;
	}

	private static boolean isInterfaceWithAnnotatedMethods(Class<?> iface) {
		synchronized (annotatedInterfaceCache) {
			Boolean flag = annotatedInterfaceCache.get(iface);
			if (flag != null) {
				return flag;
171
			}
172 173 174 175 176 177
			boolean found = false;
			for (Method ifcMethod : iface.getMethods()) {
				if (ifcMethod.getAnnotations().length > 0) {
					found = true;
					break;
				}
178
			}
179 180
			annotatedInterfaceCache.put(iface, found);
			return found;
181 182 183
		}
	}

A
Arjen Poutsma 已提交
184
	/**
185
	 * Find a single {@link Annotation} of {@code annotationType} from the supplied {@link Class},
186
	 * traversing its interfaces and superclasses if no annotation can be found on the given class itself.
J
Juergen Hoeller 已提交
187
	 * <p>This method explicitly handles class-level annotations which are not declared as
188
	 * {@link java.lang.annotation.Inherited inherited} <i>as well as annotations on interfaces</i>.
J
Juergen Hoeller 已提交
189 190 191 192 193 194
	 * <p>The algorithm operates as follows: Searches for an annotation on the given class and returns
	 * it if found. Else searches all interfaces that the given class declares, returning the annotation
	 * from the first matching candidate, if any. Else proceeds with introspection of the superclass
	 * of the given class, checking the superclass itself; if no annotation found there, proceeds
	 * with the interfaces that the superclass declares. Recursing up through the entire superclass
	 * hierarchy if no match is found.
A
Arjen Poutsma 已提交
195 196
	 * @param clazz the class to look for annotations on
	 * @param annotationType the annotation class to look for
197
	 * @return the annotation found, or {@code null} if none found
A
Arjen Poutsma 已提交
198 199 200 201 202 203 204 205 206 207 208 209 210
	 */
	public static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType) {
		Assert.notNull(clazz, "Class must not be null");
		A annotation = clazz.getAnnotation(annotationType);
		if (annotation != null) {
			return annotation;
		}
		for (Class<?> ifc : clazz.getInterfaces()) {
			annotation = findAnnotation(ifc, annotationType);
			if (annotation != null) {
				return annotation;
			}
		}
211 212 213 214 215 216 217 218
		if (!Annotation.class.isAssignableFrom(clazz)) {
			for (Annotation ann : clazz.getAnnotations()) {
				annotation = findAnnotation(ann.annotationType(), annotationType);
				if (annotation != null) {
					return annotation;
				}
			}
		}
219
		Class<?> superClass = clazz.getSuperclass();
220
		if (superClass == null || superClass == Object.class) {
A
Arjen Poutsma 已提交
221 222 223 224 225 226
			return null;
		}
		return findAnnotation(superClass, annotationType);
	}

	/**
227 228 229 230 231
	 * Find the first {@link Class} in the inheritance hierarchy of the specified {@code clazz}
	 * (including the specified {@code clazz} itself) which declares an annotation for the
	 * specified {@code annotationType}, or {@code null} if not found. If the supplied
	 * {@code clazz} is {@code null}, {@code null} will be returned.
	 * <p>If the supplied {@code clazz} is an interface, only the interface itself will be checked;
J
Juergen Hoeller 已提交
232 233 234 235
	 * the inheritance hierarchy for interfaces will not be traversed.
	 * <p>The standard {@link Class} API does not provide a mechanism for determining which class
	 * in an inheritance hierarchy actually declares an {@link Annotation}, so we need to handle
	 * this explicitly.
A
Arjen Poutsma 已提交
236
	 * @param annotationType the Class object corresponding to the annotation type
J
Juergen Hoeller 已提交
237
	 * @param clazz the Class object corresponding to the class on which to check for the annotation,
238 239 240
	 * or {@code null}
	 * @return the first {@link Class} in the inheritance hierarchy of the specified {@code clazz}
	 * which declares an annotation for the specified {@code annotationType}, or {@code null}
J
Juergen Hoeller 已提交
241
	 * if not found
A
Arjen Poutsma 已提交
242 243
	 * @see Class#isAnnotationPresent(Class)
	 * @see Class#getDeclaredAnnotations()
244 245
	 * @see #findAnnotationDeclaringClassForTypes(List, Class)
	 * @see #isAnnotationDeclaredLocally(Class, Class)
A
Arjen Poutsma 已提交
246 247 248 249 250 251
	 */
	public static Class<?> findAnnotationDeclaringClass(Class<? extends Annotation> annotationType, Class<?> clazz) {
		Assert.notNull(annotationType, "Annotation type must not be null");
		if (clazz == null || clazz.equals(Object.class)) {
			return null;
		}
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
		return (isAnnotationDeclaredLocally(annotationType, clazz)) ? clazz : findAnnotationDeclaringClass(
			annotationType, clazz.getSuperclass());
	}

	/**
	 * Find the first {@link Class} in the inheritance hierarchy of the specified
	 * {@code clazz} (including the specified {@code clazz} itself) which declares
	 * at least one of the specified {@code annotationTypes}, or {@code null} if
	 * none of the specified annotation types could be found.
	 * <p>If the supplied {@code clazz} is {@code null}, {@code null} will be
	 * returned.
	 * <p>If the supplied {@code clazz} is an interface, only the interface itself
	 * will be checked; the inheritance hierarchy for interfaces will not be traversed.
	 * <p>The standard {@link Class} API does not provide a mechanism for determining
	 * which class in an inheritance hierarchy actually declares one of several
	 * candidate {@linkplain Annotation annotations}, so we need to handle this
	 * explicitly.
	 * @param annotationTypes the list of Class objects corresponding to the
	 * annotation types
	 * @param clazz the Class object corresponding to the class on which to check
	 * for the annotations, or {@code null}
	 * @return the first {@link Class} in the inheritance hierarchy of the specified
	 * {@code clazz} which declares an annotation of at least one of the specified
	 * {@code annotationTypes}, or {@code null} if not found
	 * @see Class#isAnnotationPresent(Class)
	 * @see Class#getDeclaredAnnotations()
	 * @see #findAnnotationDeclaringClass(Class, Class)
	 * @see #isAnnotationDeclaredLocally(Class, Class)
	 * @since 3.2.2
	 */
	public static Class<?> findAnnotationDeclaringClassForTypes(List<Class<? extends Annotation>> annotationTypes,
			Class<?> clazz) {
		Assert.notEmpty(annotationTypes, "The list of annotation types must not be empty");
		if (clazz == null || clazz.equals(Object.class)) {
			return null;
		}

		for (Class<? extends Annotation> annotationType : annotationTypes) {
			if (isAnnotationDeclaredLocally(annotationType, clazz)) {
				return clazz;
			}
		}

		return findAnnotationDeclaringClassForTypes(annotationTypes, clazz.getSuperclass());
A
Arjen Poutsma 已提交
296 297 298
	}

	/**
299 300
	 * Determine whether an annotation for the specified {@code annotationType} is
	 * declared locally on the supplied {@code clazz}. The supplied {@link Class}
J
Juergen Hoeller 已提交
301 302
	 * may represent any type.
	 * <p>Note: This method does <strong>not</strong> determine if the annotation is
S
Sam Brannen 已提交
303 304 305
	 * {@linkplain java.lang.annotation.Inherited inherited}. For greater clarity
	 * regarding inherited annotations, consider using
	 * {@link #isAnnotationInherited(Class, Class)} instead.
A
Arjen Poutsma 已提交
306
	 * @param annotationType the Class object corresponding to the annotation type
J
Juergen Hoeller 已提交
307
	 * @param clazz the Class object corresponding to the class on which to check for the annotation
308 309
	 * @return {@code true} if an annotation for the specified {@code annotationType}
	 * is declared locally on the supplied {@code clazz}
A
Arjen Poutsma 已提交
310 311 312 313 314 315 316
	 * @see Class#getDeclaredAnnotations()
	 * @see #isAnnotationInherited(Class, Class)
	 */
	public static boolean isAnnotationDeclaredLocally(Class<? extends Annotation> annotationType, Class<?> clazz) {
		Assert.notNull(annotationType, "Annotation type must not be null");
		Assert.notNull(clazz, "Class must not be null");
		boolean declaredLocally = false;
S
Sam Brannen 已提交
317
		for (Annotation annotation : clazz.getDeclaredAnnotations()) {
A
Arjen Poutsma 已提交
318 319 320 321 322 323 324 325 326
			if (annotation.annotationType().equals(annotationType)) {
				declaredLocally = true;
				break;
			}
		}
		return declaredLocally;
	}

	/**
327
	 * Determine whether an annotation for the specified {@code annotationType} is present
S
Sam Brannen 已提交
328 329
	 * on the supplied {@code clazz} and is {@linkplain java.lang.annotation.Inherited inherited}
	 * (i.e., not declared locally for the class).
330
	 * <p>If the supplied {@code clazz} is an interface, only the interface itself will be checked.
J
Juergen Hoeller 已提交
331
	 * In accordance with standard meta-annotation semantics, the inheritance hierarchy for interfaces
S
Sam Brannen 已提交
332 333
	 * will not be traversed. See the {@linkplain java.lang.annotation.Inherited Javadoc} for the
	 * {@code @Inherited} meta-annotation for further details regarding annotation inheritance.
A
Arjen Poutsma 已提交
334
	 * @param annotationType the Class object corresponding to the annotation type
J
Juergen Hoeller 已提交
335
	 * @param clazz the Class object corresponding to the class on which to check for the annotation
336
	 * @return {@code true} if an annotation for the specified {@code annotationType} is present
S
Sam Brannen 已提交
337
	 * on the supplied {@code clazz} and is <em>inherited</em>
A
Arjen Poutsma 已提交
338 339 340 341 342 343 344 345 346 347
	 * @see Class#isAnnotationPresent(Class)
	 * @see #isAnnotationDeclaredLocally(Class, Class)
	 */
	public static boolean isAnnotationInherited(Class<? extends Annotation> annotationType, Class<?> clazz) {
		Assert.notNull(annotationType, "Annotation type must not be null");
		Assert.notNull(clazz, "Class must not be null");
		return (clazz.isAnnotationPresent(annotationType) && !isAnnotationDeclaredLocally(annotationType, clazz));
	}

	/**
348 349 350 351 352
	 * Retrieve the given annotation's attributes as a Map, preserving all attribute types
	 * as-is.
	 * <p>Note: As of Spring 3.1.1, the returned map is actually an
	 * {@link AnnotationAttributes} instance, however the Map signature of this method has
	 * been preserved for binary compatibility.
A
Arjen Poutsma 已提交
353
	 * @param annotation the annotation to retrieve the attributes for
J
Juergen Hoeller 已提交
354 355
	 * @return the Map of annotation attributes, with attribute names as keys and
	 * corresponding attribute values as values
A
Arjen Poutsma 已提交
356 357
	 */
	public static Map<String, Object> getAnnotationAttributes(Annotation annotation) {
358
		return getAnnotationAttributes(annotation, false, false);
359 360 361
	}

	/**
362 363 364 365 366 367
	 * Retrieve the given annotation's attributes as a Map. Equivalent to calling
	 * {@link #getAnnotationAttributes(Annotation, boolean, boolean)} with
	 * the {@code nestedAnnotationsAsMap} parameter set to {@code false}.
	 * <p>Note: As of Spring 3.1.1, the returned map is actually an
	 * {@link AnnotationAttributes} instance, however the Map signature of this method has
	 * been preserved for binary compatibility.
368
	 * @param annotation the annotation to retrieve the attributes for
369 370 371
	 * @param classValuesAsString whether to turn Class references into Strings (for
	 * compatibility with {@link org.springframework.core.type.AnnotationMetadata} or to
	 * preserve them as Class references
J
Juergen Hoeller 已提交
372 373
	 * @return the Map of annotation attributes, with attribute names as keys and
	 * corresponding attribute values as values
374
	 */
375
	public static Map<String, Object> getAnnotationAttributes(Annotation annotation, boolean classValuesAsString) {
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395
		return getAnnotationAttributes(annotation, classValuesAsString, false);
	}

	/**
	 * Retrieve the given annotation's attributes as an {@link AnnotationAttributes}
	 * map structure. Implemented in Spring 3.1.1 to provide fully recursive annotation
	 * reading capabilities on par with that of the reflection-based
	 * {@link org.springframework.core.type.StandardAnnotationMetadata}.
	 * @param annotation the annotation to retrieve the attributes for
	 * @param classValuesAsString whether to turn Class references into Strings (for
	 * compatibility with {@link org.springframework.core.type.AnnotationMetadata} or to
	 * preserve them as Class references
	 * @param nestedAnnotationsAsMap whether to turn nested Annotation instances into
	 * {@link AnnotationAttributes} maps (for compatibility with
	 * {@link org.springframework.core.type.AnnotationMetadata} or to preserve them as
	 * Annotation instances
	 * @return the annotation attributes (a specialized Map) with attribute names as keys
	 * and corresponding attribute values as values
	 * @since 3.1.1
	 */
396 397
	public static AnnotationAttributes getAnnotationAttributes(Annotation annotation, boolean classValuesAsString,
			boolean nestedAnnotationsAsMap) {
398 399

		AnnotationAttributes attrs = new AnnotationAttributes();
A
Arjen Poutsma 已提交
400
		Method[] methods = annotation.annotationType().getDeclaredMethods();
401
		for (Method method : methods) {
A
Arjen Poutsma 已提交
402 403
			if (method.getParameterTypes().length == 0 && method.getReturnType() != void.class) {
				try {
404
					Object value = method.invoke(annotation);
405
					if (classValuesAsString) {
406
						if (value instanceof Class) {
407
							value = ((Class<?>) value).getName();
408 409
						}
						else if (value instanceof Class[]) {
410
							Class<?>[] clazzArray = (Class[]) value;
411 412 413 414 415 416 417
							String[] newValue = new String[clazzArray.length];
							for (int i = 0; i < clazzArray.length; i++) {
								newValue[i] = clazzArray[i].getName();
							}
							value = newValue;
						}
					}
418
					if (nestedAnnotationsAsMap && value instanceof Annotation) {
419 420
						attrs.put(method.getName(),
							getAnnotationAttributes((Annotation) value, classValuesAsString, nestedAnnotationsAsMap));
421 422
					}
					else if (nestedAnnotationsAsMap && value instanceof Annotation[]) {
423
						Annotation[] realAnnotations = (Annotation[]) value;
424 425
						AnnotationAttributes[] mappedAnnotations = new AnnotationAttributes[realAnnotations.length];
						for (int i = 0; i < realAnnotations.length; i++) {
426 427
							mappedAnnotations[i] = getAnnotationAttributes(realAnnotations[i], classValuesAsString,
								nestedAnnotationsAsMap);
428 429 430 431 432 433
						}
						attrs.put(method.getName(), mappedAnnotations);
					}
					else {
						attrs.put(method.getName(), value);
					}
A
Arjen Poutsma 已提交
434 435 436 437 438 439 440 441 442 443
				}
				catch (Exception ex) {
					throw new IllegalStateException("Could not obtain annotation attribute values", ex);
				}
			}
		}
		return attrs;
	}

	/**
444
	 * Retrieve the <em>value</em> of the {@code &quot;value&quot;} attribute of a
J
Juergen Hoeller 已提交
445
	 * single-element Annotation, given an annotation instance.
A
Arjen Poutsma 已提交
446
	 * @param annotation the annotation instance from which to retrieve the value
447
	 * @return the attribute value, or {@code null} if not found
A
Arjen Poutsma 已提交
448 449 450 451 452 453 454
	 * @see #getValue(Annotation, String)
	 */
	public static Object getValue(Annotation annotation) {
		return getValue(annotation, VALUE);
	}

	/**
J
Juergen Hoeller 已提交
455
	 * Retrieve the <em>value</em> of a named Annotation attribute, given an annotation instance.
A
Arjen Poutsma 已提交
456 457
	 * @param annotation the annotation instance from which to retrieve the value
	 * @param attributeName the name of the attribute value to retrieve
458
	 * @return the attribute value, or {@code null} if not found
J
Juergen Hoeller 已提交
459
	 * @see #getValue(Annotation)
A
Arjen Poutsma 已提交
460 461 462 463 464 465 466 467 468 469 470 471
	 */
	public static Object getValue(Annotation annotation, String attributeName) {
		try {
			Method method = annotation.annotationType().getDeclaredMethod(attributeName, new Class[0]);
			return method.invoke(annotation);
		}
		catch (Exception ex) {
			return null;
		}
	}

	/**
472
	 * Retrieve the <em>default value</em> of the {@code &quot;value&quot;} attribute
J
Juergen Hoeller 已提交
473 474
	 * of a single-element Annotation, given an annotation instance.
	 * @param annotation the annotation instance from which to retrieve the default value
475
	 * @return the default value, or {@code null} if not found
A
Arjen Poutsma 已提交
476 477 478 479 480 481 482
	 * @see #getDefaultValue(Annotation, String)
	 */
	public static Object getDefaultValue(Annotation annotation) {
		return getDefaultValue(annotation, VALUE);
	}

	/**
J
Juergen Hoeller 已提交
483 484
	 * Retrieve the <em>default value</em> of a named Annotation attribute, given an annotation instance.
	 * @param annotation the annotation instance from which to retrieve the default value
A
Arjen Poutsma 已提交
485
	 * @param attributeName the name of the attribute value to retrieve
486
	 * @return the default value of the named attribute, or {@code null} if not found
A
Arjen Poutsma 已提交
487 488 489 490 491 492 493
	 * @see #getDefaultValue(Class, String)
	 */
	public static Object getDefaultValue(Annotation annotation, String attributeName) {
		return getDefaultValue(annotation.annotationType(), attributeName);
	}

	/**
494
	 * Retrieve the <em>default value</em> of the {@code &quot;value&quot;} attribute
J
Juergen Hoeller 已提交
495 496
	 * of a single-element Annotation, given the {@link Class annotation type}.
	 * @param annotationType the <em>annotation type</em> for which the default value should be retrieved
497
	 * @return the default value, or {@code null} if not found
A
Arjen Poutsma 已提交
498 499 500 501 502 503 504
	 * @see #getDefaultValue(Class, String)
	 */
	public static Object getDefaultValue(Class<? extends Annotation> annotationType) {
		return getDefaultValue(annotationType, VALUE);
	}

	/**
J
Juergen Hoeller 已提交
505 506
	 * Retrieve the <em>default value</em> of a named Annotation attribute, given the {@link Class annotation type}.
	 * @param annotationType the <em>annotation type</em> for which the default value should be retrieved
A
Arjen Poutsma 已提交
507
	 * @param attributeName the name of the attribute value to retrieve.
508
	 * @return the default value of the named attribute, or {@code null} if not found
A
Arjen Poutsma 已提交
509 510 511 512 513 514 515 516 517 518 519 520 521
	 * @see #getDefaultValue(Annotation, String)
	 */
	public static Object getDefaultValue(Class<? extends Annotation> annotationType, String attributeName) {
		try {
			Method method = annotationType.getDeclaredMethod(attributeName, new Class[0]);
			return method.getDefaultValue();
		}
		catch (Exception ex) {
			return null;
		}
	}

}