Browse Source

Consistent detection of meta-annotation attributes via ASM

Issue: SPR-13394
(cherry picked from commit 3430f76)
pull/931/head
Juergen Hoeller 11 years ago
parent
commit
75187e3a8e
  1. 41
      spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java
  2. 15
      spring-core/src/main/java/org/springframework/core/type/classreading/AnnotationMetadataReadingVisitor.java
  3. 25
      spring-core/src/main/java/org/springframework/core/type/classreading/MethodMetadataReadingVisitor.java

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

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -27,6 +27,7 @@ import org.junit.Test; @@ -27,6 +27,7 @@ import org.junit.Test;
import org.springframework.aop.scope.ScopedObject;
import org.springframework.aop.scope.ScopedProxyUtils;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
@ -280,6 +281,7 @@ public class ConfigurationClassPostProcessorTests { @@ -280,6 +281,7 @@ public class ConfigurationClassPostProcessorTests {
beanFactory.registerBeanDefinition("consumer", new RootBeanDefinition(ScopedProxyConsumer.class));
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
pp.postProcessBeanFactory(beanFactory);
ITestBean injected = beanFactory.getBean("consumer", ScopedProxyConsumer.class).testBean;
assertTrue(injected instanceof ScopedObject);
assertSame(beanFactory.getBean("scopedClass"), injected);
@ -357,6 +359,28 @@ public class ConfigurationClassPostProcessorTests { @@ -357,6 +359,28 @@ public class ConfigurationClassPostProcessorTests {
RepositoryInjectionBean bean = (RepositoryInjectionBean) beanFactory.getBean("annotatedBean");
assertEquals("Repository<String>", bean.stringRepository.toString());
assertEquals("Repository<Integer>", bean.integerRepository.toString());
assertTrue(AopUtils.isCglibProxy(bean.stringRepository));
assertTrue(AopUtils.isCglibProxy(bean.integerRepository));
}
@Test
public void genericsBasedInjectionWithScopedProxyUsingAsm() {
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(beanFactory);
beanFactory.addBeanPostProcessor(bpp);
RootBeanDefinition bd = new RootBeanDefinition(RepositoryInjectionBean.class.getName());
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
beanFactory.registerBeanDefinition("annotatedBean", bd);
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(ScopedProxyRepositoryConfiguration.class.getName()));
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
pp.postProcessBeanFactory(beanFactory);
beanFactory.freezeConfiguration();
RepositoryInjectionBean bean = (RepositoryInjectionBean) beanFactory.getBean("annotatedBean");
assertEquals("Repository<String>", bean.stringRepository.toString());
assertEquals("Repository<Integer>", bean.integerRepository.toString());
assertTrue(AopUtils.isCglibProxy(bean.stringRepository));
assertTrue(AopUtils.isCglibProxy(bean.integerRepository));
}
@Test
@ -487,13 +511,11 @@ public class ConfigurationClassPostProcessorTests { @@ -487,13 +511,11 @@ public class ConfigurationClassPostProcessorTests {
@Configuration
static class SingletonBeanConfig {
public @Bean
Foo foo() {
public @Bean Foo foo() {
return new Foo();
}
public @Bean
Bar bar() {
public @Bean Bar bar() {
return new Bar(foo());
}
}
@ -650,6 +672,13 @@ public class ConfigurationClassPostProcessorTests { @@ -650,6 +672,13 @@ public class ConfigurationClassPostProcessorTests {
}
}
@Retention(RetentionPolicy.RUNTIME)
@Scope(value = "prototype")
public @interface PrototypeScoped {
ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;
}
@Configuration
public static class ScopedProxyRepositoryConfiguration {
@ -665,7 +694,7 @@ public class ConfigurationClassPostProcessorTests { @@ -665,7 +694,7 @@ public class ConfigurationClassPostProcessorTests {
}
@Bean
@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
@PrototypeScoped
public Repository<Integer> integerRepo() {
return new Repository<Integer>() {
@Override

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

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -58,7 +58,8 @@ public class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisito @@ -58,7 +58,8 @@ public class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisito
* to ensure that the hierarchical ordering of the entries is preserved.
* @see AnnotationReadingVisitorUtils#getMergedAnnotationAttributes
*/
protected final LinkedMultiValueMap<String, AnnotationAttributes> attributesMap = new LinkedMultiValueMap<String, AnnotationAttributes>(4);
protected final LinkedMultiValueMap<String, AnnotationAttributes> attributesMap =
new LinkedMultiValueMap<String, AnnotationAttributes>(4);
protected final Set<MethodMetadata> methodMetadataSet = new LinkedHashSet<MethodMetadata>(4);
@ -75,14 +76,16 @@ public class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisito @@ -75,14 +76,16 @@ public class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisito
if ((access & Opcodes.ACC_BRIDGE) != 0) {
return super.visitMethod(access, name, desc, signature, exceptions);
}
return new MethodMetadataReadingVisitor(name, access, getClassName(), this.classLoader, this.methodMetadataSet);
return new MethodMetadataReadingVisitor(
name, access, getClassName(), this.classLoader, this.methodMetadataSet);
}
@Override
public AnnotationVisitor visitAnnotation(final String desc, boolean visible) {
String className = Type.getType(desc).getClassName();
this.annotationSet.add(className);
return new AnnotationAttributesReadingVisitor(className, this.attributesMap, this.metaAnnotationMap, this.classLoader);
return new AnnotationAttributesReadingVisitor(
className, this.attributesMap, this.metaAnnotationMap, this.classLoader);
}
@ -142,8 +145,8 @@ public class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisito @@ -142,8 +145,8 @@ public class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisito
return null;
}
for (AnnotationAttributes raw : attributes) {
for (Map.Entry<String, Object> entry :
AnnotationReadingVisitorUtils.convertClassValues(this.classLoader, raw, classValuesAsString).entrySet()) {
for (Map.Entry<String, Object> entry : AnnotationReadingVisitorUtils.convertClassValues(
this.classLoader, raw, classValuesAsString).entrySet()) {
allAttributes.add(entry.getKey(), entry.getValue());
}
}

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

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,7 +16,7 @@ @@ -16,7 +16,7 @@
package org.springframework.core.type.classreading;
import java.util.List;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
@ -31,7 +31,7 @@ import org.springframework.util.LinkedMultiValueMap; @@ -31,7 +31,7 @@ import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
/**
* ASM method visitor which looks for the annotations defined on the method,
* ASM method visitor which looks for the annotations defined on a method,
* exposing them through the {@link org.springframework.core.type.MethodMetadata}
* interface.
*
@ -54,7 +54,9 @@ public class MethodMetadataReadingVisitor extends MethodVisitor implements Metho @@ -54,7 +54,9 @@ public class MethodMetadataReadingVisitor extends MethodVisitor implements Metho
protected final Set<MethodMetadata> methodMetadataSet;
protected final MultiValueMap<String, AnnotationAttributes> attributeMap =
protected final Map<String, Set<String>> metaAnnotationMap = new LinkedHashMap<String, Set<String>>(4);
protected final LinkedMultiValueMap<String, AnnotationAttributes> attributesMap =
new LinkedMultiValueMap<String, AnnotationAttributes>(4);
@ -74,7 +76,8 @@ public class MethodMetadataReadingVisitor extends MethodVisitor implements Metho @@ -74,7 +76,8 @@ public class MethodMetadataReadingVisitor extends MethodVisitor implements Metho
public AnnotationVisitor visitAnnotation(final String desc, boolean visible) {
String className = Type.getType(desc).getClassName();
this.methodMetadataSet.add(this);
return new AnnotationAttributesReadingVisitor(className, this.attributeMap, null, this.classLoader);
return new AnnotationAttributesReadingVisitor(
className, this.attributesMap, this.metaAnnotationMap, this.classLoader);
}
@Override
@ -99,7 +102,7 @@ public class MethodMetadataReadingVisitor extends MethodVisitor implements Metho @@ -99,7 +102,7 @@ public class MethodMetadataReadingVisitor extends MethodVisitor implements Metho
@Override
public boolean isAnnotated(String annotationType) {
return this.attributeMap.containsKey(annotationType);
return this.attributesMap.containsKey(annotationType);
}
@Override
@ -109,9 +112,9 @@ public class MethodMetadataReadingVisitor extends MethodVisitor implements Metho @@ -109,9 +112,9 @@ public class MethodMetadataReadingVisitor extends MethodVisitor implements Metho
@Override
public Map<String, Object> getAnnotationAttributes(String annotationType, boolean classValuesAsString) {
List<AnnotationAttributes> attributes = this.attributeMap.get(annotationType);
return (attributes == null ? null : AnnotationReadingVisitorUtils.convertClassValues(
this.classLoader, attributes.get(0), classValuesAsString));
AnnotationAttributes raw = AnnotationReadingVisitorUtils.getMergedAnnotationAttributes(
this.attributesMap, this.metaAnnotationMap, annotationType);
return AnnotationReadingVisitorUtils.convertClassValues(this.classLoader, raw, classValuesAsString);
}
@Override
@ -121,11 +124,11 @@ public class MethodMetadataReadingVisitor extends MethodVisitor implements Metho @@ -121,11 +124,11 @@ public class MethodMetadataReadingVisitor extends MethodVisitor implements Metho
@Override
public MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationType, boolean classValuesAsString) {
if (!this.attributeMap.containsKey(annotationType)) {
if (!this.attributesMap.containsKey(annotationType)) {
return null;
}
MultiValueMap<String, Object> allAttributes = new LinkedMultiValueMap<String, Object>();
for (AnnotationAttributes annotationAttributes : this.attributeMap.get(annotationType)) {
for (AnnotationAttributes annotationAttributes : this.attributesMap.get(annotationType)) {
for (Map.Entry<String, Object> entry : AnnotationReadingVisitorUtils.convertClassValues(
this.classLoader, annotationAttributes, classValuesAsString).entrySet()) {
allAttributes.add(entry.getKey(), entry.getValue());

Loading…
Cancel
Save