diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnMissingClass.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnMissingClass.java index 7e9782c9eda..4fbbdba6b77 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnMissingClass.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnMissingClass.java @@ -32,7 +32,7 @@ import org.springframework.context.annotation.Conditional; @Target({ ElementType.TYPE, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @Documented -@Conditional(OnMissingClassCondition.class) +@Conditional(OnClassCondition.class) public @interface ConditionalOnMissingClass { /** diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnClassCondition.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnClassCondition.java index 4617dffadbf..3bdc97f51a6 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnClassCondition.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnClassCondition.java @@ -16,7 +16,8 @@ package org.springframework.boot.autoconfigure.condition; -import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import org.apache.commons.logging.Log; @@ -24,15 +25,16 @@ import org.apache.commons.logging.LogFactory; import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.type.AnnotatedTypeMetadata; -import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.MultiValueMap; +import org.springframework.util.StringUtils; /** - * {@link Condition} that checks for the specific classes. + * {@link Condition} that checks for the presence or absence of specific classes. * * @author Phillip Webb * @see ConditionalOnClass + * @see ConditionalOnMissingClass */ class OnClassCondition implements Condition { @@ -43,40 +45,90 @@ class OnClassCondition implements Condition { String checking = ConditionLogUtils.getPrefix(logger, metadata); - MultiValueMap attributes = metadata.getAllAnnotationAttributes( - ConditionalOnClass.class.getName(), true); - if (attributes != null) { - List classNames = new ArrayList(); - collectClassNames(classNames, attributes.get("value")); - collectClassNames(classNames, attributes.get("name")); - Assert.isTrue(classNames.size() > 0, - "@ConditionalOnClass annotations must specify at least one class value"); - for (String className : classNames) { + MultiValueMap onClasses = getAttributes(metadata, + ConditionalOnClass.class); + if (onClasses != null) { + List missing = getMatchingClasses(onClasses, MatchType.MISSING, + context); + if (!missing.isEmpty()) { if (logger.isDebugEnabled()) { - logger.debug(checking + "Looking for class: " + className); - } - if (!ClassUtils.isPresent(className, context.getClassLoader())) { - if (logger.isDebugEnabled()) { - logger.debug(checking + "Class not found: " + className - + " (search terminated with matches=false)"); - } - return false; + logger.debug(checking + + "Required @ConditionalOnClass classes not found: " + + StringUtils.collectionToCommaDelimitedString(missing) + + " (search terminated with matches=false)"); } + return false; } } + + MultiValueMap onMissingClasses = getAttributes(metadata, + ConditionalOnMissingClass.class); + if (onMissingClasses != null) { + List present = getMatchingClasses(onMissingClasses, + MatchType.PRESENT, context); + if (!present.isEmpty()) { + if (logger.isDebugEnabled()) { + logger.debug(checking + + "Required @ConditionalOnMissing classes found: " + + StringUtils.collectionToCommaDelimitedString(present) + + " (search terminated with matches=false)"); + } + return false; + } + } + if (logger.isDebugEnabled()) { logger.debug(checking + "Match result is: true"); } return true; } - private void collectClassNames(List classNames, List values) { - for (Object value : values) { - for (Object valueItem : (Object[]) value) { - classNames.add(valueItem instanceof Class ? ((Class) valueItem) - .getName() : valueItem.toString()); + private MultiValueMap getAttributes(AnnotatedTypeMetadata metadata, + Class annotationType) { + return metadata.getAllAnnotationAttributes(annotationType.getName(), true); + } + + private List getMatchingClasses(MultiValueMap attributes, + MatchType matchType, ConditionContext context) { + List matches = new LinkedList(); + addAll(matches, attributes.get("value")); + addAll(matches, attributes.get("name")); + Iterator iterator = matches.iterator(); + while (iterator.hasNext()) { + if (!matchType.matches(iterator.next(), context)) { + iterator.remove(); + } + } + return matches; + } + + private void addAll(List list, List itemsToAdd) { + if (itemsToAdd != null) { + for (Object item : itemsToAdd) { + for (String arrayItem : (String[]) item) { + list.add(arrayItem.toString()); + } } } } + private static enum MatchType { + + PRESENT { + @Override + public boolean matches(String className, ConditionContext context) { + return ClassUtils.isPresent(className, context.getClassLoader()); + } + }, + + MISSING { + @Override + public boolean matches(String className, ConditionContext context) { + return !ClassUtils.isPresent(className, context.getClassLoader()); + } + }; + + public abstract boolean matches(String className, ConditionContext context); + + }; } diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnMissingClassCondition.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnMissingClassCondition.java deleted file mode 100644 index d5d09a73979..00000000000 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnMissingClassCondition.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2012-2013 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.List; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.context.annotation.Condition; -import org.springframework.context.annotation.ConditionContext; -import org.springframework.core.type.AnnotatedTypeMetadata; -import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; -import org.springframework.util.MultiValueMap; - -/** - * {@link Condition} that checks for the specific classes. - * - * @author Dave Syer - * @see ConditionalOnMissingClass - */ -class OnMissingClassCondition implements Condition { - - private static Log logger = LogFactory.getLog(OnMissingClassCondition.class); - - @Override - public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { - - String checking = ConditionLogUtils.getPrefix(logger, metadata); - - MultiValueMap attributes = metadata.getAllAnnotationAttributes( - ConditionalOnMissingClass.class.getName(), true); - if (attributes != null) { - List classNames = new ArrayList(); - collectClassNames(classNames, attributes.get("value")); - Assert.isTrue(classNames.size() > 0, - "@ConditionalOnMissingClass annotations must specify at least one class value"); - for (String className : classNames) { - if (logger.isDebugEnabled()) { - logger.debug(checking + "Looking for class: " + className); - } - if (ClassUtils.isPresent(className, context.getClassLoader())) { - if (logger.isDebugEnabled()) { - logger.debug(checking + "Found class: " + className - + " (search terminated with matches=false)"); - } - return false; - } - } - } - if (logger.isDebugEnabled()) { - logger.debug(checking + "Match result is: true"); - } - return true; - } - - private void collectClassNames(List classNames, List values) { - for (Object value : values) { - for (Object valueItem : (Object[]) value) { - classNames.add(valueItem instanceof Class ? ((Class) valueItem) - .getName() : valueItem.toString()); - } - } - } - - // FIXME merge with OnClassCondition -} diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/OnMissingClassConditionTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/OnMissingClassConditionTests.java index 1b1bdf46583..faa11f7d6c1 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/OnMissingClassConditionTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/OnMissingClassConditionTests.java @@ -26,7 +26,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; /** - * Tests for {@link OnMissingClassCondition}. + * Tests for {@link ConditionalOnMissingClass}. * * @author Dave Syer */