Avoid getObjectType exception for uninitialized ProxyFactoryBean

Closes gh-31473
This commit is contained in:
Juergen Hoeller 2023-10-23 17:32:25 +02:00
parent bb446a3905
commit f9be717602
2 changed files with 44 additions and 24 deletions

View File

@ -265,18 +265,32 @@ public class ProxyFactoryBean extends ProxyCreatorSupport
* Return the type of the proxy. Will check the singleton instance if * Return the type of the proxy. Will check the singleton instance if
* already created, else fall back to the proxy interface (in case of just * already created, else fall back to the proxy interface (in case of just
* a single one), the target bean type, or the TargetSource's target class. * a single one), the target bean type, or the TargetSource's target class.
* @see org.springframework.aop.TargetSource#getTargetClass * @see org.springframework.aop.framework.AopProxy#getProxyClass
*/ */
@Override @Override
@Nullable
public Class<?> getObjectType() { public Class<?> getObjectType() {
synchronized (this) { synchronized (this) {
if (this.singletonInstance != null) { if (this.singletonInstance != null) {
return this.singletonInstance.getClass(); return this.singletonInstance.getClass();
} }
} }
// This might be incomplete since it potentially misses introduced interfaces try {
// from Advisors that will be lazily retrieved via setInterceptorNames. // This might be incomplete since it potentially misses introduced interfaces
return createAopProxy().getProxyClass(this.proxyClassLoader); // from Advisors that will be lazily retrieved via setInterceptorNames.
return createAopProxy().getProxyClass(this.proxyClassLoader);
}
catch (AopConfigException ex) {
if (getTargetClass() == null) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to determine early proxy class: " + ex.getMessage());
}
return null;
}
else {
throw ex;
}
}
} }
@Override @Override

View File

