Skip to content

Commit ca24fd5

Browse files
committed
Rethrow original BeanCreationException if fallback producer fails
Closes gh-22689
1 parent c543557 commit ca24fd5

File tree

4 files changed

+95
-30
lines changed

4 files changed

+95
-30
lines changed

spring-orm/src/main/java/org/springframework/orm/hibernate5/SpringBeanContainer.java

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.hibernate.resource.beans.spi.BeanInstanceProducer;
2727

2828
import org.springframework.beans.BeansException;
29+
import org.springframework.beans.factory.BeanCreationException;
2930
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
3031
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
3132
import org.springframework.lang.Nullable;
@@ -155,7 +156,22 @@ private SpringContainedBean<?> createBean(
155156
logger.debug("Falling back to Hibernate's default producer after bean creation failure for " +
156157
beanType + ": " + ex);
157158
}
158-
return new SpringContainedBean<>(fallbackProducer.produceBeanInstance(beanType));
159+
try {
160+
return new SpringContainedBean<>(fallbackProducer.produceBeanInstance(beanType));
161+
}
162+
catch (RuntimeException ex2) {
163+
if (ex instanceof BeanCreationException) {
164+
if (logger.isDebugEnabled()) {
165+
logger.debug("Fallback producer failed for " + beanType + ": " + ex2);
166+
}
167+
// Rethrow original Spring exception from first attempt.
168+
throw ex;
169+
}
170+
else {
171+
// Throw fallback producer exception since original was probably NoSuchBeanDefinitionException.
172+
throw ex2;
173+
}
174+
}
159175
}
160176
}
161177

@@ -177,9 +193,24 @@ private SpringContainedBean<?> createBean(
177193
catch (BeansException ex) {
178194
if (logger.isDebugEnabled()) {
179195
logger.debug("Falling back to Hibernate's default producer after bean creation failure for " +
180-
beanType + ": " + ex);
196+
beanType + " with name '" + name + "': " + ex);
197+
}
198+
try {
199+
return new SpringContainedBean<>(fallbackProducer.produceBeanInstance(name, beanType));
200+
}
201+
catch (RuntimeException ex2) {
202+
if (ex instanceof BeanCreationException) {
203+
if (logger.isDebugEnabled()) {
204+
logger.debug("Fallback producer failed for " + beanType + " with name '" + name + "': " + ex2);
205+
}
206+
// Rethrow original Spring exception from first attempt.
207+
throw ex;
208+
}
209+
else {
210+
// Throw fallback producer exception since original was probably NoSuchBeanDefinitionException.
211+
throw ex2;
212+
}
181213
}
182-
return new SpringContainedBean<>(fallbackProducer.produceBeanInstance(name, beanType));
183214
}
184215
}
185216

spring-orm/src/test/java/org/springframework/orm/jpa/hibernate/HibernateNativeEntityManagerFactorySpringBeanContainerIntegrationTests.java

Lines changed: 57 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -16,26 +16,32 @@
1616

1717
package org.springframework.orm.jpa.hibernate;
1818

19+
import javax.persistence.AttributeConverter;
20+
1921
import org.hibernate.SessionFactory;
2022
import org.hibernate.resource.beans.container.spi.BeanContainer;
2123
import org.hibernate.resource.beans.container.spi.ContainedBean;
2224
import org.hibernate.resource.beans.spi.BeanInstanceProducer;
2325
import org.hibernate.resource.beans.spi.ManagedBeanRegistry;
2426
import org.hibernate.service.ServiceRegistry;
25-
2627
import org.junit.Test;
2728

29+
import org.springframework.beans.factory.BeanCreationException;
2830
import org.springframework.beans.factory.annotation.Autowired;
2931
import org.springframework.context.ApplicationContext;
3032
import org.springframework.orm.jpa.AbstractEntityManagerFactoryIntegrationTests;
31-
import org.springframework.orm.jpa.hibernate.beans.*;
33+
import org.springframework.orm.jpa.hibernate.beans.BeanSource;
34+
import org.springframework.orm.jpa.hibernate.beans.MultiplePrototypesInSpringContextTestBean;
35+
import org.springframework.orm.jpa.hibernate.beans.NoDefinitionInSpringContextTestBean;
36+
import org.springframework.orm.jpa.hibernate.beans.SinglePrototypeInSpringContextTestBean;
3237

