Introduce 'value' alias for 'attribute' in @AliasFor
SPR-11512 introduced support for annotation attribute aliases via
@AliasFor, requiring the explicit declaration of the 'attribute'
attribute. However, for aliases within an annotation, this explicit
declaration is unnecessary.
This commit improves the readability of alias pairs declared within an
annotation by introducing a 'value' attribute in @AliasFor that is an
alias for the existing 'attribute' attribute. This allows annotations
such as @ContextConfiguration from the spring-test module to declare
aliases as follows.
public @interface ContextConfiguration {
@AliasFor("locations")
String[] value() default {};
@AliasFor("value")
String[] locations() default {};
// ...
}
Issue: SPR-13289
This commit is contained in:
@@ -120,9 +120,21 @@ import java.lang.annotation.Target;
|
||||
public @interface AliasFor {
|
||||
|
||||
/**
|
||||
* The name of the attribute that <em>this</em> attribute is an alias for.
|
||||
* Alias for {@link #attribute}.
|
||||
* <p>Intended to be used instead of {@link #attribute} when {@link #annotation}
|
||||
* is not declared — for example: {@code @AliasFor("value")} instead of
|
||||
* {@code @AliasFor(attribute = "value")}.
|
||||
*/
|
||||
String attribute();
|
||||
@AliasFor("attribute")
|
||||
String value() default "";
|
||||
|
||||
/**
|
||||
* The name of the attribute that <em>this</em> attribute is an alias for.
|
||||
* @see #value
|
||||
*/
|
||||
@AliasFor("value")
|
||||
String attribute() default "";
|
||||
|
||||
|
||||
/**
|
||||
* The type of annotation in which the aliased {@link #attribute} is declared.
|
||||
|
||||
@@ -1427,7 +1427,7 @@ public abstract class AnnotationUtils {
|
||||
* @see #getAliasedAttributeName(Method, Class)
|
||||
*/
|
||||
static String getAliasedAttributeName(Method attribute) {
|
||||
return getAliasedAttributeName(attribute, null);
|
||||
return getAliasedAttributeName(attribute, (Class<? extends Annotation>) null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1471,7 +1471,7 @@ public abstract class AnnotationUtils {
|
||||
}
|
||||
|
||||
String attributeName = attribute.getName();
|
||||
String aliasedAttributeName = aliasFor.attribute();
|
||||
String aliasedAttributeName = getAliasedAttributeName(aliasFor, attribute);
|
||||
|
||||
if (!StringUtils.hasText(aliasedAttributeName)) {
|
||||
String msg = String.format(
|
||||
@@ -1503,7 +1503,7 @@ public abstract class AnnotationUtils {
|
||||
throw new AnnotationConfigurationException(msg);
|
||||
}
|
||||
|
||||
String mirrorAliasedAttributeName = mirrorAliasFor.attribute();
|
||||
String mirrorAliasedAttributeName = getAliasedAttributeName(mirrorAliasFor, aliasedAttribute);
|
||||
if (!attributeName.equals(mirrorAliasedAttributeName)) {
|
||||
String msg = String.format(
|
||||
"Attribute [%s] in annotation [%s] must be declared as an @AliasFor [%s], not [%s].",
|
||||
@@ -1543,6 +1543,38 @@ public abstract class AnnotationUtils {
|
||||
return aliasedAttributeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the aliased attribute configured via the supplied
|
||||
* {@link AliasFor @AliasFor} annotation on the supplied {@code attribute}.
|
||||
* <p>This method returns the value of either the {@code attribute}
|
||||
* or {@code value} attribute of {@code @AliasFor}, ensuring that only
|
||||
* one of the attributes has been declared.
|
||||
* @param aliasFor the {@code @AliasFor} annotation from which to retrieve
|
||||
* the aliased attribute name
|
||||
* @param attribute the attribute that is annotated with {@code @AliasFor},
|
||||
* used solely for building an exception message
|
||||
* @return the name of the aliased attribute, potentially an empty string
|
||||
* @throws AnnotationConfigurationException if invalid configuration of
|
||||
* {@code @AliasFor} is detected
|
||||
* @since 4.2
|
||||
* @see #getAliasedAttributeName(Method, Class)
|
||||
*/
|
||||
private static String getAliasedAttributeName(AliasFor aliasFor, Method attribute) {
|
||||
String attributeName = aliasFor.attribute();
|
||||
String value = aliasFor.value();
|
||||
boolean attributeDeclared = StringUtils.hasText(attributeName);
|
||||
boolean valueDeclared = StringUtils.hasText(value);
|
||||
|
||||
if (attributeDeclared && valueDeclared) {
|
||||
throw new AnnotationConfigurationException(String.format(
|
||||
"In @AliasFor declared on attribute [%s] in annotation [%s], attribute 'attribute' and its alias 'value' "
|
||||
+ "are present with values of [%s] and [%s], but only one is permitted.",
|
||||
attribute.getName(), attribute.getDeclaringClass().getName(), attributeName, value));
|
||||
}
|
||||
|
||||
return (attributeDeclared ? attributeName : value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all methods declared in the supplied {@code annotationType} that
|
||||
* match Java's requirements for annotation <em>attributes</em>.
|
||||
|
||||
Reference in New Issue
Block a user