Merge branch 'gh-13328'
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
* Copyright 2012-2018 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.
|
||||
@@ -45,7 +45,8 @@ public interface AutoConfigurationImportFilter {
|
||||
/**
|
||||
* Apply the filter to the given auto-configuration class candidates.
|
||||
* @param autoConfigurationClasses the auto-configuration classes being considered.
|
||||
* Implementations should not change the values in this array.
|
||||
* This array may contain {@code null} elements. Implementations should not change the
|
||||
* values in this array.
|
||||
* @param autoConfigurationMetadata access to the meta-data generated by the
|
||||
* auto-configure annotation processor
|
||||
* @return a boolean array indicating which of the auto-configuration classes should
|
||||
|
||||
@@ -263,6 +263,7 @@ public class AutoConfigurationImportSelector
|
||||
for (int i = 0; i < match.length; i++) {
|
||||
if (!match[i]) {
|
||||
skip[i] = true;
|
||||
candidates[i] = null;
|
||||
skipped = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
@@ -159,6 +160,20 @@ public final class ConditionEvaluationReport {
|
||||
return this.parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to find the {@link ConditionEvaluationReport} for the specified bean
|
||||
* factory.
|
||||
* @param beanFactory the bean factory (may be {@code null})
|
||||
* @return the {@link ConditionEvaluationReport} or {@code null}
|
||||
*/
|
||||
public static ConditionEvaluationReport find(BeanFactory beanFactory) {
|
||||
if (beanFactory != null && beanFactory instanceof ConfigurableBeanFactory) {
|
||||
return ConditionEvaluationReport
|
||||
.get((ConfigurableListableBeanFactory) beanFactory);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain a {@link ConditionEvaluationReport} for the specified bean factory.
|
||||
* @param beanFactory the bean factory
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright 2012-2018 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.boot.autoconfigure.condition;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurationImportFilter;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurationMetadata;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* Abstract base class for a {@link SpringBootCondition} that also implements
|
||||
* {@link AutoConfigurationImportFilter}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
abstract class FilteringSpringBootCondition extends SpringBootCondition
|
||||
implements AutoConfigurationImportFilter, BeanFactoryAware, BeanClassLoaderAware {
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
private ClassLoader beanClassLoader;
|
||||
|
||||
@Override
|
||||
public boolean[] match(String[] autoConfigurationClasses,
|
||||
AutoConfigurationMetadata autoConfigurationMetadata) {
|
||||
ConditionEvaluationReport report = ConditionEvaluationReport
|
||||
.find(this.beanFactory);
|
||||
ConditionOutcome[] outcomes = getOutcomes(autoConfigurationClasses,
|
||||
autoConfigurationMetadata);
|
||||
boolean[] match = new boolean[outcomes.length];
|
||||
for (int i = 0; i < outcomes.length; i++) {
|
||||
match[i] = (outcomes[i] == null || outcomes[i].isMatch());
|
||||
if (!match[i] && outcomes[i] != null) {
|
||||
logOutcome(autoConfigurationClasses[i], outcomes[i]);
|
||||
if (report != null) {
|
||||
report.recordConditionEvaluation(autoConfigurationClasses[i], this,
|
||||
outcomes[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
protected abstract ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,
|
||||
AutoConfigurationMetadata autoConfigurationMetadata);
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
protected final BeanFactory getBeanFactory() {
|
||||
return this.beanFactory;
|
||||
}
|
||||
|
||||
protected final ClassLoader getBeanClassLoader() {
|
||||
return this.beanClassLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
this.beanClassLoader = classLoader;
|
||||
}
|
||||
|
||||
protected List<String> filter(Collection<String> classNames,
|
||||
ClassNameFilter classNameFilter, ClassLoader classLoader) {
|
||||
if (CollectionUtils.isEmpty(classNames)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<String> matches = new ArrayList<>(classNames.size());
|
||||
for (String candidate : classNames) {
|
||||
if (classNameFilter.matches(candidate, classLoader)) {
|
||||
matches.add(candidate);
|
||||
}
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
protected enum ClassNameFilter {
|
||||
|
||||
PRESENT {
|
||||
|
||||
@Override
|
||||
public boolean matches(String className, ClassLoader classLoader) {
|
||||
return isPresent(className, classLoader);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
MISSING {
|
||||
|
||||
@Override
|
||||
public boolean matches(String className, ClassLoader classLoader) {
|
||||
return !isPresent(className, classLoader);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
public abstract boolean matches(String className, ClassLoader classLoader);
|
||||
|
||||
public static boolean isPresent(String className, ClassLoader classLoader) {
|
||||
if (classLoader == null) {
|
||||
classLoader = ClassUtils.getDefaultClassLoader();
|
||||
}
|
||||
try {
|
||||
forName(className, classLoader);
|
||||
return true;
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static Class<?> forName(String className, ClassLoader classLoader)
|
||||
throws ClassNotFoundException {
|
||||
if (classLoader != null) {
|
||||
return classLoader.loadClass(className);
|
||||
}
|
||||
return Class.forName(className);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -34,6 +34,7 @@ import org.springframework.beans.factory.HierarchicalBeanFactory;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurationMetadata;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage.Style;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
@@ -58,7 +59,8 @@ import org.springframework.util.StringUtils;
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@Order(Ordered.LOWEST_PRECEDENCE)
|
||||
class OnBeanCondition extends SpringBootCondition implements ConfigurationCondition {
|
||||
class OnBeanCondition extends FilteringSpringBootCondition
|
||||
implements ConfigurationCondition {
|
||||
|
||||
/**
|
||||
* Bean definition attribute name for factory beans to signal their product type (if
|
||||
@@ -66,6 +68,40 @@ class OnBeanCondition extends SpringBootCondition implements ConfigurationCondit
|
||||
*/
|
||||
public static final String FACTORY_BEAN_OBJECT_TYPE = BeanTypeRegistry.FACTORY_BEAN_OBJECT_TYPE;
|
||||
|
||||
@Override
|
||||
protected final ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,
|
||||
AutoConfigurationMetadata autoConfigurationMetadata) {
|
||||
ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length];
|
||||
for (int i = 0; i < outcomes.length; i++) {
|
||||
String autoConfigurationClass = autoConfigurationClasses[i];
|
||||
if (autoConfigurationClass != null) {
|
||||
Set<String> onBeanTypes = autoConfigurationMetadata
|
||||
.getSet(autoConfigurationClass, "ConditionalOnBean");
|
||||
outcomes[i] = getOutcome(onBeanTypes, ConditionalOnBean.class);
|
||||
if (outcomes[i] == null) {
|
||||
Set<String> onSingleCandidateTypes = autoConfigurationMetadata.getSet(
|
||||
autoConfigurationClass, "ConditionalOnSingleCandidate");
|
||||
outcomes[i] = getOutcome(onSingleCandidateTypes,
|
||||
ConditionalOnSingleCandidate.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
return outcomes;
|
||||
}
|
||||
|
||||
private ConditionOutcome getOutcome(Set<String> requiredBeanTypes,
|
||||
Class<? extends Annotation> annotation) {
|
||||
List<String> missing = filter(requiredBeanTypes, ClassNameFilter.MISSING,
|
||||
getBeanClassLoader());
|
||||
if (!missing.isEmpty()) {
|
||||
ConditionMessage message = ConditionMessage.forCondition(annotation)
|
||||
.didNotFind("required type", "required types")
|
||||
.items(Style.QUOTE, missing);
|
||||
return ConditionOutcome.noMatch(message);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigurationPhase getConfigurationPhase() {
|
||||
return ConfigurationPhase.REGISTER_BEAN;
|
||||
@@ -337,7 +373,6 @@ class OnBeanCondition extends SpringBootCondition implements ConfigurationCondit
|
||||
.getParentBeanFactory()), beanName, considerHierarchy);
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
private static class BeanSearchSpec {
|
||||
|
||||
@@ -18,17 +18,10 @@ package org.springframework.boot.autoconfigure.condition;
|
||||
|
||||
import java.security.AccessControlException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurationImportFilter;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurationMetadata;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage.Style;
|
||||
@@ -37,7 +30,6 @@ import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
@@ -49,43 +41,10 @@ import org.springframework.util.MultiValueMap;
|
||||
* @see ConditionalOnMissingClass
|
||||
*/
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
class OnClassCondition extends SpringBootCondition
|
||||
implements AutoConfigurationImportFilter, BeanFactoryAware, BeanClassLoaderAware {
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
private ClassLoader beanClassLoader;
|
||||
class OnClassCondition extends FilteringSpringBootCondition {
|
||||
|
||||
@Override
|
||||
public boolean[] match(String[] autoConfigurationClasses,
|
||||
AutoConfigurationMetadata autoConfigurationMetadata) {
|
||||
ConditionEvaluationReport report = getConditionEvaluationReport();
|
||||
ConditionOutcome[] outcomes = getOutcomes(autoConfigurationClasses,
|
||||
autoConfigurationMetadata);
|
||||
boolean[] match = new boolean[outcomes.length];
|
||||
for (int i = 0; i < outcomes.length; i++) {
|
||||
match[i] = (outcomes[i] == null || outcomes[i].isMatch());
|
||||
if (!match[i] && outcomes[i] != null) {
|
||||
logOutcome(autoConfigurationClasses[i], outcomes[i]);
|
||||
if (report != null) {
|
||||
report.recordConditionEvaluation(autoConfigurationClasses[i], this,
|
||||
outcomes[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
private ConditionEvaluationReport getConditionEvaluationReport() {
|
||||
if (this.beanFactory != null
|
||||
&& this.beanFactory instanceof ConfigurableBeanFactory) {
|
||||
return ConditionEvaluationReport
|
||||
.get((ConfigurableListableBeanFactory) this.beanFactory);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,
|
||||
protected final ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,
|
||||
AutoConfigurationMetadata autoConfigurationMetadata) {
|
||||
// Split the work and perform half in a background thread. Using a single
|
||||
// additional thread seems to offer the best performance. More threads make
|
||||
@@ -95,7 +54,7 @@ class OnClassCondition extends SpringBootCondition
|
||||
autoConfigurationClasses, 0, split, autoConfigurationMetadata);
|
||||
OutcomesResolver secondHalfResolver = new StandardOutcomesResolver(
|
||||
autoConfigurationClasses, split, autoConfigurationClasses.length,
|
||||
autoConfigurationMetadata, this.beanClassLoader);
|
||||
autoConfigurationMetadata, getBeanClassLoader());
|
||||
ConditionOutcome[] secondHalf = secondHalfResolver.resolveOutcomes();
|
||||
ConditionOutcome[] firstHalf = firstHalfResolver.resolveOutcomes();
|
||||
ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length];
|
||||
@@ -108,7 +67,7 @@ class OnClassCondition extends SpringBootCondition
|
||||
int start, int end, AutoConfigurationMetadata autoConfigurationMetadata) {
|
||||
OutcomesResolver outcomesResolver = new StandardOutcomesResolver(
|
||||
autoConfigurationClasses, start, end, autoConfigurationMetadata,
|
||||
this.beanClassLoader);
|
||||
getBeanClassLoader());
|
||||
try {
|
||||
return new ThreadedOutcomesResolver(outcomesResolver);
|
||||
}
|
||||
@@ -124,7 +83,8 @@ class OnClassCondition extends SpringBootCondition
|
||||
ConditionMessage matchMessage = ConditionMessage.empty();
|
||||
List<String> onClasses = getCandidates(metadata, ConditionalOnClass.class);
|
||||
if (onClasses != null) {
|
||||
List<String> missing = getMatches(onClasses, MatchType.MISSING, classLoader);
|
||||
List<String> missing = filter(onClasses, ClassNameFilter.MISSING,
|
||||
classLoader);
|
||||
if (!missing.isEmpty()) {
|
||||
return ConditionOutcome
|
||||
.noMatch(ConditionMessage.forCondition(ConditionalOnClass.class)
|
||||
@@ -133,12 +93,12 @@ class OnClassCondition extends SpringBootCondition
|
||||
}
|
||||
matchMessage = matchMessage.andCondition(ConditionalOnClass.class)
|
||||
.found("required class", "required classes").items(Style.QUOTE,
|
||||
getMatches(onClasses, MatchType.PRESENT, classLoader));
|
||||
filter(onClasses, ClassNameFilter.PRESENT, classLoader));
|
||||
}
|
||||
List<String> onMissingClasses = getCandidates(metadata,
|
||||
ConditionalOnMissingClass.class);
|
||||
if (onMissingClasses != null) {
|
||||
List<String> present = getMatches(onMissingClasses, MatchType.PRESENT,
|
||||
List<String> present = filter(onMissingClasses, ClassNameFilter.PRESENT,
|
||||
classLoader);
|
||||
if (!present.isEmpty()) {
|
||||
return ConditionOutcome.noMatch(
|
||||
@@ -147,8 +107,9 @@ class OnClassCondition extends SpringBootCondition
|
||||
.items(Style.QUOTE, present));
|
||||
}
|
||||
matchMessage = matchMessage.andCondition(ConditionalOnMissingClass.class)
|
||||
.didNotFind("unwanted class", "unwanted classes").items(Style.QUOTE,
|
||||
getMatches(onMissingClasses, MatchType.MISSING, classLoader));
|
||||
.didNotFind("unwanted class", "unwanted classes")
|
||||
.items(Style.QUOTE, filter(onMissingClasses, ClassNameFilter.MISSING,
|
||||
classLoader));
|
||||
}
|
||||
return ConditionOutcome.match(matchMessage);
|
||||
}
|
||||
@@ -174,72 +135,6 @@ class OnClassCondition extends SpringBootCondition
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> getMatches(Collection<String> candidates, MatchType matchType,
|
||||
ClassLoader classLoader) {
|
||||
List<String> matches = new ArrayList<>(candidates.size());
|
||||
for (String candidate : candidates) {
|
||||
if (matchType.matches(candidate, classLoader)) {
|
||||
matches.add(candidate);
|
||||
}
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
this.beanClassLoader = classLoader;
|
||||
}
|
||||
|
||||
private enum MatchType {
|
||||
|
||||
PRESENT {
|
||||
|
||||
@Override
|
||||
public boolean matches(String className, ClassLoader classLoader) {
|
||||
return isPresent(className, classLoader);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
MISSING {
|
||||
|
||||
@Override
|
||||
public boolean matches(String className, ClassLoader classLoader) {
|
||||
return !isPresent(className, classLoader);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private static boolean isPresent(String className, ClassLoader classLoader) {
|
||||
if (classLoader == null) {
|
||||
classLoader = ClassUtils.getDefaultClassLoader();
|
||||
}
|
||||
try {
|
||||
forName(className, classLoader);
|
||||
return true;
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static Class<?> forName(String className, ClassLoader classLoader)
|
||||
throws ClassNotFoundException {
|
||||
if (classLoader != null) {
|
||||
return classLoader.loadClass(className);
|
||||
}
|
||||
return Class.forName(className);
|
||||
}
|
||||
|
||||
public abstract boolean matches(String className, ClassLoader classLoader);
|
||||
|
||||
}
|
||||
|
||||
private interface OutcomesResolver {
|
||||
|
||||
ConditionOutcome[] resolveOutcomes();
|
||||
@@ -304,10 +199,12 @@ class OnClassCondition extends SpringBootCondition
|
||||
ConditionOutcome[] outcomes = new ConditionOutcome[end - start];
|
||||
for (int i = start; i < end; i++) {
|
||||
String autoConfigurationClass = autoConfigurationClasses[i];
|
||||
Set<String> candidates = autoConfigurationMetadata
|
||||
.getSet(autoConfigurationClass, "ConditionalOnClass");
|
||||
if (candidates != null) {
|
||||
outcomes[i - start] = getOutcome(candidates);
|
||||
if (autoConfigurationClass != null) {
|
||||
Set<String> candidates = autoConfigurationMetadata
|
||||
.getSet(autoConfigurationClass, "ConditionalOnClass");
|
||||
if (candidates != null) {
|
||||
outcomes[i - start] = getOutcome(candidates);
|
||||
}
|
||||
}
|
||||
}
|
||||
return outcomes;
|
||||
@@ -315,7 +212,7 @@ class OnClassCondition extends SpringBootCondition
|
||||
|
||||
private ConditionOutcome getOutcome(Set<String> candidates) {
|
||||
try {
|
||||
List<String> missing = getMatches(candidates, MatchType.MISSING,
|
||||
List<String> missing = filter(candidates, ClassNameFilter.MISSING,
|
||||
this.beanClassLoader);
|
||||
if (!missing.isEmpty()) {
|
||||
return ConditionOutcome.noMatch(
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.boot.autoconfigure.condition;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurationMetadata;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
|
||||
import org.springframework.boot.web.reactive.context.ConfigurableReactiveWebEnvironment;
|
||||
import org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext;
|
||||
@@ -36,14 +37,60 @@ import org.springframework.web.context.WebApplicationContext;
|
||||
* {@link WebApplicationContext}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Phillip Webb
|
||||
* @see ConditionalOnWebApplication
|
||||
* @see ConditionalOnNotWebApplication
|
||||
*/
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE + 20)
|
||||
class OnWebApplicationCondition extends SpringBootCondition {
|
||||
class OnWebApplicationCondition extends FilteringSpringBootCondition {
|
||||
|
||||
private static final String WEB_CONTEXT_CLASS = "org.springframework.web.context."
|
||||
+ "support.GenericWebApplicationContext";
|
||||
private static final String SERVLET_WEB_APPLICATION_CLASS = "org.springframework.web.context.support.GenericWebApplicationContext";
|
||||
|
||||
private static final String REACTIVE_WEB_APPLICATION_CLASS = "org.springframework.web.reactive.HandlerResult";
|
||||
|
||||
@Override
|
||||
protected ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,
|
||||
AutoConfigurationMetadata autoConfigurationMetadata) {
|
||||
ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length];
|
||||
for (int i = 0; i < outcomes.length; i++) {
|
||||
String autoConfigurationClass = autoConfigurationClasses[i];
|
||||
if (autoConfigurationClass != null) {
|
||||
outcomes[i] = getOutcome(autoConfigurationMetadata
|
||||
.get(autoConfigurationClass, "ConditionalOnWebApplication"));
|
||||
}
|
||||
}
|
||||
return outcomes;
|
||||
}
|
||||
|
||||
private ConditionOutcome getOutcome(String type) {
|
||||
if (type == null) {
|
||||
return null;
|
||||
}
|
||||
ConditionMessage.Builder message = ConditionMessage
|
||||
.forCondition(ConditionalOnWebApplication.class);
|
||||
if (ConditionalOnWebApplication.Type.SERVLET.name().equals(type)) {
|
||||
if (!ClassNameFilter.isPresent(SERVLET_WEB_APPLICATION_CLASS,
|
||||
getBeanClassLoader())) {
|
||||
return ConditionOutcome.noMatch(
|
||||
message.didNotFind("servlet web application classes").atAll());
|
||||
}
|
||||
}
|
||||
if (ConditionalOnWebApplication.Type.REACTIVE.name().equals(type)) {
|
||||
if (!ClassNameFilter.isPresent(REACTIVE_WEB_APPLICATION_CLASS,
|
||||
getBeanClassLoader())) {
|
||||
return ConditionOutcome.noMatch(
|
||||
message.didNotFind("reactive web application classes").atAll());
|
||||
}
|
||||
}
|
||||
if (!ClassNameFilter.isPresent(SERVLET_WEB_APPLICATION_CLASS,
|
||||
getBeanClassLoader())
|
||||
&& !ClassUtils.isPresent(REACTIVE_WEB_APPLICATION_CLASS,
|
||||
getBeanClassLoader())) {
|
||||
return ConditionOutcome.noMatch(message
|
||||
.didNotFind("reactive or servlet web application classes").atAll());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||
@@ -93,9 +140,10 @@ class OnWebApplicationCondition extends SpringBootCondition {
|
||||
|
||||
private ConditionOutcome isServletWebApplication(ConditionContext context) {
|
||||
ConditionMessage.Builder message = ConditionMessage.forCondition("");
|
||||
if (!ClassUtils.isPresent(WEB_CONTEXT_CLASS, context.getClassLoader())) {
|
||||
return ConditionOutcome
|
||||
.noMatch(message.didNotFind("web application classes").atAll());
|
||||
if (!ClassNameFilter.isPresent(SERVLET_WEB_APPLICATION_CLASS,
|
||||
context.getClassLoader())) {
|
||||
return ConditionOutcome.noMatch(
|
||||
message.didNotFind("servlet web application classes").atAll());
|
||||
}
|
||||
if (context.getBeanFactory() != null) {
|
||||
String[] scopes = context.getBeanFactory().getRegisteredScopeNames();
|
||||
@@ -115,6 +163,11 @@ class OnWebApplicationCondition extends SpringBootCondition {
|
||||
|
||||
private ConditionOutcome isReactiveWebApplication(ConditionContext context) {
|
||||
ConditionMessage.Builder message = ConditionMessage.forCondition("");
|
||||
if (!ClassNameFilter.isPresent(REACTIVE_WEB_APPLICATION_CLASS,
|
||||
context.getClassLoader())) {
|
||||
return ConditionOutcome.noMatch(
|
||||
message.didNotFind("reactive web application classes").atAll());
|
||||
}
|
||||
if (context.getEnvironment() instanceof ConfigurableReactiveWebEnvironment) {
|
||||
return ConditionOutcome
|
||||
.match(message.foundExactly("ConfigurableReactiveWebEnvironment"));
|
||||
|
||||
@@ -17,7 +17,9 @@ org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoCo
|
||||
|
||||
# Auto Configuration Import Filters
|
||||
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
|
||||
org.springframework.boot.autoconfigure.condition.OnClassCondition
|
||||
org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
|
||||
org.springframework.boot.autoconfigure.condition.OnClassCondition,\
|
||||
org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition
|
||||
|
||||
# Auto Configure
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
|
||||
@@ -18,14 +18,15 @@ package org.springframework.boot.autoconfigureprocessor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.annotation.processing.AbstractProcessor;
|
||||
@@ -36,10 +37,8 @@ import javax.lang.model.element.AnnotationMirror;
|
||||
import javax.lang.model.element.AnnotationValue;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ElementKind;
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.type.DeclaredType;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
import javax.tools.FileObject;
|
||||
import javax.tools.StandardLocation;
|
||||
|
||||
@@ -52,6 +51,9 @@ import javax.tools.StandardLocation;
|
||||
*/
|
||||
@SupportedAnnotationTypes({ "org.springframework.context.annotation.Configuration",
|
||||
"org.springframework.boot.autoconfigure.condition.ConditionalOnClass",
|
||||
"org.springframework.boot.autoconfigure.condition.ConditionalOnBean",
|
||||
"org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate",
|
||||
"org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication",
|
||||
"org.springframework.boot.autoconfigure.AutoConfigureBefore",
|
||||
"org.springframework.boot.autoconfigure.AutoConfigureAfter",
|
||||
"org.springframework.boot.autoconfigure.AutoConfigureOrder" })
|
||||
@@ -60,7 +62,9 @@ public class AutoConfigureAnnotationProcessor extends AbstractProcessor {
|
||||
protected static final String PROPERTIES_PATH = "META-INF/"
|
||||
+ "spring-autoconfigure-metadata.properties";
|
||||
|
||||
private Map<String, String> annotations;
|
||||
private final Map<String, String> annotations;
|
||||
|
||||
private final Map<String, ValueExtractor> valueExtractors;
|
||||
|
||||
private final Properties properties = new Properties();
|
||||
|
||||
@@ -68,6 +72,9 @@ public class AutoConfigureAnnotationProcessor extends AbstractProcessor {
|
||||
Map<String, String> annotations = new LinkedHashMap<>();
|
||||
addAnnotations(annotations);
|
||||
this.annotations = Collections.unmodifiableMap(annotations);
|
||||
Map<String, ValueExtractor> valueExtractors = new LinkedHashMap<>();
|
||||
addValueExtractors(valueExtractors);
|
||||
this.valueExtractors = Collections.unmodifiableMap(valueExtractors);
|
||||
}
|
||||
|
||||
protected void addAnnotations(Map<String, String> annotations) {
|
||||
@@ -75,6 +82,12 @@ public class AutoConfigureAnnotationProcessor extends AbstractProcessor {
|
||||
"org.springframework.context.annotation.Configuration");
|
||||
annotations.put("ConditionalOnClass",
|
||||
"org.springframework.boot.autoconfigure.condition.ConditionalOnClass");
|
||||
annotations.put("ConditionalOnBean",
|
||||
"org.springframework.boot.autoconfigure.condition.ConditionalOnBean");
|
||||
annotations.put("ConditionalOnSingleCandidate",
|
||||
"org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate");
|
||||
annotations.put("ConditionalOnWebApplication",
|
||||
"org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication");
|
||||
annotations.put("AutoConfigureBefore",
|
||||
"org.springframework.boot.autoconfigure.AutoConfigureBefore");
|
||||
annotations.put("AutoConfigureAfter",
|
||||
@@ -83,6 +96,18 @@ public class AutoConfigureAnnotationProcessor extends AbstractProcessor {
|
||||
"org.springframework.boot.autoconfigure.AutoConfigureOrder");
|
||||
}
|
||||
|
||||
private void addValueExtractors(Map<String, ValueExtractor> attributes) {
|
||||
attributes.put("Configuration", ValueExtractor.allFrom("value"));
|
||||
attributes.put("ConditionalOnClass", ValueExtractor.allFrom("value", "name"));
|
||||
attributes.put("ConditionalOnBean", new OnBeanConditionValueExtractor());
|
||||
attributes.put("ConditionalOnSingleCandidate",
|
||||
new OnBeanConditionValueExtractor());
|
||||
attributes.put("ConditionalOnWebApplication", ValueExtractor.allFrom("type"));
|
||||
attributes.put("AutoConfigureBefore", ValueExtractor.allFrom("value", "name"));
|
||||
attributes.put("AutoConfigureAfter", ValueExtractor.allFrom("value", "name"));
|
||||
attributes.put("AutoConfigureOrder", ValueExtractor.allFrom("value"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceVersion getSupportedSourceVersion() {
|
||||
return SourceVersion.latestSupported();
|
||||
@@ -123,10 +148,10 @@ public class AutoConfigureAnnotationProcessor extends AbstractProcessor {
|
||||
private void processElement(Element element, String propertyKey,
|
||||
String annotationName) {
|
||||
try {
|
||||
String qualifiedName = getQualifiedName(element);
|
||||
String qualifiedName = Elements.getQualifiedName(element);
|
||||
AnnotationMirror annotation = getAnnotation(element, annotationName);
|
||||
if (qualifiedName != null && annotation != null) {
|
||||
List<Object> values = getValues(annotation);
|
||||
List<Object> values = getValues(propertyKey, annotation);
|
||||
this.properties.put(qualifiedName + "." + propertyKey,
|
||||
toCommaDelimitedString(values));
|
||||
this.properties.put(qualifiedName, "");
|
||||
@@ -158,58 +183,12 @@ public class AutoConfigureAnnotationProcessor extends AbstractProcessor {
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
private List<Object> getValues(AnnotationMirror annotation) {
|
||||
return annotation.getElementValues().entrySet().stream()
|
||||
.filter(this::isNameOrValueAttribute).flatMap(this::getValues)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private boolean isNameOrValueAttribute(Entry<? extends ExecutableElement, ?> entry) {
|
||||
String attributeName = entry.getKey().getSimpleName().toString();
|
||||
return "name".equals(attributeName) || "value".equals(attributeName);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Stream<Object> getValues(Entry<?, ? extends AnnotationValue> entry) {
|
||||
Object value = entry.getValue().getValue();
|
||||
if (value instanceof List) {
|
||||
return ((List<AnnotationValue>) value).stream()
|
||||
.map((annotation) -> processValue(annotation.getValue()));
|
||||
private List<Object> getValues(String propertyKey, AnnotationMirror annotation) {
|
||||
ValueExtractor extractor = this.valueExtractors.get(propertyKey);
|
||||
if (extractor == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return Stream.of(processValue(value));
|
||||
}
|
||||
|
||||
private Object processValue(Object value) {
|
||||
if (value instanceof DeclaredType) {
|
||||
return getQualifiedName(((DeclaredType) value).asElement());
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private String getQualifiedName(Element element) {
|
||||
if (element != null) {
|
||||
TypeElement enclosingElement = getEnclosingTypeElement(element.asType());
|
||||
if (enclosingElement != null) {
|
||||
return getQualifiedName(enclosingElement) + "$"
|
||||
+ ((DeclaredType) element.asType()).asElement().getSimpleName()
|
||||
.toString();
|
||||
}
|
||||
if (element instanceof TypeElement) {
|
||||
return ((TypeElement) element).getQualifiedName().toString();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private TypeElement getEnclosingTypeElement(TypeMirror type) {
|
||||
if (type instanceof DeclaredType) {
|
||||
DeclaredType declaredType = (DeclaredType) type;
|
||||
Element enclosingElement = declaredType.asElement().getEnclosingElement();
|
||||
if (enclosingElement != null && enclosingElement instanceof TypeElement) {
|
||||
return (TypeElement) enclosingElement;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return extractor.getValues(annotation);
|
||||
}
|
||||
|
||||
private void writeProperties() throws IOException {
|
||||
@@ -222,4 +201,71 @@ public class AutoConfigureAnnotationProcessor extends AbstractProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
private interface ValueExtractor {
|
||||
|
||||
List<Object> getValues(AnnotationMirror annotation);
|
||||
|
||||
static ValueExtractor allFrom(String... attributes) {
|
||||
Set<String> names = new HashSet<>(Arrays.asList(attributes));
|
||||
return new AbstractValueExtractor() {
|
||||
|
||||
@Override
|
||||
public List<Object> getValues(AnnotationMirror annotation) {
|
||||
List<Object> result = new ArrayList<>();
|
||||
annotation.getElementValues().forEach((key, value) -> {
|
||||
if (names.contains(key.getSimpleName().toString())) {
|
||||
extractValues(value).forEach(result::add);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private abstract static class AbstractValueExtractor implements ValueExtractor {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected Stream<Object> extractValues(AnnotationValue annotationValue) {
|
||||
if (annotationValue == null) {
|
||||
return Stream.empty();
|
||||
}
|
||||
Object value = annotationValue.getValue();
|
||||
if (value instanceof List) {
|
||||
return ((List<AnnotationValue>) value).stream()
|
||||
.map((annotation) -> extractValue(annotation.getValue()));
|
||||
}
|
||||
return Stream.of(extractValue(value));
|
||||
}
|
||||
|
||||
private Object extractValue(Object value) {
|
||||
if (value instanceof DeclaredType) {
|
||||
return Elements.getQualifiedName(((DeclaredType) value).asElement());
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class OnBeanConditionValueExtractor extends AbstractValueExtractor {
|
||||
|
||||
@Override
|
||||
public List<Object> getValues(AnnotationMirror annotation) {
|
||||
Map<String, AnnotationValue> attributes = new LinkedHashMap<>();
|
||||
annotation.getElementValues().forEach((key, value) -> attributes
|
||||
.put(key.getSimpleName().toString(), value));
|
||||
if (attributes.containsKey("name")) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<Object> result = new ArrayList<>();
|
||||
extractValues(attributes.get("value")).forEach(result::add);
|
||||
extractValues(attributes.get("type")).forEach(result::add);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2012-2018 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.boot.autoconfigureprocessor;
|
||||
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.type.DeclaredType;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
|
||||
/**
|
||||
* Utilities for dealing with {@link Element} classes.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
final class Elements {
|
||||
|
||||
private Elements() {
|
||||
}
|
||||
|
||||
static String getQualifiedName(Element element) {
|
||||
if (element != null) {
|
||||
TypeElement enclosingElement = getEnclosingTypeElement(element.asType());
|
||||
if (enclosingElement != null) {
|
||||
return getQualifiedName(enclosingElement) + "$"
|
||||
+ ((DeclaredType) element.asType()).asElement().getSimpleName()
|
||||
.toString();
|
||||
}
|
||||
if (element instanceof TypeElement) {
|
||||
return ((TypeElement) element).getQualifiedName().toString();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static TypeElement getEnclosingTypeElement(TypeMirror type) {
|
||||
if (type instanceof DeclaredType) {
|
||||
DeclaredType declaredType = (DeclaredType) type;
|
||||
Element enclosingElement = declaredType.asElement().getEnclosingElement();
|
||||
if (enclosingElement != null && enclosingElement instanceof TypeElement) {
|
||||
return (TypeElement) enclosingElement;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
* Copyright 2012-2018 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.
|
||||
@@ -50,18 +50,42 @@ public class AutoConfigureAnnotationProcessorTests {
|
||||
@Test
|
||||
public void annotatedClass() throws Exception {
|
||||
Properties properties = compile(TestClassConfiguration.class);
|
||||
assertThat(properties).hasSize(3);
|
||||
assertThat(properties).hasSize(6);
|
||||
assertThat(properties).containsEntry(
|
||||
"org.springframework.boot.autoconfigureprocessor."
|
||||
+ "TestClassConfiguration.ConditionalOnClass",
|
||||
"java.io.InputStream,org.springframework.boot.autoconfigureprocessor."
|
||||
+ "TestClassConfiguration$Nested");
|
||||
assertThat(properties).containsKey(
|
||||
"org.springframework.boot.autoconfigureprocessor.TestClassConfiguration");
|
||||
assertThat(properties).containsKey(
|
||||
"org.springframework.boot.autoconfigureprocessor.TestClassConfiguration.Configuration");
|
||||
assertThat(properties).doesNotContainKey(
|
||||
"org.springframework.boot.autoconfigureprocessor.TestClassConfiguration$Nested");
|
||||
assertThat(properties)
|
||||
.containsKey("org.springframework.boot.autoconfigureprocessor."
|
||||
+ "TestClassConfiguration");
|
||||
assertThat(properties)
|
||||
.containsKey("org.springframework.boot.autoconfigureprocessor."
|
||||
+ "TestClassConfiguration.Configuration");
|
||||
assertThat(properties)
|
||||
.doesNotContainKey("org.springframework.boot.autoconfigureprocessor."
|
||||
+ "TestClassConfiguration$Nested");
|
||||
assertThat(properties).containsEntry(
|
||||
"org.springframework.boot.autoconfigureprocessor."
|
||||
+ "TestClassConfiguration.ConditionalOnBean",
|
||||
"java.io.OutputStream");
|
||||
assertThat(properties).containsEntry(
|
||||
"org.springframework.boot.autoconfigureprocessor."
|
||||
+ "TestClassConfiguration.ConditionalOnSingleCandidate",
|
||||
"java.io.OutputStream");
|
||||
assertThat(properties).containsEntry(
|
||||
"org.springframework.boot.autoconfigureprocessor."
|
||||
+ "TestClassConfiguration.ConditionalOnWebApplication",
|
||||
"SERVLET");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void annoatedClassWithOnBeanThatHasName() throws Exception {
|
||||
Properties properties = compile(TestOnBeanWithNameClassConfiguration.class);
|
||||
assertThat(properties).hasSize(3);
|
||||
assertThat(properties).containsEntry(
|
||||
"org.springframework.boot.autoconfigureprocessor.TestOnBeanWithNameClassConfiguration.ConditionalOnBean",
|
||||
"");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -104,7 +128,7 @@ public class AutoConfigureAnnotationProcessorTests {
|
||||
}
|
||||
|
||||
private Properties compile(Class<?>... types) throws IOException {
|
||||
TestConditionMetadataAnnotationProcessor processor = new TestConditionMetadataAnnotationProcessor(
|
||||
TestAutoConfigureAnnotationProcessor processor = new TestAutoConfigureAnnotationProcessor(
|
||||
this.compiler.getOutputLocation());
|
||||
this.compiler.getTask(types).call(processor);
|
||||
return processor.getWrittenProperties();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
* Copyright 2012-2018 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.
|
||||
@@ -32,15 +32,18 @@ import javax.annotation.processing.SupportedAnnotationTypes;
|
||||
@SupportedAnnotationTypes({
|
||||
"org.springframework.boot.autoconfigureprocessor.TestConfiguration",
|
||||
"org.springframework.boot.autoconfigureprocessor.TestConditionalOnClass",
|
||||
"org.springframework.boot.autoconfigure.condition.TestConditionalOnBean",
|
||||
"org.springframework.boot.autoconfigure.condition.TestConditionalOnSingleCandidate",
|
||||
"org.springframework.boot.autoconfigure.condition.TestConditionalOnWebApplication",
|
||||
"org.springframework.boot.autoconfigureprocessor.TestAutoConfigureBefore",
|
||||
"org.springframework.boot.autoconfigureprocessor.TestAutoConfigureAfter",
|
||||
"org.springframework.boot.autoconfigureprocessor.TestAutoConfigureOrder" })
|
||||
public class TestConditionMetadataAnnotationProcessor
|
||||
public class TestAutoConfigureAnnotationProcessor
|
||||
extends AutoConfigureAnnotationProcessor {
|
||||
|
||||
private final File outputLocation;
|
||||
|
||||
public TestConditionMetadataAnnotationProcessor(File outputLocation) {
|
||||
public TestAutoConfigureAnnotationProcessor(File outputLocation) {
|
||||
this.outputLocation = outputLocation;
|
||||
}
|
||||
|
||||
@@ -48,6 +51,11 @@ public class TestConditionMetadataAnnotationProcessor
|
||||
protected void addAnnotations(Map<String, String> annotations) {
|
||||
put(annotations, "Configuration", TestConfiguration.class);
|
||||
put(annotations, "ConditionalOnClass", TestConditionalOnClass.class);
|
||||
put(annotations, "ConditionalOnBean", TestConditionalOnBean.class);
|
||||
put(annotations, "ConditionalOnSingleCandidate",
|
||||
TestConditionalOnSingleCandidate.class);
|
||||
put(annotations, "ConditionalOnWebApplication",
|
||||
TestConditionalOnWebApplication.class);
|
||||
put(annotations, "AutoConfigureBefore", TestAutoConfigureBefore.class);
|
||||
put(annotations, "AutoConfigureAfter", TestAutoConfigureAfter.class);
|
||||
put(annotations, "AutoConfigureOrder", TestAutoConfigureOrder.class);
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
* Copyright 2012-2018 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.
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.boot.autoconfigureprocessor;
|
||||
|
||||
import org.springframework.boot.autoconfigureprocessor.TestConditionalOnWebApplication.Type;
|
||||
|
||||
/**
|
||||
* Test configuration with an annotated class.
|
||||
*
|
||||
@@ -23,6 +25,9 @@ package org.springframework.boot.autoconfigureprocessor;
|
||||
*/
|
||||
@TestConfiguration
|
||||
@TestConditionalOnClass(name = "java.io.InputStream", value = TestClassConfiguration.Nested.class)
|
||||
@TestConditionalOnBean(type = "java.io.OutputStream")
|
||||
@TestConditionalOnSingleCandidate(type = "java.io.OutputStream")
|
||||
@TestConditionalOnWebApplication(type = Type.SERVLET)
|
||||
public class TestClassConfiguration {
|
||||
|
||||
@TestAutoConfigureOrder
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2012-2018 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.boot.autoconfigureprocessor;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Alternative to Spring Boot's {@code ConditionalOnBean} for testing (removes the need
|
||||
* for a dependency on the real annotation).
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface TestConditionalOnBean {
|
||||
|
||||
Class<?>[] value() default {};
|
||||
|
||||
String[] type() default {};
|
||||
|
||||
Class<? extends Annotation>[] annotation() default {};
|
||||
|
||||
String[] name() default {};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2012-2018 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.boot.autoconfigureprocessor;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Alternative to Spring Boot's {@code ConditionalOnSingleCandidate} for testing (removes
|
||||
* the need for a dependency on the real annotation).
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface TestConditionalOnSingleCandidate {
|
||||
|
||||
Class<?> value() default Object.class;
|
||||
|
||||
String type() default "";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2012-2018 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.boot.autoconfigureprocessor;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Alternative to Spring Boot's {@code @ConditionalOnWebApplication} for testing (removes
|
||||
* the need for a dependency on the real annotation).
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface TestConditionalOnWebApplication {
|
||||
|
||||
Type type() default Type.ANY;
|
||||
|
||||
enum Type {
|
||||
|
||||
ANY, SERVLET, REACTIVE
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2012-2018 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.boot.autoconfigureprocessor;
|
||||
|
||||
/**
|
||||
* Test configuration with an annotated class.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@TestConfiguration
|
||||
@TestConditionalOnBean(name = "test", type = "java.io.OutputStream")
|
||||
public class TestOnBeanWithNameClassConfiguration {
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user