Skip to content

Commit 9571064

Browse files
committed
Pass pre-determined merged bean definition into InstanceSupplier (for inner beans)
Replaces useless protected obtainFromSupplier method with obtainInstanceFromSupplier. Moves InstanceSupplier handling to appropriate subclass (DefaultListableBeanFactory). BeanInstanceSupplier throws BeanInstantiationException instead of BeanCreationException. Closes gh-29803
1 parent 6cd6741 commit 9571064

File tree

6 files changed

+151
-117
lines changed

6 files changed

+151
-117
lines changed

spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanInstanceSupplier.java

Lines changed: 38 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@
2727
import java.util.stream.Collectors;
2828

2929
import org.springframework.aot.hint.ExecutableMode;
30+
import org.springframework.beans.BeanInstantiationException;
3031
import org.springframework.beans.BeansException;
3132
import org.springframework.beans.TypeConverter;
32-
import org.springframework.beans.factory.BeanCreationException;
3333
import org.springframework.beans.factory.BeanFactory;
3434
import org.springframework.beans.factory.InjectionPoint;
3535
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
@@ -97,21 +97,21 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
9797
private BeanInstanceSupplier(ExecutableLookup lookup,
9898
@Nullable ThrowingBiFunction<RegisteredBean, AutowiredArguments, T> generator,
9999
@Nullable String[] shortcuts) {
100+
100101
this.lookup = lookup;
101102
this.generator = generator;
102103
this.shortcuts = shortcuts;
103104
}
104105

