From 197f6594f4b04482f64402cf423e0607adafb843 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Sun, 24 May 2015 17:20:49 +0200 Subject: [PATCH] Simplify annotation attribute override algorithm Issue: SPR-11513 --- .../annotation/AnnotatedElementUtils.java | 37 +++++++------------ .../core/annotation/AnnotationUtils.java | 34 ++++++++--------- 2 files changed, 30 insertions(+), 41 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java b/spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java index 27c1201b95..60ebf16335 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java @@ -31,7 +31,6 @@ import org.springframework.core.BridgeMethodResolver; import org.springframework.util.Assert; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; -import org.springframework.util.ReflectionUtils; import org.springframework.util.StringUtils; /** @@ -941,35 +940,25 @@ public class AnnotatedElementUtils { targetAnnotationType); // Explicit annotation attribute override declared via @AliasFor - if (StringUtils.hasText(aliasedAttributeName)) { - if (attributes.containsKey(aliasedAttributeName)) { - Object value = AnnotationUtils.getValue(annotation, attributeName); - attributes.put(aliasedAttributeName, AnnotationUtils.adaptValue(element, value, - this.classValuesAsString, this.nestedAnnotationsAsMap)); - } + if (StringUtils.hasText(aliasedAttributeName) && attributes.containsKey(aliasedAttributeName)) { + overrideAttribute(element, annotation, attributes, attributeName, aliasedAttributeName); } // Implicit annotation attribute override based on convention else if (!AnnotationUtils.VALUE.equals(attributeName) && attributes.containsKey(attributeName)) { - Object value = AnnotationUtils.getValue(annotation, attributeName); - Object adaptedValue = AnnotationUtils.adaptValue(element, value, this.classValuesAsString, - this.nestedAnnotationsAsMap); - attributes.put(attributeName, adaptedValue); - - // If an aliased attribute defined by @AliasFor semantics does not - // already have an explicit value, ensure that the aliased attribute - // is also present in the map with a value identical to its mirror - // alias. - Method attributeMethodInTarget = ReflectionUtils.findMethod(targetAnnotationType, attributeName); - if (attributeMethodInTarget != null) { - String aliasedAttributeNameInTarget = AnnotationUtils.getAliasedAttributeName( - attributeMethodInTarget, null); - if (aliasedAttributeNameInTarget != null) { - attributes.putIfAbsent(aliasedAttributeNameInTarget, adaptedValue); - } - } + overrideAttribute(element, annotation, attributes, attributeName, attributeName); } } } + + private void overrideAttribute(AnnotatedElement element, Annotation annotation, + AnnotationAttributes attributes, String sourceAttributeName, String targetAttributeName) { + + Object value = AnnotationUtils.getValue(annotation, sourceAttributeName); + Object adaptedValue = AnnotationUtils.adaptValue(element, value, this.classValuesAsString, + this.nestedAnnotationsAsMap); + attributes.put(targetAttributeName, adaptedValue); + } + } } diff --git a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java index 0302c13498..0a5f7246c3 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java @@ -107,7 +107,7 @@ public abstract class AnnotationUtils { * An object that can be stored in {@link AnnotationAttributes} as a * placeholder for an attribute's declared default value. */ - private static final Object DEFAULT_VALUE_PLACEHOLDER = ""; + private static final Object DEFAULT_VALUE_PLACEHOLDER = new String(""); private static final Map findAnnotationCache = new ConcurrentReferenceHashMap(256); @@ -803,15 +803,15 @@ public abstract class AnnotationUtils { *

This method provides fully recursive annotation reading capabilities on par with * the reflection-based {@link org.springframework.core.type.StandardAnnotationMetadata}. * - *

NOTE: this variant of {@code getAnnotationAttributes()} is - * only intended for use within the framework. Specifically, the - * {@code defaultValuesAsPlaceholder} flag can be set to {@code true} in order to - * support processing of attribute aliases while merging attributes within an annotation - * hierarchy. If this method is invoked with {@code defaultValuesAsPlaceholder} set to - * {@code true}: + *

NOTE: This variant of {@code getAnnotationAttributes()} is + * only intended for use within the framework. Specifically, the {@code mergeMode} flag + * can be set to {@code true} in order to support processing of attribute aliases while + * merging attributes within an annotation hierarchy. When running in merge mode, + * the following special rules apply: *

    *
  1. The supplied annotation will not be * {@linkplain #synthesizeAnnotation synthesized} before retrieving its attributes.
  2. + *
  3. Default values will be replaced with {@link #DEFAULT_VALUE_PLACEHOLDER}.
  4. *
  5. The resulting, merged annotation attributes should eventually be * {@linkplain #postProcessAnnotationAttributes post-processed} in order to * ensure that placeholders have been replaced by actual default values and @@ -828,17 +828,17 @@ public abstract class AnnotationUtils { * {@link AnnotationAttributes} maps (for compatibility with * {@link org.springframework.core.type.AnnotationMetadata}) or to preserve them as * {@code Annotation} instances - * @param defaultValuesAsPlaceholder whether to replace default values with - * {@link #DEFAULT_VALUE_PLACEHOLDER} or leave them as is + * @param mergeMode whether the annotation attributes should be created + * using merge mode * @return the annotation attributes (a specialized Map) with attribute names as keys * and corresponding attribute values as values; never {@code null} * @since 4.2 * @see #postProcessAnnotationAttributes */ static AnnotationAttributes getAnnotationAttributes(AnnotatedElement annotatedElement, Annotation annotation, - boolean classValuesAsString, boolean nestedAnnotationsAsMap, boolean defaultValuesAsPlaceholder) { + boolean classValuesAsString, boolean nestedAnnotationsAsMap, boolean mergeMode) { - if (!defaultValuesAsPlaceholder) { + if (!mergeMode) { annotation = synthesizeAnnotation(annotation, annotatedElement); } @@ -848,7 +848,7 @@ public abstract class AnnotationUtils { try { Object value = method.invoke(annotation); Object defaultValue = method.getDefaultValue(); - if (defaultValuesAsPlaceholder && (defaultValue != null)) { + if (mergeMode && (defaultValue != null)) { if (ObjectUtils.nullSafeEquals(value, defaultValue)) { value = DEFAULT_VALUE_PLACEHOLDER; } @@ -1390,8 +1390,8 @@ public abstract class AnnotationUtils { Object value = attributes.get(attributeName); Object aliasedValue = attributes.get(aliasedAttributeName); - if (!ObjectUtils.nullSafeEquals(value, aliasedValue) && !DEFAULT_VALUE_PLACEHOLDER.equals(value) - && !DEFAULT_VALUE_PLACEHOLDER.equals(aliasedValue)) { + if (!ObjectUtils.nullSafeEquals(value, aliasedValue) && (value != DEFAULT_VALUE_PLACEHOLDER) + && (aliasedValue != DEFAULT_VALUE_PLACEHOLDER)) { String elementAsString = (element == null ? "unknown element" : element.toString()); String msg = String.format( "In AnnotationAttributes for annotation [%s] declared on [%s], attribute [%s] and its alias [%s] are " @@ -1402,11 +1402,11 @@ public abstract class AnnotationUtils { } // Replace default values with aliased values... - if (DEFAULT_VALUE_PLACEHOLDER.equals(value)) { + if (value == DEFAULT_VALUE_PLACEHOLDER) { attributes.put(attributeName, adaptValue(element, aliasedValue, classValuesAsString, nestedAnnotationsAsMap)); } - if (DEFAULT_VALUE_PLACEHOLDER.equals(aliasedValue)) { + if (aliasedValue == DEFAULT_VALUE_PLACEHOLDER) { attributes.put(aliasedAttributeName, adaptValue(element, value, classValuesAsString, nestedAnnotationsAsMap)); } @@ -1415,7 +1415,7 @@ public abstract class AnnotationUtils { for (String attributeName : attributes.keySet()) { Object value = attributes.get(attributeName); - if (DEFAULT_VALUE_PLACEHOLDER.equals(value)) { + if (value == DEFAULT_VALUE_PLACEHOLDER) { attributes.put(attributeName, adaptValue(element, getDefaultValue(annotationType, attributeName), classValuesAsString, nestedAnnotationsAsMap));