Browse Source

Detect factory method annotations in getBeanNamesForAnnotation and co

As of 5.2, ListableBeanFactory.findAnnotationOnBean and its retrieval companions getBeanNamesForAnnotation and getBeansWithAnnotation detect annotations on @Bean methods as well.

Closes gh-22541
pull/22737/head
Juergen Hoeller 7 years ago
parent
commit
e0fe32af05
  1. 17
      spring-beans/src/main/java/org/springframework/beans/factory/ListableBeanFactory.java
  2. 43
      spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java
  3. 12
      spring-context/src/test/java/org/springframework/context/annotation/configuration/BeanMethodQualificationTests.java

17
spring-beans/src/main/java/org/springframework/beans/factory/ListableBeanFactory.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2019 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.
@ -248,8 +248,10 @@ public interface ListableBeanFactory extends BeanFactory { @@ -248,8 +248,10 @@ public interface ListableBeanFactory extends BeanFactory {
* <p>Note that this method considers objects created by FactoryBeans, which means
* that FactoryBeans will get initialized in order to determine their object type.
* @param annotationType the type of annotation to look for
* (at class, interface or factory method level of the specified bean)
* @return the names of all matching beans
* @since 4.0
* @see #findAnnotationOnBean
*/
String[] getBeanNamesForAnnotation(Class<? extends Annotation> annotationType);
@ -259,22 +261,27 @@ public interface ListableBeanFactory extends BeanFactory { @@ -259,22 +261,27 @@ public interface ListableBeanFactory extends BeanFactory {
* <p>Note that this method considers objects created by FactoryBeans, which means
* that FactoryBeans will get initialized in order to determine their object type.
* @param annotationType the type of annotation to look for
* (at class, interface or factory method level of the specified bean)
* @return a Map with the matching beans, containing the bean names as
* keys and the corresponding bean instances as values
* @throws BeansException if a bean could not be created
* @since 3.0
* @see #findAnnotationOnBean
*/
Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType) throws BeansException;
/**
* Find an {@link Annotation} of {@code annotationType} on the specified
* bean, traversing its interfaces and super classes if no annotation can be
* found on the given class itself.
* Find an {@link Annotation} of {@code annotationType} on the specified bean,
* traversing its interfaces and super classes if no annotation can be found on
* the given class itself, as well as checking the bean's factory method (if any).
* @param beanName the name of the bean to look for annotations on
* @param annotationType the annotation class to look for
* @param annotationType the type of annotation to look for
* (at class, interface or factory method level of the specified bean)
* @return the annotation of the given type if found, or {@code null} otherwise
* @throws NoSuchBeanDefinitionException if there is no bean with the given name
* @since 3.0
* @see #getBeanNamesForAnnotation
* @see #getBeansWithAnnotation
*/
@Nullable
<A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType)

43
spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java

@ -678,23 +678,32 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto @@ -678,23 +678,32 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
Class<?> beanType = getType(beanName);
if (beanType != null) {
MergedAnnotation<A> annotation = MergedAnnotations.from(beanType,
SearchStrategy.EXHAUSTIVE).get(annotationType);
MergedAnnotation<A> annotation =
MergedAnnotations.from(beanType, SearchStrategy.EXHAUSTIVE).get(annotationType);
if (annotation.isPresent()) {
return annotation;
}
}
if (containsBeanDefinition(beanName)) {
BeanDefinition bd = getMergedBeanDefinition(beanName);
if (bd instanceof AbstractBeanDefinition) {
AbstractBeanDefinition abd = (AbstractBeanDefinition) bd;
if (abd.hasBeanClass()) {
Class<?> beanClass = abd.getBeanClass();
if (beanClass != beanType) {
return MergedAnnotations.from(beanClass, SearchStrategy.EXHAUSTIVE).get(annotationType);
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (bd.hasBeanClass()) {
Class<?> beanClass = bd.getBeanClass();
if (beanClass != beanType) {
MergedAnnotation<A> annotation =
MergedAnnotations.from(beanClass, SearchStrategy.EXHAUSTIVE).get(annotationType);
if (annotation.isPresent()) {
return annotation;
}
}
}
Method factoryMethod = bd.getResolvedFactoryMethod();
if (factoryMethod != null) {
MergedAnnotation<A> annotation =
MergedAnnotations.from(factoryMethod, SearchStrategy.EXHAUSTIVE).get(annotationType);
if (annotation.isPresent()) {
return annotation;
}
}
}
return MergedAnnotation.missing();
}
@ -1988,10 +1997,11 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto @@ -1988,10 +1997,11 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
@Override
@Nullable
public Object getOrderSource(Object obj) {
RootBeanDefinition beanDefinition = getRootBeanDefinition(this.instancesToBeanNames.get(obj));
if (beanDefinition == null) {
String beanName = this.instancesToBeanNames.get(obj);
if (beanName == null || !containsBeanDefinition(beanName)) {
return null;
}
RootBeanDefinition beanDefinition = getMergedLocalBeanDefinition(beanName);
List<Object> sources = new ArrayList<>(2);
Method factoryMethod = beanDefinition.getResolvedFactoryMethod();
if (factoryMethod != null) {
@ -2003,17 +2013,6 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto @@ -2003,17 +2013,6 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
}
return sources.toArray();
}
@Nullable
private RootBeanDefinition getRootBeanDefinition(@Nullable String beanName) {
if (beanName != null && containsBeanDefinition(beanName)) {
BeanDefinition bd = getMergedBeanDefinition(beanName);
if (bd instanceof RootBeanDefinition) {
return (RootBeanDefinition) bd;
}
}
return null;
}
}
}

12
spring-context/src/test/java/org/springframework/context/annotation/configuration/BeanMethodQualificationTests.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2019 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.
@ -129,6 +129,16 @@ public class BeanMethodQualificationTests { @@ -129,6 +129,16 @@ public class BeanMethodQualificationTests {
assertThat(pojo.testBean.getName(), equalTo("interesting"));
}
@Test
public void testBeanNamesForAnnotation() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(StandardConfig.class);
assertArrayEquals(new String[] {"beanMethodQualificationTests.StandardConfig"},
ctx.getBeanNamesForAnnotation(Configuration.class));
assertArrayEquals(new String[] {}, ctx.getBeanNamesForAnnotation(Scope.class));
assertArrayEquals(new String[] {"testBean1"}, ctx.getBeanNamesForAnnotation(Lazy.class));
assertArrayEquals(new String[] {"testBean2"}, ctx.getBeanNamesForAnnotation(Boring.class));
}
@Configuration
static class StandardConfig {

Loading…
Cancel
Save