Browse Source

AnnotatedElementUtils adapts post-processed values to AnnotationAttributes as well

Issue: SPR-12065
pull/610/merge
Juergen Hoeller 11 years ago
parent
commit
ef51d4dbdb
  1. 65
      spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java
  2. 24
      spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java
  3. 71
      spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java

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

@ -28,6 +28,7 @@ import org.junit.Test; @@ -28,6 +28,7 @@ import org.junit.Test;
import org.springframework.aop.scope.ScopedObject;
import org.springframework.aop.scope.ScopedProxyUtils;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.annotation.Qualifier;
@ -39,6 +40,7 @@ import org.springframework.beans.factory.support.RootBeanDefinition; @@ -39,6 +40,7 @@ import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.componentscan.simple.SimpleComponent;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.DescriptiveResource;
import org.springframework.stereotype.Component;
import org.springframework.tests.sample.beans.ITestBean;
import org.springframework.tests.sample.beans.TestBean;
import org.springframework.util.Assert;
@ -126,19 +128,33 @@ public class ConfigurationClassPostProcessorTests { @@ -126,19 +128,33 @@ public class ConfigurationClassPostProcessorTests {
}
@Test
public void postProcessorWorksWithComposedConfigurationWithAttributeOverridesUsingReflection() {
public void postProcessorWorksWithComposedConfigurationWithAttributeOverrideForBasePackageUsingReflection() {
RootBeanDefinition beanDefinition = new RootBeanDefinition(
ComposedConfigurationWithAttributeOverridesClass.class);
ComposedConfigurationWithAttributeOverrideForBasePackage.class);
assertSupportForComposedAnnotation(beanDefinition);
}
@Test
public void postProcessorWorksWithComposedConfigurationWithAttributeOverridesUsingAsm() {
public void postProcessorWorksWithComposedConfigurationWithAttributeOverrideForBasePackageUsingAsm() {
RootBeanDefinition beanDefinition = new RootBeanDefinition(
ComposedConfigurationWithAttributeOverridesClass.class.getName());
ComposedConfigurationWithAttributeOverrideForBasePackage.class.getName());
assertSupportForComposedAnnotation(beanDefinition);
}
@Test
public void postProcessorWorksWithComposedConfigurationWithAttributeOverrideForExcludeFilterUsingReflection() {
RootBeanDefinition beanDefinition = new RootBeanDefinition(
ComposedConfigurationWithAttributeOverrideForExcludeFilter.class);
assertSupportForComposedAnnotationWithExclude(beanDefinition);
}
@Test
public void postProcessorWorksWithComposedConfigurationWithAttributeOverrideForExcludeFilterUsingAsm() {
RootBeanDefinition beanDefinition = new RootBeanDefinition(
ComposedConfigurationWithAttributeOverrideForExcludeFilter.class.getName());
assertSupportForComposedAnnotationWithExclude(beanDefinition);
}
@Test
public void postProcessorWorksWithComposedComposedConfigurationWithAttributeOverridesUsingReflection() {
RootBeanDefinition beanDefinition = new RootBeanDefinition(
@ -181,6 +197,29 @@ public class ConfigurationClassPostProcessorTests { @@ -181,6 +197,29 @@ public class ConfigurationClassPostProcessorTests {
assertSupportForComposedAnnotation(beanDefinition);
}
private void assertSupportForComposedAnnotation(RootBeanDefinition beanDefinition) {
beanFactory.registerBeanDefinition("config", beanDefinition);
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
pp.setEnvironment(new StandardEnvironment());
pp.postProcessBeanFactory(beanFactory);
SimpleComponent simpleComponent = beanFactory.getBean(SimpleComponent.class);
assertNotNull(simpleComponent);
}
private void assertSupportForComposedAnnotationWithExclude(RootBeanDefinition beanDefinition) {
beanFactory.registerBeanDefinition("config", beanDefinition);
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
pp.setEnvironment(new StandardEnvironment());
pp.postProcessBeanFactory(beanFactory);
try {
beanFactory.getBean(SimpleComponent.class);
fail("Should have thrown NoSuchBeanDefinitionException");
}
catch (NoSuchBeanDefinitionException ex) {
// expected
}
}
@Test
public void postProcessorOverridesNonApplicationBeanDefinitions() {
RootBeanDefinition rbd = new RootBeanDefinition(TestBean.class);
@ -378,15 +417,6 @@ public class ConfigurationClassPostProcessorTests { @@ -378,15 +417,6 @@ public class ConfigurationClassPostProcessorTests {
assertSame(beanFactory.getBean("genericRepo"), beanFactory.getBean("repoConsumer"));
}
private void assertSupportForComposedAnnotation(RootBeanDefinition beanDefinition) {
beanFactory.registerBeanDefinition("config", beanDefinition);
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
pp.setEnvironment(new StandardEnvironment());
pp.postProcessBeanFactory(beanFactory);
SimpleComponent simpleComponent = beanFactory.getBean(SimpleComponent.class);
assertNotNull(simpleComponent);
}
@Test
public void testSelfReferenceExclusionForFactoryMethodOnSameBean() {
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
@ -718,10 +748,17 @@ public class ConfigurationClassPostProcessorTests { @@ -718,10 +748,17 @@ public class ConfigurationClassPostProcessorTests {
public static @interface ComposedConfigurationWithAttributeOverrides {
String[] basePackages() default {};
ComponentScan.Filter[] excludeFilters() default {};
}
@ComposedConfigurationWithAttributeOverrides(basePackages = "org.springframework.context.annotation.componentscan.simple")
public static class ComposedConfigurationWithAttributeOverridesClass {
public static class ComposedConfigurationWithAttributeOverrideForBasePackage {
}
@ComposedConfigurationWithAttributeOverrides(basePackages = "org.springframework.context.annotation.componentscan.simple",
excludeFilters = @ComponentScan.Filter(Component.class))
public static class ComposedConfigurationWithAttributeOverrideForExcludeFilter {
}
@ComposedConfigurationWithAttributeOverrides

24
spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java

@ -40,7 +40,6 @@ public class AnnotatedElementUtils { @@ -40,7 +40,6 @@ public class AnnotatedElementUtils {
public static Set<String> getMetaAnnotationTypes(AnnotatedElement element, String annotationType) {
final Set<String> types = new LinkedHashSet<String>();
process(element, annotationType, false, new Processor<Object>() {
@Override
public Object process(Annotation annotation, int metaDepth) {
if (metaDepth > 0) {
@ -48,7 +47,6 @@ public class AnnotatedElementUtils { @@ -48,7 +47,6 @@ public class AnnotatedElementUtils {
}
return null;
}
@Override
public void postProcess(Annotation annotation, Object result) {
}
@ -101,7 +99,7 @@ public class AnnotatedElementUtils { @@ -101,7 +99,7 @@ public class AnnotatedElementUtils {
if (!AnnotationUtils.VALUE.equals(key)) {
Object value = AnnotationUtils.getValue(annotation, key);
if (value != null) {
result.put(key, value);
result.put(key, AnnotationUtils.adaptValue(value, classValuesAsString, nestedAnnotationsAsMap));
}
}
}
@ -109,8 +107,7 @@ public class AnnotatedElementUtils { @@ -109,8 +107,7 @@ public class AnnotatedElementUtils {
});
}
public static MultiValueMap<String, Object> getAllAnnotationAttributes(AnnotatedElement element,
String annotationType) {
public static MultiValueMap<String, Object> getAllAnnotationAttributes(AnnotatedElement element, String annotationType) {
return getAllAnnotationAttributes(element, annotationType, false, false);
}
@ -122,8 +119,8 @@ public class AnnotatedElementUtils { @@ -122,8 +119,8 @@ public class AnnotatedElementUtils {
@Override
public Void process(Annotation annotation, int metaDepth) {
if (annotation.annotationType().getName().equals(annotationType)) {
for (Map.Entry<String, Object> entry : AnnotationUtils.getAnnotationAttributes(annotation,
classValuesAsString, nestedAnnotationsAsMap).entrySet()) {
for (Map.Entry<String, Object> entry : AnnotationUtils.getAnnotationAttributes(
annotation, classValuesAsString, nestedAnnotationsAsMap).entrySet()) {
attributes.add(entry.getKey(), entry.getValue());
}
}
@ -163,7 +160,7 @@ public class AnnotatedElementUtils { @@ -163,7 +160,7 @@ public class AnnotatedElementUtils {
try {
return doProcess(element, annotationType, traverseClassHierarchy, processor,
new HashSet<AnnotatedElement>(), 0);
new HashSet<AnnotatedElement>(), 0);
}
catch (Throwable ex) {
throw new IllegalStateException("Failed to introspect annotations: " + element, ex);
@ -199,8 +196,8 @@ public class AnnotatedElementUtils { @@ -199,8 +196,8 @@ public class AnnotatedElementUtils {
if (result != null) {
return result;
}
result = doProcess(annotation.annotationType(), annotationType, traverseClassHierarchy, processor,
visited, metaDepth + 1);
result = doProcess(annotation.annotationType(), annotationType, traverseClassHierarchy,
processor, visited, metaDepth + 1);
if (result != null) {
processor.postProcess(annotation, result);
return result;
@ -210,7 +207,7 @@ public class AnnotatedElementUtils { @@ -210,7 +207,7 @@ public class AnnotatedElementUtils {
for (Annotation annotation : annotations) {
if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)) {
T result = doProcess(annotation.annotationType(), annotationType, traverseClassHierarchy,
processor, visited, metaDepth);
processor, visited, metaDepth);
if (result != null) {
processor.postProcess(annotation, result);
return result;
@ -220,8 +217,7 @@ public class AnnotatedElementUtils { @@ -220,8 +217,7 @@ public class AnnotatedElementUtils {
if (traverseClassHierarchy && element instanceof Class) {
Class<?> superclass = ((Class<?>) element).getSuperclass();
if (superclass != null && !superclass.equals(Object.class)) {
T result = doProcess(superclass, annotationType, true, processor, visited,
metaDepth);
T result = doProcess(superclass, annotationType, true, processor, visited, metaDepth);
if (result != null) {
return result;
}
@ -247,7 +243,7 @@ public class AnnotatedElementUtils { @@ -247,7 +243,7 @@ public class AnnotatedElementUtils {
* will have a depth of 2.
* @param annotation the annotation to process
* @param metaDepth the depth of the annotation relative to the initial element
* @return the result of the processing or {@code null} to continue
* @return the result of the processing, or {@code null} to continue
*/
T process(Annotation annotation, int metaDepth);

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

@ -578,34 +578,7 @@ public abstract class AnnotationUtils { @@ -578,34 +578,7 @@ public abstract class AnnotationUtils {
if (method.getParameterTypes().length == 0 && method.getReturnType() != void.class) {
try {
Object value = method.invoke(annotation);
if (classValuesAsString) {
if (value instanceof Class) {
value = ((Class<?>) value).getName();
}
else if (value instanceof Class[]) {
Class<?>[] clazzArray = (Class[]) value;
String[] newValue = new String[clazzArray.length];
for (int i = 0; i < clazzArray.length; i++) {
newValue[i] = clazzArray[i].getName();
}
value = newValue;
}
}
if (nestedAnnotationsAsMap && value instanceof Annotation) {
attrs.put(method.getName(),
getAnnotationAttributes((Annotation) value, classValuesAsString, true));
}
else if (nestedAnnotationsAsMap && value instanceof Annotation[]) {
Annotation[] realAnnotations = (Annotation[]) value;
AnnotationAttributes[] mappedAnnotations = new AnnotationAttributes[realAnnotations.length];
for (int i = 0; i < realAnnotations.length; i++) {
mappedAnnotations[i] = getAnnotationAttributes(realAnnotations[i], classValuesAsString, true);
}
attrs.put(method.getName(), mappedAnnotations);
}
else {
attrs.put(method.getName(), value);
}
attrs.put(method.getName(), adaptValue(value, classValuesAsString, nestedAnnotationsAsMap));
}
catch (Exception ex) {
throw new IllegalStateException("Could not obtain annotation attribute values", ex);
@ -615,6 +588,48 @@ public abstract class AnnotationUtils { @@ -615,6 +588,48 @@ public abstract class AnnotationUtils {
return attrs;
}
/**
* Adapt the given value according to the given class and nested annotation settings.
* @param value the annotation attribute value
* @param classValuesAsString whether to turn Class references into Strings (for
* compatibility with {@link org.springframework.core.type.AnnotationMetadata}
* or to preserve them as Class references
* @param nestedAnnotationsAsMap whether to turn nested Annotation instances into
* {@link AnnotationAttributes} maps (for compatibility with
* {@link org.springframework.core.type.AnnotationMetadata} or to preserve them as
* Annotation instances
* @return the adapted value, or the original value if no adaptation is needed
*/
static Object adaptValue(Object value, boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
if (classValuesAsString) {
if (value instanceof Class) {
value = ((Class<?>) value).getName();
}
else if (value instanceof Class[]) {
Class<?>[] clazzArray = (Class[]) value;
String[] newValue = new String[clazzArray.length];
for (int i = 0; i < clazzArray.length; i++) {
newValue[i] = clazzArray[i].getName();
}
value = newValue;
}
}
if (nestedAnnotationsAsMap && value instanceof Annotation) {
return getAnnotationAttributes((Annotation) value, classValuesAsString, true);
}
else if (nestedAnnotationsAsMap && value instanceof Annotation[]) {
Annotation[] realAnnotations = (Annotation[]) value;
AnnotationAttributes[] mappedAnnotations = new AnnotationAttributes[realAnnotations.length];
for (int i = 0; i < realAnnotations.length; i++) {
mappedAnnotations[i] = getAnnotationAttributes(realAnnotations[i], classValuesAsString, true);
}
return mappedAnnotations;
}
else {
return value;
}
}
/**
* Retrieve the <em>value</em> of the {@code &quot;value&quot;} attribute of a
* single-element Annotation, given an annotation instance.

Loading…
Cancel
Save