Skip to content

Commit

Permalink
Merge branch '2.2.x' into 2.3.x
Browse files Browse the repository at this point in the history
Closes gh-22197
  • Loading branch information
wilkinsona committed Jul 2, 2020
2 parents f0b78fb + 21453b5 commit f6b3666
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 87 deletions.
Expand Up @@ -24,12 +24,14 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import org.springframework.aop.scope.ScopedProxyUtils;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.HierarchicalBeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
Expand Down Expand Up @@ -166,7 +168,13 @@ protected final MatchResult getMatchingBeans(ConditionContext context, Spec<?> s
for (String type : spec.getTypes()) {
Collection<String> typeMatches = getBeanNamesForType(classLoader, considerHierarchy, beanFactory, type,
parameterizedContainers);
typeMatches.removeAll(beansIgnoredByType);
Iterator<String> iterator = typeMatches.iterator();
while (iterator.hasNext()) {
String match = iterator.next();
if (beansIgnoredByType.contains(match) || ScopedProxyUtils.isScopedTarget(match)) {
iterator.remove();
}
}
if (typeMatches.isEmpty()) {
result.recordUnmatchedType(type);
}
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2020 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.
Expand All @@ -16,16 +16,16 @@

package org.springframework.boot.autoconfigure.condition;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;

/**
* Tests for {@link ConditionalOnSingleCandidate @ConditionalOnSingleCandidate}.
Expand All @@ -35,125 +35,122 @@
*/
class ConditionalOnSingleCandidateTests {

private final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

@AfterEach
void close() {
if (this.context != null) {
this.context.close();
}
}
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner();

@Test
void singleCandidateNoCandidate() {
load(OnBeanSingleCandidateConfiguration.class);
assertThat(this.context.containsBean("baz")).isFalse();
this.contextRunner.withUserConfiguration(OnBeanSingleCandidateConfiguration.class)
.run((context) -> assertThat(context).doesNotHaveBean("consumer"));
}

@Test
void singleCandidateOneCandidate() {
load(FooConfiguration.class, OnBeanSingleCandidateConfiguration.class);
assertThat(this.context.containsBean("baz")).isTrue();
assertThat(this.context.getBean("baz")).isEqualTo("foo");
this.contextRunner.withUserConfiguration(AlphaConfiguration.class, OnBeanSingleCandidateConfiguration.class)
.run((context) -> {
assertThat(context).hasBean("consumer");
assertThat(context.getBean("consumer")).isEqualTo("alpha");
});
}

@Test
void singleCandidateOneScopedProxyCandidate() {
this.contextRunner
.withUserConfiguration(AlphaScopedProxyConfiguration.class, OnBeanSingleCandidateConfiguration.class)
.run((context) -> {
assertThat(context).hasBean("consumer");
assertThat(context.getBean("consumer").toString()).isEqualTo("alpha");
});
}

@Test
void singleCandidateInAncestorsOneCandidateInCurrent() {
load();
AnnotationConfigApplicationContext child = new AnnotationConfigApplicationContext();
child.register(FooConfiguration.class, OnBeanSingleCandidateInAncestorsConfiguration.class);
child.setParent(this.context);
child.refresh();
assertThat(child.containsBean("baz")).isFalse();
child.close();
this.contextRunner.run((parent) -> this.contextRunner
.withUserConfiguration(AlphaConfiguration.class, OnBeanSingleCandidateInAncestorsConfiguration.class)
.withParent(parent).run((child) -> assertThat(child).doesNotHaveBean("consumer")));
}

@Test
void singleCandidateInAncestorsOneCandidateInParent() {
load(FooConfiguration.class);
AnnotationConfigApplicationContext child = new AnnotationConfigApplicationContext();
child.register(OnBeanSingleCandidateInAncestorsConfiguration.class);
child.setParent(this.context);
child.refresh();
assertThat(child.containsBean("baz")).isTrue();
assertThat(child.getBean("baz")).isEqualTo("foo");
child.close();
this.contextRunner.withUserConfiguration(AlphaConfiguration.class)
.run((parent) -> this.contextRunner
.withUserConfiguration(OnBeanSingleCandidateInAncestorsConfiguration.class).withParent(parent)
.run((child) -> {
assertThat(child).hasBean("consumer");
assertThat(child.getBean("consumer")).isEqualTo("alpha");
}));
}

@Test
void singleCandidateInAncestorsOneCandidateInGrandparent() {
load(FooConfiguration.class);
AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext();
parent.setParent(this.context);
parent.refresh();
AnnotationConfigApplicationContext child = new AnnotationConfigApplicationContext();
child.register(OnBeanSingleCandidateInAncestorsConfiguration.class);
child.setParent(parent);
child.refresh();
assertThat(child.containsBean("baz")).isTrue();
assertThat(child.getBean("baz")).isEqualTo("foo");
child.close();
parent.close();
this.contextRunner.withUserConfiguration(AlphaConfiguration.class)
.run((grandparent) -> this.contextRunner.withParent(grandparent)
.run((parent) -> this.contextRunner
.withUserConfiguration(OnBeanSingleCandidateInAncestorsConfiguration.class)
.withParent(parent).run((child) -> {
assertThat(child).hasBean("consumer");
assertThat(child.getBean("consumer")).isEqualTo("alpha");
})));
}

@Test
void singleCandidateMultipleCandidates() {
load(FooConfiguration.class, BarConfiguration.class, OnBeanSingleCandidateConfiguration.class);
assertThat(this.context.containsBean("baz")).isFalse();
this.contextRunner
.withUserConfiguration(AlphaConfiguration.class, BravoConfiguration.class,
OnBeanSingleCandidateConfiguration.class)
.run((context) -> assertThat(context).doesNotHaveBean("consumer"));
}

@Test
void singleCandidateMultipleCandidatesOnePrimary() {
load(FooPrimaryConfiguration.class, BarConfiguration.class, OnBeanSingleCandidateConfiguration.class);
assertThat(this.context.containsBean("baz")).isTrue();
assertThat(this.context.getBean("baz")).isEqualTo("foo");
this.contextRunner.withUserConfiguration(AlphaPrimaryConfiguration.class, BravoConfiguration.class,
OnBeanSingleCandidateConfiguration.class).run((context) -> {
assertThat(context).hasBean("consumer");
assertThat(context.getBean("consumer")).isEqualTo("alpha");
});
}

@Test
void singleCandidateMultipleCandidatesMultiplePrimary() {
load(FooPrimaryConfiguration.class, BarPrimaryConfiguration.class, OnBeanSingleCandidateConfiguration.class);
assertThat(this.context.containsBean("baz")).isFalse();
this.contextRunner
.withUserConfiguration(AlphaPrimaryConfiguration.class, BravoPrimaryConfiguration.class,
OnBeanSingleCandidateConfiguration.class)
.run((context) -> assertThat(context).doesNotHaveBean("consumer"));
}

@Test
void invalidAnnotationTwoTypes() {
assertThatIllegalStateException().isThrownBy(() -> load(OnBeanSingleCandidateTwoTypesConfiguration.class))
.withCauseInstanceOf(IllegalArgumentException.class)
.withMessageContaining(OnBeanSingleCandidateTwoTypesConfiguration.class.getName());
this.contextRunner.withUserConfiguration(OnBeanSingleCandidateTwoTypesConfiguration.class).run((context) -> {
assertThat(context).hasFailed();
assertThat(context).getFailure().hasCauseInstanceOf(IllegalArgumentException.class)
.hasMessageContaining(OnBeanSingleCandidateTwoTypesConfiguration.class.getName());
});
}

@Test
void invalidAnnotationNoType() {
assertThatIllegalStateException().isThrownBy(() -> load(OnBeanSingleCandidateNoTypeConfiguration.class))
.withCauseInstanceOf(IllegalArgumentException.class)
.withMessageContaining(OnBeanSingleCandidateNoTypeConfiguration.class.getName());
this.contextRunner.withUserConfiguration(OnBeanSingleCandidateNoTypeConfiguration.class).run((context) -> {
assertThat(context).hasFailed();
assertThat(context).getFailure().hasCauseInstanceOf(IllegalArgumentException.class)
.hasMessageContaining(OnBeanSingleCandidateNoTypeConfiguration.class.getName());
});
}

@Test
void singleCandidateMultipleCandidatesInContextHierarchy() {
load(FooPrimaryConfiguration.class, BarConfiguration.class);
try (AnnotationConfigApplicationContext child = new AnnotationConfigApplicationContext()) {
child.setParent(this.context);
child.register(OnBeanSingleCandidateConfiguration.class);
child.refresh();
assertThat(child.containsBean("baz")).isTrue();
assertThat(child.getBean("baz")).isEqualTo("foo");
}
}

private void load(Class<?>... classes) {
if (classes.length > 0) {
this.context.register(classes);
}
this.context.refresh();
this.contextRunner.withUserConfiguration(AlphaPrimaryConfiguration.class, BravoConfiguration.class)
.run((parent) -> this.contextRunner.withUserConfiguration(OnBeanSingleCandidateConfiguration.class)
.withParent(parent).run((child) -> {
assertThat(child).hasBean("consumer");
assertThat(child.getBean("consumer")).isEqualTo("alpha");
}));
}

@Configuration(proxyBeanMethods = false)
@ConditionalOnSingleCandidate(String.class)
static class OnBeanSingleCandidateConfiguration {

@Bean
String baz(String s) {
CharSequence consumer(CharSequence s) {
return s;
}

Expand All @@ -164,7 +161,7 @@ String baz(String s) {
static class OnBeanSingleCandidateInAncestorsConfiguration {

@Bean
String baz(String s) {
CharSequence consumer(CharSequence s) {
return s;
}

Expand All @@ -183,43 +180,54 @@ static class OnBeanSingleCandidateNoTypeConfiguration {
}

@Configuration(proxyBeanMethods = false)
static class FooConfiguration {
static class AlphaConfiguration {

@Bean
String foo() {
return "foo";
String alpha() {
return "alpha";
}

}

@Configuration(proxyBeanMethods = false)
static class FooPrimaryConfiguration {
static class AlphaPrimaryConfiguration {

@Bean
@Primary
String foo() {
return "foo";
String alpha() {
return "alpha";
}

}

@Configuration(proxyBeanMethods = false)
static class AlphaScopedProxyConfiguration {

@Bean
@Scope(proxyMode = ScopedProxyMode.INTERFACES)
String alpha() {
return "alpha";
}

}

@Configuration(proxyBeanMethods = false)
static class BarConfiguration {
static class BravoConfiguration {

@Bean
String bar() {
return "bar";
String bravo() {
return "bravo";
}

}

@Configuration(proxyBeanMethods = false)
static class BarPrimaryConfiguration {
static class BravoPrimaryConfiguration {

@Bean
@Primary
String bar() {
return "bar";
String bravo() {
return "bravo";
}

}
Expand Down

0 comments on commit f6b3666

Please sign in to comment.