Skip to content

Commit 7de2976

Browse files
committed
Consistent meta-annotation attributes lookup through ASM
Issue: SPR-14257 (cherry picked from commit 24f5f36)
1 parent cc77588 commit 7de2976

File tree

4 files changed

+76
-32
lines changed

4 files changed

+76
-32
lines changed

spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassWithConditionTests.java

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -22,12 +22,10 @@
2222
import java.lang.annotation.Target;
2323
import java.util.Map;
2424

25-
import org.junit.Rule;
2625
import org.junit.Test;
27-
import org.junit.rules.ExpectedException;
2826

29-
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
3027
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
28+
import org.springframework.beans.factory.support.RootBeanDefinition;
3129
import org.springframework.core.annotation.AnnotationAttributes;
3230
import org.springframework.core.type.AnnotatedTypeMetadata;
3331
import org.springframework.core.type.AnnotationMetadata;
@@ -45,9 +43,6 @@
4543
@SuppressWarnings("resource")
4644
public class ConfigurationClassWithConditionTests {
4745

48-
@Rule
49-
public ExpectedException thrown = ExpectedException.none();
50-
5146
@Test
5247
public void conditionalOnMissingBeanMatch() throws Exception {
5348
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
@@ -94,22 +89,44 @@ public void metaConditional() throws Exception {
9489
assertTrue(ctx.containsBean("bean"));
9590
}
9691

92+
@Test
93+
public void metaConditionalWithAsm() throws Exception {
94+
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
95+
ctx.registerBeanDefinition("config", new RootBeanDefinition(ConfigurationWithMetaCondition.class.getName()));
96+
ctx.refresh();
97+
assertTrue(ctx.containsBean("bean"));
98+
}
99+
97100
@Test
98101
public void nonConfigurationClass() throws Exception {
99102
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
100103
ctx.register(NonConfigurationClass.class);
101104
ctx.refresh();
102-
thrown.expect(NoSuchBeanDefinitionException.class);
103-
assertNull(ctx.getBean(NonConfigurationClass.class));
105+
assertFalse(ctx.containsBean("bean1"));
106+
}
107+
108+
@Test
109+
public void nonConfigurationClassWithAsm() throws Exception {
110+
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
111+
ctx.registerBeanDefinition("config", new RootBeanDefinition(NonConfigurationClass.class.getName()));
112+
ctx.refresh();
113+
assertFalse(ctx.containsBean("bean1"));
104114
}
105115

106116
@Test
107117
public void methodConditional() throws Exception {
108118
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
109119
ctx.register(ConditionOnMethodConfiguration.class);
110120
ctx.refresh();
111-
thrown.expect(NoSuchBeanDefinitionException.class);
112-
assertNull(ctx.getBean(ExampleBean.class));
121+
assertFalse(ctx.containsBean("bean1"));
122+
}
123+
124+
@Test
125+
public void methodConditionalWithAsm() throws Exception {
126+
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
127+
ctx.registerBeanDefinition("config", new RootBeanDefinition(ConditionOnMethodConfiguration.class.getName()));
128+
ctx.refresh();
129+
assertFalse(ctx.containsBean("bean1"));
113130
}
114131

115132
@Test
@@ -144,6 +161,7 @@ public void configWithAlternativeBeans() {
144161

145162
@Configuration
146163
static class BeanOneConfiguration {
164+
147165
@Bean
148166
public ExampleBean bean1() {
149167
return new ExampleBean();
@@ -153,6 +171,7 @@ public ExampleBean bean1() {
153171
@Configuration
154172
@Conditional(NoBeanOneCondition.class)
155173
static class BeanTwoConfiguration {
174+
156175
@Bean
157176
public ExampleBean bean2() {
158177
return new ExampleBean();
@@ -162,6 +181,7 @@ public ExampleBean bean2() {
162181
@Configuration
163182
@Conditional(HasBeanOneCondition.class)
164183
static class BeanThreeConfiguration {
184+
165185
@Bean
166186
public ExampleBean bean3() {
167187
return new ExampleBean();
@@ -171,6 +191,7 @@ public ExampleBean bean3() {
171191
@Configuration
172192
@MetaConditional("test")
173193
static class ConfigurationWithMetaCondition {
194+
174195
@Bean
175196
public ExampleBean bean() {
176197
return new ExampleBean();
@@ -180,14 +201,22 @@ public ExampleBean bean() {
180201
@Conditional(MetaConditionalFilter.class)
181202
@Retention(RetentionPolicy.RUNTIME)
182203
@Target(ElementType.TYPE)
183-
public static @interface MetaConditional {
204+
public @interface MetaConditional {
205+
184206
String value();
185207
}
186208

187209
@Conditional(NeverCondition.class)
188210
@Retention(RetentionPolicy.RUNTIME)
189211
@Target({ElementType.TYPE, ElementType.METHOD})
190-
public static @interface Never {
212+
public @interface Never {
213+
}
214+
215+
@Conditional(AlwaysCondition.class)
216+
@Never
217+
@Retention(RetentionPolicy.RUNTIME)
218+
@Target({ElementType.TYPE, ElementType.METHOD})
219+
public @interface MetaNever {
191220
}
192221

193222
static class NoBeanOneCondition implements Condition {
@@ -238,8 +267,13 @@ public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata)
238267
}
239268

240269
@Component
241-
@Never
270+
@MetaNever
242271
static class NonConfigurationClass {
272+
273+
@Bean
274+
public ExampleBean bean1() {
275+
return new ExampleBean();
276+
}
243277
}
244278

245279
@Configuration
@@ -254,7 +288,7 @@ public ExampleBean bean1() {
254288

255289
@Configuration
256290
@Never
257-
@Import({ ConfigurationNotCreated.class, RegistrarNotCreated.class, ImportSelectorNotCreated.class })
291+
@Import({ConfigurationNotCreated.class, RegistrarNotCreated.class, ImportSelectorNotCreated.class})
258292
static class ImportsNotCreated {
259293
static {
260294
if (true) throw new RuntimeException();

spring-core/src/main/java/org/springframework/core/type/classreading/AnnotationAttributesReadingVisitor.java

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -72,32 +72,43 @@ public void doVisitEnd(Class<?> annotationClass) {
7272
else {
7373
attributes.add(0, this.attributes);
7474
}
75-
Set<String> metaAnnotationTypeNames = new LinkedHashSet<String>();
75+
Set<Annotation> visited = new LinkedHashSet<Annotation>();
7676
Annotation[] metaAnnotations = AnnotationUtils.getAnnotations(annotationClass);
7777
if (!ObjectUtils.isEmpty(metaAnnotations)) {
7878
for (Annotation metaAnnotation : metaAnnotations) {
7979
if (!AnnotationUtils.isInJavaLangAnnotationPackage(metaAnnotation)) {
80-
recursivelyCollectMetaAnnotations(metaAnnotationTypeNames, metaAnnotation);
80+
recursivelyCollectMetaAnnotations(visited, metaAnnotation);
8181
}
8282
}
8383
}
8484
if (this.metaAnnotationMap != null) {
85+
Set<String> metaAnnotationTypeNames = new LinkedHashSet<String>(visited.size());
86+
for (Annotation ann : visited) {
87+
metaAnnotationTypeNames.add(ann.annotationType().getName());
88+
}
8589
this.metaAnnotationMap.put(annotationClass.getName(), metaAnnotationTypeNames);
8690
}
8791
}
8892

89-
private void recursivelyCollectMetaAnnotations(Set<String> visited, Annotation annotation) {
90-
String annotationName = annotation.annotationType().getName();
91-
if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation) && visited.add(annotationName)) {
92-
// Only do further scanning for public annotations; we'd run into
93-
// IllegalAccessExceptions otherwise, and we don't want to mess with
94-
// accessibility in a SecurityManager environment.
95-
if (Modifier.isPublic(annotation.annotationType().getModifiers())) {
96-
this.attributesMap.add(annotationName, AnnotationUtils.getAnnotationAttributes(annotation, false, true));
93+
private void recursivelyCollectMetaAnnotations(Set<Annotation> visited, Annotation annotation) {
94+
if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation) && visited.add(annotation)) {
95+
try {
96+
// Only do attribute scanning for public annotations; we'd run into
97+
// IllegalAccessExceptions otherwise, and we don't want to mess with
98+
// accessibility in a SecurityManager environment.
99+
if (Modifier.isPublic(annotation.annotationType().getModifiers())) {
100+
String annotationName = annotation.annotationType().getName();
101+
this.attributesMap.add(annotationName, AnnotationUtils.getAnnotationAttributes(annotation, false, true));
102+
}
97103
for (Annotation metaMetaAnnotation : annotation.annotationType().getAnnotations()) {
98104
recursivelyCollectMetaAnnotations(visited, metaMetaAnnotation);
99105
}
100106
}
107+
catch (Exception ex) {
108+
if (logger.isDebugEnabled()) {
109+
logger.debug("Failed to introspect meta-annotations on [" + annotation + "]: " + ex);
110+
}
111+
}
101112
}
102113
}
103114

spring-core/src/main/java/org/springframework/core/type/classreading/AnnotationReadingVisitorUtils.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -150,9 +150,8 @@ public static AnnotationAttributes getMergedAnnotationAttributes(
150150
for (String overridableAttributeName : overridableAttributeNames) {
151151
Object value = currentAttributes.get(overridableAttributeName);
152152
if (value != null) {
153-
// Store the value, potentially overriding a value from an
154-
// attribute of the same name found higher in the annotation
155-
// hierarchy.
153+
// Store the value, potentially overriding a value from an attribute
154+
// of the same name found higher in the annotation hierarchy.
156155
results.put(overridableAttributeName, value);
157156
}
158157
}

spring-core/src/main/java/org/springframework/core/type/classreading/RecursiveAnnotationAttributesVisitor.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -58,7 +58,7 @@ protected void doVisitEnd(Class<?> annotationClass) {
5858
}
5959

6060
private void registerDefaultValues(Class<?> annotationClass) {
61-
// Only do further scanning for public annotations; we'd run into
61+
// Only do defaults scanning for public annotations; we'd run into
6262
// IllegalAccessExceptions otherwise, and we don't want to mess with
6363
// accessibility in a SecurityManager environment.
6464
if (Modifier.isPublic(annotationClass.getModifiers())) {

0 commit comments

Comments
 (0)