From f46c706e443860e9ada7768a16cfa01526c10645 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Fri, 26 Sep 2014 14:46:09 +0200 Subject: [PATCH] Bean method metadata exposed through AnnotatedBeanDefinition Issue: SPR-12232 --- .../annotation/AnnotatedBeanDefinition.java | 10 ++- .../AnnotatedGenericBeanDefinition.java | 24 ++++++- ...onfigurationClassBeanDefinitionReader.java | 21 ++++-- .../ScannedGenericBeanDefinition.java | 8 ++- .../annotation/BeanMethodMetadataTests.java | 70 +++++++++++++++++++ 5 files changed, 125 insertions(+), 8 deletions(-) create mode 100644 spring-context/src/test/java/org/springframework/context/annotation/BeanMethodMetadataTests.java diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AnnotatedBeanDefinition.java b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AnnotatedBeanDefinition.java index 7eef126d8d6..befb4118601 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AnnotatedBeanDefinition.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AnnotatedBeanDefinition.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2014 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. @@ -18,6 +18,7 @@ package org.springframework.beans.factory.annotation; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.core.type.AnnotationMetadata; +import org.springframework.core.type.MethodMetadata; /** * Extended {@link org.springframework.beans.factory.config.BeanDefinition} @@ -38,4 +39,11 @@ public interface AnnotatedBeanDefinition extends BeanDefinition { */ AnnotationMetadata getMetadata(); + /** + * Obtain metadata for this bean definition's factory method, if any. + * @return the factory method metadata, or {@code null} if none + * @since 4.1.1 + */ + MethodMetadata getFactoryMethodMetadata(); + } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AnnotatedGenericBeanDefinition.java b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AnnotatedGenericBeanDefinition.java index a5afead3183..559145268b3 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AnnotatedGenericBeanDefinition.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AnnotatedGenericBeanDefinition.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 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. @@ -18,6 +18,7 @@ package org.springframework.beans.factory.annotation; import org.springframework.beans.factory.support.GenericBeanDefinition; import org.springframework.core.type.AnnotationMetadata; +import org.springframework.core.type.MethodMetadata; import org.springframework.core.type.StandardAnnotationMetadata; import org.springframework.util.Assert; @@ -43,6 +44,8 @@ public class AnnotatedGenericBeanDefinition extends GenericBeanDefinition implem private final AnnotationMetadata metadata; + private MethodMetadata factoryMethodMetadata; + /** * Create a new AnnotatedGenericBeanDefinition for the given bean class. @@ -74,10 +77,29 @@ public class AnnotatedGenericBeanDefinition extends GenericBeanDefinition implem this.metadata = metadata; } + /** + * Create a new AnnotatedGenericBeanDefinition for the given annotation metadata, + * based on an annotated class and a factory method on that class. + * @param metadata the annotation metadata for the bean class in question + * @param factoryMethodMetadata metadata for the selected factory method + * @since 4.1.1 + */ + public AnnotatedGenericBeanDefinition(AnnotationMetadata metadata, MethodMetadata factoryMethodMetadata) { + this(metadata); + Assert.notNull(factoryMethodMetadata, "MethodMetadata must not be null"); + setFactoryMethodName(factoryMethodMetadata.getMethodName()); + this.factoryMethodMetadata = factoryMethodMetadata; + } + @Override public final AnnotationMetadata getMetadata() { return this.metadata; } + @Override + public final MethodMetadata getFactoryMethodMetadata() { + return this.factoryMethodMetadata; + } + } diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java index 7de16bf2908..98333791f26 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java @@ -181,7 +181,7 @@ class ConfigurationClassBeanDefinitionReader { ConfigurationClass configClass = beanMethod.getConfigurationClass(); MethodMetadata metadata = beanMethod.getMetadata(); - ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass); + ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata); beanDef.setResource(configClass.getResource()); beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource())); if (metadata.isStatic()) { @@ -243,8 +243,8 @@ class ConfigurationClassBeanDefinitionReader { if (proxyMode != ScopedProxyMode.NO) { BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy( new BeanDefinitionHolder(beanDef, beanName), this.registry, proxyMode == ScopedProxyMode.TARGET_CLASS); - beanDefToRegister = - new ConfigurationClassBeanDefinition((RootBeanDefinition) proxyDef.getBeanDefinition(), configClass); + beanDefToRegister = new ConfigurationClassBeanDefinition( + (RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata); } if (logger.isDebugEnabled()) { @@ -349,19 +349,25 @@ class ConfigurationClassBeanDefinitionReader { private final AnnotationMetadata annotationMetadata; - public ConfigurationClassBeanDefinition(ConfigurationClass configClass) { + private final MethodMetadata factoryMethodMetadata; + + public ConfigurationClassBeanDefinition(ConfigurationClass configClass, MethodMetadata beanMethodMetadata) { this.annotationMetadata = configClass.getMetadata(); + this.factoryMethodMetadata = beanMethodMetadata; setLenientConstructorResolution(false); } - public ConfigurationClassBeanDefinition(RootBeanDefinition original, ConfigurationClass configClass) { + public ConfigurationClassBeanDefinition( + RootBeanDefinition original, ConfigurationClass configClass, MethodMetadata beanMethodMetadata) { super(original); this.annotationMetadata = configClass.getMetadata(); + this.factoryMethodMetadata = beanMethodMetadata; } private ConfigurationClassBeanDefinition(ConfigurationClassBeanDefinition original) { super(original); this.annotationMetadata = original.annotationMetadata; + this.factoryMethodMetadata = original.factoryMethodMetadata; } @Override @@ -369,6 +375,11 @@ class ConfigurationClassBeanDefinitionReader { return this.annotationMetadata; } + @Override + public MethodMetadata getFactoryMethodMetadata() { + return this.factoryMethodMetadata; + } + @Override public boolean isFactoryMethod(Method candidate) { return (super.isFactoryMethod(candidate) && BeanAnnotationHelper.isBeanAnnotated(candidate)); diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ScannedGenericBeanDefinition.java b/spring-context/src/main/java/org/springframework/context/annotation/ScannedGenericBeanDefinition.java index 7ed9bed6fe6..1b815588459 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ScannedGenericBeanDefinition.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ScannedGenericBeanDefinition.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2014 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. @@ -20,6 +20,7 @@ import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition; import org.springframework.beans.factory.support.GenericBeanDefinition; import org.springframework.core.type.AnnotationMetadata; +import org.springframework.core.type.MethodMetadata; import org.springframework.core.type.classreading.MetadataReader; import org.springframework.util.Assert; @@ -66,4 +67,9 @@ public class ScannedGenericBeanDefinition extends GenericBeanDefinition implemen return this.metadata; } + @Override + public MethodMetadata getFactoryMethodMetadata() { + return null; + } + } diff --git a/spring-context/src/test/java/org/springframework/context/annotation/BeanMethodMetadataTests.java b/spring-context/src/test/java/org/springframework/context/annotation/BeanMethodMetadataTests.java new file mode 100644 index 00000000000..3a59cfb9902 --- /dev/null +++ b/spring-context/src/test/java/org/springframework/context/annotation/BeanMethodMetadataTests.java @@ -0,0 +1,70 @@ +/* + * Copyright 2002-2014 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Map; + +import org.junit.Test; + +import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; +import org.springframework.beans.factory.config.BeanDefinition; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + +/** + * @author Phillip Webb + * @author Juergen Hoeller + */ +public class BeanMethodMetadataTests { + + @Test + public void providesBeanMethodBeanDefinition() throws Exception { + AnnotationConfigApplicationContext context= new AnnotationConfigApplicationContext(Conf.class); + BeanDefinition beanDefinition = context.getBeanDefinition("myBean"); + assertThat("should provide AnnotatedBeanDefinition", beanDefinition, instanceOf(AnnotatedBeanDefinition.class)); + Map annotationAttributes = + ((AnnotatedBeanDefinition) beanDefinition).getFactoryMethodMetadata().getAnnotationAttributes(MyAnnotation.class.getName()); + assertThat(annotationAttributes.get("value"), equalTo("test")); + context.close(); + } + + + @Configuration + static class Conf { + + @Bean + @MyAnnotation("test") + public MyBean myBean() { + return new MyBean(); + } + } + + + static class MyBean { + } + + + @Retention(RetentionPolicy.RUNTIME) + public static @interface MyAnnotation { + + String value(); + } + +}