Browse Source
Merge OnMissingBeanCondition into OnBeanCondition and simplify code. Polish on bean conditionspull/23/head
6 changed files with 203 additions and 235 deletions
@ -1,184 +0,0 @@
@@ -1,184 +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.lang.reflect.Method; |
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
import org.apache.commons.logging.Log; |
||||
import org.apache.commons.logging.LogFactory; |
||||
import org.springframework.beans.factory.BeanFactory; |
||||
import org.springframework.beans.factory.BeanFactoryUtils; |
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.ConditionContext; |
||||
import org.springframework.context.annotation.ConfigurationCondition; |
||||
import org.springframework.core.type.AnnotatedTypeMetadata; |
||||
import org.springframework.core.type.MethodMetadata; |
||||
import org.springframework.util.Assert; |
||||
import org.springframework.util.ClassUtils; |
||||
import org.springframework.util.MultiValueMap; |
||||
import org.springframework.util.ReflectionUtils; |
||||
import org.springframework.util.ReflectionUtils.MethodCallback; |
||||
|
||||
/** |
||||
* Base for {@link OnBeanCondition} and {@link OnMissingBeanCondition}. |
||||
* |
||||
* @author Phillip Webb |
||||
* @author Dave Syer |
||||
*/ |
||||
abstract class AbstractOnBeanCondition implements ConfigurationCondition { |
||||
|
||||
private final Log logger = LogFactory.getLog(getClass()); |
||||
|
||||
protected abstract Class<?> annotationClass(); |
||||
|
||||
@Override |
||||
public ConfigurationPhase getConfigurationPhase() { |
||||
return ConfigurationPhase.REGISTER_BEAN; |
||||
} |
||||
|
||||
@Override |
||||
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { |
||||
MultiValueMap<String, Object> attributes = metadata.getAllAnnotationAttributes( |
||||
annotationClass().getName(), true); |
||||
final List<String> beanClasses = collect(attributes, "value"); |
||||
final List<String> beanNames = collect(attributes, "name"); |
||||
|
||||
if (beanClasses.size() == 0) { |
||||
if (metadata instanceof MethodMetadata |
||||
&& metadata.isAnnotated(Bean.class.getName())) { |
||||
try { |
||||
final MethodMetadata methodMetadata = (MethodMetadata) metadata; |
||||
// We should be safe to load at this point since we are in the
|
||||
// REGISTER_BEAN phase
|
||||
Class<?> configClass = ClassUtils.forName( |
||||
methodMetadata.getDeclaringClassName(), |
||||
context.getClassLoader()); |
||||
ReflectionUtils.doWithMethods(configClass, new MethodCallback() { |
||||
@Override |
||||
public void doWith(Method method) |
||||
throws IllegalArgumentException, IllegalAccessException { |
||||
if (methodMetadata.getMethodName().equals(method.getName())) { |
||||
beanClasses.add(method.getReturnType().getName()); |
||||
} |
||||
} |
||||
}); |
||||
} |
||||
catch (Exception ex) { |
||||
// swallow exception and continue
|
||||
} |
||||
} |
||||
} |
||||
|
||||
Assert.isTrue(beanClasses.size() > 0 || beanNames.size() > 0, |
||||
"@" + ClassUtils.getShortName(annotationClass()) |
||||
+ " annotations must specify at least one bean"); |
||||
|
||||
return matches(context, metadata, beanClasses, beanNames); |
||||
} |
||||
|
||||
protected boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata, |
||||
List<String> beanClasses, List<String> beanNames) throws LinkageError { |
||||
|
||||
String checking = ConditionLogUtils.getPrefix(this.logger, metadata); |
||||
|
||||
SearchStrategy search = (SearchStrategy) metadata.getAnnotationAttributes( |
||||
annotationClass().getName()).get("search"); |
||||
search = search == null ? SearchStrategy.ALL : search; |
||||
|
||||
boolean considerHierarchy = search == SearchStrategy.ALL; |
||||
boolean parentOnly = search == SearchStrategy.PARENTS; |
||||
|
||||
List<String> beanClassesFound = new ArrayList<String>(); |
||||
List<String> beanNamesFound = new ArrayList<String>(); |
||||
|
||||
// eagerInit set to false to prevent early instantiation (some
|
||||
// factory beans will not be able to determine their object type at this
|
||||
// stage, so those are not eligible for matching this condition)
|
||||
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); |
||||
if (parentOnly) { |
||||
BeanFactory parent = beanFactory.getParentBeanFactory(); |
||||
if (!(parent instanceof ConfigurableListableBeanFactory)) { |
||||
throw new IllegalStateException( |
||||
"Cannot use parentOnly if parent is not ConfigurableListableBeanFactory"); |
||||
} |
||||
beanFactory = (ConfigurableListableBeanFactory) parent; |
||||
} |
||||
for (String beanClass : beanClasses) { |
||||
try { |
||||
Class<?> type = ClassUtils.forName(beanClass, context.getClassLoader()); |
||||
String[] beans = (considerHierarchy ? BeanFactoryUtils |
||||
.beanNamesForTypeIncludingAncestors(beanFactory, type, false, |
||||
false) : beanFactory.getBeanNamesForType(type, false, |
||||
false)); |
||||
if (beans.length != 0) { |
||||
beanClassesFound.add(beanClass); |
||||
} |
||||
} |
||||
catch (ClassNotFoundException ex) { |
||||
// swallow exception and continue
|
||||
} |
||||
} |
||||
for (String beanName : beanNames) { |
||||
if (considerHierarchy ? beanFactory.containsBean(beanName) : beanFactory |
||||
.containsLocalBean(beanName)) { |
||||
beanNamesFound.add(beanName); |
||||
} |
||||
} |
||||
|
||||
boolean result = evaluate(beanClassesFound, beanNamesFound); |
||||
if (this.logger.isDebugEnabled()) { |
||||
logFoundResults(checking, "class", beanClasses, beanClassesFound); |
||||
logFoundResults(checking, "name", beanNames, beanClassesFound); |
||||
this.logger.debug(checking + "Match result is: " + result); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
private void logFoundResults(String prefix, String type, List<?> candidates, |
||||
List<?> found) { |
||||
if (!candidates.isEmpty()) { |
||||
this.logger.debug(prefix + "Looking for beans with " + type + ": " |
||||
+ candidates); |
||||
if (found.isEmpty()) { |
||||
this.logger.debug(prefix + "Found no beans"); |
||||
} |
||||
else { |
||||
this.logger.debug(prefix + "Found beans with " + type + ": " + found); |
||||
} |
||||
} |
||||
} |
||||
|
||||
protected boolean evaluate(List<String> beanClassesFound, List<String> beanNamesFound) { |
||||
return !beanClassesFound.isEmpty() || !beanNamesFound.isEmpty(); |
||||
} |
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" }) |
||||
private List<String> collect(MultiValueMap<String, Object> attributes, String key) { |
||||
List<String> collected = new ArrayList<String>(); |
||||
List<String[]> valueList = (List) attributes.get(key); |
||||
for (String[] valueArray : valueList) { |
||||
for (String value : valueArray) { |
||||
collected.add(value); |
||||
} |
||||
} |
||||
return collected; |
||||
} |
||||
|
||||
} |
||||
@ -1,40 +0,0 @@
@@ -1,40 +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.List; |
||||
|
||||
import org.springframework.context.annotation.Condition; |
||||
|
||||
/** |
||||
* {@link Condition} that checks that specific beans are missing. |
||||
* |
||||
* @author Phillip Webb |
||||
* @see ConditionalOnMissingBean |
||||
*/ |
||||
class OnMissingBeanCondition extends AbstractOnBeanCondition { |
||||
|
||||
@Override |
||||
protected Class<?> annotationClass() { |
||||
return ConditionalOnMissingBean.class; |
||||
} |
||||
|
||||
@Override |
||||
protected boolean evaluate(List<String> beanClassesFound, List<String> beanNamesFound) { |
||||
return !super.evaluate(beanClassesFound, beanNamesFound); |
||||
} |
||||
} |
||||
Loading…
Reference in new issue