@ -139,22 +139,24 @@ public class ProxyFactoryBeanTests {
private void testDoubleTargetSourceIsRejected(String name) { private void testDoubleTargetSourceIsRejected(String name) {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader(bf).loadBeanDefinitions(new ClassPathResource(DBL_TARGETSOURCE_CONTEXT, CLASS)); new XmlBeanDefinitionReader(bf).loadBeanDefinitions(new ClassPathResource(DBL_TARGETSOURCE_CONTEXT, CLASS));
assertThatExceptionOfType(BeanCreationException.class).as("Should not allow TargetSource to be specified in interceptorNames as well as targetSource property") assertThatExceptionOfType(BeanCreationException.class).as("Should not allow TargetSource to be specified in interceptorNames as well as targetSource property")
.isThrownBy(() -> bf.getBean(name)) .isThrownBy(() -> bf.getBean(name))
.havingCause() .havingCause()
.isInstanceOf(AopConfigException.class) .isInstanceOf(AopConfigException.class)
.withMessageContaining("TargetSource"); .withMessageContaining("TargetSource");
} }
@Test @Test
public void testTargetSourceNotAtEndOfInterceptorNamesIsRejected() { public void testTargetSourceNotAtEndOfInterceptorNamesIsRejected() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader(bf).loadBeanDefinitions(new ClassPathResource(NOTLAST_TARGETSOURCE_CONTEXT, CLASS)); new XmlBeanDefinitionReader(bf).loadBeanDefinitions(new ClassPathResource(NOTLAST_TARGETSOURCE_CONTEXT, CLASS));
assertThatExceptionOfType(BeanCreationException.class).as("TargetSource or non-advised object must be last in interceptorNames") assertThatExceptionOfType(BeanCreationException.class).as("TargetSource or non-advised object must be last in interceptorNames")
.isThrownBy(() -> bf.getBean("targetSourceNotLast")) .isThrownBy(() -> bf.getBean("targetSourceNotLast"))
.havingCause() .havingCause()
.isInstanceOf(AopConfigException.class) .isInstanceOf(AopConfigException.class)
.withMessageContaining("interceptorNames"); .withMessageContaining("interceptorNames");
} }
@Test @Test
@ -171,7 +173,7 @@ public class ProxyFactoryBeanTests {
assertThat(cba.getCalls()).isEqualTo(1); assertThat(cba.getCalls()).isEqualTo(1);
ProxyFactoryBean pfb = (ProxyFactoryBean) bf.getBean("&directTarget"); ProxyFactoryBean pfb = (ProxyFactoryBean) bf.getBean("&directTarget");
assertThat(TestBean.class.isAssignableFrom(pfb.getObjectType())).as("Has correct object type").isTrue(); assertThat(pfb.getObjectType()).isAssignableTo(TestBean.class);
} }
@Test @Test
@ -181,7 +183,7 @@ public class ProxyFactoryBeanTests {
ITestBean tb = (ITestBean) bf.getBean("viaTargetSource"); ITestBean tb = (ITestBean) bf.getBean("viaTargetSource");
assertThat(tb.getName()).isEqualTo("Adam"); assertThat(tb.getName()).isEqualTo("Adam");
ProxyFactoryBean pfb = (ProxyFactoryBean) bf.getBean("&viaTargetSource"); ProxyFactoryBean pfb = (ProxyFactoryBean) bf.getBean("&viaTargetSource");
assertThat(TestBean.class.isAssignableFrom(pfb.getObjectType())).as("Has correct object type").isTrue(); assertThat(pfb.getObjectType()).isAssignableTo(TestBean.class);
} }
@Test @Test
@ -190,11 +192,15 @@ public class ProxyFactoryBeanTests {
new XmlBeanDefinitionReader(bf).loadBeanDefinitions(new ClassPathResource(TARGETSOURCE_CONTEXT, CLASS)); new XmlBeanDefinitionReader(bf).loadBeanDefinitions(new ClassPathResource(TARGETSOURCE_CONTEXT, CLASS));
ITestBean tb = (ITestBean) bf.getBean("noTarget"); ITestBean tb = (ITestBean) bf.getBean("noTarget");
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(tb::getName).withMessage("getName");
tb.getName())
.withMessage("getName");
FactoryBean<?> pfb = (ProxyFactoryBean) bf.getBean("&noTarget"); FactoryBean<?> pfb = (ProxyFactoryBean) bf.getBean("&noTarget");
assertThat(ITestBean.class.isAssignableFrom(pfb.getObjectType())).as("Has correct object type").isTrue(); assertThat(pfb.getObjectType()).isAssignableTo(ITestBean.class);
}
@Test
public void testGetObjectTypeOnUninitializedFactoryBean() {
ProxyFactoryBean pfb = new ProxyFactoryBean();
assertThat(pfb.getObjectType()).isNull();
} }
/** /**
@ -227,12 +233,12 @@ public class ProxyFactoryBeanTests {
@Test @Test
public void testPrototypeInstancesAreNotEqual() { public void testPrototypeInstancesAreNotEqual() {
assertThat(ITestBean.class.isAssignableFrom(factory.getType("prototype"))).as("Has correct object type").isTrue(); assertThat(factory.getType("prototype")).isAssignableTo(ITestBean.class);
ITestBean test2 = (ITestBean) factory.getBean("prototype"); ITestBean test2 = (ITestBean) factory.getBean("prototype");
ITestBean test2_1 = (ITestBean) factory.getBean("prototype"); ITestBean test2_1 = (ITestBean) factory.getBean("prototype");
assertThat(test2).as("Prototype instances !=").isNotSameAs(test2_1); assertThat(test2).as("Prototype instances !=").isNotSameAs(test2_1);
assertThat(test2).as("Prototype instances equal").isEqualTo(test2_1); assertThat(test2).as("Prototype instances equal").isEqualTo(test2_1);
assertThat(ITestBean.class.isAssignableFrom(factory.getType("prototype"))).as("Has correct object type").isTrue(); assertThat(factory.getType("prototype")).isAssignableTo(ITestBean.class);
} }
/** /**
@ -291,13 +297,13 @@ public class ProxyFactoryBeanTests {
@Test @Test
public void testCanGetFactoryReferenceAndManipulate() { public void testCanGetFactoryReferenceAndManipulate() {
ProxyFactoryBean config = (ProxyFactoryBean) factory.getBean("&test1"); ProxyFactoryBean config = (ProxyFactoryBean) factory.getBean("&test1");
assertThat(ITestBean.class.isAssignableFrom(config.getObjectType())).as("Has correct object type").isTrue(); assertThat(config.getObjectType()).isAssignableTo(ITestBean.class);
assertThat(ITestBean.class.isAssignableFrom(factory.getType("test1"))).as("Has correct object type").isTrue(); assertThat(factory.getType("test1")).isAssignableTo(ITestBean.class);
// Trigger lazy initialization. // Trigger lazy initialization.
config.getObject(); config.getObject();
assertThat(config.getAdvisors().length).as("Have one advisors").isEqualTo(1); assertThat(config.getAdvisors().length).as("Have one advisors").isEqualTo(1);
assertThat(ITestBean.class.isAssignableFrom(config.getObjectType())).as("Has correct object type").isTrue(); assertThat(config.getObjectType()).isAssignableTo(ITestBean.class);
assertThat(ITestBean.class.isAssignableFrom(factory.getType("test1"))).as("Has correct object type").isTrue(); assertThat(factory.getType("test1")).isAssignableTo(ITestBean.class);
ITestBean tb = (ITestBean) factory.getBean("test1"); ITestBean tb = (ITestBean) factory.getBean("test1");
// no exception // no exception