Skip to content

Commit d3a385d

Browse files
quaffjhoeller
authored andcommitted
Retain original requested bean class for SpringContainedBean
Closes GH-36115 Signed-off-by: Yanming Zhou <zhouyanming@gmail.com>
1 parent 38a3978 commit d3a385d

2 files changed

Lines changed: 42 additions & 19 deletions

File tree

spring-orm/src/main/java/org/springframework/orm/jpa/hibernate/SpringBeanContainer.java

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
* integration will be registered out of the box.
7070
*
7171
* @author Juergen Hoeller
72+
* @author Yanming Zhou
7273
* @since 7.0
7374
* @see LocalSessionFactoryBean#setBeanFactory
7475
* @see LocalSessionFactoryBuilder#setBeanContainer
@@ -139,17 +140,18 @@ public void stop() {
139140
}
140141

141142

142-
private SpringContainedBean<?> createBean(
143-
Class<?> beanType, LifecycleOptions lifecycleOptions, BeanInstanceProducer fallbackProducer) {
143+
private <B> SpringContainedBean<B> createBean(
144+
Class<B> beanType, LifecycleOptions lifecycleOptions, BeanInstanceProducer fallbackProducer) {
144145

145146
try {
146147
if (lifecycleOptions.useJpaCompliantCreation()) {
147148
return new SpringContainedBean<>(
149+
beanType,
148150
this.beanFactory.createBean(beanType),
149151
this.beanFactory::destroyBean);
150152
}
151153
else {
152-
return new SpringContainedBean<>(this.beanFactory.getBean(beanType));
154+
return new SpringContainedBean<>(beanType, this.beanFactory.getBean(beanType));
153155
}
154156
}
155157
catch (BeansException ex) {
@@ -158,7 +160,7 @@ private SpringContainedBean<?> createBean(
158160
beanType + ": " + ex);
159161
}
160162
try {
161-
return new SpringContainedBean<>(fallbackProducer.produceBeanInstance(beanType));
163+
return new SpringContainedBean<>(beanType, fallbackProducer.produceBeanInstance(beanType));
162164
}
163165
catch (RuntimeException ex2) {
164166
if (ex instanceof BeanCreationException) {
@@ -176,42 +178,44 @@ private SpringContainedBean<?> createBean(
176178
}
177179
}
178180

179-
private SpringContainedBean<?> createBean(
180-
String name, Class<?> beanType, LifecycleOptions lifecycleOptions, BeanInstanceProducer fallbackProducer) {
181+
@SuppressWarnings("unchecked")
182+
private <B> SpringContainedBean<B> createBean(
183+
String name, Class<B> beanType, LifecycleOptions lifecycleOptions, BeanInstanceProducer fallbackProducer) {
181184

182185
try {
183186
if (lifecycleOptions.useJpaCompliantCreation()) {
184-
Object bean = null;
187+
B bean = null;
185188
if (fallbackProducer instanceof TypeBootstrapContext) {
186189
// Special Hibernate type construction rules, including TypeBootstrapContext resolution.
187190
bean = fallbackProducer.produceBeanInstance(name, beanType);
188191
}
189192
if (this.beanFactory.containsBean(name)) {
190193
if (bean == null) {
191-
bean = this.beanFactory.autowire(beanType, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, false);
194+
bean = (B) this.beanFactory.autowire(beanType, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, false);
192195
}
193196
this.beanFactory.autowireBeanProperties(bean, AutowireCapableBeanFactory.AUTOWIRE_NO, false);
194197
this.beanFactory.applyBeanPropertyValues(bean, name);
195-
bean = this.beanFactory.initializeBean(bean, name);
196-
return new SpringContainedBean<>(bean, beanInstance -> this.beanFactory.destroyBean(name, beanInstance));
198+
bean = (B) this.beanFactory.initializeBean(bean, name);
199+
return new SpringContainedBean<>(beanType, bean, beanInstance -> this.beanFactory.destroyBean(name, beanInstance));
197200
}
198201
else if (bean != null) {
199202
// No bean found by name but constructed with TypeBootstrapContext rules
200203
this.beanFactory.autowireBeanProperties(bean, AutowireCapableBeanFactory.AUTOWIRE_NO, false);
201-
bean = this.beanFactory.initializeBean(bean, name);
202-
return new SpringContainedBean<>(bean, this.beanFactory::destroyBean);
204+
bean = (B) this.beanFactory.initializeBean(bean, name);
205+
return new SpringContainedBean<>(beanType, bean, this.beanFactory::destroyBean);
203206
}
204207
else {
205208
// No bean found by name -> construct by type using createBean
206209
return new SpringContainedBean<>(
210+
beanType,
207211
this.beanFactory.createBean(beanType),
208212
this.beanFactory::destroyBean);
209213
}
210214
}
211215
else {
212216
return (this.beanFactory.containsBean(name) ?
213-
new SpringContainedBean<>(this.beanFactory.getBean(name, beanType)) :
214-
new SpringContainedBean<>(this.beanFactory.getBean(beanType)));
217+
new SpringContainedBean<>(beanType, this.beanFactory.getBean(name, beanType)) :
218+
new SpringContainedBean<>(beanType, this.beanFactory.getBean(beanType)));
215219
}
216220
}
217221
catch (BeansException ex) {
@@ -220,7 +224,7 @@ else if (bean != null) {
220224
beanType + " with name '" + name + "': " + ex);
221225
}
222226
try {
223-
return new SpringContainedBean<>(fallbackProducer.produceBeanInstance(name, beanType));
227+
return new SpringContainedBean<>(beanType, fallbackProducer.produceBeanInstance(name, beanType));
224228
}
225229
catch (RuntimeException ex2) {
226230
if (ex instanceof BeanCreationException) {
@@ -241,15 +245,19 @@ else if (bean != null) {
241245

242246
private static final class SpringContainedBean<B> implements ContainedBean<B> {
243247

248+
private final Class<B> beanClass;
249+
244250
private final B beanInstance;
245251

246252
private @Nullable Consumer<B> destructionCallback;
247253

248-
public SpringContainedBean(B beanInstance) {
254+
public SpringContainedBean(Class<B> beanClass, B beanInstance) {
255+
this.beanClass = beanClass;
249256
this.beanInstance = beanInstance;
250257
}
251258

252-
public SpringContainedBean(B beanInstance, Consumer<B> destructionCallback) {
259+
public SpringContainedBean(Class<B> beanClass, B beanInstance, Consumer<B> destructionCallback) {
260+
this.beanClass = beanClass;
253261
this.beanInstance = beanInstance;
254262
this.destructionCallback = destructionCallback;
255263
}
@@ -260,9 +268,8 @@ public B getBeanInstance() {
260268
}
261269

262270
@Override
263-
@SuppressWarnings("unchecked")
264271
public Class<B> getBeanClass() {
265-
return (Class<B>) this.beanInstance.getClass();
272+
return this.beanClass;
266273
}
267274

268275
public void destroyIfNecessary() {

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import org.springframework.orm.jpa.hibernate.beans.MultiplePrototypesInSpringContextTestBean;
3434
import org.springframework.orm.jpa.hibernate.beans.NoDefinitionInSpringContextTestBean;
3535
import org.springframework.orm.jpa.hibernate.beans.SinglePrototypeInSpringContextTestBean;
36+
import org.springframework.orm.jpa.hibernate.beans.TestBean;
3637

3738
import static org.assertj.core.api.Assertions.assertThat;
3839
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@@ -42,6 +43,7 @@
4243
*
4344
* @author Yoann Rodiere
4445
* @author Juergen Hoeller
46+
* @author Yanming Zhou
4547
*/
4648
class HibernateNativeEntityManagerFactorySpringBeanContainerIntegrationTests
4749
extends AbstractEntityManagerFactoryIntegrationTests {
@@ -275,6 +277,20 @@ void testOriginalExceptionInCaseOfFallbackProducerFailureByName() {
275277
));
276278
}
277279

280+
@Test
281+
void testRetrieveBeanShouldRetainOriginalBeanType() {
282+
BeanContainer beanContainer = getBeanContainer();
283+
assertThat(beanContainer).isNotNull();
284+
285+
ContainedBean<TestBean> bean = beanContainer.getBean(
286+
"single", TestBean.class,
287+
NativeLifecycleOptions.INSTANCE, IneffectiveBeanInstanceProducer.INSTANCE
288+
);
289+
290+
assertThat(bean).isNotNull();
291+
assertThat(bean.getBeanClass()).isSameAs(TestBean.class);
292+
}
293+
278294

279295
/**
280296
* The lifecycle options mandated by the JPA spec and used as a default in Hibernate ORM.

0 commit comments

Comments
 (0)