Browse Source

Merge branch 'gh-13328'

pull/14592/head
Phillip Webb 7 years ago
parent
commit
4d705dffdf
  1. 5
      spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportFilter.java
  2. 1
      spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java
  3. 15
      spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionEvaluationReport.java
  4. 147
      spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/FilteringSpringBootCondition.java
  5. 39
      spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnBeanCondition.java
  6. 139
      spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnClassCondition.java
  7. 65
      spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnWebApplicationCondition.java
  8. 4
      spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories
  9. 148
      spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/main/java/org/springframework/boot/autoconfigureprocessor/AutoConfigureAnnotationProcessor.java
  10. 60
      spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/main/java/org/springframework/boot/autoconfigureprocessor/Elements.java
  11. 42
      spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/AutoConfigureAnnotationProcessorTests.java
  12. 14
      spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestAutoConfigureAnnotationProcessor.java
  13. 7
      spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestClassConfiguration.java
  14. 45
      spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestConditionalOnBean.java
  15. 40
      spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestConditionalOnSingleCandidate.java
  16. 44
      spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestConditionalOnWebApplication.java
  17. 28
      spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestOnBeanWithNameClassConfiguration.java

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

@ -1,5 +1,5 @@ @@ -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 { @@ -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

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

@ -263,6 +263,7 @@ public class AutoConfigurationImportSelector @@ -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;
}
}

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

@ -29,6 +29,7 @@ import java.util.SortedMap; @@ -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 { @@ -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

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

@ -0,0 +1,147 @@ @@ -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);
}
}
}

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

@ -34,6 +34,7 @@ import org.springframework.beans.factory.HierarchicalBeanFactory; @@ -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; @@ -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 @@ -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 @@ -337,7 +373,6 @@ class OnBeanCondition extends SpringBootCondition implements ConfigurationCondit
.getParentBeanFactory()), beanName, considerHierarchy);
}
return null;
}
private static class BeanSearchSpec {

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

@ -18,17 +18,10 @@ package org.springframework.boot.autoconfigure.condition; @@ -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; @@ -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; @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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(

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

@ -18,6 +18,7 @@ package org.springframework.boot.autoconfigure.condition; @@ -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; @@ -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 { @@ -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 { @@ -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"));

4
spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories

@ -17,7 +17,9 @@ org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoCo @@ -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=\

148
spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/main/java/org/springframework/boot/autoconfigureprocessor/AutoConfigureAnnotationProcessor.java

@ -18,14 +18,15 @@ package org.springframework.boot.autoconfigureprocessor; @@ -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; @@ -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; @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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,68 +183,89 @@ public class AutoConfigureAnnotationProcessor extends AbstractProcessor { @@ -158,68 +183,89 @@ 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);
private List<Object> getValues(String propertyKey, AnnotationMirror annotation) {
ValueExtractor extractor = this.valueExtractors.get(propertyKey);
if (extractor == null) {
return Collections.emptyList();
}
return extractor.getValues(annotation);
}
@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 void writeProperties() throws IOException {
if (!this.properties.isEmpty()) {
FileObject file = this.processingEnv.getFiler()
.createResource(StandardLocation.CLASS_OUTPUT, "", PROPERTIES_PATH);
try (OutputStream outputStream = file.openOutputStream()) {
this.properties.store(outputStream, null);
}
}
return Stream.of(processValue(value));
}
private Object processValue(Object value) {
if (value instanceof DeclaredType) {
return getQualifiedName(((DeclaredType) value).asElement());
@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;
}
};
}
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();
private abstract static class AbstractValueExtractor implements ValueExtractor {
@SuppressWarnings("unchecked")
protected Stream<Object> extractValues(AnnotationValue annotationValue) {
if (annotationValue == null) {
return Stream.empty();
}
if (element instanceof TypeElement) {
return ((TypeElement) element).getQualifiedName().toString();
Object value = annotationValue.getValue();
if (value instanceof List) {
return ((List<AnnotationValue>) value).stream()
.map((annotation) -> extractValue(annotation.getValue()));
}
return Stream.of(extractValue(value));
}
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;
private Object extractValue(Object value) {
if (value instanceof DeclaredType) {
return Elements.getQualifiedName(((DeclaredType) value).asElement());
}
return value;
}
return null;
}
private void writeProperties() throws IOException {
if (!this.properties.isEmpty()) {
FileObject file = this.processingEnv.getFiler()
.createResource(StandardLocation.CLASS_OUTPUT, "", PROPERTIES_PATH);
try (OutputStream outputStream = file.openOutputStream()) {
this.properties.store(outputStream, null);
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;
}
}
}

60
spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/main/java/org/springframework/boot/autoconfigureprocessor/Elements.java

@ -0,0 +1,60 @@ @@ -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;
}
}

42
spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/AutoConfigureAnnotationProcessorTests.java

@ -1,5 +1,5 @@ @@ -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 { @@ -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 { @@ -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();

14
spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestConditionMetadataAnnotationProcessor.java → spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestAutoConfigureAnnotationProcessor.java

@ -1,5 +1,5 @@ @@ -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; @@ -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 @@ -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);

7
spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestClassConfiguration.java

@ -1,5 +1,5 @@ @@ -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 @@ @@ -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; @@ -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

45
spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestConditionalOnBean.java

@ -0,0 +1,45 @@ @@ -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 {};
}

40
spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestConditionalOnSingleCandidate.java

@ -0,0 +1,40 @@ @@ -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 "";
}

44
spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestConditionalOnWebApplication.java

@ -0,0 +1,44 @@ @@ -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
}
}

28
spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestOnBeanWithNameClassConfiguration.java

@ -0,0 +1,28 @@ @@ -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 {
}
Loading…
Cancel
Save