From bd72f1fefc19221b51c246203ae9e11a5d5a748f Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Fri, 27 Jun 2025 12:28:52 +0200 Subject: [PATCH] Fix inconsistencies in StaticListableBeanFactory Closes gh-35119 --- .../support/DefaultListableBeanFactory.java | 18 ++++--- .../support/StaticListableBeanFactory.java | 54 ++++++++----------- .../beans/factory/BeanFactoryUtilsTests.java | 28 +++++----- 3 files changed, 47 insertions(+), 53 deletions(-) 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 2a4f94ff72..4173274a39 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 @@ -2701,7 +2701,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto return null; } try { - RootBeanDefinition beanDefinition = (RootBeanDefinition) getMergedBeanDefinition(beanName); + BeanDefinition beanDefinition = getMergedBeanDefinition(beanName); List sources = new ArrayList<>(3); Object orderAttribute = beanDefinition.getAttribute(AbstractBeanDefinition.ORDER_ATTRIBUTE); if (orderAttribute != null) { @@ -2713,13 +2713,15 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto AbstractBeanDefinition.ORDER_ATTRIBUTE + "': " + orderAttribute.getClass().getName()); } } - Method factoryMethod = beanDefinition.getResolvedFactoryMethod(); - if (factoryMethod != null) { - sources.add(factoryMethod); - } - Class targetType = beanDefinition.getTargetType(); - if (targetType != null && targetType != obj.getClass()) { - sources.add(targetType); + if (beanDefinition instanceof RootBeanDefinition rootBeanDefinition) { + Method factoryMethod = rootBeanDefinition.getResolvedFactoryMethod(); + if (factoryMethod != null) { + sources.add(factoryMethod); + } + Class targetType = rootBeanDefinition.getTargetType(); + if (targetType != null && targetType != obj.getClass()) { + sources.add(targetType); + } } return sources.toArray(); } 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 d19c843faa..7b061e1957 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 @@ -113,15 +113,8 @@ public class StaticListableBeanFactory implements ListableBeanFactory { @Override public Object getBean(String name) throws BeansException { String beanName = BeanFactoryUtils.transformedBeanName(name); - Object bean = this.beans.get(beanName); + Object bean = obtainBean(beanName); - if (bean == null) { - throw new NoSuchBeanDefinitionException(beanName, - "Defined beans are [" + StringUtils.collectionToCommaDelimitedString(this.beans.keySet()) + "]"); - } - - // Don't let calling code try to dereference the - // bean factory if the bean isn't a factory if (BeanFactoryUtils.isFactoryDereference(name) && !(bean instanceof FactoryBean)) { throw new BeanIsNotAFactoryException(beanName, bean.getClass()); } @@ -162,6 +155,15 @@ public class StaticListableBeanFactory implements ListableBeanFactory { return getBean(name); } + private Object obtainBean(String beanName) { + Object bean = this.beans.get(beanName); + if (bean == null) { + throw new NoSuchBeanDefinitionException(beanName, + "Defined beans are [" + StringUtils.collectionToCommaDelimitedString(this.beans.keySet()) + "]"); + } + return bean; + } + @Override public T getBean(Class requiredType) throws BeansException { String[] beanNames = getBeanNamesForType(requiredType); @@ -202,9 +204,9 @@ public class StaticListableBeanFactory implements ListableBeanFactory { @Override public boolean isSingleton(String name) throws NoSuchBeanDefinitionException { - Object bean = getBean(name); - // In case of FactoryBean, return singleton status of created object. - if (bean instanceof FactoryBean factoryBean) { + String beanName = BeanFactoryUtils.transformedBeanName(name); + Object bean = obtainBean(beanName); + if (bean instanceof FactoryBean factoryBean && !BeanFactoryUtils.isFactoryDereference(name)) { return factoryBean.isSingleton(); } return true; @@ -212,10 +214,11 @@ public class StaticListableBeanFactory implements ListableBeanFactory { @Override public boolean isPrototype(String name) throws NoSuchBeanDefinitionException { - Object bean = getBean(name); - // In case of FactoryBean, return prototype status of created object. - return ((bean instanceof SmartFactoryBean smartFactoryBean && smartFactoryBean.isPrototype()) || - (bean instanceof FactoryBean factoryBean && !factoryBean.isSingleton())); + String beanName = BeanFactoryUtils.transformedBeanName(name); + Object bean = obtainBean(beanName); + return (!BeanFactoryUtils.isFactoryDereference(name) && + ((bean instanceof SmartFactoryBean smartFactoryBean && smartFactoryBean.isPrototype()) || + (bean instanceof FactoryBean factoryBean && !factoryBean.isSingleton()))); } @Override @@ -240,15 +243,8 @@ public class StaticListableBeanFactory implements ListableBeanFactory { @Nullable public Class getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException { String beanName = BeanFactoryUtils.transformedBeanName(name); - - Object bean = this.beans.get(beanName); - if (bean == null) { - throw new NoSuchBeanDefinitionException(beanName, - "Defined beans are [" + StringUtils.collectionToCommaDelimitedString(this.beans.keySet()) + "]"); - } - + Object bean = obtainBean(beanName); if (bean instanceof FactoryBean factoryBean && !BeanFactoryUtils.isFactoryDereference(name)) { - // If it's a FactoryBean, we want to look at what it creates, not the factory class. return factoryBean.getObjectType(); } return bean.getClass(); @@ -292,7 +288,7 @@ public class StaticListableBeanFactory implements ListableBeanFactory { public T getObject() throws BeansException { String[] beanNames = getBeanNamesForType(requiredType); if (beanNames.length == 1) { - return (T) getBean(beanNames[0], requiredType); + return (T) getBean(beanNames[0]); } else if (beanNames.length > 1) { throw new NoUniqueBeanDefinitionException(requiredType, beanNames); @@ -356,7 +352,7 @@ public class StaticListableBeanFactory implements ListableBeanFactory { boolean includeNonSingletons, boolean allowEagerInit) { Class resolved = (type != null ? type.resolve() : null); - boolean isFactoryType = resolved != null && FactoryBean.class.isAssignableFrom(resolved); + boolean isFactoryType = (resolved != null && FactoryBean.class.isAssignableFrom(resolved)); List matches = new ArrayList<>(); for (Map.Entry entry : this.beans.entrySet()) { @@ -365,7 +361,7 @@ public class StaticListableBeanFactory implements ListableBeanFactory { if (beanInstance instanceof FactoryBean factoryBean && !isFactoryType) { Class objectType = factoryBean.getObjectType(); if ((includeNonSingletons || factoryBean.isSingleton()) && - objectType != null && (type == null || type.isAssignableFrom(objectType))) { + (type == null || (objectType != null && type.isAssignableFrom(objectType)))) { matches.add(beanName); } } @@ -404,19 +400,15 @@ public class StaticListableBeanFactory implements ListableBeanFactory { for (Map.Entry entry : this.beans.entrySet()) { String beanName = entry.getKey(); Object beanInstance = entry.getValue(); - // Is bean a FactoryBean? if (beanInstance instanceof FactoryBean factoryBean && !isFactoryType) { - // Match object created by FactoryBean. Class objectType = factoryBean.getObjectType(); if ((includeNonSingletons || factoryBean.isSingleton()) && - objectType != null && (type == null || type.isAssignableFrom(objectType))) { + (type == null || (objectType != null && type.isAssignableFrom(objectType)))) { matches.put(beanName, getBean(beanName, type)); } } else { if (type == null || type.isInstance(beanInstance)) { - // If type to match is FactoryBean, return FactoryBean itself. - // Else, return bean instance. if (isFactoryType) { beanName = FACTORY_BEAN_PREFIX + beanName; } 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 6e8ec29134..e8bc3b6644 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 @@ -388,33 +388,33 @@ class BeanFactoryUtilsTests { assertThat(lbf.isSingleton("bean")).isTrue(); assertThat(lbf.isSingleton("fb1")).isTrue(); - assertThat(lbf.isSingleton("fb2")).isTrue(); + assertThat(lbf.isSingleton("fb2")).isFalse(); assertThat(lbf.isSingleton("sfb1")).isTrue(); assertThat(lbf.isSingleton("sfb2")).isTrue(); - assertThat(lbf.isSingleton("sfb3")).isTrue(); - assertThat(lbf.isSingleton("sfb4")).isTrue(); + assertThat(lbf.isSingleton("sfb3")).isFalse(); + assertThat(lbf.isSingleton("sfb4")).isFalse(); assertThat(lbf.isSingleton("&fb1")).isTrue(); - assertThat(lbf.isSingleton("&fb2")).isFalse(); + assertThat(lbf.isSingleton("&fb2")).isTrue(); assertThat(lbf.isSingleton("&sfb1")).isTrue(); assertThat(lbf.isSingleton("&sfb2")).isTrue(); - assertThat(lbf.isSingleton("&sfb3")).isFalse(); - assertThat(lbf.isSingleton("&sfb4")).isFalse(); + assertThat(lbf.isSingleton("&sfb3")).isTrue(); + assertThat(lbf.isSingleton("&sfb4")).isTrue(); assertThat(lbf.isPrototype("bean")).isFalse(); assertThat(lbf.isPrototype("fb1")).isFalse(); - assertThat(lbf.isPrototype("fb2")).isFalse(); - assertThat(lbf.isPrototype("sfb1")).isFalse(); + assertThat(lbf.isPrototype("fb2")).isTrue(); + assertThat(lbf.isPrototype("sfb1")).isTrue(); assertThat(lbf.isPrototype("sfb2")).isFalse(); - assertThat(lbf.isPrototype("sfb3")).isFalse(); - assertThat(lbf.isPrototype("sfb4")).isFalse(); + assertThat(lbf.isPrototype("sfb3")).isTrue(); + assertThat(lbf.isPrototype("sfb4")).isTrue(); assertThat(lbf.isPrototype("&fb1")).isFalse(); - assertThat(lbf.isPrototype("&fb2")).isTrue(); - assertThat(lbf.isPrototype("&sfb1")).isTrue(); + assertThat(lbf.isPrototype("&fb2")).isFalse(); + assertThat(lbf.isPrototype("&sfb1")).isFalse(); assertThat(lbf.isPrototype("&sfb2")).isFalse(); - assertThat(lbf.isPrototype("&sfb3")).isTrue(); - assertThat(lbf.isPrototype("&sfb4")).isTrue(); + assertThat(lbf.isPrototype("&sfb3")).isFalse(); + assertThat(lbf.isPrototype("&sfb4")).isFalse(); }