Skip to content

Commit 75187e3

Browse files
committed
Consistent detection of meta-annotation attributes via ASM
Issue: SPR-13394 (cherry picked from commit 3430f76)
1 parent 4ff23f4 commit 75187e3

File tree

3 files changed

+58
-23
lines changed

3 files changed

+58
-23
lines changed

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

Lines changed: 35 additions & 6 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-2015 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.
@@ -27,6 +27,7 @@
2727

2828
import org.springframework.aop.scope.ScopedObject;
2929
import org.springframework.aop.scope.ScopedProxyUtils;
30+
import org.springframework.aop.support.AopUtils;
3031
import org.springframework.beans.factory.BeanCreationException;
3132
import org.springframework.beans.factory.FactoryBean;
3233
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
@@ -280,6 +281,7 @@ public void scopedProxyTargetMarkedAsNonAutowireCandidate() {
280281
beanFactory.registerBeanDefinition("consumer", new RootBeanDefinition(ScopedProxyConsumer.class));
281282
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
282283
pp.postProcessBeanFactory(beanFactory);
284+
283285
ITestBean injected = beanFactory.getBean("consumer", ScopedProxyConsumer.class).testBean;
284286
assertTrue(injected instanceof ScopedObject);
285287
assertSame(beanFactory.getBean("scopedClass"), injected);
@@ -357,6 +359,28 @@ public void genericsBasedInjectionWithScopedProxy() {
357359
RepositoryInjectionBean bean = (RepositoryInjectionBean) beanFactory.getBean("annotatedBean");
358360
assertEquals("Repository<String>", bean.stringRepository.toString());
359361
assertEquals("Repository<Integer>", bean.integerRepository.toString());
362+
assertTrue(AopUtils.isCglibProxy(bean.stringRepository));
363+
assertTrue(AopUtils.isCglibProxy(bean.integerRepository));
364+
}
365+
366+
@Test
367+
public void genericsBasedInjectionWithScopedProxyUsingAsm() {
368+
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
369+
bpp.setBeanFactory(beanFactory);
370+
beanFactory.addBeanPostProcessor(bpp);
371+
RootBeanDefinition bd = new RootBeanDefinition(RepositoryInjectionBean.class.getName());
372+
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
373+
beanFactory.registerBeanDefinition("annotatedBean", bd);
374+
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(ScopedProxyRepositoryConfiguration.class.getName()));
375+
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
376+
pp.postProcessBeanFactory(beanFactory);
377+
beanFactory.freezeConfiguration();
378+
379+
RepositoryInjectionBean bean = (RepositoryInjectionBean) beanFactory.getBean("annotatedBean");
380+
assertEquals("Repository<String>", bean.stringRepository.toString());
381+
assertEquals("Repository<Integer>", bean.integerRepository.toString());
382+
assertTrue(AopUtils.isCglibProxy(bean.stringRepository));
383+
assertTrue(AopUtils.isCglibProxy(bean.integerRepository));
360384
}
361385

