From 500b48d0bbf8a623d01eded4f443ca610925fd05 Mon Sep 17 00:00:00 2001 From: Yanming Zhou Date: Tue, 14 Jul 2026 09:50:52 +0800 Subject: [PATCH] Fix `BeanFactory.getBean(String, ParameterizedTypeReference)` to respect AOP proxy Before this commit, the implementation uses `ResolvableType::isInstance` which doesn't take JDK proxy into account, it fails if `proxyTargetClass = false`: ``` Bean named 'userDao' is expected to be of type 'org.springframework.cache.config.ExpressionCachingIntegrationTests$BaseDao' but was actually of type 'org.springframework.cache.config.$Proxy53' org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'userDao' is expected to be of type 'org.springframework.cache.config.ExpressionCachingIntegrationTests$BaseDao' but was actually of type 'org.springframework.cache.config.$Proxy53' at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:212) at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1312) at org.springframework.cache.config.ExpressionCachingIntegrationTests.expressionIsCacheBasedOnActualMethod(ExpressionCachingIntegrationTests.java:42) ``` See GH-34687 Signed-off-by: Yanming Zhou --- .../beans/factory/support/AbstractBeanFactory.java | 2 +- .../cache/config/ExpressionCachingIntegrationTests.java | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) 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 1f8c483db66b..6ee57aecbe44 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 @@ -208,7 +208,7 @@ public T getBean(String name, Class requiredType) throws BeansException { public T getBean(String name, ParameterizedTypeReference typeReference) throws BeansException { Object bean = getBean(name); Type requiredType = typeReference.getType(); - if (!ResolvableType.forType(requiredType).isInstance(bean)) { + if (!isTypeMatch(name, ResolvableType.forType(requiredType), true)) { throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } return (T) bean; diff --git a/spring-context/src/test/java/org/springframework/cache/config/ExpressionCachingIntegrationTests.java b/spring-context/src/test/java/org/springframework/cache/config/ExpressionCachingIntegrationTests.java index 6d1e3aab6d53..de0385fd064c 100644 --- a/spring-context/src/test/java/org/springframework/cache/config/ExpressionCachingIntegrationTests.java +++ b/spring-context/src/test/java/org/springframework/cache/config/ExpressionCachingIntegrationTests.java @@ -27,20 +27,21 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.ParameterizedTypeReference; /** * @author Stephane Nicoll + * @author Yanming Zhou */ class ExpressionCachingIntegrationTests { @Test // SPR-11692 - @SuppressWarnings("unchecked") void expressionIsCacheBasedOnActualMethod() { ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(SharedConfig.class, Spr11692Config.class); - BaseDao userDao = (BaseDao) context.getBean("userDao"); - BaseDao orderDao = (BaseDao) context.getBean("orderDao"); + BaseDao userDao = context.getBean("userDao", new ParameterizedTypeReference<>() {}); + BaseDao orderDao = context.getBean("orderDao", new ParameterizedTypeReference<>() {}); userDao.persist(new User("1")); orderDao.persist(new Order("2"));