Skip to content

Commit 4d705df

Browse files
committed
Merge branch 'gh-13328'
2 parents 5765ed0 + ff98ba0 commit 4d705df

File tree

17 files changed

+647
-196
lines changed

17 files changed

+647
-196
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportFilter.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2017 the original author or authors.
2+
* Copyright 2012-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -45,7 +45,8 @@ public interface AutoConfigurationImportFilter {
4545
/**
4646
* Apply the filter to the given auto-configuration class candidates.
4747
* @param autoConfigurationClasses the auto-configuration classes being considered.
48-
* Implementations should not change the values in this array.
48+
* This array may contain {@code null} elements. Implementations should not change the
49+
* values in this array.
4950
* @param autoConfigurationMetadata access to the meta-data generated by the
5051
* auto-configure annotation processor
5152
* @return a boolean array indicating which of the auto-configuration classes should

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@ private List<String> filter(List<String> configurations,
263263
for (int i = 0; i < match.length; i++) {
264264
if (!match[i]) {
265265
skip[i] = true;
266+
candidates[i] = null;
266267
skipped = true;
267268
}
268269
}

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionEvaluationReport.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import java.util.TreeMap;
3030

3131
import org.springframework.beans.factory.BeanFactory;
32+
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
3233
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
3334
import org.springframework.context.annotation.Condition;
3435
import org.springframework.context.annotation.ConditionContext;
@@ -159,6 +160,20 @@ public ConditionEvaluationReport getParent() {
159160
return this.parent;
160161
}
161162

163+
/**
164+
* Attempt to find the {@link ConditionEvaluationReport} for the specified bean
165+
* factory.
166+
* @param beanFactory the bean factory (may be {@code null})
167+
* @return the {@link ConditionEvaluationReport} or {@code null}
168+
*/
169+
public static ConditionEvaluationReport find(BeanFactory beanFactory) {
170+
if (beanFactory != null && beanFactory instanceof ConfigurableBeanFactory) {
171+
return ConditionEvaluationReport
172+
.get((ConfigurableListableBeanFactory) beanFactory);
173+
}
174+
return null;
175+
}
176+
162177
/**
163178
* Obtain a {@link ConditionEvaluationReport} for the specified bean factory.
164179
* @param beanFactory the bean factory
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
/*
2+
* Copyright 2012-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.condition;
18+
19+
import java.util.ArrayList;
20+
import java.util.Collection;
21+
import java.util.Collections;
22+
import java.util.List;
23+
24+
import org.springframework.beans.BeansException;
25+
import org.springframework.beans.factory.BeanClassLoaderAware;
26+
import org.springframework.beans.factory.BeanFactory;
27+
import org.springframework.beans.factory.BeanFactoryAware;
28+
import org.springframework.boot.autoconfigure.AutoConfigurationImportFilter;
29+
import org.springframework.boot.autoconfigure.AutoConfigurationMetadata;
30+
import org.springframework.util.ClassUtils;
31+
import org.springframework.util.CollectionUtils;
32+
33+
/**
34+
* Abstract base class for a {@link SpringBootCondition} that also implements
35+
* {@link AutoConfigurationImportFilter}.
36+
*
37+
* @author Phillip Webb
38+
*/
39+
abstract class FilteringSpringBootCondition extends SpringBootCondition
40+
implements AutoConfigurationImportFilter, BeanFactoryAware, BeanClassLoaderAware {
41+
42+
private BeanFactory beanFactory;
43+
44+
private ClassLoader beanClassLoader;
45+
46+
@Override
47+
public boolean[] match(String[] autoConfigurationClasses,
48+
AutoConfigurationMetadata autoConfigurationMetadata) {
49+
ConditionEvaluationReport report = ConditionEvaluationReport
50+
.find(this.beanFactory);
51+
ConditionOutcome[] outcomes = getOutcomes(autoConfigurationClasses,
52+
autoConfigurationMetadata);
53+
boolean[] match = new boolean[outcomes.length];
54+
for (int i = 0; i < outcomes.length; i++) {
55+
match[i] = (outcomes[i] == null || outcomes[i].isMatch());
56+
if (!match[i] && outcomes[i] != null) {
57+
logOutcome(autoConfigurationClasses[i], outcomes[i]);
58+
if (report != null) {
59+
report.recordConditionEvaluation(autoConfigurationClasses[i], this,
60+
outcomes[i]);
61+
}
62+
}
63+
}
64+
return match;
65+
}
66+
67+
protected abstract ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,
68+
AutoConfigurationMetadata autoConfigurationMetadata);
69+
70+
@Override
71+
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
72+
this.beanFactory = beanFactory;
73+
}
74+
75+
protected final BeanFactory getBeanFactory() {
76+
return this.beanFactory;
77+
}
78+
79+
protected final ClassLoader getBeanClassLoader() {
80+
return this.beanClassLoader;
81+
}
82+
83+
@Override
84+
public void setBeanClassLoader(ClassLoader classLoader) {
85+
this.beanClassLoader = classLoader;
86+
}
87+
88+
protected List<String> filter(Collection<String> classNames,
89+
ClassNameFilter classNameFilter, ClassLoader classLoader) {
90+
if (CollectionUtils.isEmpty(classNames)) {
91+
return Collections.emptyList();
92+
}
93+
List<String> matches = new ArrayList<>(classNames.size());
94+
for (String candidate : classNames) {
95+
if (classNameFilter.matches(candidate, classLoader)) {
96+
matches.add(candidate);
97+
}
98+
}
99+
return matches;
100+
}
101+
102+
protected enum ClassNameFilter {
103+
104+
PRESENT {
105+
106+
@Override
107+
public boolean matches(String className, ClassLoader classLoader) {
108+
return isPresent(className, classLoader);
109+
}
110+
111+
},
112+
113+
MISSING {
114+
115+
@Override
116+
public boolean matches(String className, ClassLoader classLoader) {
117+
return !isPresent(className, classLoader);
118+
}
119+
120+
};
121+
122+
public abstract boolean matches(String className, ClassLoader classLoader);
123+
124+
public static boolean isPresent(String className, ClassLoader classLoader) {
125+
if (classLoader == null) {
126+
classLoader = ClassUtils.getDefaultClassLoader();
127+
}
128+
try {
129+
forName(className, classLoader);
130+
return true;
131+
}
132+
catch (Throwable ex) {
133+
return false;
134+
}
135+
}
136+
137+
private static Class<?> forName(String className, ClassLoader classLoader)
138+
throws ClassNotFoundException {
139+
if (classLoader != null) {
140+
return classLoader.loadClass(className);
141+
}
142+
return Class.forName(className);
143+
}
144+
145+
}
146+
147+
}

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnBeanCondition.java

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.springframework.beans.factory.ListableBeanFactory;
3535
import org.springframework.beans.factory.config.BeanDefinition;
3636
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
37+
import org.springframework.boot.autoconfigure.AutoConfigurationMetadata;
3738
import org.springframework.boot.autoconfigure.condition.ConditionMessage.Style;
3839
import org.springframework.context.annotation.Bean;
3940
import org.springframework.context.annotation.Condition;
@@ -58,14 +59,49 @@
5859
* @author Andy Wilkinson
5960
*/
6061
@Order(Ordered.LOWEST_PRECEDENCE)
61-
class OnBeanCondition extends SpringBootCondition implements ConfigurationCondition {
62+
class OnBeanCondition extends FilteringSpringBootCondition
63+
implements ConfigurationCondition {
6264

6365
/**
6466
* Bean definition attribute name for factory beans to signal their product type (if
6567
* known and it can't be deduced from the factory bean class).
6668
*/
6769
public static final String FACTORY_BEAN_OBJECT_TYPE = BeanTypeRegistry.FACTORY_BEAN_OBJECT_TYPE;
6870

71+
@Override
72+
protected final ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,
73+
AutoConfigurationMetadata autoConfigurationMetadata) {
74+
ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length];
75+
for (int i = 0; i < outcomes.length; i++) {
76+
String autoConfigurationClass = autoConfigurationClasses[i];
77+
if (autoConfigurationClass != null) {
78+
Set<String> onBeanTypes = autoConfigurationMetadata
79+
.getSet(autoConfigurationClass, "ConditionalOnBean");
80+
outcomes[i] = getOutcome(onBeanTypes, ConditionalOnBean.class);
81+
if (outcomes[i] == null) {
82+
Set<String> onSingleCandidateTypes = autoConfigurationMetadata.getSet(
83+
autoConfigurationClass, "ConditionalOnSingleCandidate");
84+
outcomes[i] = getOutcome(onSingleCandidateTypes,
85+
ConditionalOnSingleCandidate.class);
86+
}
87+
}
88+
}
89+
return outcomes;
90+
}
91+
92+
private ConditionOutcome getOutcome(Set<String> requiredBeanTypes,
93+
Class<? extends Annotation> annotation) {
94+
List<String> missing = filter(requiredBeanTypes, ClassNameFilter.MISSING,
95+
getBeanClassLoader());
96+
if (!missing.isEmpty()) {
97+
ConditionMessage message = ConditionMessage.forCondition(annotation)
98+
.didNotFind("required type", "required types")
99+
.items(Style.QUOTE, missing);
100+
return ConditionOutcome.noMatch(message);
101+
}
102+
return null;
103+
}
104+
69105
@Override
70106
public ConfigurationPhase getConfigurationPhase() {
71107
return ConfigurationPhase.REGISTER_BEAN;
@@ -337,7 +373,6 @@ private BeanDefinition findBeanDefinition(ConfigurableListableBeanFactory beanFa
337373
.getParentBeanFactory()), beanName, considerHierarchy);
338374
}
339375
return null;
340-
341376
}
342377

343378
private static class BeanSearchSpec {

0 commit comments

Comments
 (0)