Rethrow original BeanCreationException if fallback producer fails
Closes gh-22689
This commit is contained in:
parent
c54355784e
commit
ca24fd50b0
|
|
@ -26,6 +26,7 @@ import org.hibernate.resource.beans.container.spi.ContainedBean;
|
|||
import org.hibernate.resource.beans.spi.BeanInstanceProducer;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
|
@ -155,7 +156,22 @@ public final class SpringBeanContainer implements BeanContainer {
|
|||
logger.debug("Falling back to Hibernate's default producer after bean creation failure for " +
|
||||
beanType + ": " + ex);
|
||||
}
|
||||
return new SpringContainedBean<>(fallbackProducer.produceBeanInstance(beanType));
|
||||
try {
|
||||
return new SpringContainedBean<>(fallbackProducer.produceBeanInstance(beanType));
|
||||
}
|
||||
catch (RuntimeException ex2) {
|
||||
if (ex instanceof BeanCreationException) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Fallback producer failed for " + beanType + ": " + ex2);
|
||||
}
|
||||
// Rethrow original Spring exception from first attempt.
|
||||
throw ex;
|
||||
}
|
||||
else {
|
||||
// Throw fallback producer exception since original was probably NoSuchBeanDefinitionException.
|
||||
throw ex2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -177,9 +193,24 @@ public final class SpringBeanContainer implements BeanContainer {
|
|||
catch (BeansException ex) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Falling back to Hibernate's default producer after bean creation failure for " +
|
||||
beanType + ": " + ex);
|
||||
beanType + " with name '" + name + "': " + ex);
|
||||
}
|
||||
try {
|
||||
return new SpringContainedBean<>(fallbackProducer.produceBeanInstance(name, beanType));
|
||||
}
|
||||
catch (RuntimeException ex2) {
|
||||
if (ex instanceof BeanCreationException) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Fallback producer failed for " + beanType + " with name '" + name + "': " + ex2);
|
||||
}
|
||||
// Rethrow original Spring exception from first attempt.
|
||||
throw ex;
|
||||
}
|
||||
else {
|
||||
// Throw fallback producer exception since original was probably NoSuchBeanDefinitionException.
|
||||
throw ex2;
|
||||
}
|
||||
}
|
||||
return new SpringContainedBean<>(fallbackProducer.produceBeanInstance(name, beanType));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,19 +16,24 @@
|
|||
|
||||
package org.springframework.orm.jpa.hibernate;
|
||||
|
||||
import javax.persistence.AttributeConverter;
|
||||
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.resource.beans.container.spi.BeanContainer;
|
||||
import org.hibernate.resource.beans.container.spi.ContainedBean;
|
||||
import org.hibernate.resource.beans.spi.BeanInstanceProducer;
|
||||
import org.hibernate.resource.beans.spi.ManagedBeanRegistry;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.orm.jpa.AbstractEntityManagerFactoryIntegrationTests;
|
||||
import org.springframework.orm.jpa.hibernate.beans.*;
|
||||
import org.springframework.orm.jpa.hibernate.beans.BeanSource;
|
||||
import org.springframework.orm.jpa.hibernate.beans.MultiplePrototypesInSpringContextTestBean;
|
||||
import org.springframework.orm.jpa.hibernate.beans.NoDefinitionInSpringContextTestBean;
|
||||
import org.springframework.orm.jpa.hibernate.beans.SinglePrototypeInSpringContextTestBean;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
|
|
@ -36,6 +41,7 @@ import static org.junit.Assert.*;
|
|||
* Hibernate-specific SpringBeanContainer integration tests.
|
||||
*
|
||||
* @author Yoann Rodiere
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class HibernateNativeEntityManagerFactorySpringBeanContainerIntegrationTests
|
||||
extends AbstractEntityManagerFactoryIntegrationTests {
|
||||
|
|
@ -51,9 +57,9 @@ public class HibernateNativeEntityManagerFactorySpringBeanContainerIntegrationTe
|
|||
}
|
||||
|
||||
private ManagedBeanRegistry getManagedBeanRegistry() {
|
||||
SessionFactory sessionFactory = entityManagerFactory.unwrap( SessionFactory.class );
|
||||
SessionFactory sessionFactory = entityManagerFactory.unwrap(SessionFactory.class);
|
||||
ServiceRegistry serviceRegistry = sessionFactory.getSessionFactoryOptions().getServiceRegistry();
|
||||
return serviceRegistry.requireService( ManagedBeanRegistry.class );
|
||||
return serviceRegistry.requireService(ManagedBeanRegistry.class);
|
||||
}
|
||||
|
||||
private BeanContainer getBeanContainer() {
|
||||
|
|
@ -68,8 +74,7 @@ public class HibernateNativeEntityManagerFactorySpringBeanContainerIntegrationTe
|
|||
|
||||
ContainedBean<SinglePrototypeInSpringContextTestBean> bean = beanContainer.getBean(
|
||||
SinglePrototypeInSpringContextTestBean.class,
|
||||
JpaLifecycleOptions.INSTANCE,
|
||||
IneffectiveBeanInstanceProducer.INSTANCE
|
||||
JpaLifecycleOptions.INSTANCE, IneffectiveBeanInstanceProducer.INSTANCE
|
||||
);
|
||||
|
||||
assertNotNull(bean);
|
||||
|
|
@ -85,8 +90,7 @@ public class HibernateNativeEntityManagerFactorySpringBeanContainerIntegrationTe
|
|||
|
||||
ContainedBean<MultiplePrototypesInSpringContextTestBean> bean = beanContainer.getBean(
|
||||
"multiple-1", MultiplePrototypesInSpringContextTestBean.class,
|
||||
JpaLifecycleOptions.INSTANCE,
|
||||
IneffectiveBeanInstanceProducer.INSTANCE
|
||||
JpaLifecycleOptions.INSTANCE, IneffectiveBeanInstanceProducer.INSTANCE
|
||||
);
|
||||
|
||||
assertNotNull(bean);
|
||||
|
|
@ -103,8 +107,7 @@ public class HibernateNativeEntityManagerFactorySpringBeanContainerIntegrationTe
|
|||
|
||||
ContainedBean<SinglePrototypeInSpringContextTestBean> bean = beanContainer.getBean(
|
||||
SinglePrototypeInSpringContextTestBean.class,
|
||||
NativeLifecycleOptions.INSTANCE,
|
||||
IneffectiveBeanInstanceProducer.INSTANCE
|
||||
NativeLifecycleOptions.INSTANCE, IneffectiveBeanInstanceProducer.INSTANCE
|
||||
);
|
||||
|
||||
assertNotNull(bean);
|
||||
|
|
@ -115,8 +118,7 @@ public class HibernateNativeEntityManagerFactorySpringBeanContainerIntegrationTe
|
|||
|
||||
ContainedBean<SinglePrototypeInSpringContextTestBean> bean2 = beanContainer.getBean(
|
||||
SinglePrototypeInSpringContextTestBean.class,
|
||||
NativeLifecycleOptions.INSTANCE,
|
||||
IneffectiveBeanInstanceProducer.INSTANCE
|
||||
NativeLifecycleOptions.INSTANCE, IneffectiveBeanInstanceProducer.INSTANCE
|
||||
);
|
||||
|
||||
assertNotNull(bean2);
|
||||
|
|
@ -133,8 +135,7 @@ public class HibernateNativeEntityManagerFactorySpringBeanContainerIntegrationTe
|
|||
|
||||
ContainedBean<MultiplePrototypesInSpringContextTestBean> bean = beanContainer.getBean(
|
||||
"multiple-1", MultiplePrototypesInSpringContextTestBean.class,
|
||||
NativeLifecycleOptions.INSTANCE,
|
||||
IneffectiveBeanInstanceProducer.INSTANCE
|
||||
NativeLifecycleOptions.INSTANCE, IneffectiveBeanInstanceProducer.INSTANCE
|
||||
);
|
||||
|
||||
assertNotNull(bean);
|
||||
|
|
@ -145,8 +146,7 @@ public class HibernateNativeEntityManagerFactorySpringBeanContainerIntegrationTe
|
|||
|
||||
ContainedBean<MultiplePrototypesInSpringContextTestBean> bean2 = beanContainer.getBean(
|
||||
"multiple-1", MultiplePrototypesInSpringContextTestBean.class,
|
||||
NativeLifecycleOptions.INSTANCE,
|
||||
IneffectiveBeanInstanceProducer.INSTANCE
|
||||
NativeLifecycleOptions.INSTANCE, IneffectiveBeanInstanceProducer.INSTANCE
|
||||
);
|
||||
|
||||
assertNotNull(bean2);
|
||||
|
|
@ -164,8 +164,7 @@ public class HibernateNativeEntityManagerFactorySpringBeanContainerIntegrationTe
|
|||
|
||||
ContainedBean<NoDefinitionInSpringContextTestBean> bean = beanContainer.getBean(
|
||||
NoDefinitionInSpringContextTestBean.class,
|
||||
JpaLifecycleOptions.INSTANCE,
|
||||
fallbackProducer
|
||||
JpaLifecycleOptions.INSTANCE, fallbackProducer
|
||||
);
|
||||
|
||||
assertEquals(1, fallbackProducer.currentUnnamedInstantiationCount());
|
||||
|
|
@ -186,8 +185,7 @@ public class HibernateNativeEntityManagerFactorySpringBeanContainerIntegrationTe
|
|||
|
||||
ContainedBean<NoDefinitionInSpringContextTestBean> bean = beanContainer.getBean(
|
||||
"some name", NoDefinitionInSpringContextTestBean.class,
|
||||
JpaLifecycleOptions.INSTANCE,
|
||||
fallbackProducer
|
||||
JpaLifecycleOptions.INSTANCE, fallbackProducer
|
||||
);
|
||||
|
||||
assertEquals(0, fallbackProducer.currentUnnamedInstantiationCount());
|
||||
|
|
@ -209,8 +207,7 @@ public class HibernateNativeEntityManagerFactorySpringBeanContainerIntegrationTe
|
|||
|
||||
ContainedBean<NoDefinitionInSpringContextTestBean> bean = beanContainer.getBean(
|
||||
NoDefinitionInSpringContextTestBean.class,
|
||||
NativeLifecycleOptions.INSTANCE,
|
||||
fallbackProducer
|
||||
NativeLifecycleOptions.INSTANCE, fallbackProducer
|
||||
);
|
||||
|
||||
assertEquals(1, fallbackProducer.currentUnnamedInstantiationCount());
|
||||
|
|
@ -231,8 +228,7 @@ public class HibernateNativeEntityManagerFactorySpringBeanContainerIntegrationTe
|
|||
|
||||
ContainedBean<NoDefinitionInSpringContextTestBean> bean = beanContainer.getBean(
|
||||
"some name", NoDefinitionInSpringContextTestBean.class,
|
||||
NativeLifecycleOptions.INSTANCE,
|
||||
fallbackProducer
|
||||
NativeLifecycleOptions.INSTANCE, fallbackProducer
|
||||
);
|
||||
|
||||
assertEquals(0, fallbackProducer.currentUnnamedInstantiationCount());
|
||||
|
|
@ -246,11 +242,40 @@ public class HibernateNativeEntityManagerFactorySpringBeanContainerIntegrationTe
|
|||
assertNull(instance.getApplicationContext());
|
||||
}
|
||||
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void testFallbackExceptionInCaseOfNoSpringBeanFound() {
|
||||
getBeanContainer().getBean(NoDefinitionInSpringContextTestBean.class,
|
||||
NativeLifecycleOptions.INSTANCE, IneffectiveBeanInstanceProducer.INSTANCE
|
||||
);
|
||||
}
|
||||
|
||||
@Test(expected = BeanCreationException.class)
|
||||
public void testOriginalExceptionInCaseOfFallbackProducerFailure() {
|
||||
getBeanContainer().getBean(AttributeConverter.class,
|
||||
NativeLifecycleOptions.INSTANCE, IneffectiveBeanInstanceProducer.INSTANCE
|
||||
);
|
||||
}
|
||||
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void testFallbackExceptionInCaseOfNoSpringBeanFoundByName() {
|
||||
getBeanContainer().getBean("some name", NoDefinitionInSpringContextTestBean.class,
|
||||
NativeLifecycleOptions.INSTANCE, IneffectiveBeanInstanceProducer.INSTANCE
|
||||
);
|
||||
}
|
||||
|
||||
@Test(expected = BeanCreationException.class)
|
||||
public void testOriginalExceptionInCaseOfFallbackProducerFailureByName() {
|
||||
getBeanContainer().getBean("invalid", AttributeConverter.class,
|
||||
NativeLifecycleOptions.INSTANCE, IneffectiveBeanInstanceProducer.INSTANCE
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The lifecycle options mandated by the JPA spec and used as a default in Hibernate ORM.
|
||||
*/
|
||||
private static class JpaLifecycleOptions implements BeanContainer.LifecycleOptions {
|
||||
|
||||
public static final JpaLifecycleOptions INSTANCE = new JpaLifecycleOptions();
|
||||
|
||||
@Override
|
||||
|
|
@ -264,12 +289,14 @@ public class HibernateNativeEntityManagerFactorySpringBeanContainerIntegrationTe
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The lifecycle options used by libraries integrating into Hibernate ORM
|
||||
* and that want a behavior closer to Spring's native behavior,
|
||||
* such as Hibernate Search.
|
||||
*/
|
||||
private static class NativeLifecycleOptions implements BeanContainer.LifecycleOptions {
|
||||
|
||||
public static final NativeLifecycleOptions INSTANCE = new NativeLifecycleOptions();
|
||||
|
||||
@Override
|
||||
|
|
@ -283,7 +310,9 @@ public class HibernateNativeEntityManagerFactorySpringBeanContainerIntegrationTe
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private static class IneffectiveBeanInstanceProducer implements BeanInstanceProducer {
|
||||
|
||||
public static final IneffectiveBeanInstanceProducer INSTANCE = new IneffectiveBeanInstanceProducer();
|
||||
|
||||
@Override
|
||||
|
|
@ -297,8 +326,11 @@ public class HibernateNativeEntityManagerFactorySpringBeanContainerIntegrationTe
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private static class NoDefinitionInSpringContextTestBeanInstanceProducer implements BeanInstanceProducer {
|
||||
|
||||
private int unnamedInstantiationCount = 0;
|
||||
|
||||
private int namedInstantiationCount = 0;
|
||||
|
||||
@Override
|
||||
|
|
@ -341,4 +373,5 @@ public class HibernateNativeEntityManagerFactorySpringBeanContainerIntegrationTe
|
|||
return namedInstantiationCount;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,9 +19,8 @@ package org.springframework.orm.jpa.hibernate.beans;
|
|||
public class NoDefinitionInSpringContextTestBean extends TestBean {
|
||||
|
||||
private NoDefinitionInSpringContextTestBean() {
|
||||
throw new AssertionError(
|
||||
"Unexpected call to the default constructor."
|
||||
+ " Is Spring trying to instantiate this class by itself, even though it should delegate to the fallback producer?"
|
||||
throw new AssertionError("Unexpected call to the default constructor. " +
|
||||
"Is Spring trying to instantiate this class by itself, even though it should delegate to the fallback producer?"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,4 +28,6 @@
|
|||
|
||||
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
|
||||
|
||||
<bean id="invalid" class="javax.persistence.AttributeConverter" lazy-init="true"/>
|
||||
|
||||
</beans>
|
||||
|
|
|
|||
Loading…
Reference in New Issue