Nested annotations will be
- * {@linkplain #synthesizeAnnotation(AnnotatedElement, Annotation) synthesized}.
+ * {@linkplain #synthesizeAnnotation(Annotation, AnnotatedElement) synthesized}.
* @param annotatedElement the element that is annotated, used for contextual
* logging; may be {@code null} if unknown
* @param value the annotation attribute value
@@ -892,7 +892,7 @@ public abstract class AnnotationUtils {
nestedAnnotationsAsMap);
}
else {
- return synthesizeAnnotation(annotatedElement, annotation);
+ return synthesizeAnnotation(annotation, annotatedElement);
}
}
@@ -910,7 +910,7 @@ public abstract class AnnotationUtils {
else {
Annotation[] synthesizedAnnotations = new Annotation[annotations.length];
for (int i = 0; i < annotations.length; i++) {
- synthesizedAnnotations[i] = synthesizeAnnotation(annotatedElement, annotations[i]);
+ synthesizedAnnotations[i] = synthesizeAnnotation(annotations[i], annotatedElement);
}
return synthesizedAnnotations;
}
@@ -1009,26 +1009,42 @@ public abstract class AnnotationUtils {
}
/**
- * TODO Document synthesizeAnnotation().
+ * Synthesize the supplied {@code annotation} by wrapping it in
+ * a dynamic proxy that transparently enforces attribute alias
+ * semantics for annotation attributes that are annotated with
+ * {@link AliasFor @AliasFor}.
*
* @param annotation the annotation to synthesize
+ * @return the synthesized annotation, if the supplied annotation is
+ * synthesizable; {@code null} if the supplied annotation is
+ * {@code null}; otherwise, the supplied annotation unmodified
+ * @throws AnnotationConfigurationException if invalid configuration of
+ * {@code @AliasFor} is detected
* @since 4.2
- * @see #synthesizeAnnotation(AnnotatedElement, Annotation)
+ * @see #synthesizeAnnotation(Annotation, AnnotatedElement)
*/
- public static A synthesizeAnnotation(A annotation) {
- return synthesizeAnnotation(null, annotation);
+ static A synthesizeAnnotation(A annotation) {
+ return synthesizeAnnotation(annotation, null);
}
/**
- * TODO Document synthesizeAnnotation().
+ * Synthesize the supplied {@code annotation} by wrapping it in
+ * a dynamic proxy that transparently enforces attribute alias
+ * semantics for annotation attributes that are annotated with
+ * {@link AliasFor @AliasFor}.
*
- * @param annotatedElement the element that is annotated with the supplied
- * annotation, used for contextual logging; may be {@code null} if unknown
* @param annotation the annotation to synthesize
+ * @param annotatedElement the element that is annotated with the supplied
+ * annotation; may be {@code null} if unknown
+ * @return the synthesized annotation, if the supplied annotation is
+ * synthesizable; {@code null} if the supplied annotation is
+ * {@code null}; otherwise, the supplied annotation unmodified
+ * @throws AnnotationConfigurationException if invalid configuration of
+ * {@code @AliasFor} is detected
* @since 4.2
*/
@SuppressWarnings("unchecked")
- public static A synthesizeAnnotation(AnnotatedElement annotatedElement, A annotation) {
+ public static A synthesizeAnnotation(A annotation, AnnotatedElement annotatedElement) {
if (annotation == null) {
return null;
}
@@ -1438,7 +1454,7 @@ public abstract class AnnotationUtils {
for (Annotation ann : element.getAnnotations()) {
Class extends Annotation> currentAnnotationType = ann.annotationType();
if (ObjectUtils.nullSafeEquals(this.annotationType, currentAnnotationType)) {
- this.result.add(synthesizeAnnotation(element, (A) ann));
+ this.result.add(synthesizeAnnotation((A) ann, element));
}
else if (ObjectUtils.nullSafeEquals(this.containerAnnotationType, currentAnnotationType)) {
this.result.addAll(getValue(element, ann));
@@ -1463,7 +1479,7 @@ public abstract class AnnotationUtils {
List synthesizedAnnotations = new ArrayList();
for (A anno : annotations) {
- synthesizedAnnotations.add(synthesizeAnnotation(element, anno));
+ synthesizedAnnotations.add(synthesizeAnnotation(anno, element));
}
return synthesizedAnnotations;
}
diff --git a/spring-core/src/main/java/org/springframework/core/annotation/SynthesizedAnnotationInvocationHandler.java b/spring-core/src/main/java/org/springframework/core/annotation/SynthesizedAnnotationInvocationHandler.java
index a4b6555a197..e6dfa647487 100644
--- a/spring-core/src/main/java/org/springframework/core/annotation/SynthesizedAnnotationInvocationHandler.java
+++ b/spring-core/src/main/java/org/springframework/core/annotation/SynthesizedAnnotationInvocationHandler.java
@@ -26,10 +26,20 @@ import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
/**
- * TODO Document SynthesizedAnnotationInvocationHandler.
+ * {@link InvocationHandler} for an {@link Annotation} that Spring has
+ * synthesized (i.e., wrapped in a dynamic proxy) with additional
+ * functionality.
+ *
+ * {@code SynthesizedAnnotationInvocationHandler} transparently enforces
+ * attribute alias semantics for annotation attributes that are annotated
+ * with {@link AliasFor @AliasFor}. In addition, nested annotations and
+ * arrays of nested annotations will be synthesized upon first access (i.e.,
+ * lazily).
*
* @author Sam Brannen
* @since 4.2
+ * @see AliasFor
+ * @see AnnotationUtils#synthesizeAnnotation(Annotation, AnnotatedElement)
*/
class SynthesizedAnnotationInvocationHandler implements InvocationHandler {
@@ -37,18 +47,17 @@ class SynthesizedAnnotationInvocationHandler implements InvocationHandler {
private final Annotation annotation;
- private final Map