From c4ddce6b7396a2ba6a53f5d2ca5a0634ccd041ca Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 7 Apr 2015 13:14:21 -0700 Subject: [PATCH] Polish --- .../ConditionalOnSingleCandidate.java | 17 +++--- .../condition/OnBeanCondition.java | 60 ++++++++----------- .../ConditionalOnSingleCandidateTests.java | 28 ++++++--- 3 files changed, 54 insertions(+), 51 deletions(-) diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnSingleCandidate.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnSingleCandidate.java index cc5b95ac79..6300cf8476 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnSingleCandidate.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnSingleCandidate.java @@ -30,15 +30,14 @@ import org.springframework.context.annotation.Conditional; * {@link Conditional} that only matches when the specified bean class is already * contained in the {@link BeanFactory} and a single candidate can be determined. *

- * The conditional will also match if multiple matching bean instances are already - * contained in the {@link BeanFactory} but a primary candidate has been defined; - * essentially, the condition match if auto-wiring a bean with the defined type - * will succeed. + * The condition will also match if multiple matching bean instances are already contained + * in the {@link BeanFactory} but a primary candidate has been defined; essentially, the + * condition match if auto-wiring a bean with the defined type will succeed. * * @author Stephane Nicoll * @since 1.3.0 */ -@Target({ElementType.TYPE, ElementType.METHOD}) +@Target({ ElementType.TYPE, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @Documented @Conditional(OnBeanCondition.class) @@ -48,8 +47,9 @@ public @interface ConditionalOnSingleCandidate { * The class type of bean that should be checked. The condition match if the class * specified is contained in the {@link ApplicationContext} and a primary candidate * exists in case of multiple instances. - *

This attribute may not be used in conjunction with - * {@link #type()}, but it may be used instead of {@link #type()}. + *

+ * This attribute may not be used in conjunction with {@link #type()} + * , but it may be used instead of {@link #type()}. * @return the class type of the bean to check */ Class value() default Object.class; @@ -58,7 +58,8 @@ public @interface ConditionalOnSingleCandidate { * The class type name of bean that should be checked. The condition matches if the * class specified is contained in the {@link ApplicationContext} and a primary * candidate exists in case of multiple instances. - *

This attribute may not be used in conjunction with + *

+ * This attribute may not be used in conjunction with * {@link #value()}, but it may be used instead of {@link #value()}. * @return the class type name of the bean to check */ diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnBeanCondition.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnBeanCondition.java index 36923e1ab5..ff5e6b5a42 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnBeanCondition.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnBeanCondition.java @@ -24,12 +24,10 @@ import java.util.Collection; import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; -import java.util.ListIterator; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.HierarchicalBeanFactory; import org.springframework.beans.factory.ListableBeanFactory; @@ -100,15 +98,13 @@ public class OnBeanCondition extends SpringBootCondition implements return ConditionOutcome.noMatch("@ConditionalOnSingleCandidate " + spec + " found no beans"); } - else if (hasSingleAutowireCandidate(context.getBeanFactory(), matching)) { - matchMessage.append("@ConditionalOnSingleCandidate " + spec + " found a primary " + - "candidate amongst the following " + matching); - } - else { + else if (!hasSingleAutowireCandidate(context.getBeanFactory(), matching)) { return ConditionOutcome.noMatch("@ConditionalOnSingleCandidate " + spec - + " found no primary candidate amongst the" - + " following " + matching); + + " found no primary candidate amongst the" + " following " + + matching); } + matchMessage.append("@ConditionalOnSingleCandidate " + spec + " found " + + "a primary candidate amongst the following " + matching); } if (metadata.isAnnotated(ConditionalOnMissingBean.class.getName())) { BeanSearchSpec spec = new BeanSearchSpec(context, metadata, @@ -221,23 +217,21 @@ public class OnBeanCondition extends SpringBootCondition implements } } - private boolean hasSingleAutowireCandidate(ConfigurableListableBeanFactory beanFactory, - List beans) { + private boolean hasSingleAutowireCandidate( + ConfigurableListableBeanFactory beanFactory, List beanNames) { + return (beanNames.size() == 1 || getPrimaryBeans(beanFactory, beanNames).size() == 1); + } - if (beans.size() == 1) { - return true; - } - boolean primaryFound = false; - for (String bean : beans) { - BeanDefinition beanDefinition = beanFactory.getBeanDefinition(bean); + private List getPrimaryBeans(ConfigurableListableBeanFactory beanFactory, + List beanNames) { + List primaryBeans = new ArrayList(); + for (String beanName : beanNames) { + BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName); if (beanDefinition != null && beanDefinition.isPrimary()) { - if (primaryFound) { - return false; - } - primaryFound = true; + primaryBeans.add(beanName); } } - return primaryFound; + return primaryBeans; } private static class BeanSearchSpec { @@ -288,8 +282,7 @@ public class OnBeanCondition extends SpringBootCondition implements return "@" + ClassUtils.getShortName(this.annotationType); } - @SuppressWarnings({ "unchecked", "rawtypes" }) - private void collect(MultiValueMap attributes, String key, + protected void collect(MultiValueMap attributes, String key, List destination) { List values = attributes.get(key); if (values != null) { @@ -388,18 +381,17 @@ public class OnBeanCondition extends SpringBootCondition implements super(context, metadata, annotationType); } + @Override + protected void collect(MultiValueMap attributes, String key, + List destination) { + super.collect(attributes, key, destination); + destination.removeAll(Arrays.asList("", Object.class.getName())); + } + @Override protected void validate() { - List types = getTypes(); - ListIterator it = types.listIterator(); - while (it.hasNext()) { - String value = it.next(); - if (!StringUtils.hasText(value) || Object.class.getName().equals(value)) { - it.remove(); - } - } - Assert.isTrue(types.size() == 1, annotationName() + " annotations must " - + "specify only one type (got " + types + ")"); + Assert.isTrue(getTypes().size() == 1, annotationName() + " annotations must " + + "specify only one type (got " + getTypes() + ")"); } } diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnSingleCandidateTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnSingleCandidateTests.java index c1feb8ad44..f6579c8dc4 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnSingleCandidateTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnSingleCandidateTests.java @@ -20,7 +20,6 @@ import org.junit.After; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; - import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -58,8 +57,7 @@ public class ConditionalOnSingleCandidateTests { @Test public void singleCandidateOneCandidate() { - load(FooConfiguration.class, - OnBeanSingleCandidateConfiguration.class); + load(FooConfiguration.class, OnBeanSingleCandidateConfiguration.class); assertTrue(this.context.containsBean("baz")); assertEquals("foo", this.context.getBean("baz")); } @@ -88,17 +86,19 @@ public class ConditionalOnSingleCandidateTests { @Test public void invalidAnnotationTwoTypes() { - thrown.expect(IllegalStateException.class); - thrown.expectCause(isA(IllegalArgumentException.class)); - thrown.expectMessage(OnBeanSingleCandidateTwoTypesConfiguration.class.getName()); + this.thrown.expect(IllegalStateException.class); + this.thrown.expectCause(isA(IllegalArgumentException.class)); + this.thrown.expectMessage(OnBeanSingleCandidateTwoTypesConfiguration.class + .getName()); load(OnBeanSingleCandidateTwoTypesConfiguration.class); } @Test public void invalidAnnotationNoType() { - thrown.expect(IllegalStateException.class); - thrown.expectCause(isA(IllegalArgumentException.class)); - thrown.expectMessage(OnBeanSingleCandidateNoTypeConfiguration.class.getName()); + this.thrown.expect(IllegalStateException.class); + this.thrown.expectCause(isA(IllegalArgumentException.class)); + this.thrown.expectMessage(OnBeanSingleCandidateNoTypeConfiguration.class + .getName()); load(OnBeanSingleCandidateNoTypeConfiguration.class); } @@ -110,10 +110,12 @@ public class ConditionalOnSingleCandidateTests { @Configuration @ConditionalOnSingleCandidate(value = String.class) protected static class OnBeanSingleCandidateConfiguration { + @Bean public String baz(String s) { return s; } + } @Configuration @@ -130,35 +132,43 @@ public class ConditionalOnSingleCandidateTests { @Configuration protected static class FooConfiguration { + @Bean public String foo() { return "foo"; } + } @Configuration protected static class FooPrimaryConfiguration { + @Bean @Primary public String foo() { return "foo"; } + } @Configuration protected static class BarConfiguration { + @Bean public String bar() { return "bar"; } + } @Configuration protected static class BarPrimaryConfiguration { + @Bean @Primary public String bar() { return "bar"; } + } }