3338
import static org.junit.Assert.*;
3439

3540
/**
3641
* Hibernate-specific SpringBeanContainer integration tests.
3742
*
3843
* @author Yoann Rodiere
44+
* @author Juergen Hoeller
3945
*/
4046
public class HibernateNativeEntityManagerFactorySpringBeanContainerIntegrationTests
4147
extends AbstractEntityManagerFactoryIntegrationTests {
@@ -51,9 +57,9 @@ protected String[] getConfigLocations() {
5157
}
5258

5359
private ManagedBeanRegistry getManagedBeanRegistry() {
54-
SessionFactory sessionFactory = entityManagerFactory.unwrap( SessionFactory.class );
60+
SessionFactory sessionFactory = entityManagerFactory.unwrap(SessionFactory.class);
5561
ServiceRegistry serviceRegistry = sessionFactory.getSessionFactoryOptions().getServiceRegistry();
56-
return serviceRegistry.requireService( ManagedBeanRegistry.class );
62+
return serviceRegistry.requireService(ManagedBeanRegistry.class);
5763
}
5864

5965
private BeanContainer getBeanContainer() {
@@ -68,8 +74,7 @@ public void testCanRetrieveBeanByTypeWithJpaCompliantOptions() {
6874

6975
ContainedBean<SinglePrototypeInSpringContextTestBean> bean = beanContainer.getBean(
7076
SinglePrototypeInSpringContextTestBean.class,
71-
JpaLifecycleOptions.INSTANCE,
72-
IneffectiveBeanInstanceProducer.INSTANCE
77+
JpaLifecycleOptions.INSTANCE, IneffectiveBeanInstanceProducer.INSTANCE
7378
);
7479

7580
assertNotNull(bean);
@@ -85,8 +90,7 @@ public void testCanRetrieveBeanByNameWithJpaCompliantOptions() {
8590

8691
ContainedBean<MultiplePrototypesInSpringContextTestBean> bean = beanContainer.getBean(
8792
"multiple-1", MultiplePrototypesInSpringContextTestBean.class,
88-
JpaLifecycleOptions.INSTANCE,
89-
IneffectiveBeanInstanceProducer.INSTANCE
93+
JpaLifecycleOptions.INSTANCE, IneffectiveBeanInstanceProducer.INSTANCE
9094
);
9195

9296
assertNotNull(bean);
@@ -103,8 +107,7 @@ public void testCanRetrieveBeanByTypeWithNativeOptions() {
103107

104108
ContainedBean<SinglePrototypeInSpringContextTestBean> bean = beanContainer.getBean(
105109
SinglePrototypeInSpringContextTestBean.class,
106-
NativeLifecycleOptions.INSTANCE,
107-
IneffectiveBeanInstanceProducer.INSTANCE
110+
NativeLifecycleOptions.INSTANCE, IneffectiveBeanInstanceProducer.INSTANCE
108111
);
109112

110113
assertNotNull(bean);
@@ -115,8 +118,7 @@ public void testCanRetrieveBeanByTypeWithNativeOptions() {
115118

116119
ContainedBean<SinglePrototypeInSpringContextTestBean> bean2 = beanContainer.getBean(
117120
SinglePrototypeInSpringContextTestBean.class,
118-
NativeLifecycleOptions.INSTANCE,
119-
IneffectiveBeanInstanceProducer.INSTANCE
121+
NativeLifecycleOptions.INSTANCE, IneffectiveBeanInstanceProducer.INSTANCE
120122
);
121123

122124
assertNotNull(bean2);
@@ -133,8 +135,7 @@ public void testCanRetrieveBeanByNameWithNativeOptions() {
133135

134136
ContainedBean<MultiplePrototypesInSpringContextTestBean> bean = beanContainer.getBean(
135137
"multiple-1", MultiplePrototypesInSpringContextTestBean.class,
136-
NativeLifecycleOptions.INSTANCE,
137-
IneffectiveBeanInstanceProducer.INSTANCE
138+
NativeLifecycleOptions.INSTANCE, IneffectiveBeanInstanceProducer.INSTANCE
138139
);
139140

140141
assertNotNull(bean);
@@ -145,8 +146,7 @@ public void testCanRetrieveBeanByNameWithNativeOptions() {
145146

146147
ContainedBean<MultiplePrototypesInSpringContextTestBean> bean2 = beanContainer.getBean(
147148
"multiple-1", MultiplePrototypesInSpringContextTestBean.class,
148-
NativeLifecycleOptions.INSTANCE,
149-
IneffectiveBeanInstanceProducer.INSTANCE
149+
NativeLifecycleOptions.INSTANCE, IneffectiveBeanInstanceProducer.INSTANCE
150150
);
151151

152152
assertNotNull(bean2);
@@ -164,8 +164,7 @@ public void testCanRetrieveFallbackBeanByTypeWithJpaCompliantOptions() {
164164

165165
ContainedBean<NoDefinitionInSpringContextTestBean> bean = beanContainer.getBean(
166166
NoDefinitionInSpringContextTestBean.class,
167-
JpaLifecycleOptions.INSTANCE,
168-
fallbackProducer
167+
JpaLifecycleOptions.INSTANCE, fallbackProducer
169168
);
170169

171170
assertEquals(1, fallbackProducer.currentUnnamedInstantiationCount());
@@ -186,8 +185,7 @@ public void testCanRetrieveFallbackBeanByNameWithJpaCompliantOptions() {
186185

187186
ContainedBean<NoDefinitionInSpringContextTestBean> bean = beanContainer.getBean(
188187
"some name", NoDefinitionInSpringContextTestBean.class,
189-
JpaLifecycleOptions.INSTANCE,
190-
fallbackProducer
188+
JpaLifecycleOptions.INSTANCE, fallbackProducer
191189
);
192190

193191
assertEquals(0, fallbackProducer.currentUnnamedInstantiationCount());
@@ -209,8 +207,7 @@ public void testCanRetrieveFallbackBeanByTypeWithNativeOptions() {
209207

210208
ContainedBean<NoDefinitionInSpringContextTestBean> bean = beanContainer.getBean(
211209
NoDefinitionInSpringContextTestBean.class,
212-
NativeLifecycleOptions.INSTANCE,
213-
fallbackProducer
210+
NativeLifecycleOptions.INSTANCE, fallbackProducer
214211
);
215212

216213
assertEquals(1, fallbackProducer.currentUnnamedInstantiationCount());
@@ -231,8 +228,7 @@ public void testCanRetrieveFallbackBeanByNameWithNativeOptions() {
231228

232229
ContainedBean<NoDefinitionInSpringContextTestBean> bean = beanContainer.getBean(
233230
"some name", NoDefinitionInSpringContextTestBean.class,
234-
NativeLifecycleOptions.INSTANCE,
235-
fallbackProducer
231+
NativeLifecycleOptions.INSTANCE, fallbackProducer
236232
);
237233

238234
assertEquals(0, fallbackProducer.currentUnnamedInstantiationCount());
@@ -246,11 +242,40 @@ public void testCanRetrieveFallbackBeanByNameWithNativeOptions() {
246242
assertNull(instance.getApplicationContext());
247243
}
248244

245+
@Test(expected = UnsupportedOperationException.class)
246+
public void testFallbackExceptionInCaseOfNoSpringBeanFound() {
247+
getBeanContainer().getBean(NoDefinitionInSpringContextTestBean.class,
248+
NativeLifecycleOptions.INSTANCE, IneffectiveBeanInstanceProducer.INSTANCE
249+
);
250+
}
251+
252+
@Test(expected = BeanCreationException.class)
253+
public void testOriginalExceptionInCaseOfFallbackProducerFailure() {
254+
getBeanContainer().getBean(AttributeConverter.class,
255+
NativeLifecycleOptions.INSTANCE, IneffectiveBeanInstanceProducer.INSTANCE
256+
);
257+
}
258+
259+
@Test(expected = UnsupportedOperationException.class)
260+
public void testFallbackExceptionInCaseOfNoSpringBeanFoundByName() {
261+
getBeanContainer().getBean("some name", NoDefinitionInSpringContextTestBean.class,
262+
NativeLifecycleOptions.INSTANCE, IneffectiveBeanInstanceProducer.INSTANCE
263+
);
264+
}
265+
266+
@Test(expected = BeanCreationException.class)
267+
public void testOriginalExceptionInCaseOfFallbackProducerFailureByName() {
268+
getBeanContainer().getBean("invalid", AttributeConverter.class,
269+
NativeLifecycleOptions.INSTANCE, IneffectiveBeanInstanceProducer.INSTANCE
270+
);
271+
}
272+
249273

250274
/**
251275
* The lifecycle options mandated by the JPA spec and used as a default in Hibernate ORM.
252276
*/
253277
private static class JpaLifecycleOptions implements BeanContainer.LifecycleOptions {
278+
254279
public static final JpaLifecycleOptions INSTANCE = new JpaLifecycleOptions();
255280

256281
@Override
@@ -264,12 +289,14 @@ public boolean useJpaCompliantCreation() {
264289
}
265290
}
266291

292+
267293
/**
268294
* The lifecycle options used by libraries integrating into Hibernate ORM
269295
* and that want a behavior closer to Spring's native behavior,
270296
* such as Hibernate Search.
271297
*/
272298
private static class NativeLifecycleOptions implements BeanContainer.LifecycleOptions {
299+
273300
public static final NativeLifecycleOptions INSTANCE = new NativeLifecycleOptions();
274301

275302
@Override
@@ -283,7 +310,9 @@ public boolean useJpaCompliantCreation() {
283310
}
284311
}
285312

313+
286314
private static class IneffectiveBeanInstanceProducer implements BeanInstanceProducer {
315+
287316
public static final IneffectiveBeanInstanceProducer INSTANCE = new IneffectiveBeanInstanceProducer();
288317

289318
@Override
@@ -297,8 +326,11 @@ public <B> B produceBeanInstance(String s, Class<B> aClass) {
297326
}
298327
}
299328

329+
300330
private static class NoDefinitionInSpringContextTestBeanInstanceProducer implements BeanInstanceProducer {
331+
301332
private int unnamedInstantiationCount = 0;
333+
302334
private int namedInstantiationCount = 0;
303335

304336
@Override
@@ -341,4 +373,5 @@ private int currentNamedInstantiationCount() {
341373
return namedInstantiationCount;
342374
}
343375
}
376+
344377
}

spring-orm/src/test/java/org/springframework/orm/jpa/hibernate/beans/NoDefinitionInSpringContextTestBean.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,8 @@
1919
public class NoDefinitionInSpringContextTestBean extends TestBean {
2020

2121
private NoDefinitionInSpringContextTestBean() {
22-
throw new AssertionError(
23-
"Unexpected call to the default constructor."
24-
+ " Is Spring trying to instantiate this class by itself, even though it should delegate to the fallback producer?"
22+
throw new AssertionError("Unexpected call to the default constructor. " +
23+
"Is Spring trying to instantiate this class by itself, even though it should delegate to the fallback producer?"
2524
);
2625
}
2726

spring-orm/src/test/resources/org/springframework/orm/jpa/hibernate/hibernate-manager-native.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,6 @@
2828

2929
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
3030

31+
<bean id="invalid" class="javax.persistence.AttributeConverter" lazy-init="true"/>
32+
3133
</beans>

0 commit comments

Comments
 (0)