362386
@Test
@@ -487,13 +511,11 @@ public void testSingletonArgumentsThroughBeanMethodCall() {
487511
@Configuration
488512
static class SingletonBeanConfig {
489513

490-
public @Bean
491-
Foo foo() {
514+
public @Bean Foo foo() {
492515
return new Foo();
493516
}
494517

495-
public @Bean
496-
Bar bar() {
518+
public @Bean Bar bar() {
497519
return new Bar(foo());
498520
}
499521
}
@@ -650,6 +672,13 @@ public String toString() {
650672
}
651673
}
652674

675+
@Retention(RetentionPolicy.RUNTIME)
676+
@Scope(value = "prototype")
677+
public @interface PrototypeScoped {
678+
679+
ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;
680+
}
681+
653682
@Configuration
654683
public static class ScopedProxyRepositoryConfiguration {
655684

@@ -665,7 +694,7 @@ public String toString() {
665694
}
666695

667696
@Bean
668-
@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
697+
@PrototypeScoped
669698
public Repository<Integer> integerRepo() {
670699
return new Repository<Integer>() {
671700
@Override

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

Lines changed: 9 additions & 6 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-2015 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,8 @@ public class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisito
5858
* to ensure that the hierarchical ordering of the entries is preserved.
5959
* @see AnnotationReadingVisitorUtils#getMergedAnnotationAttributes
6060
*/
61-
protected final LinkedMultiValueMap<String, AnnotationAttributes> attributesMap = new LinkedMultiValueMap<String, AnnotationAttributes>(4);
61+
protected final LinkedMultiValueMap<String, AnnotationAttributes> attributesMap =
62+
new LinkedMultiValueMap<String, AnnotationAttributes>(4);
6263

6364
protected final Set<MethodMetadata> methodMetadataSet = new LinkedHashSet<MethodMetadata>(4);
6465

@@ -75,14 +76,16 @@ public MethodVisitor visitMethod(int access, String name, String desc, String si
7576
if ((access & Opcodes.ACC_BRIDGE) != 0) {
7677
return super.visitMethod(access, name, desc, signature, exceptions);
7778
}
78-
return new MethodMetadataReadingVisitor(name, access, getClassName(), this.classLoader, this.methodMetadataSet);
79+
return new MethodMetadataReadingVisitor(
80+
name, access, getClassName(), this.classLoader, this.methodMetadataSet);
7981
}
8082

8183
@Override
8284
public AnnotationVisitor visitAnnotation(final String desc, boolean visible) {
8385
String className = Type.getType(desc).getClassName();
8486
this.annotationSet.add(className);
85-
return new AnnotationAttributesReadingVisitor(className, this.attributesMap, this.metaAnnotationMap, this.classLoader);
87+
return new AnnotationAttributesReadingVisitor(
88+
className, this.attributesMap, this.metaAnnotationMap, this.classLoader);
8689
}
8790

8891

@@ -142,8 +145,8 @@ public MultiValueMap<String, Object> getAllAnnotationAttributes(String annotatio
142145
return null;
143146
}
144147
for (AnnotationAttributes raw : attributes) {
145-
for (Map.Entry<String, Object> entry :
146-
AnnotationReadingVisitorUtils.convertClassValues(this.classLoader, raw, classValuesAsString).entrySet()) {
148+
for (Map.Entry<String, Object> entry : AnnotationReadingVisitorUtils.convertClassValues(
149+
this.classLoader, raw, classValuesAsString).entrySet()) {
147150
allAttributes.add(entry.getKey(), entry.getValue());
148151
}
149152
}

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

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2013 the original author or authors.
2+
* Copyright 2002-2015 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.
@@ -16,7 +16,7 @@
1616

1717
package org.springframework.core.type.classreading;
1818

19-
import java.util.List;
19+
import java.util.LinkedHashMap;
2020
import java.util.Map;
2121
import java.util.Set;
2222

@@ -31,7 +31,7 @@
3131
import org.springframework.util.MultiValueMap;
3232

3333
/**
34-
* ASM method visitor which looks for the annotations defined on the method,
34+
* ASM method visitor which looks for the annotations defined on a method,
3535
* exposing them through the {@link org.springframework.core.type.MethodMetadata}
3636
* interface.
3737
*
@@ -54,7 +54,9 @@ public class MethodMetadataReadingVisitor extends MethodVisitor implements Metho
5454

5555
protected final Set<MethodMetadata> methodMetadataSet;
5656

57-
protected final MultiValueMap<String, AnnotationAttributes> attributeMap =
57+
protected final Map<String, Set<String>> metaAnnotationMap = new LinkedHashMap<String, Set<String>>(4);
58+
59+
protected final LinkedMultiValueMap<String, AnnotationAttributes> attributesMap =
5860
new LinkedMultiValueMap<String, AnnotationAttributes>(4);
5961

6062

@@ -74,7 +76,8 @@ public MethodMetadataReadingVisitor(String name, int access, String declaringCla
7476
public AnnotationVisitor visitAnnotation(final String desc, boolean visible) {
7577
String className = Type.getType(desc).getClassName();
7678
this.methodMetadataSet.add(this);
77-
return new AnnotationAttributesReadingVisitor(className, this.attributeMap, null, this.classLoader);
79+
return new AnnotationAttributesReadingVisitor(
80+
className, this.attributesMap, this.metaAnnotationMap, this.classLoader);
7881
}
7982

8083
@Override
@@ -99,7 +102,7 @@ public boolean isOverridable() {
99102

100103
@Override
101104
public boolean isAnnotated(String annotationType) {
102-
return this.attributeMap.containsKey(annotationType);
105+
return this.attributesMap.containsKey(annotationType);
103106
}
104107

105108
@Override
@@ -109,9 +112,9 @@ public Map<String, Object> getAnnotationAttributes(String annotationType) {
109112

110113
@Override
111114
public Map<String, Object> getAnnotationAttributes(String annotationType, boolean classValuesAsString) {
112-
List<AnnotationAttributes> attributes = this.attributeMap.get(annotationType);
113-
return (attributes == null ? null : AnnotationReadingVisitorUtils.convertClassValues(
114-
this.classLoader, attributes.get(0), classValuesAsString));
115+
AnnotationAttributes raw = AnnotationReadingVisitorUtils.getMergedAnnotationAttributes(
116+
this.attributesMap, this.metaAnnotationMap, annotationType);
117+
return AnnotationReadingVisitorUtils.convertClassValues(this.classLoader, raw, classValuesAsString);
115118
}
116119

117120
@Override
@@ -121,11 +124,11 @@ public MultiValueMap<String, Object> getAllAnnotationAttributes(String annotatio
121124

122125
@Override
123126
public MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationType, boolean classValuesAsString) {
124-
if (!this.attributeMap.containsKey(annotationType)) {
127+
if (!this.attributesMap.containsKey(annotationType)) {
125128
return null;
126129
}
127130
MultiValueMap<String, Object> allAttributes = new LinkedMultiValueMap<String, Object>();
128-
for (AnnotationAttributes annotationAttributes : this.attributeMap.get(annotationType)) {
131+
for (AnnotationAttributes annotationAttributes : this.attributesMap.get(annotationType)) {
129132
for (Map.Entry<String, Object> entry : AnnotationReadingVisitorUtils.convertClassValues(
130133
this.classLoader, annotationAttributes, classValuesAsString).entrySet()) {
131134
allAttributes.add(entry.getKey(), entry.getValue());

0 commit comments

Comments
 (0)