Skip to content

Commit 7252920

Browse files
committed
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
1 parent 90493f4 commit 7252920

File tree

35 files changed

+169
-83
lines changed

35 files changed

+169
-83
lines changed

spring-context/src/main/java/org/springframework/cache/annotation/CacheEvict.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
/**
4545
* Alias for {@link #cacheNames}.
4646
*/
47-
@AliasFor(attribute = "cacheNames")
47+
@AliasFor("cacheNames")
4848
String[] value() default {};
4949

5050
/**
@@ -55,7 +55,7 @@
5555
* @see #value
5656
* @see CacheConfig#cacheNames
5757
*/
58-
@AliasFor(attribute = "value")
58+
@AliasFor("value")
5959
String[] cacheNames() default {};
6060

6161
/**

spring-context/src/main/java/org/springframework/cache/annotation/CachePut.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
/**
5151
* Alias for {@link #cacheNames}.
5252
*/
53-
@AliasFor(attribute = "cacheNames")
53+
@AliasFor("cacheNames")
5454
String[] value() default {};
5555

5656
/**
@@ -61,7 +61,7 @@
6161
* @see #value
6262
* @see CacheConfig#cacheNames
6363
*/
64-
@AliasFor(attribute = "value")
64+
@AliasFor("value")
6565
String[] cacheNames() default {};
6666

6767
/**

spring-context/src/main/java/org/springframework/cache/annotation/Cacheable.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
/**
5656
* Alias for {@link #cacheNames}.
5757
*/
58-
@AliasFor(attribute = "cacheNames")
58+
@AliasFor("cacheNames")
5959
String[] value() default {};
6060

6161
/**
@@ -66,7 +66,7 @@
6666
* @see #value
6767
* @see CacheConfig#cacheNames
6868
*/
69-
@AliasFor(attribute = "value")
69+
@AliasFor("value")
7070
String[] cacheNames() default {};
7171

7272
/**

spring-context/src/main/java/org/springframework/context/annotation/ComponentScan.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@
6262
* are needed — for example, {@code @ComponentScan("org.my.pkg")}
6363
* instead of {@code @ComponentScan(basePackages = "org.my.pkg")}.
6464
*/
65-
@AliasFor(attribute = "basePackages")
65+
@AliasFor("basePackages")
6666
String[] value() default {};
6767

6868
/**
@@ -72,7 +72,7 @@
7272
* <p>Use {@link #basePackageClasses} for a type-safe alternative to
7373
* String-based package names.
7474
*/
75-
@AliasFor(attribute = "value")
75+
@AliasFor("value")
7676
String[] basePackages() default {};
7777

7878
/**
@@ -166,7 +166,7 @@
166166
* Alias for {@link #classes}.
167167
* @see #classes
168168
*/
169-
@AliasFor(attribute = "classes")
169+
@AliasFor("classes")
170170
Class<?>[] value() default {};
171171

172172
/**
@@ -190,7 +190,7 @@
190190
* @see #value
191191
* @see #type
192192
*/
193-
@AliasFor(attribute = "value")
193+
@AliasFor("value")
194194
Class<?>[] classes() default {};
195195

196196
/**

spring-context/src/main/java/org/springframework/context/annotation/ImportResource.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
* @see #locations
6060
* @see #reader
6161
*/
62-
@AliasFor(attribute = "locations")
62+
@AliasFor("locations")
6363
String[] value() default {};
6464

6565
/**
@@ -72,7 +72,7 @@
7272
* @see #value
7373
* @see #reader
7474
*/
75-
@AliasFor(attribute = "value")
75+
@AliasFor("value")
7676
String[] locations() default {};
7777

7878
/**

spring-context/src/main/java/org/springframework/context/annotation/Scope.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161
* Alias for {@link #scopeName}.
6262
* @see #scopeName
6363
*/
64-
@AliasFor(attribute = "scopeName")
64+
@AliasFor("scopeName")
6565
String value() default "";
6666

6767
/**
@@ -75,7 +75,7 @@
7575
* @see org.springframework.web.context.WebApplicationContext#SCOPE_SESSION
7676
* @see #value
7777
*/
78-
@AliasFor(attribute = "value")
78+
@AliasFor("value")
7979
String scopeName() default "";
8080

8181
/**

spring-context/src/main/java/org/springframework/context/event/EventListener.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@
6969
/**
7070
* Alias for {@link #classes}.
7171
*/
72-
@AliasFor(attribute = "classes")
72+
@AliasFor("classes")
7373
Class<?>[] value() default {};
7474

7575
/**
@@ -79,7 +79,7 @@
7979
* attribute is specified with multiple values, the annotated method
8080
* must <em>not</em> declare any parameters.
8181
*/
82-
@AliasFor(attribute = "value")
82+
@AliasFor("value")
8383
Class<?>[] classes() default {};
8484

