diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/aot/AutowiredArguments.java b/spring-beans/src/main/java/org/springframework/beans/factory/aot/AutowiredArguments.java
index 14178b512d9..f4c09064791 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/aot/AutowiredArguments.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/aot/AutowiredArguments.java
@@ -26,7 +26,7 @@ import org.springframework.util.ClassUtils;
* @author Phillip Webb
* @author Stephane Nicoll
* @since 6.0
- * @see AutowiredInstantiationArgumentsResolver
+ * @see BeanInstanceSupplier
* @see AutowiredMethodArgumentsResolver
*/
@FunctionalInterface
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/aot/AutowiredMethodArgumentsResolver.java b/spring-beans/src/main/java/org/springframework/beans/factory/aot/AutowiredMethodArgumentsResolver.java
index 681297eb347..dea4d192267 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/aot/AutowiredMethodArgumentsResolver.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/aot/AutowiredMethodArgumentsResolver.java
@@ -105,7 +105,7 @@ public final class AutowiredMethodArgumentsResolver extends AutowiredElementReso
}
/**
- * Return a new {@link AutowiredInstantiationArgumentsResolver} instance
+ * Return a new {@link AutowiredMethodArgumentsResolver} instance
* that uses direct bean name injection shortcuts for specific parameters.
* @param beanNames the bean names to use as shortcuts (aligned with the
* method parameters)
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/aot/AutowiredInstantiationArgumentsResolver.java b/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanInstanceSupplier.java
similarity index 74%
rename from spring-beans/src/main/java/org/springframework/beans/factory/aot/AutowiredInstantiationArgumentsResolver.java
rename to spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanInstanceSupplier.java
index cc8be0706a3..64bfcdab397 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/aot/AutowiredInstantiationArgumentsResolver.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanInstanceSupplier.java
@@ -40,6 +40,7 @@ import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueH
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionValueResolver;
+import org.springframework.beans.factory.support.InstanceSupplier;
import org.springframework.beans.factory.support.RegisteredBean;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.core.CollectionFactory;
@@ -49,67 +50,81 @@ import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
+import org.springframework.util.function.ThrowingBiFunction;
import org.springframework.util.function.ThrowingFunction;
+import org.springframework.util.function.ThrowingSupplier;
/**
- * Resolver used to support the autowiring of constructors or factory methods.
- * Typically used in AOT-processed applications as a targeted alternative to the
- * reflection based injection.
+ * Specialized {@link InstanceSupplier} that provides the factory {@link Method}
+ * used to instantiate the underlying bean instance, if any. Transparently
+ * handles resolution of {@link AutowiredArguments} if necessary. Typically used
+ * in AOT-processed applications as a targeted alternative to the reflection
+ * based injection.
*
- * When resolving arguments in a native image, the {@link Constructor} or
- * {@link Method} being used must be marked with an
- * {@link ExecutableMode#INTROSPECT introspection} hint so that parameter
- * annotations can be read. Full {@link ExecutableMode#INVOKE invocation} hints
- * are only required if the {@code resolveAndInstantiate} methods of this class
- * are being used (typically to support private constructors, methods or
- * classes).
+ * If no {@code generator} is provided, reflection is used to instantiate the
+ * bean instance, and full {@link ExecutableMode#INVOKE invocation} hints are
+ * contributed. Multiple generator callback styles are supported:
+ *
+ * A function with the {@code registeredBean} and resolved {@code arguments}
+ * for executables that require arguments resolution. An
+ * {@link ExecutableMode#INTROSPECT introspection} hint is added so that
+ * parameter annotations can be read
+ * A function with only the {@code registeredBean} for simpler cases that
+ * do not require resolution of arguments
+ * A supplier when a method reference can be used
+ *
+ * Generator callbacks handle checked exceptions so that the caller does not
+ * have to deal with it.
*
* @author Phillip Webb
* @author Stephane Nicoll
* @since 6.0
* @see AutowiredArguments
*/
-public final class AutowiredInstantiationArgumentsResolver extends AutowiredElementResolver {
+public final class BeanInstanceSupplier extends AutowiredElementResolver implements InstanceSupplier {
private final ExecutableLookup lookup;
+ @Nullable
+ private final ThrowingBiFunction generator;
+
@Nullable
private final String[] shortcuts;
- private AutowiredInstantiationArgumentsResolver(ExecutableLookup lookup,
+ private BeanInstanceSupplier(ExecutableLookup lookup,
+ @Nullable ThrowingBiFunction generator,
@Nullable String[] shortcuts) {
-
this.lookup = lookup;
+ this.generator = generator;
this.shortcuts = shortcuts;
}
-
/**
- * Create a {@link AutowiredInstantiationArgumentsResolver} that resolves
+ * Create a {@link BeanInstanceSupplier} that resolves
* arguments for the specified bean constructor.
* @param parameterTypes the constructor parameter types
- * @return a new {@link AutowiredInstantiationArgumentsResolver} instance
+ * @return a new {@link BeanInstanceSupplier} instance
*/
- public static AutowiredInstantiationArgumentsResolver forConstructor(
+ public static BeanInstanceSupplier forConstructor(
Class>... parameterTypes) {
Assert.notNull(parameterTypes, "'parameterTypes' must not be null");
Assert.noNullElements(parameterTypes,
"'parameterTypes' must not contain null elements");
- return new AutowiredInstantiationArgumentsResolver(
- new ConstructorLookup(parameterTypes), null);
+ return new BeanInstanceSupplier(
+ new ConstructorLookup(parameterTypes), null, null);
}
/**
- * Create a new {@link AutowiredInstantiationArgumentsResolver} that
+ * Create a new {@link BeanInstanceSupplier} that
* resolves arguments for the specified factory method.
* @param declaringClass the class that declares the factory method
* @param methodName the factory method name
* @param parameterTypes the factory method parameter types
- * @return a new {@link AutowiredInstantiationArgumentsResolver} instance
+ * @return a new {@link BeanInstanceSupplier} instance
*/
- public static AutowiredInstantiationArgumentsResolver forFactoryMethod(
+ public static BeanInstanceSupplier forFactoryMethod(
Class> declaringClass, String methodName, Class>... parameterTypes) {
Assert.notNull(declaringClass, "'declaringClass' must not be null");
@@ -117,9 +132,9 @@ public final class AutowiredInstantiationArgumentsResolver extends AutowiredElem
Assert.notNull(parameterTypes, "'parameterTypes' must not be null");
Assert.noNullElements(parameterTypes,
"'parameterTypes' must not contain null elements");
- return new AutowiredInstantiationArgumentsResolver(
+ return new BeanInstanceSupplier(
new FactoryMethodLookup(declaringClass, methodName, parameterTypes),
- null);
+ null, null);
}
@@ -128,74 +143,92 @@ public final class AutowiredInstantiationArgumentsResolver extends AutowiredElem
}
/**
- * Return a new {@link AutowiredInstantiationArgumentsResolver} instance
- * that uses direct bean name injection shortcuts for specific parameters.
- * @param beanNames the bean names to use as shortcuts (aligned with the
- * constructor or factory method parameters)
- * @return a new {@link AutowiredInstantiationArgumentsResolver} instance
- * that uses the shortcuts
+ * Return a new {@link BeanInstanceSupplier} instance that uses the specified
+ * {@code generator} bi-function to instantiate the underlying bean.
+ * @param generator a {@link ThrowingBiFunction} that uses the
+ * {@link RegisteredBean} and resolved {@link AutowiredArguments} to
+ * instantiate the underlying bean
+ * @return a new {@link BeanInstanceSupplier} instance with the specified
+ * generator
*/
- public AutowiredInstantiationArgumentsResolver withShortcuts(String... beanNames) {
- return new AutowiredInstantiationArgumentsResolver(this.lookup, beanNames);
+ public BeanInstanceSupplier withGenerator(
+ ThrowingBiFunction generator) {
+ Assert.notNull(generator, "'generator' must not be null");
+ return new BeanInstanceSupplier(this.lookup, generator, this.shortcuts);
}
/**
- * Resolve arguments for the specified registered bean and provide them to
- * the given generator in order to return a result.
- * @param registeredBean the registered bean
- * @param generator the generator to execute with the resolved constructor
- * or factory method arguments
+ * Return a new {@link BeanInstanceSupplier} instance that uses the specified
+ * {@code generator} function to instantiate the underlying bean.
+ * @param generator a {@link ThrowingFunction} that uses the
+ * {@link RegisteredBean} to instantiate the underlying bean
+ * @return a new {@link BeanInstanceSupplier} instance with the specified
+ * generator
*/
- public T resolve(RegisteredBean registeredBean,
- ThrowingFunction generator) {
-
- Assert.notNull(registeredBean, "'registeredBean' must not be null");
- Assert.notNull(generator, "'action' must not be null");
- AutowiredArguments resolved = resolveArguments(registeredBean,
- this.lookup.get(registeredBean));
- return generator.apply(resolved);
+ public BeanInstanceSupplier withGenerator(
+ ThrowingFunction generator) {
+ Assert.notNull(generator, "'generator' must not be null");
+ return new BeanInstanceSupplier(this.lookup, (registeredBean, args) ->
+ generator.apply(registeredBean), this.shortcuts);
}
/**
- * Resolve arguments for the specified registered bean.
- * @param registeredBean the registered bean
- * @return the resolved constructor or factory method arguments
+ * Return a new {@link BeanInstanceSupplier} instance that uses the specified
+ * {@code generator} supplier to instantiate the underlying bean.
+ * @param generator a {@link ThrowingSupplier} to instantiate the underlying
+ * bean
+ * @return a new {@link BeanInstanceSupplier} instance with the specified
+ * generator
*/
- public AutowiredArguments resolve(RegisteredBean registeredBean) {
- Assert.notNull(registeredBean, "'registeredBean' must not be null");
- return resolveArguments(registeredBean, this.lookup.get(registeredBean));
+ public BeanInstanceSupplier withGenerator(ThrowingSupplier generator) {
+ Assert.notNull(generator, "'generator' must not be null");
+ return new BeanInstanceSupplier(this.lookup, (registeredBean, args) ->
+ generator.get(), this.shortcuts);
}
/**
- * Resolve arguments for the specified registered bean and instantiate a new
- * instance using reflection.
- * @param registeredBean the registered bean
- * @return an instance of the bean
+ * Return a new {@link BeanInstanceSupplier} instance
+ * that uses direct bean name injection shortcuts for specific parameters.
+ * @param beanNames the bean names to use as shortcuts (aligned with the
+ * constructor or factory method parameters)
+ * @return a new {@link BeanInstanceSupplier} instance
+ * that uses the shortcuts
*/
- @SuppressWarnings("unchecked")
- public T resolveAndInstantiate(RegisteredBean registeredBean) {
- return (T) resolveAndInstantiate(registeredBean, Object.class);
+ public BeanInstanceSupplier withShortcuts(String... beanNames) {
+ return new BeanInstanceSupplier(this.lookup, this.generator, beanNames);
+ }
+
+ @Override
+ public Object get(RegisteredBean registeredBean) throws Exception {
+ Assert.notNull(registeredBean, "'registeredBean' must not be null");
+ Executable executable = this.lookup.get(registeredBean);
+ AutowiredArguments arguments = resolveArguments(registeredBean, executable);
+ if (this.generator != null) {
+ return this.generator.apply(registeredBean, arguments);
+ }
+ else {
+ return instantiate(registeredBean.getBeanFactory(), executable,
+ arguments.toArray());
+ }
+ }
+
+ @Nullable
+ @Override
+ public Method getFactoryMethod() {
+ if (this.lookup instanceof FactoryMethodLookup factoryMethodLookup) {
+ return factoryMethodLookup.get();
+ }
+ return null;
}
/**
- * Resolve arguments for the specified registered bean and instantiate a new
- * instance using reflection.
+ * Resolve arguments for the specified registered bean.
* @param registeredBean the registered bean
- * @param requiredType the required result type
- * @return an instance of the bean
+ * @return the resolved constructor or factory method arguments
*/
- @SuppressWarnings("unchecked")
- public T resolveAndInstantiate(RegisteredBean registeredBean,
- Class requiredType) {
-
+ AutowiredArguments resolveArguments(RegisteredBean registeredBean) {
Assert.notNull(registeredBean, "'registeredBean' must not be null");
- Assert.notNull(registeredBean, "'requiredType' must not be null");
- Executable executable = this.lookup.get(registeredBean);
- AutowiredArguments arguments = resolveArguments(registeredBean, executable);
- Object instance = instantiate(registeredBean.getBeanFactory(), executable,
- arguments.toArray());
- Assert.isInstanceOf(requiredType, instance);
- return (T) instance;
+ return resolveArguments(registeredBean, this.lookup.get(registeredBean));
}
private AutowiredArguments resolveArguments(RegisteredBean registeredBean,
@@ -233,9 +266,6 @@ public final class AutowiredInstantiationArgumentsResolver extends AutowiredElem
autowiredBeans, parameter, dependencyDescriptor, argumentValue);
}
registerDependentBeans(beanFactory, beanName, autowiredBeans);
- if (executable instanceof Method method) {
- mergedBeanDefinition.setResolvedFactoryMethod(method);
- }
return AutowiredArguments.of(resolved);
}
@@ -403,10 +433,12 @@ public final class AutowiredInstantiationArgumentsResolver extends AutowiredElem
private final Class>[] parameterTypes;
+
ConstructorLookup(Class>[] parameterTypes) {
this.parameterTypes = parameterTypes;
}
+
@Override
public Executable get(RegisteredBean registeredBean) {
Class> beanClass = registeredBean.getBeanClass();
@@ -453,6 +485,10 @@ public final class AutowiredInstantiationArgumentsResolver extends AutowiredElem
@Override
public Executable get(RegisteredBean registeredBean) {
+ return get();
+ }
+
+ Method get() {
Method method = ReflectionUtils.findMethod(this.declaringClass,
this.methodName, this.parameterTypes);
Assert.notNull(method, () -> String.format("%s cannot be found", this));
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/aot/InstanceSupplierCodeGenerator.java b/spring-beans/src/main/java/org/springframework/beans/factory/aot/InstanceSupplierCodeGenerator.java
index 8ec4ad93e86..d54644ac1ad 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/aot/InstanceSupplierCodeGenerator.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/aot/InstanceSupplierCodeGenerator.java
@@ -35,17 +35,22 @@ import org.springframework.beans.factory.support.RegisteredBean;
import org.springframework.core.ResolvableType;
import org.springframework.javapoet.ClassName;
import org.springframework.javapoet.CodeBlock;
+import org.springframework.javapoet.CodeBlock.Builder;
import org.springframework.javapoet.MethodSpec;
-import org.springframework.javapoet.MethodSpec.Builder;
import org.springframework.util.ClassUtils;
import org.springframework.util.function.ThrowingSupplier;
/**
- * Internal code generator to create an {@link InstanceSupplier}.
+ * Internal code generator to create an {@link InstanceSupplier}, usually in
+ * the form of a {@link BeanInstanceSupplier} that retains the executable
+ * that is used to instantiate the bean.
*
- * Generates code in the form:
{@code
- * InstanceSupplier.of(TheGeneratedClass::getMyBeanInstance);
- * }
+ * Generated code is usually a method reference that generate the
+ * {@link BeanInstanceSupplier}, but some shortcut can be used as well such
+ * as:
+ *
+ * {@code InstanceSupplier.of(TheGeneratedClass::getMyBeanInstance);}
+ *
*
* @author Phillip Webb
* @author Stephane Nicoll
@@ -55,6 +60,8 @@ class InstanceSupplierCodeGenerator {
private static final String REGISTERED_BEAN_PARAMETER_NAME = "registeredBean";
+ private static final String ARGS_PARAMETER_NAME = "args";
+
private static final javax.lang.model.element.Modifier[] PRIVATE_STATIC = {
javax.lang.model.element.Modifier.PRIVATE,
javax.lang.model.element.Modifier.STATIC };
@@ -109,15 +116,14 @@ class InstanceSupplierCodeGenerator {
constructor);
if (accessVisibility == AccessVisibility.PUBLIC
|| accessVisibility == AccessVisibility.PACKAGE_PRIVATE) {
- return generateCodeForAccessibleConstructor(name, constructor, declaringClass,
- dependsOnBean);
+ return generateCodeForAccessibleConstructor(name, constructor, dependsOnBean,
+ declaringClass);
}
- return generateCodeForInaccessibleConstructor(name, constructor, declaringClass,
- dependsOnBean);
+ return generateCodeForInaccessibleConstructor(name, constructor, dependsOnBean);
}
private CodeBlock generateCodeForAccessibleConstructor(String name,
- Constructor> constructor, Class> declaringClass, boolean dependsOnBean) {
+ Constructor> constructor, boolean dependsOnBean, Class> declaringClass) {
this.generationContext.getRuntimeHints().reflection()
.registerConstructor(constructor, INTROSPECT);
@@ -132,60 +138,47 @@ class InstanceSupplierCodeGenerator {
return CodeBlock.of("$T.of($T::new)", ThrowingSupplier.class,
declaringClass);
}
- GeneratedMethod generatedMethod = generateGetInstanceMethod(method ->
- buildGetInstanceMethodForConstructor(method, name, constructor, declaringClass,
- dependsOnBean, PRIVATE_STATIC));
- return CodeBlock.of("$T.of($T::$L)", InstanceSupplier.class, this.className,
- generatedMethod.getName());
+ GeneratedMethod generatedMethod = generateGetInstanceSupplierMethod(method ->
+ buildGetInstanceMethodForConstructor(method, name, constructor,
+ declaringClass, dependsOnBean, PRIVATE_STATIC));
+ return generateReturnStatement(generatedMethod);
}
private CodeBlock generateCodeForInaccessibleConstructor(String name,
- Constructor> constructor, Class> declaringClass, boolean dependsOnBean) {
+ Constructor> constructor, boolean dependsOnBean) {
this.generationContext.getRuntimeHints().reflection()
.registerConstructor(constructor);
- GeneratedMethod generatedMethod = generateGetInstanceMethod(method -> {
- method.addJavadoc("Instantiate the bean instance for '$L'.", name);
+ GeneratedMethod generatedMethod = generateGetInstanceSupplierMethod(method -> {
+ method.addJavadoc("Get the bean instance supplier for '$L'.", name);
method.addModifiers(PRIVATE_STATIC);
- method.returns(declaringClass);
- method.addParameter(RegisteredBean.class, REGISTERED_BEAN_PARAMETER_NAME);
+ method.returns(BeanInstanceSupplier.class);
int parameterOffset = (!dependsOnBean) ? 0 : 1;
method.addStatement(
generateResolverForConstructor(constructor, parameterOffset));
- method.addStatement("return resolver.resolveAndInstantiate($L)",
- REGISTERED_BEAN_PARAMETER_NAME);
});
- return CodeBlock.of("$T.of($T::$L)", InstanceSupplier.class, this.className,
- generatedMethod.getName());
+ return generateReturnStatement(generatedMethod);
}
private void buildGetInstanceMethodForConstructor(MethodSpec.Builder method,
String name, Constructor> constructor, Class> declaringClass,
boolean dependsOnBean, javax.lang.model.element.Modifier... modifiers) {
- method.addJavadoc("Create the bean instance for '$L'.", name);
+ method.addJavadoc("Get the bean instance supplier for '$L'.", name);
method.addModifiers(modifiers);
- method.returns(declaringClass);
- method.addParameter(RegisteredBean.class, REGISTERED_BEAN_PARAMETER_NAME);
- if (constructor.getParameterCount() == 0) {
- CodeBlock instantiationCode = generateNewInstanceCodeForConstructor(
- dependsOnBean, declaringClass, NO_ARGS);
- method.addCode(generateReturnStatement(instantiationCode));
- }
- else {
- int parameterOffset = (!dependsOnBean) ? 0 : 1;
- CodeBlock.Builder code = CodeBlock.builder();
- code.addStatement(
- generateResolverForConstructor(constructor, parameterOffset));
- CodeBlock arguments = new AutowiredArgumentsCodeGenerator(declaringClass,
- constructor).generateCode(constructor.getParameterTypes(),
- parameterOffset);
- CodeBlock newInstance = generateNewInstanceCodeForConstructor(dependsOnBean,
- declaringClass, arguments);
- code.addStatement("return resolver.resolve($L, (args) -> $L)",
- REGISTERED_BEAN_PARAMETER_NAME, newInstance);
- method.addCode(code.build());
- }
+ method.returns(BeanInstanceSupplier.class);
+ int parameterOffset = (!dependsOnBean) ? 0 : 1;
+ CodeBlock.Builder code = CodeBlock.builder();
+ code.add(generateResolverForConstructor(constructor, parameterOffset));
+ boolean hasArguments = constructor.getParameterCount() > 0;
+ CodeBlock arguments = hasArguments
+ ? new AutowiredArgumentsCodeGenerator(declaringClass, constructor)
+ .generateCode(constructor.getParameterTypes(), parameterOffset)
+ : NO_ARGS;
+ CodeBlock newInstance = generateNewInstanceCodeForConstructor(dependsOnBean,
+ declaringClass, arguments);
+ code.add(generateWithGeneratorCode(hasArguments, newInstance));
+ method.addStatement(code.build());
}
private CodeBlock generateResolverForConstructor(Constructor> constructor,
@@ -193,9 +186,8 @@ class InstanceSupplierCodeGenerator {
CodeBlock parameterTypes = generateParameterTypesCode(
constructor.getParameterTypes(), parameterOffset);
- return CodeBlock.of("$T resolver = $T.forConstructor($L)",
- AutowiredInstantiationArgumentsResolver.class,
- AutowiredInstantiationArgumentsResolver.class, parameterTypes);
+ return CodeBlock.of("return $T.forConstructor($L)",
+ BeanInstanceSupplier.class, parameterTypes);
}
private CodeBlock generateNewInstanceCodeForConstructor(boolean dependsOnBean,
@@ -232,21 +224,16 @@ class InstanceSupplierCodeGenerator {
this.generationContext.getRuntimeHints().reflection()
.registerMethod(factoryMethod, INTROSPECT);
if (!dependsOnBean && factoryMethod.getParameterCount() == 0) {
- if (!this.allowDirectSupplierShortcut) {
- return CodeBlock.of("$T.using($T::$L)", InstanceSupplier.class,
- declaringClass, factoryMethod.getName());
- }
- if (!isThrowingCheckedException(factoryMethod)) {
- return CodeBlock.of("$T::$L", declaringClass, factoryMethod.getName());
- }
- return CodeBlock.of("$T.of($T::$L)", ThrowingSupplier.class, declaringClass,
- factoryMethod.getName());
+ CodeBlock.Builder code = CodeBlock.builder();
+ code.add("$T.forFactoryMethod($T.class, $S)", BeanInstanceSupplier.class,
+ declaringClass, factoryMethod.getName());
+ code.add(".withGenerator($T::$L)", declaringClass, factoryMethod.getName());
+ return code.build();
}
- GeneratedMethod generatedMethod = generateGetInstanceMethod(method ->
- buildGetInstanceMethodForFactoryMethod(method, name, factoryMethod, declaringClass,
- dependsOnBean, PRIVATE_STATIC));
- return CodeBlock.of("$T.of($T::$L)", InstanceSupplier.class, this.className,
- generatedMethod.getName());
+ GeneratedMethod getInstanceMethod = generateGetInstanceSupplierMethod(method ->
+ buildGetInstanceMethodForFactoryMethod(method, name, factoryMethod,
+ declaringClass, dependsOnBean, PRIVATE_STATIC));
+ return generateReturnStatement(getInstanceMethod);
}
private CodeBlock generateCodeForInaccessibleFactoryMethod(String name,
@@ -254,18 +241,14 @@ class InstanceSupplierCodeGenerator {
this.generationContext.getRuntimeHints().reflection()
.registerMethod(factoryMethod);
- GeneratedMethod generatedMethod = generateGetInstanceMethod(method -> {
- method.addJavadoc("Instantiate the bean instance for '$L'.", name);
+ GeneratedMethod getInstanceMethod = generateGetInstanceSupplierMethod(method -> {
+ method.addJavadoc("Get the bean instance supplier for '$L'.", name);
method.addModifiers(PRIVATE_STATIC);
- method.returns(factoryMethod.getReturnType());
- method.addParameter(RegisteredBean.class, REGISTERED_BEAN_PARAMETER_NAME);
- method.addStatement(generateResolverForFactoryMethod(factoryMethod,
+ method.returns(BeanInstanceSupplier.class);
+ method.addStatement(generateInstanceSupplierForFactoryMethod(factoryMethod,
declaringClass, factoryMethod.getName()));
- method.addStatement("return resolver.resolveAndInstantiate($L)",
- REGISTERED_BEAN_PARAMETER_NAME);
});
- return CodeBlock.of("$T.of($T::$L)", InstanceSupplier.class, this.className,
- generatedMethod.getName());
+ return generateReturnStatement(getInstanceMethod);
}
private void buildGetInstanceMethodForFactoryMethod(MethodSpec.Builder method,
@@ -273,46 +256,34 @@ class InstanceSupplierCodeGenerator {
boolean dependsOnBean, javax.lang.model.element.Modifier... modifiers) {
String factoryMethodName = factoryMethod.getName();
- method.addJavadoc("Get the bean instance for '$L'.", name);
+ method.addJavadoc("Get the bean instance supplier for '$L'.", name);
method.addModifiers(modifiers);
- method.returns(factoryMethod.getReturnType());
- if (isThrowingCheckedException(factoryMethod)) {
- method.addException(Exception.class);
- }
- method.addParameter(RegisteredBean.class, REGISTERED_BEAN_PARAMETER_NAME);
- if (factoryMethod.getParameterCount() == 0) {
- CodeBlock instantiationCode = generateNewInstanceCodeForMethod(dependsOnBean,
- declaringClass, factoryMethodName, NO_ARGS);
- method.addCode(generateReturnStatement(instantiationCode));
- }
- else {
- CodeBlock.Builder code = CodeBlock.builder();
- code.addStatement(generateResolverForFactoryMethod(factoryMethod,
- declaringClass, factoryMethodName));
- CodeBlock arguments = new AutowiredArgumentsCodeGenerator(declaringClass,
- factoryMethod).generateCode(factoryMethod.getParameterTypes());
- CodeBlock newInstance = generateNewInstanceCodeForMethod(dependsOnBean,
- declaringClass, factoryMethodName, arguments);
- code.addStatement("return resolver.resolve($L, (args) -> $L)",
- REGISTERED_BEAN_PARAMETER_NAME, newInstance);
- method.addCode(code.build());
- }
+ method.returns(BeanInstanceSupplier.class);
+ CodeBlock.Builder code = CodeBlock.builder();
+ code.add(generateInstanceSupplierForFactoryMethod(factoryMethod, declaringClass, factoryMethodName));
+ boolean hasArguments = factoryMethod.getParameterCount() > 0;
+ CodeBlock arguments = hasArguments
+ ? new AutowiredArgumentsCodeGenerator(declaringClass, factoryMethod)
+ .generateCode(factoryMethod.getParameterTypes())
+ : NO_ARGS;
+ CodeBlock newInstance = generateNewInstanceCodeForMethod(dependsOnBean,
+ declaringClass, factoryMethodName, arguments);
+ code.add(generateWithGeneratorCode(hasArguments, newInstance));
+ method.addStatement(code.build());
}
- private CodeBlock generateResolverForFactoryMethod(Method factoryMethod,
+ private CodeBlock generateInstanceSupplierForFactoryMethod(Method factoryMethod,
Class> declaringClass, String factoryMethodName) {
if (factoryMethod.getParameterCount() == 0) {
- return CodeBlock.of("$T resolver = $T.forFactoryMethod($T.class, $S)",
- AutowiredInstantiationArgumentsResolver.class,
- AutowiredInstantiationArgumentsResolver.class, declaringClass,
+ return CodeBlock.of("return $T.forFactoryMethod($T.class, $S)",
+ BeanInstanceSupplier.class, declaringClass,
factoryMethodName);
}
CodeBlock parameterTypes = generateParameterTypesCode(
factoryMethod.getParameterTypes(), 0);
- return CodeBlock.of("$T resolver = $T.forFactoryMethod($T.class, $S, $L)",
- AutowiredInstantiationArgumentsResolver.class,
- AutowiredInstantiationArgumentsResolver.class, declaringClass,
+ return CodeBlock.of("return $T.forFactoryMethod($T.class, $S, $L)",
+ BeanInstanceSupplier.class, declaringClass,
factoryMethodName, parameterTypes);
}
@@ -326,9 +297,19 @@ class InstanceSupplierCodeGenerator {
REGISTERED_BEAN_PARAMETER_NAME, declaringClass, factoryMethodName, args);
}
- private CodeBlock generateReturnStatement(CodeBlock instantiationCode) {
- CodeBlock.Builder code = CodeBlock.builder();
- code.addStatement("return $L", instantiationCode);
+ private CodeBlock generateReturnStatement(GeneratedMethod getInstanceMethod) {
+ return CodeBlock.of("$T.$L()", this.className, getInstanceMethod.getName());
+ }
+
+ private CodeBlock generateWithGeneratorCode(boolean hasArguments, CodeBlock newInstance) {
+ CodeBlock lambdaArguments = (hasArguments
+ ? CodeBlock.of("($L, $L)", REGISTERED_BEAN_PARAMETER_NAME, ARGS_PARAMETER_NAME)
+ : CodeBlock.of("($L)", REGISTERED_BEAN_PARAMETER_NAME));
+ Builder code = CodeBlock.builder();
+ code.add("\n");
+ code.indent().indent();
+ code.add(".withGenerator($L -> $L)", lambdaArguments, newInstance);
+ code.unindent().unindent();
return code.build();
}
@@ -342,16 +323,16 @@ class InstanceSupplierCodeGenerator {
}
private CodeBlock generateParameterTypesCode(Class>[] parameterTypes, int offset) {
- CodeBlock.Builder builder = CodeBlock.builder();
+ CodeBlock.Builder code = CodeBlock.builder();
for (int i = offset; i < parameterTypes.length; i++) {
- builder.add(i != offset ? ", " : "");
- builder.add("$T.class", parameterTypes[i]);
+ code.add(i != offset ? ", " : "");
+ code.add("$T.class", parameterTypes[i]);
}
- return builder.build();
+ return code.build();
}
- private GeneratedMethod generateGetInstanceMethod(Consumer method) {
- return this.generatedMethods.add("getInstance", method);
+ private GeneratedMethod generateGetInstanceSupplierMethod(Consumer method) {
+ return this.generatedMethods.add("getInstanceSupplier", method);
}
private boolean isThrowingCheckedException(Executable executable) {
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/InstanceSupplier.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/InstanceSupplier.java
index 3eede1f0884..9b7dbfcb8ec 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/support/InstanceSupplier.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/InstanceSupplier.java
@@ -16,8 +16,10 @@
package org.springframework.beans.factory.support;
+import java.lang.reflect.Method;
import java.util.function.Supplier;
+import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.function.ThrowingBiFunction;
import org.springframework.util.function.ThrowingSupplier;
@@ -29,6 +31,7 @@ import org.springframework.util.function.ThrowingSupplier;
* supply the instance.
*
* @author Phillip Webb
+ * @author Stephane Nicoll
* @since 6.0
* @param the type of instance supplied by this supplier
* @see RegisteredBean
@@ -49,6 +52,17 @@ public interface InstanceSupplier extends ThrowingSupplier {
*/
T get(RegisteredBean registeredBean) throws Exception;
+ /**
+ * Return the factory method that this supplier uses to create the
+ * instance, or {@code null} if it is not known or this supplier uses
+ * another mean.
+ * @return the factory method used to create the instance, or {@code null}
+ */
+ @Nullable
+ default Method getFactoryMethod() {
+ return null;
+ }
+
/**
* Return a composed instance supplier that first obtains the instance from
* this supplier, and then applied the {@code after} function to obtain the
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java
index 0bcd497127a..72fd154fe38 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java
@@ -429,6 +429,16 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
return this.factoryMethodToIntrospect;
}
+ @Override
+ public void setInstanceSupplier(@Nullable Supplier> instanceSupplier) {
+ super.setInstanceSupplier(instanceSupplier);
+ Method factoryMethod = (instanceSupplier instanceof InstanceSupplier>)
+ ? ((InstanceSupplier>) instanceSupplier).getFactoryMethod() : null;
+ if (factoryMethod != null) {
+ setResolvedFactoryMethod(factoryMethod);
+ }
+ }
+
/**
* Register an externally managed configuration method or field.
*/
diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/aot/AutowiredInstantiationArgumentsResolverTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanInstanceSupplierTests.java
similarity index 68%
rename from spring-beans/src/test/java/org/springframework/beans/factory/aot/AutowiredInstantiationArgumentsResolverTests.java
rename to spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanInstanceSupplierTests.java
index eedb7200508..fa3ae93ca6f 100644
--- a/spring-beans/src/test/java/org/springframework/beans/factory/aot/AutowiredInstantiationArgumentsResolverTests.java
+++ b/spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanInstanceSupplierTests.java
@@ -20,6 +20,7 @@ import java.io.InputStream;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Executable;
+import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -39,7 +40,7 @@ import org.springframework.beans.factory.BeanCurrentlyInCreationException;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.UnsatisfiedDependencyException;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
-import org.springframework.beans.factory.aot.AutowiredInstantiationArgumentsResolverTests.Enclosing.InnerSingleArgConstructor;
+import org.springframework.beans.factory.aot.BeanInstanceSupplierTests.Enclosing.InnerSingleArgConstructor;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
import org.springframework.beans.factory.config.DependencyDescriptor;
@@ -54,6 +55,10 @@ import org.springframework.core.env.Environment;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.ClassUtils;
+import org.springframework.util.ReflectionUtils;
+import org.springframework.util.function.ThrowingBiFunction;
+import org.springframework.util.function.ThrowingFunction;
+import org.springframework.util.function.ThrowingSupplier;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@@ -62,19 +67,19 @@ import static org.assertj.core.api.Assertions.entry;
import static org.mockito.Mockito.mock;
/**
- * Tests for {@link AutowiredInstantiationArgumentsResolver}.
+ * Tests for {@link BeanInstanceSupplier}.
*
* @author Phillip Webb
* @author Stephane Nicoll
*/
-class AutowiredInstantiationArgumentsResolverTests {
+class BeanInstanceSupplierTests {
private final DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
@Test
void forConstructorWhenParameterTypesIsNullThrowsException() {
assertThatIllegalArgumentException()
- .isThrownBy(() -> AutowiredInstantiationArgumentsResolver
+ .isThrownBy(() -> BeanInstanceSupplier
.forConstructor((Class>[]) null))
.withMessage("'parameterTypes' must not be null");
}
@@ -82,27 +87,33 @@ class AutowiredInstantiationArgumentsResolverTests {
@Test
void forConstructorWhenParameterTypesContainsNullThrowsException() {
assertThatIllegalArgumentException()
- .isThrownBy(() -> AutowiredInstantiationArgumentsResolver
+ .isThrownBy(() -> BeanInstanceSupplier
.forConstructor(String.class, null))
.withMessage("'parameterTypes' must not contain null elements");
}
@Test
void forConstructorWhenNotFoundThrowsException() {
- AutowiredInstantiationArgumentsResolver resolver = AutowiredInstantiationArgumentsResolver
+ BeanInstanceSupplier resolver = BeanInstanceSupplier
.forConstructor(InputStream.class);
Source source = new Source(SingleArgConstructor.class, resolver);
RegisteredBean registerBean = source.registerBean(this.beanFactory);
assertThatIllegalArgumentException()
- .isThrownBy(() -> resolver.resolve(registerBean)).withMessage(
+ .isThrownBy(() -> resolver.get(registerBean)).withMessage(
"Constructor with parameter types [java.io.InputStream] cannot be found on "
+ SingleArgConstructor.class.getName());
}
+ @Test
+ void forConstructorReturnsNullFactoryMethod() {
+ BeanInstanceSupplier resolver = BeanInstanceSupplier.forConstructor(String.class);
+ assertThat(resolver.getFactoryMethod()).isNull();
+ }
+
@Test
void forFactoryMethodWhenDeclaringClassIsNullThrowsException() {
assertThatIllegalArgumentException()
- .isThrownBy(() -> AutowiredInstantiationArgumentsResolver
+ .isThrownBy(() -> BeanInstanceSupplier
.forFactoryMethod(null, "test"))
.withMessage("'declaringClass' must not be null");
}
@@ -110,7 +121,7 @@ class AutowiredInstantiationArgumentsResolverTests {
@Test
void forFactoryMethodWhenNameIsEmptyThrowsException() {
assertThatIllegalArgumentException()
- .isThrownBy(() -> AutowiredInstantiationArgumentsResolver
+ .isThrownBy(() -> BeanInstanceSupplier
.forFactoryMethod(SingleArgFactory.class, ""))
.withMessage("'methodName' must not be empty");
}
@@ -119,7 +130,7 @@ class AutowiredInstantiationArgumentsResolverTests {
void forFactoryMethodWhenParameterTypesIsNullThrowsException() {
assertThatIllegalArgumentException()
.isThrownBy(
- () -> AutowiredInstantiationArgumentsResolver.forFactoryMethod(
+ () -> BeanInstanceSupplier.forFactoryMethod(
SingleArgFactory.class, "single", (Class>[]) null))
.withMessage("'parameterTypes' must not be null");
}
@@ -128,61 +139,136 @@ class AutowiredInstantiationArgumentsResolverTests {
void forFactoryMethodWhenParameterTypesContainsNullThrowsException() {
assertThatIllegalArgumentException()
.isThrownBy(
- () -> AutowiredInstantiationArgumentsResolver.forFactoryMethod(
+ () -> BeanInstanceSupplier.forFactoryMethod(
SingleArgFactory.class, "single", String.class, null))
.withMessage("'parameterTypes' must not contain null elements");
}
@Test
void forFactoryMethodWhenNotFoundThrowsException() {
- AutowiredInstantiationArgumentsResolver resolver = AutowiredInstantiationArgumentsResolver
+ BeanInstanceSupplier resolver = BeanInstanceSupplier
.forFactoryMethod(SingleArgFactory.class, "single", InputStream.class);
Source source = new Source(String.class, resolver);
RegisteredBean registerBean = source.registerBean(this.beanFactory);
assertThatIllegalArgumentException()
- .isThrownBy(() -> resolver.resolve(registerBean)).withMessage(
+ .isThrownBy(() -> resolver.get(registerBean)).withMessage(
"Factory method 'single' with parameter types [java.io.InputStream] declared on class "
+ SingleArgFactory.class.getName() + " cannot be found");
}
@Test
- void resolveWithActionWhenActionIsNullThrowsException() {
- AutowiredInstantiationArgumentsResolver resolver = AutowiredInstantiationArgumentsResolver
+ void forFactoryMethodReturnsFactoryMethod() {
+ BeanInstanceSupplier resolver = BeanInstanceSupplier
+ .forFactoryMethod(SingleArgFactory.class, "single", String.class);
+ Method factoryMethod = ReflectionUtils.findMethod(SingleArgFactory.class, "single", String.class);
+ assertThat(factoryMethod).isNotNull();
+ assertThat(resolver.getFactoryMethod()).isEqualTo(factoryMethod);
+ }
+
+ @Test
+ void withGeneratorWhenBiFunctionIsNullThrowsException() {
+ BeanInstanceSupplier resolver = BeanInstanceSupplier
+ .forConstructor();
+ assertThatIllegalArgumentException()
+ .isThrownBy(() -> resolver.withGenerator(
+ (ThrowingBiFunction) null))
+ .withMessage("'generator' must not be null");
+ }
+
+ @Test
+ void withGeneratorWhenFunctionIsNullThrowsException() {
+ BeanInstanceSupplier resolver = BeanInstanceSupplier
+ .forConstructor();
+ assertThatIllegalArgumentException()
+ .isThrownBy(() -> resolver.withGenerator(
+ (ThrowingFunction) null))
+ .withMessage("'generator' must not be null");
+ }
+
+ @Test
+ void withGeneratorWhenSupplierIsNullThrowsException() {
+ BeanInstanceSupplier resolver = BeanInstanceSupplier
.forConstructor();
- Source source = new Source(NoArgConstructor.class, resolver);
- RegisteredBean registerBean = source.registerBean(this.beanFactory);
assertThatIllegalArgumentException()
- .isThrownBy(() -> resolver.resolve(registerBean, null))
- .withMessage("'action' must not be null");
+ .isThrownBy(() -> resolver.withGenerator(
+ (ThrowingSupplier) null))
+ .withMessage("'generator' must not be null");
}
@Test
- void resolveWithActionCallsAction() {
- AutowiredInstantiationArgumentsResolver resolver = AutowiredInstantiationArgumentsResolver
+ void getWithConstructorDoesNotSetResolvedFactoryMethod() throws Exception {
+ BeanInstanceSupplier resolver = BeanInstanceSupplier
.forConstructor(String.class);
- Source source = new Source(SingleArgConstructor.class, resolver);
this.beanFactory.registerSingleton("one", "1");
+ Source source = new Source(SingleArgConstructor.class, resolver);
RegisteredBean registerBean = source.registerBean(this.beanFactory);
+ assertThat(registerBean.getMergedBeanDefinition().getResolvedFactoryMethod()).isNull();
+ source.getResolver().get(registerBean);
+ assertThat(registerBean.getMergedBeanDefinition().getResolvedFactoryMethod()).isNull();
+ }
+
+ @Test
+ void getWithFactoryMethodSetsResolvedFactoryMethod() {
+ Method factoryMethod = ReflectionUtils.findMethod(SingleArgFactory.class, "single", String.class);
+ assertThat(factoryMethod).isNotNull();
+ BeanInstanceSupplier resolver = BeanInstanceSupplier
+ .forFactoryMethod(SingleArgFactory.class, "single", String.class);
+ RootBeanDefinition beanDefinition = new RootBeanDefinition(String.class);
+ assertThat(beanDefinition.getResolvedFactoryMethod()).isNull();
+ beanDefinition.setInstanceSupplier(resolver);
+ assertThat(beanDefinition.getResolvedFactoryMethod()).isEqualTo(factoryMethod);
+ }
+
+ @Test
+ void getWithGeneratorCallsBiFunction() throws Exception {
+ BeanRegistrar registrar = new BeanRegistrar(SingleArgConstructor.class);
+ this.beanFactory.registerSingleton("one", "1");
+ RegisteredBean registerBean = registrar.registerBean(this.beanFactory);
List result = new ArrayList<>();
- resolver.resolve(registerBean, result::add);
+ BeanInstanceSupplier resolver = BeanInstanceSupplier
+ .forConstructor(String.class)
+ .withGenerator((registeredBean, args) -> result.add(args));
+ resolver.get(registerBean);
assertThat(result).hasSize(1);
assertThat(((AutowiredArguments) result.get(0)).toArray()).containsExactly("1");
}
@Test
- void resolveWhenRegisteredBeanIsNullThrowsException() {
- AutowiredInstantiationArgumentsResolver resolver = AutowiredInstantiationArgumentsResolver
+ void getWithGeneratorCallsFunction() throws Exception {
+ BeanRegistrar registrar = new BeanRegistrar(SingleArgConstructor.class);
+ this.beanFactory.registerSingleton("one", "1");
+ RegisteredBean registerBean = registrar.registerBean(this.beanFactory);
+ BeanInstanceSupplier resolver = BeanInstanceSupplier
+ .forConstructor(String.class)
+ .withGenerator(registeredBean -> "1");
+ assertThat(resolver.get(registerBean)).isInstanceOf(String.class).isEqualTo("1");
+ }
+
+ @Test
+ void getWithGeneratorCallsSupplier() throws Exception {
+ BeanRegistrar registrar = new BeanRegistrar(SingleArgConstructor.class);
+ this.beanFactory.registerSingleton("one", "1");
+ RegisteredBean registerBean = registrar.registerBean(this.beanFactory);
+ BeanInstanceSupplier resolver = BeanInstanceSupplier
+ .forConstructor(String.class)
+ .withGenerator(() -> "1");
+ assertThat(resolver.get(registerBean)).isInstanceOf(String.class).isEqualTo("1");
+ }
+
+ @Test
+ void getWhenRegisteredBeanIsNullThrowsException() {
+ BeanInstanceSupplier resolver = BeanInstanceSupplier
.forConstructor(String.class);
- assertThatIllegalArgumentException().isThrownBy(() -> resolver.resolve(null))
+ assertThatIllegalArgumentException().isThrownBy(() -> resolver.get((RegisteredBean) null))
.withMessage("'registeredBean' must not be null");
}
@ParameterizedResolverTest(Sources.SINGLE_ARG)
- void resolveAndInstantiate(Source source) {
+ void getWithNoGeneratorUsesReflection(Source source) throws Exception {
this.beanFactory.registerSingleton("one", "1");
this.beanFactory.registerSingleton("testFactory", new SingleArgFactory());
RegisteredBean registerBean = source.registerBean(this.beanFactory);
- Object instance = source.getResolver().resolveAndInstantiate(registerBean);
+ Object instance = source.getResolver().get(registerBean);
if (instance instanceof SingleArgConstructor singleArgConstructor) {
instance = singleArgConstructor.getString();
}
@@ -190,12 +276,12 @@ class AutowiredInstantiationArgumentsResolverTests {
}
@ParameterizedResolverTest(Sources.INNER_CLASS_SINGLE_ARG)
- void resolveAndInstantiateNested(Source source) {
+ void getNestedWithNoGeneratorUsesReflection(Source source) throws Exception {
this.beanFactory.registerSingleton("one", "1");
this.beanFactory.registerSingleton("testFactory",
new Enclosing().new InnerSingleArgFactory());
RegisteredBean registerBean = source.registerBean(this.beanFactory);
- Object instance = source.getResolver().resolveAndInstantiate(registerBean);
+ Object instance = source.getResolver().get(registerBean);
if (instance instanceof InnerSingleArgConstructor innerSingleArgConstructor) {
instance = innerSingleArgConstructor.getString();
}
@@ -203,38 +289,38 @@ class AutowiredInstantiationArgumentsResolverTests {
}
@Test
- void resolveNoArgConstructor() {
+ void resolveArgumentsWithNoArgConstructor() {
RootBeanDefinition beanDefinition = new RootBeanDefinition(
NoArgConstructor.class);
this.beanFactory.registerBeanDefinition("test", beanDefinition);
RegisteredBean registeredBean = RegisteredBean.of(this.beanFactory, "test");
- AutowiredArguments resolved = AutowiredInstantiationArgumentsResolver
- .forConstructor().resolve(registeredBean);
+ AutowiredArguments resolved = BeanInstanceSupplier
+ .forConstructor().resolveArguments(registeredBean);
assertThat(resolved.toArray()).isEmpty();
}
@ParameterizedResolverTest(Sources.SINGLE_ARG)
- void resolveSingleArgConstructor(Source source) {
+ void resolveArgumentsWithSingleArgConstructor(Source source) {
this.beanFactory.registerSingleton("one", "1");
RegisteredBean registeredBean = source.registerBean(this.beanFactory);
- assertThat(source.getResolver().resolve(registeredBean).toArray())
+ assertThat(source.getResolver().resolveArguments(registeredBean).toArray())
.containsExactly("1");
}
@ParameterizedResolverTest(Sources.INNER_CLASS_SINGLE_ARG)
- void resolvedNestedSingleArgConstructor(Source source) {
+ void resolveArgumentsWithNestedSingleArgConstructor(Source source) {
this.beanFactory.registerSingleton("one", "1");
RegisteredBean registeredBean = source.registerBean(this.beanFactory);
- assertThat(source.getResolver().resolve(registeredBean).toArray())
+ assertThat(source.getResolver().resolveArguments(registeredBean).toArray())
.containsExactly("1");
}
@ParameterizedResolverTest(Sources.SINGLE_ARG)
- void resolveRequiredDependencyNotPresentThrowsUnsatisfiedDependencyException(
+ void resolveArgumentsWithRequiredDependencyNotPresentThrowsUnsatisfiedDependencyException(
Source source) {
RegisteredBean registeredBean = source.registerBean(this.beanFactory);
assertThatExceptionOfType(UnsatisfiedDependencyException.class)
- .isThrownBy(() -> source.getResolver().resolve(registeredBean))
+ .isThrownBy(() -> source.getResolver().resolveArguments(registeredBean))
.satisfies(ex -> {
assertThat(ex.getBeanName()).isEqualTo("testBean");
assertThat(ex.getInjectionPoint()).isNotNull();
@@ -244,16 +330,16 @@ class AutowiredInstantiationArgumentsResolverTests {
}
@Test
- void resolveInInstanceSupplierWithSelfReferenceThrowsException() {
+ void resolveArgumentsInInstanceSupplierWithSelfReferenceThrowsException() {
// SingleArgFactory.single(...) expects a String to be injected
- // and our own bean is a String so it's a valid candidate
+ // and our own bean is a String, so it's a valid candidate
this.beanFactory.addBeanPostProcessor(new AutowiredAnnotationBeanPostProcessor());
RootBeanDefinition beanDefinition = new RootBeanDefinition(String.class);
beanDefinition.setInstanceSupplier(InstanceSupplier.of(registeredBean -> {
- AutowiredArguments args = AutowiredInstantiationArgumentsResolver
+ AutowiredArguments args = BeanInstanceSupplier
.forFactoryMethod(SingleArgFactory.class, "single", String.class)
- .resolve(registeredBean);
- return new SingleArgFactory().single((String) args.get(0));
+ .resolveArguments(registeredBean);
+ return new SingleArgFactory().single(args.get(0));
}));
this.beanFactory.registerBeanDefinition("test", beanDefinition);
assertThatExceptionOfType(UnsatisfiedDependencyException.class)
@@ -261,83 +347,83 @@ class AutowiredInstantiationArgumentsResolverTests {
}
@ParameterizedResolverTest(Sources.ARRAY_OF_BEANS)
- void resolveArrayOfBeans(Source source) {
+ void resolveArgumentsWithArrayOfBeans(Source source) {
this.beanFactory.registerSingleton("one", "1");
this.beanFactory.registerSingleton("two", "2");
RegisteredBean registerBean = source.registerBean(this.beanFactory);
- AutowiredArguments arguments = source.getResolver().resolve(registerBean);
+ AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean);
assertThat(arguments.toArray()).hasSize(1);
assertThat((Object[]) arguments.get(0)).containsExactly("1", "2");
}
@ParameterizedResolverTest(Sources.ARRAY_OF_BEANS)
- void resolveRequiredArrayOfBeansInjectEmptyArray(Source source) {
+ void resolveArgumentsWithRequiredArrayOfBeansInjectEmptyArray(Source source) {
RegisteredBean registerBean = source.registerBean(this.beanFactory);
- AutowiredArguments arguments = source.getResolver().resolve(registerBean);
+ AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean);
assertThat(arguments.toArray()).hasSize(1);
assertThat((Object[]) arguments.get(0)).isEmpty();
}
@ParameterizedResolverTest(Sources.LIST_OF_BEANS)
- void resolveListOfBeans(Source source) {
+ void resolveArgumentsWithListOfBeans(Source source) {
this.beanFactory.registerSingleton("one", "1");
this.beanFactory.registerSingleton("two", "2");
RegisteredBean registerBean = source.registerBean(this.beanFactory);
- AutowiredArguments arguments = source.getResolver().resolve(registerBean);
+ AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean);
assertThat(arguments.toArray()).hasSize(1);
assertThat(arguments.getObject(0)).isInstanceOf(List.class).asList()
.containsExactly("1", "2");
}
@ParameterizedResolverTest(Sources.LIST_OF_BEANS)
- void resolveRequiredListOfBeansInjectEmptyList(Source source) {
+ void resolveArgumentsWithRequiredListOfBeansInjectEmptyList(Source source) {
RegisteredBean registerBean = source.registerBean(this.beanFactory);
- AutowiredArguments arguments = source.getResolver().resolve(registerBean);
+ AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean);
assertThat(arguments.toArray()).hasSize(1);
assertThat((List>) arguments.get(0)).isEmpty();
}
@ParameterizedResolverTest(Sources.SET_OF_BEANS)
@SuppressWarnings("unchecked")
- void resolveSetOfBeans(Source source) {
+ void resolveArgumentsWithSetOfBeans(Source source) {
this.beanFactory.registerSingleton("one", "1");
this.beanFactory.registerSingleton("two", "2");
RegisteredBean registerBean = source.registerBean(this.beanFactory);
- AutowiredArguments arguments = source.getResolver().resolve(registerBean);
+ AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean);
assertThat(arguments.toArray()).hasSize(1);
assertThat((Set) arguments.get(0)).containsExactly("1", "2");
}
@ParameterizedResolverTest(Sources.SET_OF_BEANS)
- void resolveRequiredSetOfBeansInjectEmptySet(Source source) {
+ void resolveArgumentsWithRequiredSetOfBeansInjectEmptySet(Source source) {
RegisteredBean registerBean = source.registerBean(this.beanFactory);
- AutowiredArguments arguments = source.getResolver().resolve(registerBean);
+ AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean);
assertThat(arguments.toArray()).hasSize(1);
assertThat((Set>) arguments.get(0)).isEmpty();
}
@ParameterizedResolverTest(Sources.MAP_OF_BEANS)
@SuppressWarnings("unchecked")
- void resolveMapOfBeans(Source source) {
+ void resolveArgumentsWithMapOfBeans(Source source) {
this.beanFactory.registerSingleton("one", "1");
this.beanFactory.registerSingleton("two", "2");
RegisteredBean registerBean = source.registerBean(this.beanFactory);
- AutowiredArguments arguments = source.getResolver().resolve(registerBean);
+ AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean);
assertThat(arguments.toArray()).hasSize(1);
assertThat((Map) arguments.get(0))
.containsExactly(entry("one", "1"), entry("two", "2"));
}
@ParameterizedResolverTest(Sources.MAP_OF_BEANS)
- void resolveRequiredMapOfBeansInjectEmptySet(Source source) {
+ void resolveArgumentsWithRequiredMapOfBeansInjectEmptySet(Source source) {
RegisteredBean registerBean = source.registerBean(this.beanFactory);
- AutowiredArguments arguments = source.getResolver().resolve(registerBean);
+ AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean);
assertThat(arguments.toArray()).hasSize(1);
assertThat((Map, ?>) arguments.get(0)).isEmpty();
}
@ParameterizedResolverTest(Sources.MULTI_ARGS)
- void resolveMultiArgsConstructor(Source source) {
+ void resolveArgumentsWithMultiArgsConstructor(Source source) {
ResourceLoader resourceLoader = new DefaultResourceLoader();
Environment environment = mock(Environment.class);
this.beanFactory.registerResolvableDependency(ResourceLoader.class,
@@ -345,7 +431,7 @@ class AutowiredInstantiationArgumentsResolverTests {
this.beanFactory.registerSingleton("environment", environment);
this.beanFactory.registerSingleton("one", "1");
RegisteredBean registerBean = source.registerBean(this.beanFactory);
- AutowiredArguments arguments = source.getResolver().resolve(registerBean);
+ AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean);
assertThat(arguments.toArray()).hasSize(3);
assertThat(arguments.getObject(0)).isEqualTo(resourceLoader);
assertThat(arguments.getObject(1)).isEqualTo(environment);
@@ -354,7 +440,7 @@ class AutowiredInstantiationArgumentsResolverTests {
}
@ParameterizedResolverTest(Sources.MIXED_ARGS)
- void resolveMixedArgsConstructorWithUserValue(Source source) {
+ void resolveArgumentsWithMixedArgsConstructorWithUserValue(Source source) {
ResourceLoader resourceLoader = new DefaultResourceLoader();
Environment environment = mock(Environment.class);
this.beanFactory.registerResolvableDependency(ResourceLoader.class,
@@ -367,7 +453,7 @@ class AutowiredInstantiationArgumentsResolverTests {
beanDefinition.getConstructorArgumentValues()
.addIndexedArgumentValue(1, "user-value");
});
- AutowiredArguments arguments = source.getResolver().resolve(registerBean);
+ AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean);
assertThat(arguments.toArray()).hasSize(3);
assertThat(arguments.getObject(0)).isEqualTo(resourceLoader);
assertThat(arguments.getObject(1)).isEqualTo("user-value");
@@ -375,7 +461,7 @@ class AutowiredInstantiationArgumentsResolverTests {
}
@ParameterizedResolverTest(Sources.MIXED_ARGS)
- void resolveMixedArgsConstructorWithUserBeanReference(Source source) {
+ void resolveArgumentsWithMixedArgsConstructorWithUserBeanReference(Source source) {
ResourceLoader resourceLoader = new DefaultResourceLoader();
Environment environment = mock(Environment.class);
this.beanFactory.registerResolvableDependency(ResourceLoader.class,
@@ -390,7 +476,7 @@ class AutowiredInstantiationArgumentsResolverTests {
beanDefinition.getConstructorArgumentValues()
.addIndexedArgumentValue(1, new RuntimeBeanReference("two"));
});
- AutowiredArguments arguments = source.getResolver().resolve(registerBean);
+ AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean);
assertThat(arguments.toArray()).hasSize(3);
assertThat(arguments.getObject(0)).isEqualTo(resourceLoader);
assertThat(arguments.getObject(1)).isEqualTo("2");
@@ -398,9 +484,9 @@ class AutowiredInstantiationArgumentsResolverTests {
}
@Test
- void resolveUserValueWithTypeConversionRequired() {
+ void resolveArgumentsWithUserValueWithTypeConversionRequired() {
Source source = new Source(CharDependency.class,
- AutowiredInstantiationArgumentsResolver.forConstructor(char.class));
+ BeanInstanceSupplier.forConstructor(char.class));
RegisteredBean registerBean = source.registerBean(this.beanFactory,
beanDefinition -> {
beanDefinition
@@ -408,37 +494,37 @@ class AutowiredInstantiationArgumentsResolverTests {
beanDefinition.getConstructorArgumentValues()
.addIndexedArgumentValue(0, "\\");
});
- AutowiredArguments arguments = source.getResolver().resolve(registerBean);
+ AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean);
assertThat(arguments.toArray()).hasSize(1);
assertThat(arguments.getObject(0)).isInstanceOf(Character.class).isEqualTo('\\');
}
@ParameterizedResolverTest(Sources.SINGLE_ARG)
- void resolveUserValueWithBeanReference(Source source) {
+ void resolveArgumentsWithUserValueWithBeanReference(Source source) {
this.beanFactory.registerSingleton("stringBean", "string");
RegisteredBean registerBean = source.registerBean(this.beanFactory,
beanDefinition -> beanDefinition.getConstructorArgumentValues()
.addIndexedArgumentValue(0,
new RuntimeBeanReference("stringBean")));
- AutowiredArguments arguments = source.getResolver().resolve(registerBean);
+ AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean);
assertThat(arguments.toArray()).hasSize(1);
assertThat(arguments.getObject(0)).isEqualTo("string");
}
@ParameterizedResolverTest(Sources.SINGLE_ARG)
- void resolveUserValueWithBeanDefinition(Source source) {
+ void resolveArgumentsWithUserValueWithBeanDefinition(Source source) {
AbstractBeanDefinition userValue = BeanDefinitionBuilder
.rootBeanDefinition(String.class, () -> "string").getBeanDefinition();
RegisteredBean registerBean = source.registerBean(this.beanFactory,
beanDefinition -> beanDefinition.getConstructorArgumentValues()
.addIndexedArgumentValue(0, userValue));
- AutowiredArguments arguments = source.getResolver().resolve(registerBean);
+ AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean);
assertThat(arguments.toArray()).hasSize(1);
assertThat(arguments.getObject(0)).isEqualTo("string");
}
@ParameterizedResolverTest(Sources.SINGLE_ARG)
- void resolveUserValueThatIsAlreadyResolved(Source source) {
+ void resolveArgumentsWithUserValueThatIsAlreadyResolved(Source source) {
RegisteredBean registerBean = source.registerBean(this.beanFactory);
BeanDefinition mergedBeanDefinition = this.beanFactory
.getMergedBeanDefinition("testBean");
@@ -446,13 +532,13 @@ class AutowiredInstantiationArgumentsResolverTests {
valueHolder.setConvertedValue("this is an a");
mergedBeanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0,
valueHolder);
- AutowiredArguments arguments = source.getResolver().resolve(registerBean);
+ AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean);
assertThat(arguments.toArray()).hasSize(1);
assertThat(arguments.getObject(0)).isEqualTo("this is an a");
}
@Test
- void resolveWhenUsingShortcutsInjectsDirectly() {
+ void resolveArgumentsWhenUsingShortcutsInjectsDirectly() {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory() {
@Override
@@ -462,35 +548,35 @@ class AutowiredInstantiationArgumentsResolverTests {
}
};
- AutowiredInstantiationArgumentsResolver resolver = AutowiredInstantiationArgumentsResolver
+ BeanInstanceSupplier resolver = BeanInstanceSupplier
.forConstructor(String.class);
Source source = new Source(String.class, resolver);
beanFactory.registerSingleton("one", "1");
RegisteredBean registeredBean = source.registerBean(beanFactory);
assertThatExceptionOfType(AssertionError.class)
- .isThrownBy(() -> resolver.resolve(registeredBean));
- assertThat(resolver.withShortcuts("one").resolve(registeredBean).toArray())
+ .isThrownBy(() -> resolver.resolveArguments(registeredBean));
+ assertThat(resolver.withShortcuts("one").resolveArguments(registeredBean).toArray())
.containsExactly("1");
}
@Test
- void resolveRegistersDependantBeans() {
- AutowiredInstantiationArgumentsResolver resolver = AutowiredInstantiationArgumentsResolver
+ void resolveArgumentsRegistersDependantBeans() {
+ BeanInstanceSupplier resolver = BeanInstanceSupplier
.forConstructor(String.class);
Source source = new Source(SingleArgConstructor.class, resolver);
- beanFactory.registerSingleton("one", "1");
+ this.beanFactory.registerSingleton("one", "1");
RegisteredBean registeredBean = source.registerBean(this.beanFactory);
- resolver.resolve(registeredBean);
+ resolver.resolveArguments(registeredBean);
assertThat(this.beanFactory.getDependentBeans("one")).containsExactly("testBean");
}
/**
- * Parameterized {@link Using} test backed by a {@link Sources}.
+ * Parameterized test backed by a {@link Sources}.
*/
@Retention(RetentionPolicy.RUNTIME)
@ParameterizedTest
@ArgumentsSource(SourcesArguments.class)
- static @interface ParameterizedResolverTest {
+ @interface ParameterizedResolverTest {
Sources value();
@@ -510,8 +596,7 @@ class AutowiredInstantiationArgumentsResolverTests {
}
@Override
- public Stream extends Arguments> provideArguments(ExtensionContext context)
- throws Exception {
+ public Stream extends Arguments> provideArguments(ExtensionContext context) {
return this.source.provideArguments(context);
}
@@ -523,27 +608,25 @@ class AutowiredInstantiationArgumentsResolverTests {
enum Sources {
SINGLE_ARG {
-
@Override
protected void setup() {
- add(SingleArgConstructor.class, AutowiredInstantiationArgumentsResolver
+ add(SingleArgConstructor.class, BeanInstanceSupplier
.forConstructor(String.class));
add(String.class,
- AutowiredInstantiationArgumentsResolver.forFactoryMethod(
+ BeanInstanceSupplier.forFactoryMethod(
SingleArgFactory.class, "single", String.class));
}
},
INNER_CLASS_SINGLE_ARG {
-
@Override
protected void setup() {
add(Enclosing.InnerSingleArgConstructor.class,
- AutowiredInstantiationArgumentsResolver
+ BeanInstanceSupplier
.forConstructor(String.class));
add(String.class,
- AutowiredInstantiationArgumentsResolver.forFactoryMethod(
+ BeanInstanceSupplier.forFactoryMethod(
Enclosing.InnerSingleArgFactory.class, "single",
String.class));
}
@@ -551,71 +634,66 @@ class AutowiredInstantiationArgumentsResolverTests {
},
ARRAY_OF_BEANS {
-
@Override
protected void setup() {
add(BeansCollectionConstructor.class,
- AutowiredInstantiationArgumentsResolver
+ BeanInstanceSupplier
.forConstructor(String[].class));
add(String.class,
- AutowiredInstantiationArgumentsResolver.forFactoryMethod(
+ BeanInstanceSupplier.forFactoryMethod(
BeansCollectionFactory.class, "array", String[].class));
}
},
LIST_OF_BEANS {
-
@Override
protected void setup() {
add(BeansCollectionConstructor.class,
- AutowiredInstantiationArgumentsResolver
+ BeanInstanceSupplier
.forConstructor(List.class));
add(String.class,
- AutowiredInstantiationArgumentsResolver.forFactoryMethod(
+ BeanInstanceSupplier.forFactoryMethod(
BeansCollectionFactory.class, "list", List.class));
}
},
SET_OF_BEANS {
-
@Override
protected void setup() {
add(BeansCollectionConstructor.class,
- AutowiredInstantiationArgumentsResolver
+ BeanInstanceSupplier
.forConstructor(Set.class));
add(String.class,
- AutowiredInstantiationArgumentsResolver.forFactoryMethod(
+ BeanInstanceSupplier.forFactoryMethod(
BeansCollectionFactory.class, "set", Set.class));
}
},
MAP_OF_BEANS {
-
@Override
protected void setup() {
add(BeansCollectionConstructor.class,
- AutowiredInstantiationArgumentsResolver
+ BeanInstanceSupplier
.forConstructor(Map.class));
add(String.class,
- AutowiredInstantiationArgumentsResolver.forFactoryMethod(
+ BeanInstanceSupplier.forFactoryMethod(
BeansCollectionFactory.class, "map", Map.class));
}
},
MULTI_ARGS {
-
@Override
protected void setup() {
add(MultiArgsConstructor.class,
- AutowiredInstantiationArgumentsResolver.forConstructor(
+ BeanInstanceSupplier.forConstructor(
ResourceLoader.class, Environment.class,
ObjectProvider.class));
add(String.class,
- AutowiredInstantiationArgumentsResolver.forFactoryMethod(
+ BeanInstanceSupplier.forFactoryMethod(
MultiArgsFactory.class, "multiArgs", ResourceLoader.class,
Environment.class, ObjectProvider.class));
}
@@ -623,14 +701,13 @@ class AutowiredInstantiationArgumentsResolverTests {
},
MIXED_ARGS {
-
@Override
protected void setup() {
add(MixedArgsConstructor.class,
- AutowiredInstantiationArgumentsResolver.forConstructor(
+ BeanInstanceSupplier.forConstructor(
ResourceLoader.class, String.class, Environment.class));
add(String.class,
- AutowiredInstantiationArgumentsResolver.forFactoryMethod(
+ BeanInstanceSupplier.forFactoryMethod(
MixedArgsFactory.class, "mixedArgs", ResourceLoader.class,
String.class, Environment.class));
}
@@ -639,7 +716,7 @@ class AutowiredInstantiationArgumentsResolverTests {
private final List arguments;
- private Sources() {
+ Sources() {
this.arguments = new ArrayList<>();
setup();
}
@@ -647,7 +724,7 @@ class AutowiredInstantiationArgumentsResolverTests {
protected abstract void setup();
protected final void add(Class> beanClass,
- AutowiredInstantiationArgumentsResolver resolver) {
+ BeanInstanceSupplier resolver) {
this.arguments.add(Arguments.of(new Source(beanClass, resolver)));
}
@@ -657,16 +734,12 @@ class AutowiredInstantiationArgumentsResolverTests {
}
- static class Source {
-
- private final Class> beanClass;
+ static class BeanRegistrar {
- private final AutowiredInstantiationArgumentsResolver resolver;
+ final Class> beanClass;
- public Source(Class> beanClass,
- AutowiredInstantiationArgumentsResolver resolver) {
+ public BeanRegistrar(Class> beanClass) {
this.beanClass = beanClass;
- this.resolver = resolver;
}
RegisteredBean registerBean(DefaultListableBeanFactory beanFactory) {
@@ -685,8 +758,19 @@ class AutowiredInstantiationArgumentsResolverTests {
beanFactory.registerBeanDefinition(beanName, beanDefinition);
return RegisteredBean.of(beanFactory, beanName);
}
+ }
+
+ static class Source extends BeanRegistrar {
+
+ private final BeanInstanceSupplier resolver;
+
+ public Source(Class> beanClass,
+ BeanInstanceSupplier resolver) {
+ super(beanClass);
+ this.resolver = resolver;
+ }
- AutowiredInstantiationArgumentsResolver getResolver() {
+ BeanInstanceSupplier getResolver() {
return this.resolver;
}
@@ -715,7 +799,7 @@ class AutowiredInstantiationArgumentsResolverTests {
}
String getString() {
- return string;
+ return this.string;
}
}
@@ -834,7 +918,7 @@ class AutowiredInstantiationArgumentsResolverTests {
}
- static interface MethodOnInterface {
+ interface MethodOnInterface {
default String test() {
return "Test";
diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/aot/InstanceSupplierCodeGeneratorTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/aot/InstanceSupplierCodeGeneratorTests.java
index de04e7d9ab2..c1a486f2f6a 100644
--- a/spring-beans/src/test/java/org/springframework/beans/factory/aot/InstanceSupplierCodeGeneratorTests.java
+++ b/spring-beans/src/test/java/org/springframework/beans/factory/aot/InstanceSupplierCodeGeneratorTests.java
@@ -172,7 +172,7 @@ class InstanceSupplierCodeGeneratorTests {
instanceSupplier);
assertThat(bean).isInstanceOf(TestBeanWithPrivateConstructor.class);
assertThat(compiled.getSourceFile())
- .contains("resolveAndInstantiate(registeredBean)");
+ .contains("return BeanInstanceSupplier.forConstructor();");
});
assertThat(getReflectionHints().getTypeHint(TestBeanWithPrivateConstructor.class))
.satisfies(hasConstructorWithMode(ExecutableMode.INVOKE));
@@ -211,7 +211,8 @@ class InstanceSupplierCodeGeneratorTests {
assertThat(bean).isInstanceOf(String.class);
assertThat(bean).isEqualTo("Hello");
assertThat(compiled.getSourceFile())
- .contains("resolveAndInstantiate(registeredBean)");
+ .contains("BeanInstanceSupplier.forFactoryMethod")
+ .doesNotContain("withGenerator");
});
assertThat(getReflectionHints().getTypeHint(SimpleConfiguration.class))
.satisfies(hasMethodWithMode(ExecutableMode.INVOKE));
@@ -271,7 +272,7 @@ class InstanceSupplierCodeGeneratorTests {
Integer bean = getBean(beanFactory, beanDefinition, instanceSupplier);
assertThat(bean).isInstanceOf(Integer.class);
assertThat(bean).isEqualTo(42);
- assertThat(compiled.getSourceFile()).contains(") throws Exception {");
+ assertThat(compiled.getSourceFile()).doesNotContain(") throws Exception {");
});
assertThat(getReflectionHints().getTypeHint(SimpleConfiguration.class))
.satisfies(hasMethodWithMode(ExecutableMode.INTROSPECT));
diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/support/RootBeanDefinitionTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/support/RootBeanDefinitionTests.java
new file mode 100644
index 00000000000..7e1a5481b5a
--- /dev/null
+++ b/spring-beans/src/test/java/org/springframework/beans/factory/support/RootBeanDefinitionTests.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2002-2022 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.beans.factory.support;
+
+import java.lang.reflect.Method;
+
+import org.junit.jupiter.api.Test;
+
+import org.springframework.util.ReflectionUtils;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.BDDMockito.given;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+/**
+ * Tests for {@link RootBeanDefinition}.
+ *
+ * @author Stephane Nicoll
+ */
+class RootBeanDefinitionTests {
+
+ @Test
+ void setInstanceSetResolvedFactoryMethod() {
+ InstanceSupplier> instanceSupplier = mock(InstanceSupplier.class);
+ Method method = ReflectionUtils.findMethod(String.class, "toString");
+ given(instanceSupplier.getFactoryMethod()).willReturn(method);
+ RootBeanDefinition beanDefinition = new RootBeanDefinition(String.class);
+ beanDefinition.setInstanceSupplier(instanceSupplier);
+ assertThat(beanDefinition.getResolvedFactoryMethod()).isEqualTo(method);
+ verify(instanceSupplier).getFactoryMethod();
+ }
+
+ @Test
+ void setInstanceDoesNotOverrideResolvedFactoryMethodWithNull() {
+ InstanceSupplier> instanceSupplier = mock(InstanceSupplier.class);
+ given(instanceSupplier.getFactoryMethod()).willReturn(null);
+ Method method = ReflectionUtils.findMethod(String.class, "toString");
+ RootBeanDefinition beanDefinition = new RootBeanDefinition(String.class);
+ beanDefinition.setResolvedFactoryMethod(method);
+ beanDefinition.setInstanceSupplier(instanceSupplier);
+ assertThat(beanDefinition.getResolvedFactoryMethod()).isEqualTo(method);
+ verify(instanceSupplier).getFactoryMethod();
+ }
+
+}