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