8585
/**

spring-context/src/main/java/org/springframework/jmx/export/annotation/ManagedResource.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,10 @@
4949
/**
5050
* Alias for the {@link #objectName} attribute, for simple default usage.
5151
*/
52-
@AliasFor(attribute = "objectName")
52+
@AliasFor("objectName")
5353
String value() default "";
5454

55-
@AliasFor(attribute = "value")
55+
@AliasFor("value")
5656
String objectName() default "";
5757

5858
String description() default "";

spring-core/src/main/java/org/springframework/core/annotation/AliasFor.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,10 +119,22 @@
119119
@Documented
120120
public @interface AliasFor {
121121

122+
/**
123+
* Alias for {@link #attribute}.
124+
* <p>Intended to be used instead of {@link #attribute} when {@link #annotation}
125+
* is not declared &mdash; for example: {@code @AliasFor("value")} instead of
126+
* {@code @AliasFor(attribute = "value")}.
127+
*/
128+
@AliasFor("attribute")
129+
String value() default "";
130+
122131
/**
123132
* The name of the attribute that <em>this</em> attribute is an alias for.
133+
* @see #value
124134
*/
125-
String attribute();
135+
@AliasFor("value")
136+
String attribute() default "";
137+
126138

127139
/**
128140
* The type of annotation in which the aliased {@link #attribute} is declared.

spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1427,7 +1427,7 @@ else if (Annotation.class.isAssignableFrom(returnType)) {
14271427
* @see #getAliasedAttributeName(Method, Class)
14281428
*/
14291429
static String getAliasedAttributeName(Method attribute) {
1430-
return getAliasedAttributeName(attribute, null);
1430+
return getAliasedAttributeName(attribute, (Class<? extends Annotation>) null);
14311431
}
14321432

14331433
/**
@@ -1471,7 +1471,7 @@ static String getAliasedAttributeName(Method attribute, Class<? extends Annotati
14711471
}
14721472

14731473
String attributeName = attribute.getName();
1474-
String aliasedAttributeName = aliasFor.attribute();
1474+
String aliasedAttributeName = getAliasedAttributeName(aliasFor, attribute);
14751475

14761476
if (!StringUtils.hasText(aliasedAttributeName)) {
14771477
String msg = String.format(
@@ -1503,7 +1503,7 @@ static String getAliasedAttributeName(Method attribute, Class<? extends Annotati
15031503
throw new AnnotationConfigurationException(msg);
15041504
}
15051505

1506-
String mirrorAliasedAttributeName = mirrorAliasFor.attribute();
1506+
String mirrorAliasedAttributeName = getAliasedAttributeName(mirrorAliasFor, aliasedAttribute);
15071507
if (!attributeName.equals(mirrorAliasedAttributeName)) {
15081508
String msg = String.format(
15091509
"Attribute [%s] in annotation [%s] must be declared as an @AliasFor [%s], not [%s].",
@@ -1543,6 +1543,38 @@ static String getAliasedAttributeName(Method attribute, Class<? extends Annotati
15431543
return aliasedAttributeName;
15441544
}
15451545

1546+
/**
1547+
* Get the name of the aliased attribute configured via the supplied
1548+
* {@link AliasFor @AliasFor} annotation on the supplied {@code attribute}.
1549+
* <p>This method returns the value of either the {@code attribute}
1550+
* or {@code value} attribute of {@code @AliasFor}, ensuring that only
1551+
* one of the attributes has been declared.
1552+
* @param aliasFor the {@code @AliasFor} annotation from which to retrieve
1553+
* the aliased attribute name
1554+
* @param attribute the attribute that is annotated with {@code @AliasFor},
1555+
* used solely for building an exception message
1556+
* @return the name of the aliased attribute, potentially an empty string
1557+
* @throws AnnotationConfigurationException if invalid configuration of
1558+
* {@code @AliasFor} is detected
1559+
* @since 4.2
1560+
* @see #getAliasedAttributeName(Method, Class)
1561+
*/
1562+
private static String getAliasedAttributeName(AliasFor aliasFor, Method attribute) {
1563+
String attributeName = aliasFor.attribute();
1564+
String value = aliasFor.value();
1565+
boolean attributeDeclared = StringUtils.hasText(attributeName);
1566+
boolean valueDeclared = StringUtils.hasText(value);
1567+
1568+
if (attributeDeclared && valueDeclared) {
1569+
throw new AnnotationConfigurationException(String.format(
1570+
"In @AliasFor declared on attribute [%s] in annotation [%s], attribute 'attribute' and its alias 'value' "
1571+
+ "are present with values of [%s] and [%s], but only one is permitted.",
1572+
attribute.getName(), attribute.getDeclaringClass().getName(), attributeName, value));
1573+
}
1574+
1575+
return (attributeDeclared ? attributeName : value);
1576+
}
1577+
15461578
/**
15471579
* Get all methods declared in the supplied {@code annotationType} that
15481580
* match Java's requirements for annotation <em>attributes</em>.

0 commit comments

Comments
 (0)