diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactory.java
index 61b34cb64e..27e3df91ad 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactory.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2014 the original author or authors.
+ * Copyright 2002-2015 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.
@@ -17,6 +17,7 @@
package org.springframework.beans.factory;
import org.springframework.beans.BeansException;
+import org.springframework.core.ResolvableType;
/**
* The root interface for accessing a Spring bean container.
@@ -114,6 +115,7 @@ public interface BeanFactory {
*/
String FACTORY_BEAN_PREFIX = "&";
+
/**
* Return an instance, which may be shared or independent, of the specified bean.
*
This method allows a Spring BeanFactory to be used as a replacement for the
@@ -202,6 +204,7 @@ public interface BeanFactory {
*/
T getBean(Class requiredType, Object... args) throws BeansException;
+
/**
* Does this bean factory contain a bean definition or externally registered singleton
* instance with the given name?
@@ -261,7 +264,24 @@ public interface BeanFactory {
* Translates aliases back to the corresponding canonical bean name.
* Will ask the parent factory if the bean cannot be found in this factory instance.
* @param name the name of the bean to query
- * @param targetType the type to match against
+ * @param targetType the type to match against (as a {@code ResolvableType})
+ * @return {@code true} if the bean type matches,
+ * {@code false} if it doesn't match or cannot be determined yet
+ * @throws NoSuchBeanDefinitionException if there is no bean with the given name
+ * @since 4.2
+ * @see #getBean
+ * @see #getType
+ */
+ boolean isTypeMatch(String name, ResolvableType targetType) throws NoSuchBeanDefinitionException;
+
+ /**
+ * Check whether the bean with the given name matches the specified type.
+ * More specifically, check whether a {@link #getBean} call for the given name
+ * would return an object that is assignable to the specified target type.
+ *
Translates aliases back to the corresponding canonical bean name.
+ * Will ask the parent factory if the bean cannot be found in this factory instance.
+ * @param name the name of the bean to query
+ * @param targetType the type to match against (as a {@code Class})
* @return {@code true} if the bean type matches,
* {@code false} if it doesn't match or cannot be determined yet
* @throws NoSuchBeanDefinitionException if there is no bean with the given name
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactoryUtils.java b/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactoryUtils.java
index 6952087521..42b749e6fa 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactoryUtils.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactoryUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2013 the original author or authors.
+ * Copyright 2002-2015 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,7 +16,6 @@
package org.springframework.beans.factory;
-
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
@@ -24,6 +23,7 @@ import java.util.List;
import java.util.Map;
import org.springframework.beans.BeansException;
+import org.springframework.core.ResolvableType;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -126,6 +126,39 @@ public abstract class BeanFactoryUtils {
return beanNamesForTypeIncludingAncestors(lbf, Object.class);
}
+ /**
+ * Get all bean names for the given type, including those defined in ancestor
+ * factories. Will return unique names in case of overridden bean definitions.
+ *
Does consider objects created by FactoryBeans, which means that FactoryBeans
+ * will get initialized. If the object created by the FactoryBean doesn't match,
+ * the raw FactoryBean itself will be matched against the type.
+ *
This version of {@code beanNamesForTypeIncludingAncestors} automatically
+ * includes prototypes and FactoryBeans.
+ * @param lbf the bean factory
+ * @param type the type that beans must match (as a {@code ResolvableType})
+ * @return the array of matching bean names, or an empty array if none
+ * @since 4.2
+ */
+ public static String[] beanNamesForTypeIncludingAncestors(ListableBeanFactory lbf, ResolvableType type) {
+ Assert.notNull(lbf, "ListableBeanFactory must not be null");
+ String[] result = lbf.getBeanNamesForType(type);
+ if (lbf instanceof HierarchicalBeanFactory) {
+ HierarchicalBeanFactory hbf = (HierarchicalBeanFactory) lbf;
+ if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) {
+ String[] parentResult = beanNamesForTypeIncludingAncestors(
+ (ListableBeanFactory) hbf.getParentBeanFactory(), type);
+ List resultList = new ArrayList();
+ resultList.addAll(Arrays.asList(result));
+ for (String beanName : parentResult) {
+ if (!resultList.contains(beanName) && !hbf.containsLocalBean(beanName)) {
+ resultList.add(beanName);
+ }
+ }
+ result = StringUtils.toStringArray(resultList);
+ }
+ }
+ return result;
+ }
/**
* Get all bean names for the given type, including those defined in ancestor
@@ -136,7 +169,7 @@ public abstract class BeanFactoryUtils {
* This version of {@code beanNamesForTypeIncludingAncestors} automatically
* includes prototypes and FactoryBeans.
* @param lbf the bean factory
- * @param type the type that beans must match
+ * @param type the type that beans must match (as a {@code Class})
* @return the array of matching bean names, or an empty array if none
*/
public static String[] beanNamesForTypeIncludingAncestors(ListableBeanFactory lbf, Class> type) {
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/ListableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/ListableBeanFactory.java
index 5fa1f173d9..e9bc88c84f 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/ListableBeanFactory.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/ListableBeanFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2013 the original author or authors.
+ * Copyright 2002-2015 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.
@@ -20,6 +20,7 @@ import java.lang.annotation.Annotation;
import java.util.Map;
import org.springframework.beans.BeansException;
+import org.springframework.core.ResolvableType;
/**
* Extension of the {@link BeanFactory} interface to be implemented by bean factories
@@ -85,6 +86,34 @@ public interface ListableBeanFactory extends BeanFactory {
*/
String[] getBeanDefinitionNames();
+ /**
+ * Return the names of beans matching the given type (including subclasses),
+ * judging from either bean definitions or the value of {@code getObjectType}
+ * in the case of FactoryBeans.
+ *
NOTE: This method introspects top-level beans only. It does not
+ * check nested beans which might match the specified type as well.
+ *
Does consider objects created by FactoryBeans, which means that FactoryBeans
+ * will get initialized. If the object created by the FactoryBean doesn't match,
+ * the raw FactoryBean itself will be matched against the type.
+ *
Does not consider any hierarchy this factory may participate in.
+ * Use BeanFactoryUtils' {@code beanNamesForTypeIncludingAncestors}
+ * to include beans in ancestor factories too.
+ *
Note: Does not ignore singleton beans that have been registered
+ * by other means than bean definitions.
+ *
This version of {@code getBeanNamesForType} matches all kinds of beans,
+ * be it singletons, prototypes, or FactoryBeans. In most implementations, the
+ * result will be the same as for {@code getBeanNamesForType(type, true, true)}.
+ *
Bean names returned by this method should always return bean names in the
+ * order of definition in the backend configuration, as far as possible.
+ * @param type the class or interface to match, or {@code null} for all bean names
+ * @return the names of beans (or objects created by FactoryBeans) matching
+ * the given object type (including subclasses), or an empty array if none
+ * @since 4.2
+ * @see FactoryBean#getObjectType
+ * @see BeanFactoryUtils#beanNamesForTypeIncludingAncestors(ListableBeanFactory, ResolvableType)
+ */
+ String[] getBeanNamesForType(ResolvableType type);
+
/**
* Return the names of beans matching the given type (including subclasses),
* judging from either bean definitions or the value of {@code getObjectType}
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java
index 160631d16c..9e08def702 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java
@@ -68,6 +68,7 @@ import org.springframework.beans.factory.config.InstantiationAwareBeanPostProces
import org.springframework.beans.factory.config.Scope;
import org.springframework.core.DecoratingClassLoader;
import org.springframework.core.NamedThreadLocal;
+import org.springframework.core.ResolvableType;
import org.springframework.core.convert.ConversionService;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -479,9 +480,8 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
}
@Override
- public boolean isTypeMatch(String name, Class> targetType) throws NoSuchBeanDefinitionException {
+ public boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException {
String beanName = transformedBeanName(name);
- Class> typeToMatch = (targetType != null ? targetType : Object.class);
// Check manually registered singletons.
Object beanInstance = getSingleton(beanName, false);
@@ -489,15 +489,14 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
if (beanInstance instanceof FactoryBean) {
if (!BeanFactoryUtils.isFactoryDereference(name)) {
Class> type = getTypeForFactoryBean((FactoryBean>) beanInstance);
- return (type != null && ClassUtils.isAssignable(typeToMatch, type));
+ return (type != null && typeToMatch.isAssignableFrom(type));
}
else {
- return ClassUtils.isAssignableValue(typeToMatch, beanInstance);
+ return typeToMatch.isInstance(beanInstance);
}
}
else {
- return !BeanFactoryUtils.isFactoryDereference(name) &&
- ClassUtils.isAssignableValue(typeToMatch, beanInstance);
+ return (!BeanFactoryUtils.isFactoryDereference(name) && typeToMatch.isInstance(beanInstance));
}
}
else if (containsSingleton(beanName) && !containsBeanDefinition(beanName)) {
@@ -510,14 +509,15 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// No bean definition found in this factory -> delegate to parent.
- return parentBeanFactory.isTypeMatch(originalBeanName(name), targetType);
+ return parentBeanFactory.isTypeMatch(originalBeanName(name), typeToMatch);
}
// Retrieve corresponding bean definition.
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
- Class>[] typesToMatch = (FactoryBean.class.equals(typeToMatch) ?
- new Class>[] {typeToMatch} : new Class>[] {FactoryBean.class, typeToMatch});
+ Class> classToMatch = typeToMatch.getRawClass();
+ Class>[] typesToMatch = (FactoryBean.class.equals(classToMatch) ?
+ new Class>[] {classToMatch} : new Class>[] {FactoryBean.class, classToMatch});
// Check decorated bean definition, if any: We assume it'll be easier
// to determine the decorated bean's type than the proxy's type.
@@ -559,6 +559,11 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
}
}
+ @Override
+ public boolean isTypeMatch(String name, Class> targetType) throws NoSuchBeanDefinitionException {
+ return isTypeMatch(name, ResolvableType.forClass(targetType));
+ }
+
@Override
public Class> getType(String name) throws NoSuchBeanDefinitionException {
String beanName = transformedBeanName(name);
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java
index 87fc397d9a..112dbfdffc 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java
@@ -66,6 +66,7 @@ import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.core.OrderComparator;
+import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.lang.UsesJava8;
import org.springframework.util.Assert;
@@ -323,7 +324,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
//---------------------------------------------------------------------
- // Implementation of ListableBeanFactory interface
+ // Implementation of remaining BeanFactory methods
//---------------------------------------------------------------------
@Override
@@ -372,6 +373,11 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
}
}
+
+ //---------------------------------------------------------------------
+ // Implementation of ListableBeanFactory interface
+ //---------------------------------------------------------------------
+
@Override
public boolean containsBeanDefinition(String beanName) {
Assert.notNull(beanName, "Bean name must not be null");
@@ -393,6 +399,11 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
}
}
+ @Override
+ public String[] getBeanNamesForType(ResolvableType type) {
+ return doGetBeanNamesForType(type, true, true);
+ }
+
@Override
public String[] getBeanNamesForType(Class> type) {
return getBeanNamesForType(type, true, true);
@@ -401,7 +412,8 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
@Override
public String[] getBeanNamesForType(Class> type, boolean includeNonSingletons, boolean allowEagerInit) {
if (!isConfigurationFrozen() || type == null || !allowEagerInit) {
- return doGetBeanNamesForType(type, includeNonSingletons, allowEagerInit);
+ return doGetBeanNamesForType(ResolvableType.forClass(type != null ? type : Object.class),
+ includeNonSingletons, allowEagerInit);
}
Map, String[]> cache =
(includeNonSingletons ? this.allBeanNamesByType : this.singletonBeanNamesByType);
@@ -409,14 +421,14 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
if (resolvedBeanNames != null) {
return resolvedBeanNames;
}
- resolvedBeanNames = doGetBeanNamesForType(type, includeNonSingletons, allowEagerInit);
+ resolvedBeanNames = doGetBeanNamesForType(ResolvableType.forClass(type), includeNonSingletons, allowEagerInit);
if (ClassUtils.isCacheSafe(type, getBeanClassLoader())) {
cache.put(type, resolvedBeanNames);
}
return resolvedBeanNames;
}
- private String[] doGetBeanNamesForType(Class> type, boolean includeNonSingletons, boolean allowEagerInit) {
+ private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
List result = new ArrayList();
// Check all bean definitions.
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/StaticListableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/StaticListableBeanFactory.java
index 80ece144f6..4d308d7692 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/support/StaticListableBeanFactory.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/StaticListableBeanFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2014 the original author or authors.
+ * Copyright 2002-2015 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.
@@ -33,6 +33,7 @@ import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.beans.factory.SmartFactoryBean;
+import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.StringUtils;
@@ -167,6 +168,12 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
(bean instanceof FactoryBean && !((FactoryBean>) bean).isSingleton()));
}
+ @Override
+ public boolean isTypeMatch(String name, ResolvableType targetType) throws NoSuchBeanDefinitionException {
+ Class> type = getType(name);
+ return (targetType == null || (type != null && targetType.isAssignableFrom(type)));
+ }
+
@Override
public boolean isTypeMatch(String name, Class> targetType) throws NoSuchBeanDefinitionException {
Class> type = getType(name);
@@ -216,22 +223,16 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
}
@Override
- public String[] getBeanNamesForType(Class> type) {
- return getBeanNamesForType(type, true, true);
- }
-
- @Override
- public String[] getBeanNamesForType(Class> type, boolean includeNonSingletons, boolean includeFactoryBeans) {
- boolean isFactoryType = (type != null && FactoryBean.class.isAssignableFrom(type));
+ public String[] getBeanNamesForType(ResolvableType type) {
+ boolean isFactoryType = (type != null && FactoryBean.class.isAssignableFrom(type.getRawClass()));
List matches = new ArrayList();
- for (String name : this.beans.keySet()) {
- Object beanInstance = this.beans.get(name);
+ for (Map.Entry entry : this.beans.entrySet()) {
+ String name = entry.getKey();
+ Object beanInstance = entry.getValue();
if (beanInstance instanceof FactoryBean && !isFactoryType) {
- if (includeFactoryBeans) {
- Class> objectType = ((FactoryBean>) beanInstance).getObjectType();
- if (objectType != null && (type == null || type.isAssignableFrom(objectType))) {
- matches.add(name);
- }
+ Class> objectType = ((FactoryBean>) beanInstance).getObjectType();
+ if (objectType != null && (type == null || type.isAssignableFrom(objectType))) {
+ matches.add(name);
}
}
else {
@@ -243,6 +244,16 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
return StringUtils.toStringArray(matches);
}
+ @Override
+ public String[] getBeanNamesForType(Class> type) {
+ return getBeanNamesForType(ResolvableType.forClass(type));
+ }
+
+ @Override
+ public String[] getBeanNamesForType(Class> type, boolean includeNonSingletons, boolean allowEagerInit) {
+ return getBeanNamesForType(ResolvableType.forClass(type));
+ }
+
@Override
public Map getBeansOfType(Class type) throws BeansException {
return getBeansOfType(type, true, true);
@@ -250,25 +261,23 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
@Override
@SuppressWarnings("unchecked")
- public Map getBeansOfType(Class type, boolean includeNonSingletons, boolean includeFactoryBeans)
+ public Map getBeansOfType(Class type, boolean includeNonSingletons, boolean allowEagerInit)
throws BeansException {
boolean isFactoryType = (type != null && FactoryBean.class.isAssignableFrom(type));
Map matches = new HashMap();
- for (Map.Entry entry : beans.entrySet()) {
+ for (Map.Entry entry : this.beans.entrySet()) {
String beanName = entry.getKey();
Object beanInstance = entry.getValue();
// Is bean a FactoryBean?
if (beanInstance instanceof FactoryBean && !isFactoryType) {
- if (includeFactoryBeans) {
- // Match object created by FactoryBean.
- FactoryBean> factory = (FactoryBean>) beanInstance;
- Class> objectType = factory.getObjectType();
- if ((includeNonSingletons || factory.isSingleton()) &&
- objectType != null && (type == null || type.isAssignableFrom(objectType))) {
- matches.put(beanName, getBean(beanName, type));
- }
+ // Match object created by FactoryBean.
+ FactoryBean> factory = (FactoryBean>) beanInstance;
+ Class> objectType = factory.getObjectType();
+ if ((includeNonSingletons || factory.isSingleton()) &&
+ objectType != null && (type == null || type.isAssignableFrom(objectType))) {
+ matches.put(beanName, getBean(beanName, type));
}
}
else {
diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/BeanFactoryUtilsTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/BeanFactoryUtilsTests.java
index 2273d0ec11..293c43fb60 100644
--- a/spring-beans/src/test/java/org/springframework/beans/factory/BeanFactoryUtilsTests.java
+++ b/spring-beans/src/test/java/org/springframework/beans/factory/BeanFactoryUtilsTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2013 the original author or authors.
+ * Copyright 2002-2015 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.
@@ -23,8 +23,6 @@ import java.util.Map;
import org.junit.Before;
import org.junit.Test;
-import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
-import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.StaticListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
@@ -53,16 +51,16 @@ public final class BeanFactoryUtilsTests {
private static final Resource LEAF_CONTEXT = qualifiedResource(CLASS, "leaf.xml");
private static final Resource DEPENDENT_BEANS_CONTEXT = qualifiedResource(CLASS, "dependentBeans.xml");
- private ConfigurableListableBeanFactory listableBeanFactory;
+ private DefaultListableBeanFactory listableBeanFactory;
+
+ private DefaultListableBeanFactory dependentBeansFactory;
- private ConfigurableListableBeanFactory dependentBeansBF;
@Before
public void setUp() {
// Interesting hierarchical factory to test counts.
// Slow to read so we cache it.
-
DefaultListableBeanFactory grandParent = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader(grandParent).loadBeanDefinitions(ROOT_CONTEXT);
DefaultListableBeanFactory parent = new DefaultListableBeanFactory(grandParent);
@@ -70,12 +68,13 @@ public final class BeanFactoryUtilsTests {
DefaultListableBeanFactory child = new DefaultListableBeanFactory(parent);
new XmlBeanDefinitionReader(child).loadBeanDefinitions(LEAF_CONTEXT);
- this.dependentBeansBF = new DefaultListableBeanFactory();
- new XmlBeanDefinitionReader((BeanDefinitionRegistry) this.dependentBeansBF).loadBeanDefinitions(DEPENDENT_BEANS_CONTEXT);
- dependentBeansBF.preInstantiateSingletons();
+ this.dependentBeansFactory = new DefaultListableBeanFactory();
+ new XmlBeanDefinitionReader(this.dependentBeansFactory).loadBeanDefinitions(DEPENDENT_BEANS_CONTEXT);
+ dependentBeansFactory.preInstantiateSingletons();
this.listableBeanFactory = child;
}
+
@Test
public void testHierarchicalCountBeansWithNonHierarchicalFactory() {
StaticListableBeanFactory lbf = new StaticListableBeanFactory();
@@ -92,22 +91,21 @@ public final class BeanFactoryUtilsTests {
// Leaf count
assertTrue(this.listableBeanFactory.getBeanDefinitionCount() == 1);
// Count minus duplicate
- assertTrue("Should count 7 beans, not "
- + BeanFactoryUtils.countBeansIncludingAncestors(this.listableBeanFactory),
- BeanFactoryUtils.countBeansIncludingAncestors(this.listableBeanFactory) == 7);
+ assertTrue("Should count 7 beans, not " + BeanFactoryUtils.countBeansIncludingAncestors(this.listableBeanFactory),
+ BeanFactoryUtils.countBeansIncludingAncestors(this.listableBeanFactory) == 7);
}
@Test
public void testHierarchicalNamesWithNoMatch() throws Exception {
- List names = Arrays.asList(BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory,
- NoOp.class));
+ List names = Arrays.asList(
+ BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory, NoOp.class));
assertEquals(0, names.size());
}
@Test
public void testHierarchicalNamesWithMatchOnlyInRoot() throws Exception {
- List names = Arrays.asList(BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory,
- IndexedTestBean.class));
+ List names = Arrays.asList(
+ BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory, IndexedTestBean.class));
assertEquals(1, names.size());
assertTrue(names.contains("indexedBean"));
// Distinguish from default ListableBeanFactory behavior
@@ -116,8 +114,8 @@ public final class BeanFactoryUtilsTests {
@Test
public void testGetBeanNamesForTypeWithOverride() throws Exception {
- List names = Arrays.asList(BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory,
- ITestBean.class));
+ List names = Arrays.asList(
+ BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory, ITestBean.class));
// includes 2 TestBeans from FactoryBeans (DummyFactory definitions)
assertEquals(4, names.size());
assertTrue(names.contains("test"));
@@ -147,18 +145,7 @@ public final class BeanFactoryUtilsTests {
lbf.addBean("t3", t3);
lbf.addBean("t4", t4);
- Map, ?> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, ITestBean.class, true, false);
- assertEquals(2, beans.size());
- assertEquals(t1, beans.get("t1"));
- assertEquals(t2, beans.get("t2"));
-
- beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, ITestBean.class, false, true);
- assertEquals(3, beans.size());
- assertEquals(t1, beans.get("t1"));
- assertEquals(t2, beans.get("t2"));
- assertEquals(t3.getObject(), beans.get("t3"));
-
- beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, ITestBean.class, true, true);
+ Map beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, ITestBean.class, true, true);
assertEquals(4, beans.size());
assertEquals(t1, beans.get("t1"));
assertEquals(t2, beans.get("t2"));
@@ -191,8 +178,8 @@ public final class BeanFactoryUtilsTests {
this.listableBeanFactory.registerSingleton("t3", t3);
this.listableBeanFactory.registerSingleton("t4", t4);
- Map, ?> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.listableBeanFactory, ITestBean.class, true,
- false);
+ Map beans =
+ BeanFactoryUtils.beansOfTypeIncludingAncestors(this.listableBeanFactory, ITestBean.class, true, false);
assertEquals(6, beans.size());
assertEquals(test3, beans.get("test3"));
assertEquals(test, beans.get("test"));
@@ -200,12 +187,9 @@ public final class BeanFactoryUtilsTests {
assertEquals(t2, beans.get("t2"));
assertEquals(t3.getObject(), beans.get("t3"));
assertTrue(beans.get("t4") instanceof TestBean);
- // t3 and t4 are found here as of Spring 2.0, since they are
- // pre-registered
- // singleton instances, while testFactory1 and testFactory are *not*
- // found
- // because they are FactoryBean definitions that haven't been
- // initialized yet.
+ // t3 and t4 are found here as of Spring 2.0, since they are pre-registered
+ // singleton instances, while testFactory1 and testFactory are *not* found
+ // because they are FactoryBean definitions that haven't been initialized yet.
beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.listableBeanFactory, ITestBean.class, false, true);
Object testFactory1 = this.listableBeanFactory.getBean("testFactory1");
@@ -247,8 +231,8 @@ public final class BeanFactoryUtilsTests {
Object test3 = this.listableBeanFactory.getBean("test3");
Object test = this.listableBeanFactory.getBean("test");
- Map, ?> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.listableBeanFactory, ITestBean.class, true,
- false);
+ Map, ?> beans =
+ BeanFactoryUtils.beansOfTypeIncludingAncestors(this.listableBeanFactory, ITestBean.class, true, false);
assertEquals(2, beans.size());
assertEquals(test3, beans.get("test3"));
assertEquals(test, beans.get("test"));
@@ -283,25 +267,25 @@ public final class BeanFactoryUtilsTests {
@Test
public void testADependencies() {
- String[] deps = this.dependentBeansBF.getDependentBeans("a");
+ String[] deps = this.dependentBeansFactory.getDependentBeans("a");
assertTrue(ObjectUtils.isEmpty(deps));
}
@Test
public void testBDependencies() {
- String[] deps = this.dependentBeansBF.getDependentBeans("b");
+ String[] deps = this.dependentBeansFactory.getDependentBeans("b");
assertTrue(Arrays.equals(new String[] { "c" }, deps));
}
@Test
public void testCDependencies() {
- String[] deps = this.dependentBeansBF.getDependentBeans("c");
+ String[] deps = this.dependentBeansFactory.getDependentBeans("c");
assertTrue(Arrays.equals(new String[] { "int", "long" }, deps));
}
@Test
public void testIntDependencies() {
- String[] deps = this.dependentBeansBF.getDependentBeans("int");
+ String[] deps = this.dependentBeansFactory.getDependentBeans("int");
assertTrue(Arrays.equals(new String[] { "buffer" }, deps));
}
diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java
index bab9854b23..dc2a234d1f 100644
--- a/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java
+++ b/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java
@@ -73,6 +73,7 @@ import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.ConstructorDependenciesBean;
import org.springframework.beans.propertyeditors.CustomNumberEditor;
import org.springframework.core.MethodParameter;
+import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.support.DefaultConversionService;
@@ -194,13 +195,16 @@ public class DefaultListableBeanFactoryTests {
assertTrue(lbf.isTypeMatch("x1", TestBean.class));
assertFalse(lbf.isTypeMatch("&x1", TestBean.class));
assertTrue(lbf.isTypeMatch("&x1", DummyFactory.class));
+ assertTrue(lbf.isTypeMatch("&x1", ResolvableType.forClass(DummyFactory.class)));
+ assertTrue(lbf.isTypeMatch("&x1", ResolvableType.forClassWithGenerics(FactoryBean.class, Object.class)));
+ assertFalse(lbf.isTypeMatch("&x1", ResolvableType.forClassWithGenerics(FactoryBean.class, String.class)));
assertEquals(TestBean.class, lbf.getType("x1"));
assertEquals(DummyFactory.class, lbf.getType("&x1"));
assertTrue("prototype not instantiated", !DummyFactory.wasPrototypeCreated());
}
@Test
- public void testPrototypeSingletonFactoryBeanIgnoredByNonEagerTypeMatching() {
+ public void testSingletonFactoryBeanIgnoredByNonEagerTypeMatching() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
Properties p = new Properties();
p.setProperty("x1.(class)", DummyFactory.class.getName());
@@ -226,6 +230,9 @@ public class DefaultListableBeanFactoryTests {
assertTrue(lbf.isTypeMatch("x1", TestBean.class));
assertFalse(lbf.isTypeMatch("&x1", TestBean.class));
assertTrue(lbf.isTypeMatch("&x1", DummyFactory.class));
+ assertTrue(lbf.isTypeMatch("&x1", ResolvableType.forClass(DummyFactory.class)));
+ assertTrue(lbf.isTypeMatch("&x1", ResolvableType.forClassWithGenerics(FactoryBean.class, Object.class)));
+ assertFalse(lbf.isTypeMatch("&x1", ResolvableType.forClassWithGenerics(FactoryBean.class, String.class)));
assertEquals(TestBean.class, lbf.getType("x1"));
assertEquals(DummyFactory.class, lbf.getType("&x1"));
assertTrue("prototype not instantiated", !DummyFactory.wasPrototypeCreated());
@@ -257,6 +264,9 @@ public class DefaultListableBeanFactoryTests {
assertTrue(lbf.isTypeMatch("x1", TestBean.class));
assertFalse(lbf.isTypeMatch("&x1", TestBean.class));
assertTrue(lbf.isTypeMatch("&x1", DummyFactory.class));
+ assertTrue(lbf.isTypeMatch("&x1", ResolvableType.forClass(DummyFactory.class)));
+ assertTrue(lbf.isTypeMatch("&x1", ResolvableType.forClassWithGenerics(FactoryBean.class, Object.class)));
+ assertFalse(lbf.isTypeMatch("&x1", ResolvableType.forClassWithGenerics(FactoryBean.class, String.class)));
assertEquals(TestBean.class, lbf.getType("x1"));
assertEquals(DummyFactory.class, lbf.getType("&x1"));
assertTrue("prototype not instantiated", !DummyFactory.wasPrototypeCreated());
@@ -1381,7 +1391,7 @@ public class DefaultListableBeanFactoryTests {
}
}
- @Test(expected=NoSuchBeanDefinitionException.class)
+ @Test(expected = NoSuchBeanDefinitionException.class)
public void testGetBeanByTypeWithNoneFound() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
lbf.getBean(TestBean.class);
@@ -1397,7 +1407,7 @@ public class DefaultListableBeanFactoryTests {
assertThat(bean.getBeanName(), equalTo("bd1"));
}
- @Test(expected=NoUniqueBeanDefinitionException.class)
+ @Test(expected = NoUniqueBeanDefinitionException.class)
public void testGetBeanByTypeWithAmbiguity() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
RootBeanDefinition bd1 = new RootBeanDefinition(TestBean.class);
@@ -1606,6 +1616,8 @@ public class DefaultListableBeanFactoryTests {
assertEquals(1, lbf.getBeanNamesForType(ConstructorDependency.class).length);
assertEquals(1, lbf.getBeanNamesForType(ConstructorDependencyFactoryBean.class).length);
+ assertEquals(1, lbf.getBeanNamesForType(ResolvableType.forClassWithGenerics(FactoryBean.class, Object.class)).length);
+ assertEquals(0, lbf.getBeanNamesForType(ResolvableType.forClassWithGenerics(FactoryBean.class, String.class)).length);
}
private RootBeanDefinition createConstructorDependencyBeanDefinition(int age) {
@@ -1660,7 +1672,7 @@ public class DefaultListableBeanFactoryTests {
* Java method names. In other words, you can't name a method
* {@code set&FactoryBean(...)}.
*/
- @Test(expected=TypeMismatchException.class)
+ @Test(expected = TypeMismatchException.class)
public void testAutowireBeanWithFactoryBeanByName() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
RootBeanDefinition bd = new RootBeanDefinition(LazyInitFactory.class);
@@ -2537,7 +2549,7 @@ public class DefaultListableBeanFactoryTests {
assertEquals(expectedNameFromArgs, tb2.getName());
}
- @Test(expected=IllegalStateException.class)
+ @Test(expected = IllegalStateException.class)
public void testScopingBeanToUnregisteredScopeResultsInAnException() throws Exception {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(TestBean.class);
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/support/BeanFactoryGenericsTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/support/BeanFactoryGenericsTests.java
index fe75220ac4..ed1b506b7a 100644
--- a/spring-beans/src/test/java/org/springframework/beans/factory/support/BeanFactoryGenericsTests.java
+++ b/spring-beans/src/test/java/org/springframework/beans/factory/support/BeanFactoryGenericsTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2013 the original author or authors.
+ * Copyright 2002-2015 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.
@@ -40,6 +40,7 @@ import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.config.TypedStringValue;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.beans.propertyeditors.CustomNumberEditor;
+import org.springframework.core.ResolvableType;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.UrlResource;
import org.springframework.tests.Assume;
@@ -770,7 +771,7 @@ public class BeanFactoryGenericsTests {
}
@Test
- public void testSpr11250() {
+ public void testGenericMatchingWithBeanNameDifferentiation() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.setAutowireCandidateResolver(new GenericTypeAwareAutowireCandidateResolver());
@@ -780,8 +781,43 @@ public class BeanFactoryGenericsTests {
new RootBeanDefinition(NumberBean.class, RootBeanDefinition.AUTOWIRE_CONSTRUCTOR, false));
NumberBean nb = bf.getBean(NumberBean.class);
- assertNotNull(nb.getDoubleStore());
- assertNotNull(nb.getFloatStore());
+ assertSame(bf.getBean("doubleStore"), nb.getDoubleStore());
+ assertSame(bf.getBean("floatStore"), nb.getFloatStore());
+
+ String[] numberStoreNames = bf.getBeanNamesForType(ResolvableType.forClass(NumberStore.class));
+ String[] doubleStoreNames = bf.getBeanNamesForType(ResolvableType.forClassWithGenerics(NumberStore.class, Double.class));
+ String[] floatStoreNames = bf.getBeanNamesForType(ResolvableType.forClassWithGenerics(NumberStore.class, Float.class));
+ assertEquals(2, numberStoreNames.length);
+ assertEquals("doubleStore", numberStoreNames[0]);
+ assertEquals("floatStore", numberStoreNames[1]);
+ assertEquals(0, doubleStoreNames.length);
+ assertEquals(0, floatStoreNames.length);
+ }
+
+ @Test
+ public void testGenericMatchingWithFullTypeDifferentiation() {
+ DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
+ bf.setAutowireCandidateResolver(new GenericTypeAwareAutowireCandidateResolver());
+
+ bf.registerBeanDefinition("store1", new RootBeanDefinition(DoubleStore.class));
+ bf.registerBeanDefinition("store2", new RootBeanDefinition(FloatStore.class));
+ bf.registerBeanDefinition("numberBean",
+ new RootBeanDefinition(NumberBean.class, RootBeanDefinition.AUTOWIRE_CONSTRUCTOR, false));
+
+ NumberBean nb = bf.getBean(NumberBean.class);
+ assertSame(bf.getBean("store1"), nb.getDoubleStore());
+ assertSame(bf.getBean("store2"), nb.getFloatStore());
+
+ String[] numberStoreNames = bf.getBeanNamesForType(ResolvableType.forClass(NumberStore.class));
+ String[] doubleStoreNames = bf.getBeanNamesForType(ResolvableType.forClassWithGenerics(NumberStore.class, Double.class));
+ String[] floatStoreNames = bf.getBeanNamesForType(ResolvableType.forClassWithGenerics(NumberStore.class, Float.class));
+ assertEquals(2, numberStoreNames.length);
+ assertEquals("store1", numberStoreNames[0]);
+ assertEquals("store2", numberStoreNames[1]);
+ assertEquals(1, doubleStoreNames.length);
+ assertEquals("store1", doubleStoreNames[0]);
+ assertEquals(1, floatStoreNames.length);
+ assertEquals("store2", floatStoreNames[0]);
}
@@ -851,6 +887,14 @@ public class BeanFactoryGenericsTests {
}
+ public static class DoubleStore extends NumberStore {
+ }
+
+
+ public static class FloatStore extends NumberStore {
+ }
+
+
public static class NumberBean {
private final NumberStore doubleStore;
diff --git a/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java b/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java
index 8b5ba17202..6e52443f86 100644
--- a/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java
+++ b/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java
@@ -47,13 +47,13 @@ import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.EnvironmentAware;
-import org.springframework.context.PayloadApplicationEvent;
import org.springframework.context.HierarchicalMessageSource;
import org.springframework.context.LifecycleProcessor;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceAware;
import org.springframework.context.MessageSourceResolvable;
import org.springframework.context.NoSuchMessageException;
+import org.springframework.context.PayloadApplicationEvent;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.context.event.ContextClosedEvent;
@@ -1024,6 +1024,12 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
return getBeanFactory().isPrototype(name);
}
+ @Override
+ public boolean isTypeMatch(String name, ResolvableType targetType) throws NoSuchBeanDefinitionException {
+ assertBeanFactoryActive();
+ return getBeanFactory().isTypeMatch(name, targetType);
+ }
+
@Override
public boolean isTypeMatch(String name, Class> targetType) throws NoSuchBeanDefinitionException {
assertBeanFactoryActive();
@@ -1061,6 +1067,12 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
return getBeanFactory().getBeanDefinitionNames();
}
+ @Override
+ public String[] getBeanNamesForType(ResolvableType type) {
+ assertBeanFactoryActive();
+ return getBeanFactory().getBeanNamesForType(type);
+ }
+
@Override
public String[] getBeanNamesForType(Class> type) {
assertBeanFactoryActive();
diff --git a/spring-context/src/main/java/org/springframework/jndi/support/SimpleJndiBeanFactory.java b/spring-context/src/main/java/org/springframework/jndi/support/SimpleJndiBeanFactory.java
index 4d2f8ef48f..dfb9ad8778 100644
--- a/spring-context/src/main/java/org/springframework/jndi/support/SimpleJndiBeanFactory.java
+++ b/spring-context/src/main/java/org/springframework/jndi/support/SimpleJndiBeanFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2014 the original author or authors.
+ * Copyright 2002-2015 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.
@@ -29,6 +29,7 @@ import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanNotOfRequiredTypeException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.core.ResolvableType;
import org.springframework.jndi.JndiLocatorSupport;
import org.springframework.jndi.TypeMismatchNamingException;
@@ -172,6 +173,12 @@ public class SimpleJndiBeanFactory extends JndiLocatorSupport implements BeanFac
return !this.shareableResources.contains(name);
}
+ @Override
+ public boolean isTypeMatch(String name, ResolvableType targetType) throws NoSuchBeanDefinitionException {
+ Class> type = getType(name);
+ return (targetType == null || (type != null && targetType.isAssignableFrom(type)));
+ }
+
@Override
public boolean isTypeMatch(String name, Class> targetType) throws NoSuchBeanDefinitionException {
Class> type = getType(name);
diff --git a/spring-core/src/main/java/org/springframework/core/ResolvableType.java b/spring-core/src/main/java/org/springframework/core/ResolvableType.java
index aed8d7e60a..35b4393015 100644
--- a/spring-core/src/main/java/org/springframework/core/ResolvableType.java
+++ b/spring-core/src/main/java/org/springframework/core/ResolvableType.java
@@ -156,7 +156,7 @@ public final class ResolvableType implements Serializable {
}
/**
- * Return the underlying Java {@link Class} being managed, if available;
+ * Return the underlying Java {@link Class} being managed, if available;
* otherwise {@code null}.
*/
public Class> getRawClass() {
@@ -179,6 +179,27 @@ public final class ResolvableType implements Serializable {
return (source != null ? source : this.type);
}
+ /**
+ * Determine whether the given object is an instance of this {@code ResolvableType}.
+ * @param obj the object to check
+ * @since 4.2
+ * @see #isAssignableFrom(Class)
+ */
+ public boolean isInstance(Object obj) {
+ return (obj != null && isAssignableFrom(obj.getClass()));
+ }
+
+ /**
+ * Determine whether this {@code ResolvableType} is assignable from the
+ * specified other type.
+ * @param other the type to be checked against (as a {@code Class})
+ * @since 4.2
+ * @see #isAssignableFrom(ResolvableType)
+ */
+ public boolean isAssignableFrom(Class> other) {
+ return isAssignableFrom(forClass(other), null);
+ }
+
/**
* Determine whether this {@code ResolvableType} is assignable from the
* specified other type.
@@ -186,7 +207,7 @@ public final class ResolvableType implements Serializable {
* whether both the {@link #resolve() resolved} {@code Class} is
* {@link Class#isAssignableFrom(Class) assignable from} the given type
* as well as whether all {@link #getGenerics() generics} are assignable.
- * @param other the type to be checked against
+ * @param other the type to be checked against (as a {@code ResolvableType})
* @return {@code true} if the specified other type can be assigned to this
* {@code ResolvableType}; {@code false} otherwise
*/
diff --git a/spring-core/src/test/java/org/springframework/core/ResolvableTypeTests.java b/spring-core/src/test/java/org/springframework/core/ResolvableTypeTests.java
index 7b341451c5..8083e2a345 100644
--- a/spring-core/src/test/java/org/springframework/core/ResolvableTypeTests.java
+++ b/spring-core/src/test/java/org/springframework/core/ResolvableTypeTests.java
@@ -61,6 +61,7 @@ import static org.mockito.BDDMockito.*;
* Tests for {@link ResolvableType}.
*
* @author Phillip Webb
+ * @author Juergen Hoeller
*/
@SuppressWarnings("rawtypes")
@RunWith(MockitoJUnitRunner.class)
@@ -882,7 +883,7 @@ public class ResolvableTypeTests {
public void isAssignableFromMustNotBeNull() throws Exception {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Type must not be null");
- ResolvableType.forClass(Object.class).isAssignableFrom(null);
+ ResolvableType.forClass(Object.class).isAssignableFrom((ResolvableType) null);
}
@Test
@@ -901,6 +902,20 @@ public class ResolvableTypeTests {
assertAssignable(objectType, objectType, charSequenceType, stringType).equalTo(true, true, true);
assertAssignable(charSequenceType, objectType, charSequenceType, stringType).equalTo(false, true, true);
assertAssignable(stringType, objectType, charSequenceType, stringType).equalTo(false, false, true);
+
+ assertTrue(objectType.isAssignableFrom(String.class));
+ assertTrue(objectType.isAssignableFrom(StringBuilder.class));
+ assertTrue(charSequenceType.isAssignableFrom(String.class));
+ assertTrue(charSequenceType.isAssignableFrom(StringBuilder.class));
+ assertTrue(stringType.isAssignableFrom(String.class));
+ assertFalse(stringType.isAssignableFrom(StringBuilder.class));
+
+ assertTrue(objectType.isInstance("a String"));
+ assertTrue(objectType.isInstance(new StringBuilder("a StringBuilder")));
+ assertTrue(charSequenceType.isInstance("a String"));
+ assertTrue(charSequenceType.isInstance(new StringBuilder("a StringBuilder")));
+ assertTrue(stringType.isInstance("a String"));
+ assertFalse(stringType.isInstance(new StringBuilder("a StringBuilder")));
}
@Test
diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/setup/StubWebApplicationContext.java b/spring-test/src/main/java/org/springframework/test/web/servlet/setup/StubWebApplicationContext.java
index 5338455b85..06e3dd9cd1 100644
--- a/spring-test/src/main/java/org/springframework/test/web/servlet/setup/StubWebApplicationContext.java
+++ b/spring-test/src/main/java/org/springframework/test/web/servlet/setup/StubWebApplicationContext.java
@@ -38,6 +38,7 @@ import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceResolvable;
import org.springframework.context.NoSuchMessageException;
import org.springframework.context.support.DelegatingMessageSource;
+import org.springframework.core.ResolvableType;
import org.springframework.core.env.Environment;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.Resource;
@@ -98,6 +99,7 @@ class StubWebApplicationContext implements WebApplicationContext {
return this.servletContext;
}
+
//---------------------------------------------------------------------
// Implementation of ApplicationContext interface
//---------------------------------------------------------------------
@@ -146,6 +148,7 @@ class StubWebApplicationContext implements WebApplicationContext {
}
}
+
//---------------------------------------------------------------------
// Implementation of BeanFactory interface
//---------------------------------------------------------------------
@@ -190,6 +193,11 @@ class StubWebApplicationContext implements WebApplicationContext {
return this.beanFactory.isPrototype(name);
}
+ @Override
+ public boolean isTypeMatch(String name, ResolvableType targetType) throws NoSuchBeanDefinitionException {
+ return this.beanFactory.isTypeMatch(name, targetType);
+ }
+
@Override
public boolean isTypeMatch(String name, Class> targetType) throws NoSuchBeanDefinitionException {
return this.beanFactory.isTypeMatch(name, targetType);
@@ -205,6 +213,7 @@ class StubWebApplicationContext implements WebApplicationContext {
return this.beanFactory.getAliases(name);
}
+
//---------------------------------------------------------------------
// Implementation of ListableBeanFactory interface
//---------------------------------------------------------------------
@@ -224,6 +233,11 @@ class StubWebApplicationContext implements WebApplicationContext {
return this.beanFactory.getBeanDefinitionNames();
}
+ @Override
+ public String[] getBeanNamesForType(ResolvableType type) {
+ return this.beanFactory.getBeanNamesForType(type);
+ }
+
@Override
public String[] getBeanNamesForType(Class> type) {
return this.beanFactory.getBeanNamesForType(type);
@@ -265,6 +279,7 @@ class StubWebApplicationContext implements WebApplicationContext {
return this.beanFactory.findAnnotationOnBean(beanName, annotationType);
}
+
//---------------------------------------------------------------------
// Implementation of HierarchicalBeanFactory interface
//---------------------------------------------------------------------
@@ -279,6 +294,7 @@ class StubWebApplicationContext implements WebApplicationContext {
return this.beanFactory.containsBean(name);
}
+
//---------------------------------------------------------------------
// Implementation of MessageSource interface
//---------------------------------------------------------------------
@@ -298,6 +314,7 @@ class StubWebApplicationContext implements WebApplicationContext {
return this.messageSource.getMessage(resolvable, locale);
}
+
//---------------------------------------------------------------------
// Implementation of ResourceLoader interface
//---------------------------------------------------------------------
@@ -312,6 +329,7 @@ class StubWebApplicationContext implements WebApplicationContext {
return this.resourcePatternResolver.getResource(location);
}
+
//---------------------------------------------------------------------
// Other
//---------------------------------------------------------------------