106+
105107
/**
106108
* Create a {@link BeanInstanceSupplier} that resolves
107109
* arguments for the specified bean constructor.
108110
* @param <T> the type of instance supplied
109111
* @param parameterTypes the constructor parameter types
110112
* @return a new {@link BeanInstanceSupplier} instance
111113
*/
112-
public static <T> BeanInstanceSupplier<T> forConstructor(
113-
Class<?>... parameterTypes) {
114-
114+
public static <T> BeanInstanceSupplier<T> forConstructor(Class<?>... parameterTypes) {
115115
Assert.notNull(parameterTypes, "'parameterTypes' must not be null");
116116
Assert.noNullElements(parameterTypes, "'parameterTypes' must not contain null elements");
117117
return new BeanInstanceSupplier<>(new ConstructorLookup(parameterTypes), null, null);
@@ -149,11 +149,11 @@ ExecutableLookup getLookup() {
149149
* @param generator a {@link ThrowingBiFunction} that uses the
150150
* {@link RegisteredBean} and resolved {@link AutowiredArguments} to
151151
* instantiate the underlying bean
152-
* @return a new {@link BeanInstanceSupplier} instance with the specified
153-
* generator
152+
* @return a new {@link BeanInstanceSupplier} instance with the specified generator
154153
*/
155154
public BeanInstanceSupplier<T> withGenerator(
156155
ThrowingBiFunction<RegisteredBean, AutowiredArguments, T> generator) {
156+
157157
Assert.notNull(generator, "'generator' must not be null");
158158
return new BeanInstanceSupplier<>(this.lookup, generator, this.shortcuts);
159159
}
@@ -163,11 +163,9 @@ public BeanInstanceSupplier<T> withGenerator(
163163
* {@code generator} function to instantiate the underlying bean.
164164
* @param generator a {@link ThrowingFunction} that uses the
165165
* {@link RegisteredBean} to instantiate the underlying bean
166-
* @return a new {@link BeanInstanceSupplier} instance with the specified
167-
* generator
166+
* @return a new {@link BeanInstanceSupplier} instance with the specified generator
168167
*/
169-
public BeanInstanceSupplier<T> withGenerator(
170-
ThrowingFunction<RegisteredBean, T> generator) {
168+
public BeanInstanceSupplier<T> withGenerator(ThrowingFunction<RegisteredBean, T> generator) {
171169
Assert.notNull(generator, "'generator' must not be null");
172170
return new BeanInstanceSupplier<>(this.lookup,
173171
(registeredBean, args) -> generator.apply(registeredBean), this.shortcuts);
@@ -176,10 +174,8 @@ public BeanInstanceSupplier<T> withGenerator(
176174
/**
177175
* Return a new {@link BeanInstanceSupplier} instance that uses the specified
178176
* {@code generator} supplier to instantiate the underlying bean.
179-
* @param generator a {@link ThrowingSupplier} to instantiate the underlying
180-
* bean
181-
* @return a new {@link BeanInstanceSupplier} instance with the specified
182-
* generator
177+
* @param generator a {@link ThrowingSupplier} to instantiate the underlying bean
178+
* @return a new {@link BeanInstanceSupplier} instance with the specified generator
183179
*/
184180
public BeanInstanceSupplier<T> withGenerator(ThrowingSupplier<T> generator) {
185181
Assert.notNull(generator, "'generator' must not be null");
@@ -282,8 +278,7 @@ private MethodParameter getMethodParameter(Executable executable, int index) {
282278
if (executable instanceof Method method) {
283279
return new MethodParameter(method, index);
284280
}
285-
throw new IllegalStateException(
286-
"Unsupported executable " + executable.getClass().getName());
281+
throw new IllegalStateException("Unsupported executable: " + executable.getClass().getName());
287282
}
288283

289284
private ConstructorArgumentValues resolveArgumentValues(
@@ -303,9 +298,7 @@ private ConstructorArgumentValues resolveArgumentValues(
303298
return resolved;
304299
}
305300

306-
private ValueHolder resolveArgumentValue(BeanDefinitionValueResolver resolver,
307-
ValueHolder valueHolder) {
308-
301+
private ValueHolder resolveArgumentValue(BeanDefinitionValueResolver resolver, ValueHolder valueHolder) {
309302
if (valueHolder.isConverted()) {
310303
return valueHolder;
311304
}
@@ -331,8 +324,7 @@ private Object resolveArgument(AbstractAutowireCapableBeanFactory beanFactory,
331324
}
332325
try {
333326
try {
334-
return beanFactory.resolveDependency(dependencyDescriptor, beanName,
335-
autowiredBeans, typeConverter);
327+
return beanFactory.resolveDependency(dependencyDescriptor, beanName, autowiredBeans, typeConverter);
336328
}
337329
catch (NoSuchBeanDefinitionException ex) {
338330
if (parameterType.isArray()) {
@@ -348,47 +340,45 @@ private Object resolveArgument(AbstractAutowireCapableBeanFactory beanFactory,
348340
}
349341
}
350342
catch (BeansException ex) {
351-
throw new UnsatisfiedDependencyException(null, beanName,
352-
new InjectionPoint(parameter), ex);
343+
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(parameter), ex);
353344
}
354345
}
355346

356347
@SuppressWarnings("unchecked")
357-
private T instantiate(ConfigurableBeanFactory beanFactory, Executable executable,
358-
Object[] arguments) {
359-
360-
try {
361-
if (executable instanceof Constructor<?> constructor) {
362-
return (T) instantiate(constructor, arguments);
348+
private T instantiate(ConfigurableBeanFactory beanFactory, Executable executable, Object[] args) {
349+
if (executable instanceof Constructor<?> constructor) {
350+
try {
351+
return (T) instantiate(constructor, args);
363352
}
364-
if (executable instanceof Method method) {
365-
return (T) instantiate(beanFactory, method, arguments);
353+
catch (Exception ex) {
354+
throw new BeanInstantiationException(constructor, ex.getMessage(), ex);
366355
}
367356
}
368-
catch (Exception ex) {
369-
throw new BeanCreationException(
370-
"Unable to instantiate bean using " + executable, ex);
357+
if (executable instanceof Method method) {
358+
try {
359+
return (T) instantiate(beanFactory, method, args);
360+
}
361+
catch (Exception ex) {
362+
throw new BeanInstantiationException(method, ex.getMessage(), ex);
363+
}
371364
}
372-
throw new IllegalStateException(
373-
"Unsupported executable " + executable.getClass().getName());
365+
throw new IllegalStateException("Unsupported executable " + executable.getClass().getName());
374366
}
375367

376-
private Object instantiate(Constructor<?> constructor, Object[] arguments) throws Exception {
368+
private Object instantiate(Constructor<?> constructor, Object[] args) throws Exception {
377369
Class<?> declaringClass = constructor.getDeclaringClass();
378370
if (ClassUtils.isInnerClass(declaringClass)) {
379371
Object enclosingInstance = createInstance(declaringClass.getEnclosingClass());
380-
arguments = ObjectUtils.addObjectToArray(arguments, enclosingInstance, 0);
372+
args = ObjectUtils.addObjectToArray(args, enclosingInstance, 0);
381373
}
382374
ReflectionUtils.makeAccessible(constructor);
383-
return constructor.newInstance(arguments);
375+
return constructor.newInstance(args);
384376
}
385377

386-
private Object instantiate(ConfigurableBeanFactory beanFactory, Method method,
387-
Object[] arguments) {
388-
389-
ReflectionUtils.makeAccessible(method);
378+
private Object instantiate(ConfigurableBeanFactory beanFactory, Method method, Object[] args) throws Exception {
390379
Object target = getFactoryMethodTarget(beanFactory, method);
391-
return ReflectionUtils.invokeMethod(method, target, arguments);
380+
ReflectionUtils.makeAccessible(method);
381+
return method.invoke(target, args);
392382
}
393383

394384
@Nullable
@@ -416,13 +406,13 @@ private static String toCommaSeparatedNames(Class<?>... parameterTypes) {
416406
return Arrays.stream(parameterTypes).map(Class::getName).collect(Collectors.joining(", "));
417407
}
418408

409+
419410
/**
420411
* Performs lookup of the {@link Executable}.
421412
*/
422413
static abstract class ExecutableLookup {
423414

424415
abstract Executable get(RegisteredBean registeredBean);
425-
426416
}
427417

428418

@@ -433,12 +423,10 @@ private static class ConstructorLookup extends ExecutableLookup {
433423

434424
private final Class<?>[] parameterTypes;
435425

436-
437426
ConstructorLookup(Class<?>[] parameterTypes) {
438427
this.parameterTypes = parameterTypes;
439428
}
440429

441-
442430
@Override
443431
public Executable get(RegisteredBean registeredBean) {
444432
Class<?> beanClass = registeredBean.getBeanClass();
@@ -456,10 +444,8 @@ public Executable get(RegisteredBean registeredBean) {
456444

457445
@Override
458446
public String toString() {
459-
return "Constructor with parameter types [%s]".formatted(
460-
toCommaSeparatedNames(this.parameterTypes));
447+
return "Constructor with parameter types [%s]".formatted(toCommaSeparatedNames(this.parameterTypes));
461448
}
462-
463449
}
464450

465451

@@ -474,23 +460,19 @@ private static class FactoryMethodLookup extends ExecutableLookup {
474460

475461
private final Class<?>[] parameterTypes;
476462

477-
478-
FactoryMethodLookup(Class<?> declaringClass, String methodName,
479-
Class<?>[] parameterTypes) {
463+
FactoryMethodLookup(Class<?> declaringClass, String methodName, Class<?>[] parameterTypes) {
480464
this.declaringClass = declaringClass;
481465
this.methodName = methodName;
482466
this.parameterTypes = parameterTypes;
483467
}
484468

485-
486469
@Override
487470
public Executable get(RegisteredBean registeredBean) {
488471
return get();
489472
}
490473

491474
Method get() {
492-
Method method = ReflectionUtils.findMethod(this.declaringClass,
493-
this.methodName, this.parameterTypes);
475+
Method method = ReflectionUtils.findMethod(this.declaringClass, this.methodName, this.parameterTypes);
494476
Assert.notNull(method, () -> "%s cannot be found".formatted(this));
495477
return method;
496478
}
@@ -501,7 +483,6 @@ public String toString() {
501483
this.methodName, toCommaSeparatedNames(this.parameterTypes),
502484
this.declaringClass);
503485
}
504-
505486
}
506487

507488
}

spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@
6161
import org.springframework.beans.factory.config.BeanDefinition;
6262
import org.springframework.beans.factory.config.BeanPostProcessor;
6363
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
64-
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
6564
import org.springframework.beans.factory.config.ConstructorArgumentValues;
6665
import org.springframework.beans.factory.config.DependencyDescriptor;
6766
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
@@ -1154,7 +1153,7 @@ protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd
11541153

11551154
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
11561155
if (instanceSupplier != null) {
1157-
return obtainFromSupplier(instanceSupplier, beanName);
1156+
return obtainFromSupplier(instanceSupplier, beanName, mbd);
11581157
}
11591158

11601159
if (mbd.getFactoryMethodName() != null) {
@@ -1203,38 +1202,20 @@ protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd
12031202
* @param supplier the configured supplier
12041203
* @param beanName the corresponding bean name
12051204
* @return a BeanWrapper for the new instance
1206-
* @since 5.0
1207-
* @see #getObjectForBeanInstance
12081205
*/
1209-
protected BeanWrapper obtainFromSupplier(Supplier<?> supplier, String beanName) {
1210-
Object instance = obtainInstanceFromSupplier(supplier, beanName);
1211-
if (instance == null) {
1212-
instance = new NullBean();
1213-
}
1214-
BeanWrapper bw = new BeanWrapperImpl(instance);
1215-
initBeanWrapper(bw);
1216-
return bw;
1217-
}
1218-
1219-
@Nullable
1220-
private Object obtainInstanceFromSupplier(Supplier<?> supplier, String beanName) {
1206+
private BeanWrapper obtainFromSupplier(Supplier<?> supplier, String beanName, RootBeanDefinition mbd) {
12211207
String outerBean = this.currentlyCreatedBean.get();
12221208
this.currentlyCreatedBean.set(beanName);
1209+
Object instance;
1210+
12231211
try {
1224-
if (supplier instanceof InstanceSupplier<?> instanceSupplier) {
1225-
return instanceSupplier.get(RegisteredBean.of((ConfigurableListableBeanFactory) this, beanName));
1226-
}
1227-
if (supplier instanceof ThrowingSupplier<?> throwingSupplier) {
1228-
return throwingSupplier.getWithException();
1229-
}
1230-
return supplier.get();
1212+
instance = obtainInstanceFromSupplier(supplier, beanName, mbd);
12311213
}
12321214
catch (Throwable ex) {
12331215
if (ex instanceof BeansException beansException) {
12341216
throw beansException;
12351217
}
1236-
throw new BeanCreationException(beanName,
1237-
"Instantiation of supplied bean failed", ex);
1218+
throw new BeanCreationException(beanName, "Instantiation of supplied bean failed", ex);
12381219
}
12391220
finally {
12401221
if (outerBean != null) {
@@ -1244,6 +1225,31 @@ private Object obtainInstanceFromSupplier(Supplier<?> supplier, String beanName)
12441225
this.currentlyCreatedBean.remove();
12451226
}
12461227
}
1228+
1229+
if (instance == null) {
1230+
instance = new NullBean();
1231+
}
1232+
BeanWrapper bw = new BeanWrapperImpl(instance);
1233+
initBeanWrapper(bw);
1234+
return bw;
1235+
}
1236+
1237+
/**
1238+
* Obtain a bean instance from the given supplier.
1239+
* @param supplier the configured supplier
1240+
* @param beanName the corresponding bean name
1241+
* @param mbd the bean definition for the bean
1242+
* @return the bean instance (possibly {@code null})
1243+
* @since 6.0.7
1244+
*/
1245+
@Nullable
1246+
protected Object obtainInstanceFromSupplier(Supplier<?> supplier, String beanName, RootBeanDefinition mbd)
1247+
throws Exception {
1248+
1249+
if (supplier instanceof ThrowingSupplier<?> throwingSupplier) {
1250+
return throwingSupplier.getWithException();
1251+
}
1252+
return supplier.get();
12471253
}
12481254

12491255
/**

spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -40,6 +40,7 @@
4040
import java.util.concurrent.ConcurrentHashMap;
4141
import java.util.function.Consumer;
4242
import java.util.function.Predicate;
43+
import java.util.function.Supplier;
4344
import java.util.stream.Stream;
4445

4546
import jakarta.inject.Provider;
@@ -937,6 +938,17 @@ protected boolean isBeanEligibleForMetadataCaching(String beanName) {
937938
return (this.configurationFrozen || super.isBeanEligibleForMetadataCaching(beanName));
938939
}
939940

941+
@Override
942+
@Nullable
943+
protected Object obtainInstanceFromSupplier(Supplier<?> supplier, String beanName, RootBeanDefinition mbd)
944+
throws Exception {
945+
946+
if (supplier instanceof InstanceSupplier<?> instanceSupplier) {
947+
return instanceSupplier.get(RegisteredBean.of(this, beanName, mbd));
948+
}
949+
return super.obtainInstanceFromSupplier(supplier, beanName, mbd);
950+
}
951+
940952
@Override
941953
public void preInstantiateSingletons() throws BeansException {
942954
if (logger.isTraceEnabled()) {

0 commit comments

Comments
 (0)