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 //---------------------------------------------------------------------