diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGenerator.java b/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGenerator.java index 49d7d8083db..3fb42523b14 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGenerator.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGenerator.java @@ -113,26 +113,34 @@ class BeanDefinitionPropertiesCodeGenerator { CodeBlock generateCode(RootBeanDefinition beanDefinition) { CodeBlock.Builder code = CodeBlock.builder(); - addStatementForValue(code, beanDefinition, BeanDefinition::isPrimary, - "$L.setPrimary($L)"); - addStatementForValue(code, beanDefinition, BeanDefinition::isFallback, - "$L.setFallback($L)"); addStatementForValue(code, beanDefinition, BeanDefinition::getScope, this::hasScope, "$L.setScope($S)"); + addStatementForValue(code, beanDefinition, AbstractBeanDefinition::isBackgroundInit, + "$L.setBackgroundInit($L)"); + addStatementForValue(code, beanDefinition, AbstractBeanDefinition::getLazyInit, + "$L.setLazyInit($L)"); addStatementForValue(code, beanDefinition, BeanDefinition::getDependsOn, this::hasDependsOn, "$L.setDependsOn($L)", this::toStringVarArgs); addStatementForValue(code, beanDefinition, BeanDefinition::isAutowireCandidate, "$L.setAutowireCandidate($L)"); - addStatementForValue(code, beanDefinition, BeanDefinition::getRole, - this::hasRole, "$L.setRole($L)", this::toRole); - addStatementForValue(code, beanDefinition, AbstractBeanDefinition::getLazyInit, - "$L.setLazyInit($L)"); + addStatementForValue(code, beanDefinition, AbstractBeanDefinition::isDefaultCandidate, + "$L.setDefaultCandidate($L)"); + addStatementForValue(code, beanDefinition, BeanDefinition::isPrimary, + "$L.setPrimary($L)"); + addStatementForValue(code, beanDefinition, BeanDefinition::isFallback, + "$L.setFallback($L)"); addStatementForValue(code, beanDefinition, AbstractBeanDefinition::isSynthetic, "$L.setSynthetic($L)"); + addStatementForValue(code, beanDefinition, BeanDefinition::getRole, + this::hasRole, "$L.setRole($L)", this::toRole); addInitDestroyMethods(code, beanDefinition, beanDefinition.getInitMethodNames(), "$L.setInitMethodNames($L)"); addInitDestroyMethods(code, beanDefinition, beanDefinition.getDestroyMethodNames(), "$L.setDestroyMethodNames($L)"); + if (beanDefinition.getFactoryBeanName() != null) { + addStatementForValue(code, beanDefinition, BeanDefinition::getFactoryBeanName, + "$L.setFactoryBeanName(\"$L\")"); + } addConstructorArgumentValues(code, beanDefinition); addPropertyValues(code, beanDefinition); addAttributes(code, beanDefinition); @@ -142,6 +150,7 @@ class BeanDefinitionPropertiesCodeGenerator { private void addInitDestroyMethods(Builder code, AbstractBeanDefinition beanDefinition, @Nullable String[] methodNames, String format) { + // For Publisher-based destroy methods this.hints.reflection().registerType(TypeReference.of("org.reactivestreams.Publisher")); if (!ObjectUtils.isEmpty(methodNames)) { @@ -210,7 +219,6 @@ class BeanDefinitionPropertiesCodeGenerator { else if (valueHolder.getType() != null) { code.addStatement("$L.getConstructorArgumentValues().addGenericArgumentValue($L, $S)", BEAN_DEFINITION_VARIABLE, valueCode, valueHolder.getType()); - } else { code.addStatement("$L.getConstructorArgumentValues().addGenericArgumentValue($L)", @@ -224,7 +232,8 @@ class BeanDefinitionPropertiesCodeGenerator { MutablePropertyValues propertyValues = beanDefinition.getPropertyValues(); if (!propertyValues.isEmpty()) { Class infrastructureType = getInfrastructureType(beanDefinition); - Map writeMethods = (infrastructureType != Object.class) ? getWriteMethods(infrastructureType) : Collections.emptyMap(); + Map writeMethods = (infrastructureType != Object.class ? + getWriteMethods(infrastructureType) : Collections.emptyMap()); for (PropertyValue propertyValue : propertyValues) { String name = propertyValue.getName(); CodeBlock valueCode = generateValue(name, propertyValue.getValue()); @@ -266,8 +275,8 @@ class BeanDefinitionPropertiesCodeGenerator { } private CodeBlock generateValue(@Nullable String name, @Nullable Object value) { + PropertyNamesStack.push(name); try { - PropertyNamesStack.push(name); return this.valueCodeGenerator.generateCode(value); } finally { @@ -308,8 +317,7 @@ class BeanDefinitionPropertiesCodeGenerator { } private boolean hasScope(String defaultValue, String actualValue) { - return StringUtils.hasText(actualValue) && - !ConfigurableBeanFactory.SCOPE_SINGLETON.equals(actualValue); + return (StringUtils.hasText(actualValue) && !ConfigurableBeanFactory.SCOPE_SINGLETON.equals(actualValue)); } private boolean hasDependsOn(String[] defaultValue, String[] actualValue) { @@ -335,8 +343,7 @@ class BeanDefinitionPropertiesCodeGenerator { } private void addStatementForValue( - CodeBlock.Builder code, BeanDefinition beanDefinition, - Function getter, String format) { + CodeBlock.Builder code, BeanDefinition beanDefinition, Function getter, String format) { addStatementForValue(code, beanDefinition, getter, (defaultValue, actualValue) -> !Objects.equals(defaultValue, actualValue), format); @@ -351,9 +358,8 @@ class BeanDefinitionPropertiesCodeGenerator { @SuppressWarnings("unchecked") private void addStatementForValue( - CodeBlock.Builder code, BeanDefinition beanDefinition, - Function getter, BiPredicate filter, String format, - Function formatter) { + CodeBlock.Builder code, BeanDefinition beanDefinition, Function getter, + BiPredicate filter, String format, Function formatter) { T defaultValue = getter.apply((B) DEFAULT_BEAN_DEFINITION); T actualValue = getter.apply((B) beanDefinition); @@ -363,9 +369,8 @@ class BeanDefinitionPropertiesCodeGenerator { } /** - * Cast the specified {@code valueCode} to the specified {@code castType} if - * the {@code castNecessary} is {@code true}. Otherwise return the valueCode - * as is. + * Cast the specified {@code valueCode} to the specified {@code castType} if the + * {@code castNecessary} is {@code true}. Otherwise, return the valueCode as-is. * @param castNecessary whether a cast is necessary * @param castType the type to cast to * @param valueCode the code for the value diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanInstanceSupplier.java b/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanInstanceSupplier.java index 8f9d2be63c3..e24d6e072f1 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanInstanceSupplier.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanInstanceSupplier.java @@ -32,9 +32,7 @@ import org.springframework.beans.BeanInstantiationException; import org.springframework.beans.BeanUtils; import org.springframework.beans.BeansException; import org.springframework.beans.TypeConverter; -import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.UnsatisfiedDependencyException; -import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.beans.factory.config.ConstructorArgumentValues; import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder; import org.springframework.beans.factory.config.DependencyDescriptor; @@ -49,7 +47,6 @@ import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.CollectionUtils; -import org.springframework.util.ObjectUtils; import org.springframework.util.ReflectionUtils; import org.springframework.util.function.ThrowingBiFunction; import org.springframework.util.function.ThrowingFunction; @@ -79,6 +76,7 @@ import org.springframework.util.function.ThrowingSupplier; * * @author Phillip Webb * @author Stephane Nicoll + * @author Juergen Hoeller * @since 6.0 * @param the type of instance supplied by this supplier * @see AutowiredArguments @@ -88,19 +86,24 @@ public final class BeanInstanceSupplier extends AutowiredElementResolver impl private final ExecutableLookup lookup; @Nullable - private final ThrowingBiFunction generator; + private final ThrowingFunction generatorWithoutArguments; @Nullable - private final String[] shortcuts; + private final ThrowingBiFunction generatorWithArguments; + + @Nullable + private final String[] shortcutBeanNames; private BeanInstanceSupplier(ExecutableLookup lookup, - @Nullable ThrowingBiFunction generator, - @Nullable String[] shortcuts) { + @Nullable ThrowingFunction generatorWithoutArguments, + @Nullable ThrowingBiFunction generatorWithArguments, + @Nullable String[] shortcutBeanNames) { this.lookup = lookup; - this.generator = generator; - this.shortcuts = shortcuts; + this.generatorWithoutArguments = generatorWithoutArguments; + this.generatorWithArguments = generatorWithArguments; + this.shortcutBeanNames = shortcutBeanNames; } @@ -114,7 +117,7 @@ public final class BeanInstanceSupplier extends AutowiredElementResolver impl public static BeanInstanceSupplier forConstructor(Class... parameterTypes) { Assert.notNull(parameterTypes, "'parameterTypes' must not be null"); Assert.noNullElements(parameterTypes, "'parameterTypes' must not contain null elements"); - return new BeanInstanceSupplier<>(new ConstructorLookup(parameterTypes), null, null); + return new BeanInstanceSupplier<>(new ConstructorLookup(parameterTypes), null, null, null); } /** @@ -135,7 +138,7 @@ public final class BeanInstanceSupplier extends AutowiredElementResolver impl Assert.noNullElements(parameterTypes, "'parameterTypes' must not contain null elements"); return new BeanInstanceSupplier<>( new FactoryMethodLookup(declaringClass, methodName, parameterTypes), - null, null); + null, null, null); } @@ -151,11 +154,9 @@ public final class BeanInstanceSupplier extends AutowiredElementResolver impl * instantiate the underlying bean * @return a new {@link BeanInstanceSupplier} instance with the specified generator */ - public BeanInstanceSupplier withGenerator( - ThrowingBiFunction generator) { - + public BeanInstanceSupplier withGenerator(ThrowingBiFunction generator) { Assert.notNull(generator, "'generator' must not be null"); - return new BeanInstanceSupplier<>(this.lookup, generator, this.shortcuts); + return new BeanInstanceSupplier<>(this.lookup, null, generator, this.shortcutBeanNames); } /** @@ -167,8 +168,7 @@ public final class BeanInstanceSupplier extends AutowiredElementResolver impl */ public BeanInstanceSupplier withGenerator(ThrowingFunction generator) { Assert.notNull(generator, "'generator' must not be null"); - return new BeanInstanceSupplier<>(this.lookup, - (registeredBean, args) -> generator.apply(registeredBean), this.shortcuts); + return new BeanInstanceSupplier<>(this.lookup, generator, null, this.shortcutBeanNames); } /** @@ -181,50 +181,83 @@ public final class BeanInstanceSupplier extends AutowiredElementResolver impl @Deprecated(since = "6.0.11", forRemoval = true) public BeanInstanceSupplier withGenerator(ThrowingSupplier generator) { Assert.notNull(generator, "'generator' must not be null"); - return new BeanInstanceSupplier<>(this.lookup, - (registeredBean, args) -> generator.get(), this.shortcuts); + return new BeanInstanceSupplier<>(this.lookup, registeredBean -> generator.get(), + null, this.shortcutBeanNames); } /** * 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 + * @deprecated in favor of {@link #withShortcut(String...)} */ + @Deprecated(since = "6.2", forRemoval = true) public BeanInstanceSupplier withShortcuts(String... beanNames) { - return new BeanInstanceSupplier<>(this.lookup, this.generator, beanNames); + return withShortcut(beanNames); } + /** + * Return a new {@link BeanInstanceSupplier} instance that uses + * direct bean name injection shortcuts for specific parameters. + * @param beanNames the bean names to use as shortcut (aligned with the + * constructor or factory method parameters) + * @return a new {@link BeanInstanceSupplier} instance that uses the + * given shortcut bean names + * @since 6.2 + */ + public BeanInstanceSupplier withShortcut(String... beanNames) { + return new BeanInstanceSupplier<>( + this.lookup, this.generatorWithoutArguments, this.generatorWithArguments, beanNames); + } + + + @SuppressWarnings("unchecked") @Override - public T get(RegisteredBean registeredBean) throws Exception { + public T get(RegisteredBean registeredBean) { Assert.notNull(registeredBean, "'registeredBean' must not be null"); - Executable executable = this.lookup.get(registeredBean); - AutowiredArguments arguments = resolveArguments(registeredBean, executable); - if (this.generator != null) { - return invokeBeanSupplier(executable, () -> this.generator.apply(registeredBean, arguments)); + if (this.generatorWithoutArguments != null) { + Executable executable = getFactoryMethodForGenerator(); + return invokeBeanSupplier(executable, () -> this.generatorWithoutArguments.apply(registeredBean)); } - return invokeBeanSupplier(executable, - () -> instantiate(registeredBean.getBeanFactory(), executable, arguments.toArray())); - } - - private T invokeBeanSupplier(Executable executable, ThrowingSupplier beanSupplier) { - if (!(executable instanceof Method method)) { - return beanSupplier.get(); + else if (this.generatorWithArguments != null) { + Executable executable = getFactoryMethodForGenerator(); + AutowiredArguments arguments = resolveArguments(registeredBean, + executable != null ? executable : this.lookup.get(registeredBean)); + return invokeBeanSupplier(executable, () -> this.generatorWithArguments.apply(registeredBean, arguments)); + } + else { + Executable executable = this.lookup.get(registeredBean); + Object[] arguments = resolveArguments(registeredBean, executable).toArray(); + return invokeBeanSupplier(executable, () -> (T) instantiate(registeredBean, executable, arguments)); } - return SimpleInstantiationStrategy.instantiateWithFactoryMethod(method, beanSupplier::get); } - @Nullable @Override + @Nullable public Method getFactoryMethod() { + // Cached factory method retrieval for qualifier introspection etc. if (this.lookup instanceof FactoryMethodLookup factoryMethodLookup) { return factoryMethodLookup.get(); } return null; } + @Nullable + private Method getFactoryMethodForGenerator() { + // Avoid unnecessary currentlyInvokedFactoryMethod exposure outside of full configuration classes. + if (this.lookup instanceof FactoryMethodLookup factoryMethodLookup && + factoryMethodLookup.declaringClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) { + return factoryMethodLookup.get(); + } + return null; + } + + private T invokeBeanSupplier(@Nullable Executable executable, ThrowingSupplier beanSupplier) { + if (executable instanceof Method method) { + return SimpleInstantiationStrategy.instantiateWithFactoryMethod(method, beanSupplier); + } + return beanSupplier.get(); + } + /** * Resolve arguments for the specified registered bean. * @param registeredBean the registered bean @@ -236,26 +269,22 @@ public final class BeanInstanceSupplier extends AutowiredElementResolver impl } private AutowiredArguments resolveArguments(RegisteredBean registeredBean, Executable executable) { - Assert.isInstanceOf(AbstractAutowireCapableBeanFactory.class, registeredBean.getBeanFactory()); - - int startIndex = (executable instanceof Constructor constructor && - ClassUtils.isInnerClass(constructor.getDeclaringClass())) ? 1 : 0; int parameterCount = executable.getParameterCount(); - Object[] resolved = new Object[parameterCount - startIndex]; - Assert.isTrue(this.shortcuts == null || this.shortcuts.length == resolved.length, + Object[] resolved = new Object[parameterCount]; + Assert.isTrue(this.shortcutBeanNames == null || this.shortcutBeanNames.length == resolved.length, () -> "'shortcuts' must contain " + resolved.length + " elements"); ValueHolder[] argumentValues = resolveArgumentValues(registeredBean, executable); Set autowiredBeanNames = new LinkedHashSet<>(resolved.length * 2); - for (int i = startIndex; i < parameterCount; i++) { + for (int i = 0; i < parameterCount; i++) { MethodParameter parameter = getMethodParameter(executable, i); DependencyDescriptor descriptor = new DependencyDescriptor(parameter, true); - String shortcut = (this.shortcuts != null ? this.shortcuts[i - startIndex] : null); + String shortcut = (this.shortcutBeanNames != null ? this.shortcutBeanNames[i] : null); if (shortcut != null) { descriptor = new ShortcutDependencyDescriptor(descriptor, shortcut); } ValueHolder argumentValue = argumentValues[i]; - resolved[i - startIndex] = resolveAutowiredArgument( + resolved[i] = resolveAutowiredArgument( registeredBean, descriptor, argumentValue, autowiredBeanNames); } registerDependentBeans(registeredBean.getBeanFactory(), registeredBean.getBeanName(), autowiredBeanNames); @@ -339,62 +368,30 @@ public final class BeanInstanceSupplier extends AutowiredElementResolver impl } } - @SuppressWarnings("unchecked") - private T instantiate(ConfigurableBeanFactory beanFactory, Executable executable, Object[] args) { + private Object instantiate(RegisteredBean registeredBean, Executable executable, Object[] args) { if (executable instanceof Constructor constructor) { - try { - return (T) instantiate(constructor, args); - } - catch (Exception ex) { - throw new BeanInstantiationException(constructor, ex.getMessage(), ex); - } + return BeanUtils.instantiateClass(constructor, args); } if (executable instanceof Method method) { + Object target = null; + String factoryBeanName = registeredBean.getMergedBeanDefinition().getFactoryBeanName(); + if (factoryBeanName != null) { + target = registeredBean.getBeanFactory().getBean(factoryBeanName, method.getDeclaringClass()); + } + else if (!Modifier.isStatic(method.getModifiers())) { + throw new IllegalStateException("Cannot invoke instance method without factoryBeanName: " + method); + } try { - return (T) instantiate(beanFactory, method, args); + ReflectionUtils.makeAccessible(method); + return method.invoke(target, args); } - catch (Exception ex) { + catch (Throwable ex) { throw new BeanInstantiationException(method, ex.getMessage(), ex); } } throw new IllegalStateException("Unsupported executable " + executable.getClass().getName()); } - private Object instantiate(Constructor constructor, Object[] args) throws Exception { - Class declaringClass = constructor.getDeclaringClass(); - if (ClassUtils.isInnerClass(declaringClass)) { - Object enclosingInstance = createInstance(declaringClass.getEnclosingClass()); - args = ObjectUtils.addObjectToArray(args, enclosingInstance, 0); - } - return BeanUtils.instantiateClass(constructor, args); - } - - private Object instantiate(ConfigurableBeanFactory beanFactory, Method method, Object[] args) throws Exception { - Object target = getFactoryMethodTarget(beanFactory, method); - ReflectionUtils.makeAccessible(method); - return method.invoke(target, args); - } - - @Nullable - private Object getFactoryMethodTarget(BeanFactory beanFactory, Method method) { - if (Modifier.isStatic(method.getModifiers())) { - return null; - } - Class declaringClass = method.getDeclaringClass(); - return beanFactory.getBean(declaringClass); - } - - private Object createInstance(Class clazz) throws Exception { - if (!ClassUtils.isInnerClass(clazz)) { - Constructor constructor = clazz.getDeclaredConstructor(); - ReflectionUtils.makeAccessible(constructor); - return constructor.newInstance(); - } - Class enclosingClass = clazz.getEnclosingClass(); - Constructor constructor = clazz.getDeclaredConstructor(enclosingClass); - return constructor.newInstance(createInstance(enclosingClass)); - } - private static String toCommaSeparatedNames(Class... parameterTypes) { return Arrays.stream(parameterTypes).map(Class::getName).collect(Collectors.joining(", ")); @@ -423,12 +420,9 @@ public final class BeanInstanceSupplier extends AutowiredElementResolver impl @Override public Executable get(RegisteredBean registeredBean) { - Class beanClass = registeredBean.getBeanClass(); + Class beanClass = registeredBean.getMergedBeanDefinition().getBeanClass(); try { - Class[] actualParameterTypes = (!ClassUtils.isInnerClass(beanClass)) ? - this.parameterTypes : ObjectUtils.addObjectToArray( - this.parameterTypes, beanClass.getEnclosingClass(), 0); - return beanClass.getDeclaredConstructor(actualParameterTypes); + return beanClass.getDeclaredConstructor(this.parameterTypes); } catch (NoSuchMethodException ex) { throw new IllegalArgumentException( @@ -454,6 +448,9 @@ public final class BeanInstanceSupplier extends AutowiredElementResolver impl private final Class[] parameterTypes; + @Nullable + private volatile Method resolvedMethod; + FactoryMethodLookup(Class declaringClass, String methodName, Class[] parameterTypes) { this.declaringClass = declaringClass; this.methodName = methodName; @@ -466,8 +463,13 @@ public final class BeanInstanceSupplier extends AutowiredElementResolver impl } Method get() { - Method method = ReflectionUtils.findMethod(this.declaringClass, this.methodName, this.parameterTypes); - Assert.notNull(method, () -> "%s cannot be found".formatted(this)); + Method method = this.resolvedMethod; + if (method == null) { + method = ReflectionUtils.findMethod( + ClassUtils.getUserClass(this.declaringClass), this.methodName, this.parameterTypes); + Assert.notNull(method, () -> "%s cannot be found".formatted(this)); + this.resolvedMethod = method; + } return method; } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/aot/DefaultBeanRegistrationCodeFragments.java b/spring-beans/src/main/java/org/springframework/beans/factory/aot/DefaultBeanRegistrationCodeFragments.java index 46f11102ce5..c9ab9247120 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/aot/DefaultBeanRegistrationCodeFragments.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/aot/DefaultBeanRegistrationCodeFragments.java @@ -123,7 +123,7 @@ class DefaultBeanRegistrationCodeFragments implements BeanRegistrationCodeFragme CodeBlock.Builder code = CodeBlock.builder(); RootBeanDefinition mbd = this.registeredBean.getMergedBeanDefinition(); - Class beanClass = (mbd.hasBeanClass() ? ClassUtils.getUserClass(mbd.getBeanClass()) : null); + Class beanClass = (mbd.hasBeanClass() ? mbd.getBeanClass() : null); CodeBlock beanClassCode = generateBeanClassCode( beanRegistrationCode.getClassName().packageName(), (beanClass != null ? beanClass : beanType.toClass())); @@ -158,7 +158,7 @@ class DefaultBeanRegistrationCodeFragments implements BeanRegistrationCodeFragme if (beanClass != null && this.registeredBean.getMergedBeanDefinition().getFactoryMethodName() != null) { return true; } - return (beanClass != null && !beanType.toClass().equals(beanClass)); + return (beanClass != null && !beanType.toClass().equals(ClassUtils.getUserClass(beanClass))); } @Override diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/aot/InstanceSupplierCodeGenerator.java b/spring-beans/src/main/java/org/springframework/beans/factory/aot/InstanceSupplierCodeGenerator.java index d6ee4124dbe..72664945b65 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/aot/InstanceSupplierCodeGenerator.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/aot/InstanceSupplierCodeGenerator.java @@ -20,7 +20,6 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Executable; import java.lang.reflect.Member; import java.lang.reflect.Method; -import java.lang.reflect.Modifier; import java.lang.reflect.Parameter; import java.lang.reflect.Proxy; import java.util.Arrays; @@ -55,6 +54,7 @@ import org.springframework.javapoet.CodeBlock; import org.springframework.javapoet.CodeBlock.Builder; import org.springframework.javapoet.MethodSpec; import org.springframework.javapoet.ParameterizedTypeName; +import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; import org.springframework.util.function.ThrowingSupplier; @@ -83,9 +83,8 @@ public class InstanceSupplierCodeGenerator { private static final String ARGS_PARAMETER_NAME = "args"; - private static final javax.lang.model.element.Modifier[] PRIVATE_STATIC = { - javax.lang.model.element.Modifier.PRIVATE, - javax.lang.model.element.Modifier.STATIC }; + private static final javax.lang.model.element.Modifier[] PRIVATE_STATIC = + {javax.lang.model.element.Modifier.PRIVATE, javax.lang.model.element.Modifier.STATIC}; private static final CodeBlock NO_ARGS = CodeBlock.of(""); @@ -165,28 +164,26 @@ public class InstanceSupplierCodeGenerator { String beanName = registeredBean.getBeanName(); Class beanClass = registeredBean.getBeanClass(); Class declaringClass = constructor.getDeclaringClass(); - boolean dependsOnBean = ClassUtils.isInnerClass(declaringClass); Visibility accessVisibility = getAccessVisibility(registeredBean, constructor); if (KotlinDetector.isKotlinReflectPresent() && KotlinDelegate.hasConstructorWithOptionalParameter(beanClass)) { return generateCodeForInaccessibleConstructor(beanName, beanClass, constructor, - dependsOnBean, hints -> hints.registerType(beanClass, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)); + hints -> hints.registerType(beanClass, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)); } else if (accessVisibility != Visibility.PRIVATE) { - return generateCodeForAccessibleConstructor(beanName, beanClass, constructor, - dependsOnBean, declaringClass); + return generateCodeForAccessibleConstructor(beanName, beanClass, constructor, declaringClass); } - return generateCodeForInaccessibleConstructor(beanName, beanClass, constructor, dependsOnBean, + return generateCodeForInaccessibleConstructor(beanName, beanClass, constructor, hints -> hints.registerConstructor(constructor, ExecutableMode.INVOKE)); } private CodeBlock generateCodeForAccessibleConstructor(String beanName, Class beanClass, - Constructor constructor, boolean dependsOnBean, Class declaringClass) { + Constructor constructor, Class declaringClass) { this.generationContext.getRuntimeHints().reflection().registerConstructor( constructor, ExecutableMode.INTROSPECT); - if (!dependsOnBean && constructor.getParameterCount() == 0) { + if (constructor.getParameterCount() == 0) { if (!this.allowDirectSupplierShortcut) { return CodeBlock.of("$T.using($T::new)", InstanceSupplier.class, declaringClass); } @@ -197,13 +194,13 @@ public class InstanceSupplierCodeGenerator { } GeneratedMethod generatedMethod = generateGetInstanceSupplierMethod(method -> - buildGetInstanceMethodForConstructor(method, beanName, beanClass, constructor, - declaringClass, dependsOnBean, PRIVATE_STATIC)); + buildGetInstanceMethodForConstructor( + method, beanName, beanClass, constructor, declaringClass, PRIVATE_STATIC)); return generateReturnStatement(generatedMethod); } private CodeBlock generateCodeForInaccessibleConstructor(String beanName, Class beanClass, - Constructor constructor, boolean dependsOnBean, Consumer hints) { + Constructor constructor, Consumer hints) { CodeWarnings codeWarnings = new CodeWarnings(); codeWarnings.detectDeprecation(beanClass, constructor) @@ -215,8 +212,7 @@ public class InstanceSupplierCodeGenerator { method.addModifiers(PRIVATE_STATIC); codeWarnings.suppress(method); method.returns(ParameterizedTypeName.get(BeanInstanceSupplier.class, beanClass)); - int parameterOffset = (!dependsOnBean) ? 0 : 1; - method.addStatement(generateResolverForConstructor(beanClass, constructor, parameterOffset)); + method.addStatement(generateResolverForConstructor(beanClass, constructor)); }); return generateReturnStatement(generatedMethod); @@ -224,7 +220,7 @@ public class InstanceSupplierCodeGenerator { private void buildGetInstanceMethodForConstructor(MethodSpec.Builder method, String beanName, Class beanClass, Constructor constructor, Class declaringClass, - boolean dependsOnBean, javax.lang.model.element.Modifier... modifiers) { + javax.lang.model.element.Modifier... modifiers) { CodeWarnings codeWarnings = new CodeWarnings(); codeWarnings.detectDeprecation(beanClass, constructor, declaringClass) @@ -234,72 +230,58 @@ public class InstanceSupplierCodeGenerator { codeWarnings.suppress(method); method.returns(ParameterizedTypeName.get(BeanInstanceSupplier.class, beanClass)); - int parameterOffset = (!dependsOnBean) ? 0 : 1; CodeBlock.Builder code = CodeBlock.builder(); - code.add(generateResolverForConstructor(beanClass, constructor, parameterOffset)); + code.add(generateResolverForConstructor(beanClass, constructor)); boolean hasArguments = constructor.getParameterCount() > 0; CodeBlock arguments = hasArguments ? new AutowiredArgumentsCodeGenerator(declaringClass, constructor) - .generateCode(constructor.getParameterTypes(), parameterOffset) + .generateCode(constructor.getParameterTypes()) : NO_ARGS; - CodeBlock newInstance = generateNewInstanceCodeForConstructor(dependsOnBean, declaringClass, arguments); + CodeBlock newInstance = generateNewInstanceCodeForConstructor(declaringClass, arguments); code.add(generateWithGeneratorCode(hasArguments, newInstance)); method.addStatement(code.build()); } - private CodeBlock generateResolverForConstructor(Class beanClass, - Constructor constructor, int parameterOffset) { - - CodeBlock parameterTypes = generateParameterTypesCode(constructor.getParameterTypes(), parameterOffset); + private CodeBlock generateResolverForConstructor(Class beanClass, Constructor constructor) { + CodeBlock parameterTypes = generateParameterTypesCode(constructor.getParameterTypes()); return CodeBlock.of("return $T.<$T>forConstructor($L)", BeanInstanceSupplier.class, beanClass, parameterTypes); } - private CodeBlock generateNewInstanceCodeForConstructor(boolean dependsOnBean, - Class declaringClass, CodeBlock args) { - - if (!dependsOnBean) { - return CodeBlock.of("new $T($L)", declaringClass, args); - } - - return CodeBlock.of("$L.getBeanFactory().getBean($T.class).new $L($L)", - REGISTERED_BEAN_PARAMETER_NAME, declaringClass.getEnclosingClass(), - declaringClass.getSimpleName(), args); + private CodeBlock generateNewInstanceCodeForConstructor(Class declaringClass, CodeBlock args) { + return CodeBlock.of("new $T($L)", declaringClass, args); } - private CodeBlock generateCodeForFactoryMethod(RegisteredBean registeredBean, Method factoryMethod, Class targetClass) { - String beanName = registeredBean.getBeanName(); - Class targetClassToUse = ClassUtils.getUserClass(targetClass); - boolean dependsOnBean = !Modifier.isStatic(factoryMethod.getModifiers()); + private CodeBlock generateCodeForFactoryMethod( + RegisteredBean registeredBean, Method factoryMethod, Class targetClass) { Visibility accessVisibility = getAccessVisibility(registeredBean, factoryMethod); if (accessVisibility != Visibility.PRIVATE) { - return generateCodeForAccessibleFactoryMethod( - beanName, factoryMethod, targetClassToUse, dependsOnBean); + return generateCodeForAccessibleFactoryMethod(registeredBean.getBeanName(), factoryMethod, targetClass, + registeredBean.getMergedBeanDefinition().getFactoryBeanName()); } - return generateCodeForInaccessibleFactoryMethod(beanName, factoryMethod, targetClassToUse); + return generateCodeForInaccessibleFactoryMethod(registeredBean.getBeanName(), factoryMethod, targetClass); } private CodeBlock generateCodeForAccessibleFactoryMethod(String beanName, - Method factoryMethod, Class targetClass, boolean dependsOnBean) { + Method factoryMethod, Class targetClass, @Nullable String factoryBeanName) { - this.generationContext.getRuntimeHints().reflection().registerMethod( - factoryMethod, ExecutableMode.INTROSPECT); + this.generationContext.getRuntimeHints().reflection().registerMethod(factoryMethod, ExecutableMode.INTROSPECT); - if (!dependsOnBean && factoryMethod.getParameterCount() == 0) { + if (factoryBeanName == null && factoryMethod.getParameterCount() == 0) { Class suppliedType = ClassUtils.resolvePrimitiveIfNecessary(factoryMethod.getReturnType()); CodeBlock.Builder code = CodeBlock.builder(); code.add("$T.<$T>forFactoryMethod($T.class, $S)", BeanInstanceSupplier.class, suppliedType, targetClass, factoryMethod.getName()); code.add(".withGenerator(($L) -> $T.$L())", REGISTERED_BEAN_PARAMETER_NAME, - targetClass, factoryMethod.getName()); + ClassUtils.getUserClass(targetClass), factoryMethod.getName()); return code.build(); } GeneratedMethod getInstanceMethod = generateGetInstanceSupplierMethod(method -> buildGetInstanceMethodForFactoryMethod(method, beanName, factoryMethod, - targetClass, dependsOnBean, PRIVATE_STATIC)); + targetClass, factoryBeanName, PRIVATE_STATIC)); return generateReturnStatement(getInstanceMethod); } @@ -320,12 +302,12 @@ public class InstanceSupplierCodeGenerator { private void buildGetInstanceMethodForFactoryMethod(MethodSpec.Builder method, String beanName, Method factoryMethod, Class targetClass, - boolean dependsOnBean, javax.lang.model.element.Modifier... modifiers) { + @Nullable String factoryBeanName, javax.lang.model.element.Modifier... modifiers) { String factoryMethodName = factoryMethod.getName(); Class suppliedType = ClassUtils.resolvePrimitiveIfNecessary(factoryMethod.getReturnType()); CodeWarnings codeWarnings = new CodeWarnings(); - codeWarnings.detectDeprecation(targetClass, factoryMethod, suppliedType) + codeWarnings.detectDeprecation(ClassUtils.getUserClass(targetClass), factoryMethod, suppliedType) .detectDeprecation(Arrays.stream(factoryMethod.getParameters()).map(Parameter::getType)); method.addJavadoc("Get the bean instance supplier for '$L'.", beanName); @@ -339,12 +321,12 @@ public class InstanceSupplierCodeGenerator { boolean hasArguments = factoryMethod.getParameterCount() > 0; CodeBlock arguments = hasArguments ? - new AutowiredArgumentsCodeGenerator(targetClass, factoryMethod) + new AutowiredArgumentsCodeGenerator(ClassUtils.getUserClass(targetClass), factoryMethod) .generateCode(factoryMethod.getParameterTypes()) : NO_ARGS; CodeBlock newInstance = generateNewInstanceCodeForMethod( - dependsOnBean, targetClass, factoryMethodName, arguments); + factoryBeanName, ClassUtils.getUserClass(targetClass), factoryMethodName, arguments); code.add(generateWithGeneratorCode(hasArguments, newInstance)); method.addStatement(code.build()); } @@ -357,19 +339,19 @@ public class InstanceSupplierCodeGenerator { BeanInstanceSupplier.class, suppliedType, targetClass, factoryMethodName); } - CodeBlock parameterTypes = generateParameterTypesCode(factoryMethod.getParameterTypes(), 0); + CodeBlock parameterTypes = generateParameterTypesCode(factoryMethod.getParameterTypes()); return CodeBlock.of("return $T.<$T>forFactoryMethod($T.class, $S, $L)", BeanInstanceSupplier.class, suppliedType, targetClass, factoryMethodName, parameterTypes); } - private CodeBlock generateNewInstanceCodeForMethod(boolean dependsOnBean, + private CodeBlock generateNewInstanceCodeForMethod(@Nullable String factoryBeanName, Class targetClass, String factoryMethodName, CodeBlock args) { - if (!dependsOnBean) { + if (factoryBeanName == null) { return CodeBlock.of("$T.$L($L)", targetClass, factoryMethodName, args); } - return CodeBlock.of("$L.getBeanFactory().getBean($T.class).$L($L)", - REGISTERED_BEAN_PARAMETER_NAME, targetClass, factoryMethodName, args); + return CodeBlock.of("$L.getBeanFactory().getBean(\"$L\", $T.class).$L($L)", + REGISTERED_BEAN_PARAMETER_NAME, factoryBeanName, targetClass, factoryMethodName, args); } private CodeBlock generateReturnStatement(GeneratedMethod generatedMethod) { @@ -395,10 +377,10 @@ public class InstanceSupplierCodeGenerator { return AccessControl.lowest(beanTypeAccessControl, memberAccessControl).getVisibility(); } - private CodeBlock generateParameterTypesCode(Class[] parameterTypes, int offset) { + private CodeBlock generateParameterTypesCode(Class[] parameterTypes) { CodeBlock.Builder code = CodeBlock.builder(); - for (int i = offset; i < parameterTypes.length; i++) { - code.add(i != offset ? ", " : ""); + for (int i = 0; i < parameterTypes.length; i++) { + code.add(i > 0 ? ", " : ""); code.add("$T.class", parameterTypes[i]); } return code.build(); diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java index dca421b9a37..4b1598e06e7 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java @@ -375,7 +375,7 @@ public class RootBeanDefinition extends AbstractBeanDefinition { if (returnType != null) { return returnType; } - Method factoryMethod = this.factoryMethodToIntrospect; + Method factoryMethod = getResolvedFactoryMethod(); if (factoryMethod != null) { return ResolvableType.forMethodReturnType(factoryMethod); } @@ -453,17 +453,12 @@ public class RootBeanDefinition extends AbstractBeanDefinition { */ @Nullable public Method getResolvedFactoryMethod() { - return this.factoryMethodToIntrospect; - } - - @Override - public void setInstanceSupplier(@Nullable Supplier supplier) { - super.setInstanceSupplier(supplier); - Method factoryMethod = (supplier instanceof InstanceSupplier instanceSupplier ? - instanceSupplier.getFactoryMethod() : null); - if (factoryMethod != null) { - setResolvedFactoryMethod(factoryMethod); + Method factoryMethod = this.factoryMethodToIntrospect; + if (factoryMethod == null && + getInstanceSupplier() instanceof InstanceSupplier instanceSupplier) { + factoryMethod = instanceSupplier.getFactoryMethod(); } + return factoryMethod; } /** diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/SimpleInstantiationStrategy.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/SimpleInstantiationStrategy.java index f4a59401aed..aec5fadd4ab 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/SimpleInstantiationStrategy.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/SimpleInstantiationStrategy.java @@ -19,6 +19,7 @@ package org.springframework.beans.factory.support; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.function.Supplier; import org.springframework.beans.BeanInstantiationException; import org.springframework.beans.BeanUtils; @@ -27,7 +28,6 @@ import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.lang.Nullable; import org.springframework.util.ReflectionUtils; import org.springframework.util.StringUtils; -import org.springframework.util.function.ThrowingSupplier; /** * Simple object instantiation strategy for use in a BeanFactory. @@ -60,7 +60,7 @@ public class SimpleInstantiationStrategy implements InstantiationStrategy { * the current value, if any. * @param method the factory method currently being invoked or {@code null} * @since 6.0 - * @deprecated in favor of {@link #instantiateWithFactoryMethod(Method, ThrowingSupplier)} + * @deprecated in favor of {@link #instantiateWithFactoryMethod(Method, Supplier)} */ @Deprecated(since = "6.2", forRemoval = true) public static void setCurrentlyInvokedFactoryMethod(@Nullable Method method) { @@ -81,7 +81,7 @@ public class SimpleInstantiationStrategy implements InstantiationStrategy { * @return the result of the instance supplier * @since 6.2 */ - public static T instantiateWithFactoryMethod(Method method, ThrowingSupplier instanceSupplier) { + public static T instantiateWithFactoryMethod(Method method, Supplier instanceSupplier) { Method priorInvokedFactoryMethod = currentlyInvokedFactoryMethod.get(); try { currentlyInvokedFactoryMethod.set(method); diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanInstanceSupplierTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanInstanceSupplierTests.java index 620f09421a0..078bbee216c 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanInstanceSupplierTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanInstanceSupplierTests.java @@ -53,6 +53,8 @@ import org.springframework.beans.factory.support.InstanceSupplier; import org.springframework.beans.factory.support.RegisteredBean; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.support.SimpleInstantiationStrategy; +import org.springframework.cglib.proxy.Enhancer; +import org.springframework.cglib.proxy.NoOp; import org.springframework.core.env.Environment; import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.ResourceLoader; @@ -79,26 +81,24 @@ class BeanInstanceSupplierTests { private final DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); + @Test void forConstructorWhenParameterTypesIsNullThrowsException() { assertThatIllegalArgumentException() - .isThrownBy(() -> BeanInstanceSupplier - .forConstructor((Class[]) null)) + .isThrownBy(() -> BeanInstanceSupplier.forConstructor((Class[]) null)) .withMessage("'parameterTypes' must not be null"); } @Test void forConstructorWhenParameterTypesContainsNullThrowsException() { assertThatIllegalArgumentException() - .isThrownBy(() -> BeanInstanceSupplier - .forConstructor(String.class, null)) + .isThrownBy(() -> BeanInstanceSupplier.forConstructor(String.class, null)) .withMessage("'parameterTypes' must not contain null elements"); } @Test void forConstructorWhenNotFoundThrowsException() { - BeanInstanceSupplier resolver = BeanInstanceSupplier - .forConstructor(InputStream.class); + BeanInstanceSupplier resolver = BeanInstanceSupplier.forConstructor(InputStream.class); Source source = new Source(SingleArgConstructor.class, resolver); RegisteredBean registerBean = source.registerBean(this.beanFactory); assertThatIllegalArgumentException() @@ -116,41 +116,37 @@ class BeanInstanceSupplierTests { @Test void forFactoryMethodWhenDeclaringClassIsNullThrowsException() { assertThatIllegalArgumentException() - .isThrownBy(() -> BeanInstanceSupplier - .forFactoryMethod(null, "test")) + .isThrownBy(() -> BeanInstanceSupplier.forFactoryMethod(null, "test")) .withMessage("'declaringClass' must not be null"); } @Test void forFactoryMethodWhenNameIsEmptyThrowsException() { assertThatIllegalArgumentException() - .isThrownBy(() -> BeanInstanceSupplier - .forFactoryMethod(SingleArgFactory.class, "")) + .isThrownBy(() -> BeanInstanceSupplier.forFactoryMethod(SingleArgFactory.class, "")) .withMessage("'methodName' must not be empty"); } @Test void forFactoryMethodWhenParameterTypesIsNullThrowsException() { assertThatIllegalArgumentException() - .isThrownBy( - () -> BeanInstanceSupplier.forFactoryMethod( - SingleArgFactory.class, "single", (Class[]) null)) + .isThrownBy(() -> BeanInstanceSupplier.forFactoryMethod( + SingleArgFactory.class, "single", (Class[]) null)) .withMessage("'parameterTypes' must not be null"); } @Test void forFactoryMethodWhenParameterTypesContainsNullThrowsException() { assertThatIllegalArgumentException() - .isThrownBy( - () -> BeanInstanceSupplier.forFactoryMethod( - SingleArgFactory.class, "single", String.class, null)) + .isThrownBy(() -> BeanInstanceSupplier.forFactoryMethod( + SingleArgFactory.class, "single", String.class, null)) .withMessage("'parameterTypes' must not contain null elements"); } @Test void forFactoryMethodWhenNotFoundThrowsException() { - BeanInstanceSupplier resolver = BeanInstanceSupplier - .forFactoryMethod(SingleArgFactory.class, "single", InputStream.class); + BeanInstanceSupplier resolver = BeanInstanceSupplier.forFactoryMethod( + SingleArgFactory.class, "single", InputStream.class); Source source = new Source(String.class, resolver); RegisteredBean registerBean = source.registerBean(this.beanFactory); assertThatIllegalArgumentException() @@ -161,8 +157,8 @@ class BeanInstanceSupplierTests { @Test void forFactoryMethodReturnsFactoryMethod() { - BeanInstanceSupplier resolver = BeanInstanceSupplier - .forFactoryMethod(SingleArgFactory.class, "single", String.class); + BeanInstanceSupplier resolver = BeanInstanceSupplier.forFactoryMethod( + SingleArgFactory.class, "single", String.class); Method factoryMethod = ReflectionUtils.findMethod(SingleArgFactory.class, "single", String.class); assertThat(factoryMethod).isNotNull(); assertThat(resolver.getFactoryMethod()).isEqualTo(factoryMethod); @@ -170,21 +166,17 @@ class BeanInstanceSupplierTests { @Test void withGeneratorWhenBiFunctionIsNullThrowsException() { - BeanInstanceSupplier resolver = BeanInstanceSupplier - .forConstructor(); + BeanInstanceSupplier resolver = BeanInstanceSupplier.forConstructor(); assertThatIllegalArgumentException() - .isThrownBy(() -> resolver.withGenerator( - (ThrowingBiFunction) null)) + .isThrownBy(() -> resolver.withGenerator((ThrowingBiFunction) null)) .withMessage("'generator' must not be null"); } @Test void withGeneratorWhenFunctionIsNullThrowsException() { - BeanInstanceSupplier resolver = BeanInstanceSupplier - .forConstructor(); + BeanInstanceSupplier resolver = BeanInstanceSupplier.forConstructor(); assertThatIllegalArgumentException() - .isThrownBy(() -> resolver.withGenerator( - (ThrowingFunction) null)) + .isThrownBy(() -> resolver.withGenerator((ThrowingFunction) null)) .withMessage("'generator' must not be null"); } @@ -192,23 +184,20 @@ class BeanInstanceSupplierTests { @Deprecated @SuppressWarnings("removal") void withGeneratorWhenSupplierIsNullThrowsException() { - BeanInstanceSupplier resolver = BeanInstanceSupplier - .forConstructor(); + BeanInstanceSupplier resolver = BeanInstanceSupplier.forConstructor(); assertThatIllegalArgumentException() - .isThrownBy(() -> resolver.withGenerator( - (ThrowingSupplier) null)) + .isThrownBy(() -> resolver.withGenerator((ThrowingSupplier) null)) .withMessage("'generator' must not be null"); } @Test - void getWithConstructorDoesNotSetResolvedFactoryMethod() throws Exception { - BeanInstanceSupplier resolver = BeanInstanceSupplier - .forConstructor(String.class); + void getWithConstructorDoesNotSetResolvedFactoryMethod() { + BeanInstanceSupplier resolver = BeanInstanceSupplier.forConstructor(String.class); this.beanFactory.registerSingleton("one", "1"); Source source = new Source(SingleArgConstructor.class, resolver); RegisteredBean registerBean = source.registerBean(this.beanFactory); assertThat(registerBean.getMergedBeanDefinition().getResolvedFactoryMethod()).isNull(); - source.getResolver().get(registerBean); + source.getSupplier().get(registerBean); assertThat(registerBean.getMergedBeanDefinition().getResolvedFactoryMethod()).isNull(); } @@ -218,20 +207,19 @@ class BeanInstanceSupplierTests { 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); + RootBeanDefinition bd = new RootBeanDefinition(String.class); + assertThat(bd.getResolvedFactoryMethod()).isNull(); + bd.setInstanceSupplier(resolver); + assertThat(bd.getResolvedFactoryMethod()).isEqualTo(factoryMethod); } @Test - void getWithGeneratorCallsBiFunction() throws Exception { + void getWithGeneratorCallsBiFunction() { BeanRegistrar registrar = new BeanRegistrar(SingleArgConstructor.class); this.beanFactory.registerSingleton("one", "1"); RegisteredBean registerBean = registrar.registerBean(this.beanFactory); List result = new ArrayList<>(); - BeanInstanceSupplier resolver = BeanInstanceSupplier - .forConstructor(String.class) + BeanInstanceSupplier resolver = BeanInstanceSupplier.forConstructor(String.class) .withGenerator((registeredBean, args) -> result.add(args)); resolver.get(registerBean); assertThat(result).hasSize(1); @@ -239,12 +227,11 @@ class BeanInstanceSupplierTests { } @Test - void getWithGeneratorCallsFunction() throws Exception { + void getWithGeneratorCallsFunction() { BeanRegistrar registrar = new BeanRegistrar(SingleArgConstructor.class); this.beanFactory.registerSingleton("one", "1"); RegisteredBean registerBean = registrar.registerBean(this.beanFactory); - BeanInstanceSupplier resolver = BeanInstanceSupplier - .forConstructor(String.class) + BeanInstanceSupplier resolver = BeanInstanceSupplier.forConstructor(String.class) .withGenerator(registeredBean -> "1"); assertThat(resolver.get(registerBean)).isInstanceOf(String.class).isEqualTo("1"); } @@ -252,30 +239,28 @@ class BeanInstanceSupplierTests { @Test @Deprecated @SuppressWarnings("removal") - void getWithGeneratorCallsSupplier() throws Exception { + void getWithGeneratorCallsSupplier() { BeanRegistrar registrar = new BeanRegistrar(SingleArgConstructor.class); this.beanFactory.registerSingleton("one", "1"); RegisteredBean registerBean = registrar.registerBean(this.beanFactory); - BeanInstanceSupplier resolver = BeanInstanceSupplier - .forConstructor(String.class) + 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); + BeanInstanceSupplier resolver = BeanInstanceSupplier.forConstructor(String.class); assertThatIllegalArgumentException().isThrownBy(() -> resolver.get((RegisteredBean) null)) .withMessage("'registeredBean' must not be null"); } @ParameterizedResolverTest(Sources.SINGLE_ARG) - void getWithNoGeneratorUsesReflection(Source source) throws Exception { + void getWithNoGeneratorUsesReflection(Source source) { this.beanFactory.registerSingleton("one", "1"); this.beanFactory.registerSingleton("testFactory", new SingleArgFactory()); - RegisteredBean registerBean = source.registerBean(this.beanFactory); - Object instance = source.getResolver().get(registerBean); + RegisteredBean registerBean = source.registerBean(this.beanFactory, bd -> bd.setFactoryBeanName("testFactory")); + Object instance = source.getSupplier().get(registerBean); if (instance instanceof SingleArgConstructor singleArgConstructor) { instance = singleArgConstructor.getString(); } @@ -283,32 +268,38 @@ class BeanInstanceSupplierTests { } @ParameterizedResolverTest(Sources.INNER_CLASS_SINGLE_ARG) - void getNestedWithNoGeneratorUsesReflection(Source source) throws Exception { + void getNestedWithNoGeneratorUsesReflection(Source source) { this.beanFactory.registerSingleton("one", "1"); - this.beanFactory.registerSingleton("testFactory", - new Enclosing().new InnerSingleArgFactory()); - RegisteredBean registerBean = source.registerBean(this.beanFactory); - Object instance = source.getResolver().get(registerBean); + this.beanFactory.registerSingleton("testFactory", new Enclosing.InnerSingleArgFactory()); + RegisteredBean registerBean = source.registerBean(this.beanFactory, bd -> bd.setFactoryBeanName("testFactory")); + Object instance = source.getSupplier().get(registerBean); if (instance instanceof InnerSingleArgConstructor innerSingleArgConstructor) { instance = innerSingleArgConstructor.getString(); } assertThat(instance).isEqualTo("1"); } - @Test // gh-33180 - void getWithNestedInvocationRetainsFactoryMethod() throws Exception { + @Test // gh-33180 + void getWithNestedInvocationRetainsFactoryMethod() { AtomicReference testMethodReference = new AtomicReference<>(); AtomicReference anotherMethodReference = new AtomicReference<>(); + Enhancer enhancer = new Enhancer(); + enhancer.setCallbackType(NoOp.class); + enhancer.setSuperclass(AnotherTestStringFactory.class); + Class nestedSupplierClass = enhancer.createClass(); + enhancer.setSuperclass(TestStringFactory.class); + Class supplierClass = enhancer.createClass(); + BeanInstanceSupplier nestedInstanceSupplier = BeanInstanceSupplier - .forFactoryMethod(AnotherTestStringFactory.class, "another") + .forFactoryMethod(nestedSupplierClass, "another") .withGenerator(registeredBean -> { anotherMethodReference.set(SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod()); return "Another"; }); RegisteredBean nestedRegisteredBean = new Source(String.class, nestedInstanceSupplier).registerBean(this.beanFactory); BeanInstanceSupplier instanceSupplier = BeanInstanceSupplier - .forFactoryMethod(TestStringFactory.class, "test") + .forFactoryMethod(supplierClass, "test") .withGenerator(registeredBean -> { Object nested = nestedInstanceSupplier.get(nestedRegisteredBean); testMethodReference.set(SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod()); @@ -324,12 +315,10 @@ class BeanInstanceSupplierTests { @Test void resolveArgumentsWithNoArgConstructor() { - RootBeanDefinition beanDefinition = new RootBeanDefinition( - NoArgConstructor.class); - this.beanFactory.registerBeanDefinition("test", beanDefinition); + RootBeanDefinition bd = new RootBeanDefinition(NoArgConstructor.class); + this.beanFactory.registerBeanDefinition("test", bd); RegisteredBean registeredBean = RegisteredBean.of(this.beanFactory, "test"); - AutowiredArguments resolved = BeanInstanceSupplier - .forConstructor().resolveArguments(registeredBean); + AutowiredArguments resolved = BeanInstanceSupplier.forConstructor().resolveArguments(registeredBean); assertThat(resolved.toArray()).isEmpty(); } @@ -337,7 +326,7 @@ class BeanInstanceSupplierTests { void resolveArgumentsWithSingleArgConstructor(Source source) { this.beanFactory.registerSingleton("one", "1"); RegisteredBean registeredBean = source.registerBean(this.beanFactory); - assertThat(source.getResolver().resolveArguments(registeredBean).toArray()) + assertThat(source.getSupplier().resolveArguments(registeredBean).toArray()) .containsExactly("1"); } @@ -345,16 +334,15 @@ class BeanInstanceSupplierTests { void resolveArgumentsWithNestedSingleArgConstructor(Source source) { this.beanFactory.registerSingleton("one", "1"); RegisteredBean registeredBean = source.registerBean(this.beanFactory); - assertThat(source.getResolver().resolveArguments(registeredBean).toArray()) + assertThat(source.getSupplier().resolveArguments(registeredBean).toArray()) .containsExactly("1"); } @ParameterizedResolverTest(Sources.SINGLE_ARG) - void resolveArgumentsWithRequiredDependencyNotPresentThrowsUnsatisfiedDependencyException( - Source source) { + void resolveArgumentsWithRequiredDependencyNotPresentThrowsUnsatisfiedDependencyException(Source source) { RegisteredBean registeredBean = source.registerBean(this.beanFactory); assertThatExceptionOfType(UnsatisfiedDependencyException.class) - .isThrownBy(() -> source.getResolver().resolveArguments(registeredBean)) + .isThrownBy(() -> source.getSupplier().resolveArguments(registeredBean)) .satisfies(ex -> { assertThat(ex.getBeanName()).isEqualTo("testBean"); assertThat(ex.getInjectionPoint()).isNotNull(); @@ -368,14 +356,14 @@ class BeanInstanceSupplierTests { // SingleArgFactory.single(...) expects a String to be injected // and our own bean is a String, so it's a valid candidate this.beanFactory.addBeanPostProcessor(new AutowiredAnnotationBeanPostProcessor()); - RootBeanDefinition beanDefinition = new RootBeanDefinition(String.class); - beanDefinition.setInstanceSupplier(InstanceSupplier.of(registeredBean -> { + RootBeanDefinition bd = new RootBeanDefinition(String.class); + bd.setInstanceSupplier(InstanceSupplier.of(registeredBean -> { AutowiredArguments args = BeanInstanceSupplier .forFactoryMethod(SingleArgFactory.class, "single", String.class) .resolveArguments(registeredBean); return new SingleArgFactory().single(args.get(0)); })); - this.beanFactory.registerBeanDefinition("test", beanDefinition); + this.beanFactory.registerBeanDefinition("test", bd); assertThatExceptionOfType(UnsatisfiedDependencyException.class) .isThrownBy(() -> this.beanFactory.getBean("test")); } @@ -385,7 +373,7 @@ class BeanInstanceSupplierTests { this.beanFactory.registerSingleton("one", "1"); this.beanFactory.registerSingleton("two", "2"); RegisteredBean registerBean = source.registerBean(this.beanFactory); - AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean); + AutowiredArguments arguments = source.getSupplier().resolveArguments(registerBean); assertThat(arguments.toArray()).hasSize(1); assertThat((Object[]) arguments.get(0)).containsExactly("1", "2"); } @@ -393,7 +381,7 @@ class BeanInstanceSupplierTests { @ParameterizedResolverTest(Sources.ARRAY_OF_BEANS) void resolveArgumentsWithRequiredArrayOfBeansInjectEmptyArray(Source source) { RegisteredBean registerBean = source.registerBean(this.beanFactory); - AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean); + AutowiredArguments arguments = source.getSupplier().resolveArguments(registerBean); assertThat(arguments.toArray()).hasSize(1); assertThat((Object[]) arguments.get(0)).isEmpty(); } @@ -403,7 +391,7 @@ class BeanInstanceSupplierTests { this.beanFactory.registerSingleton("one", "1"); this.beanFactory.registerSingleton("two", "2"); RegisteredBean registerBean = source.registerBean(this.beanFactory); - AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean); + AutowiredArguments arguments = source.getSupplier().resolveArguments(registerBean); assertThat(arguments.toArray()).hasSize(1); assertThat(arguments.getObject(0)).isInstanceOf(List.class).asInstanceOf(LIST) .containsExactly("1", "2"); @@ -412,7 +400,7 @@ class BeanInstanceSupplierTests { @ParameterizedResolverTest(Sources.LIST_OF_BEANS) void resolveArgumentsWithRequiredListOfBeansInjectEmptyList(Source source) { RegisteredBean registerBean = source.registerBean(this.beanFactory); - AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean); + AutowiredArguments arguments = source.getSupplier().resolveArguments(registerBean); assertThat(arguments.toArray()).hasSize(1); assertThat((List) arguments.get(0)).isEmpty(); } @@ -423,7 +411,7 @@ class BeanInstanceSupplierTests { this.beanFactory.registerSingleton("one", "1"); this.beanFactory.registerSingleton("two", "2"); RegisteredBean registerBean = source.registerBean(this.beanFactory); - AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean); + AutowiredArguments arguments = source.getSupplier().resolveArguments(registerBean); assertThat(arguments.toArray()).hasSize(1); assertThat((Set) arguments.get(0)).containsExactly("1", "2"); } @@ -431,7 +419,7 @@ class BeanInstanceSupplierTests { @ParameterizedResolverTest(Sources.SET_OF_BEANS) void resolveArgumentsWithRequiredSetOfBeansInjectEmptySet(Source source) { RegisteredBean registerBean = source.registerBean(this.beanFactory); - AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean); + AutowiredArguments arguments = source.getSupplier().resolveArguments(registerBean); assertThat(arguments.toArray()).hasSize(1); assertThat((Set) arguments.get(0)).isEmpty(); } @@ -442,7 +430,7 @@ class BeanInstanceSupplierTests { this.beanFactory.registerSingleton("one", "1"); this.beanFactory.registerSingleton("two", "2"); RegisteredBean registerBean = source.registerBean(this.beanFactory); - AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean); + AutowiredArguments arguments = source.getSupplier().resolveArguments(registerBean); assertThat(arguments.toArray()).hasSize(1); assertThat((Map) arguments.get(0)) .containsExactly(entry("one", "1"), entry("two", "2")); @@ -451,7 +439,7 @@ class BeanInstanceSupplierTests { @ParameterizedResolverTest(Sources.MAP_OF_BEANS) void resolveArgumentsWithRequiredMapOfBeansInjectEmptySet(Source source) { RegisteredBean registerBean = source.registerBean(this.beanFactory); - AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean); + AutowiredArguments arguments = source.getSupplier().resolveArguments(registerBean); assertThat(arguments.toArray()).hasSize(1); assertThat((Map) arguments.get(0)).isEmpty(); } @@ -460,17 +448,15 @@ class BeanInstanceSupplierTests { void resolveArgumentsWithMultiArgsConstructor(Source source) { ResourceLoader resourceLoader = new DefaultResourceLoader(); Environment environment = mock(); - this.beanFactory.registerResolvableDependency(ResourceLoader.class, - resourceLoader); + this.beanFactory.registerResolvableDependency(ResourceLoader.class, resourceLoader); this.beanFactory.registerSingleton("environment", environment); this.beanFactory.registerSingleton("one", "1"); RegisteredBean registerBean = source.registerBean(this.beanFactory); - AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean); + AutowiredArguments arguments = source.getSupplier().resolveArguments(registerBean); assertThat(arguments.toArray()).hasSize(3); assertThat(arguments.getObject(0)).isEqualTo(resourceLoader); assertThat(arguments.getObject(1)).isEqualTo(environment); - assertThat(((ObjectProvider) arguments.get(2)).getIfAvailable()) - .isEqualTo("1"); + assertThat(((ObjectProvider) arguments.get(2)).getIfAvailable()).isEqualTo("1"); } @ParameterizedResolverTest(Sources.MIXED_ARGS) @@ -481,13 +467,11 @@ class BeanInstanceSupplierTests { resourceLoader); this.beanFactory.registerSingleton("environment", environment); RegisteredBean registerBean = source.registerBean(this.beanFactory, - beanDefinition -> { - beanDefinition - .setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR); - beanDefinition.getConstructorArgumentValues() - .addIndexedArgumentValue(1, "user-value"); + bd -> { + bd.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR); + bd.getConstructorArgumentValues().addIndexedArgumentValue(1, "user-value"); }); - AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean); + AutowiredArguments arguments = source.getSupplier().resolveArguments(registerBean); assertThat(arguments.toArray()).hasSize(3); assertThat(arguments.getObject(0)).isEqualTo(resourceLoader); assertThat(arguments.getObject(1)).isEqualTo("user-value"); @@ -502,13 +486,11 @@ class BeanInstanceSupplierTests { resourceLoader); this.beanFactory.registerSingleton("environment", environment); RegisteredBean registerBean = source.registerBean(this.beanFactory, - beanDefinition -> { - beanDefinition - .setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR); - beanDefinition.getConstructorArgumentValues() - .addGenericArgumentValue("user-value"); + bd -> { + bd.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR); + bd.getConstructorArgumentValues().addGenericArgumentValue("user-value"); }); - AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean); + AutowiredArguments arguments = source.getSupplier().resolveArguments(registerBean); assertThat(arguments.toArray()).hasSize(3); assertThat(arguments.getObject(0)).isEqualTo(resourceLoader); assertThat(arguments.getObject(1)).isEqualTo("user-value"); @@ -519,19 +501,17 @@ class BeanInstanceSupplierTests { void resolveArgumentsWithMixedArgsConstructorAndIndexedUserBeanReference(Source source) { ResourceLoader resourceLoader = new DefaultResourceLoader(); Environment environment = mock(); - this.beanFactory.registerResolvableDependency(ResourceLoader.class, - resourceLoader); + this.beanFactory.registerResolvableDependency(ResourceLoader.class, resourceLoader); this.beanFactory.registerSingleton("environment", environment); this.beanFactory.registerSingleton("one", "1"); this.beanFactory.registerSingleton("two", "2"); RegisteredBean registerBean = source.registerBean(this.beanFactory, - beanDefinition -> { - beanDefinition - .setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR); - beanDefinition.getConstructorArgumentValues() - .addIndexedArgumentValue(1, new RuntimeBeanReference("two")); + bd -> { + bd.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR); + bd.getConstructorArgumentValues().addIndexedArgumentValue( + 1, new RuntimeBeanReference("two")); }); - AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean); + AutowiredArguments arguments = source.getSupplier().resolveArguments(registerBean); assertThat(arguments.toArray()).hasSize(3); assertThat(arguments.getObject(0)).isEqualTo(resourceLoader); assertThat(arguments.getObject(1)).isEqualTo("2"); @@ -542,19 +522,16 @@ class BeanInstanceSupplierTests { void resolveArgumentsWithMixedArgsConstructorAndGenericUserBeanReference(Source source) { ResourceLoader resourceLoader = new DefaultResourceLoader(); Environment environment = mock(); - this.beanFactory.registerResolvableDependency(ResourceLoader.class, - resourceLoader); + this.beanFactory.registerResolvableDependency(ResourceLoader.class, resourceLoader); this.beanFactory.registerSingleton("environment", environment); this.beanFactory.registerSingleton("one", "1"); this.beanFactory.registerSingleton("two", "2"); RegisteredBean registerBean = source.registerBean(this.beanFactory, - beanDefinition -> { - beanDefinition - .setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR); - beanDefinition.getConstructorArgumentValues() - .addGenericArgumentValue(new RuntimeBeanReference("two")); + bd -> { + bd.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR); + bd.getConstructorArgumentValues().addGenericArgumentValue(new RuntimeBeanReference("two")); }); - AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean); + AutowiredArguments arguments = source.getSupplier().resolveArguments(registerBean); assertThat(arguments.toArray()).hasSize(3); assertThat(arguments.getObject(0)).isEqualTo(resourceLoader); assertThat(arguments.getObject(1)).isEqualTo("2"); @@ -566,13 +543,11 @@ class BeanInstanceSupplierTests { Source source = new Source(CharDependency.class, BeanInstanceSupplier.forConstructor(char.class)); RegisteredBean registerBean = source.registerBean(this.beanFactory, - beanDefinition -> { - beanDefinition - .setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR); - beanDefinition.getConstructorArgumentValues() - .addIndexedArgumentValue(0, "\\"); + bd -> { + bd.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR); + bd.getConstructorArgumentValues().addIndexedArgumentValue(0, "\\"); }); - AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean); + AutowiredArguments arguments = source.getSupplier().resolveArguments(registerBean); assertThat(arguments.toArray()).hasSize(1); assertThat(arguments.getObject(0)).isInstanceOf(Character.class).isEqualTo('\\'); } @@ -582,13 +557,11 @@ class BeanInstanceSupplierTests { Source source = new Source(CharDependency.class, BeanInstanceSupplier.forConstructor(char.class)); RegisteredBean registerBean = source.registerBean(this.beanFactory, - beanDefinition -> { - beanDefinition - .setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR); - beanDefinition.getConstructorArgumentValues() - .addGenericArgumentValue("\\", char.class.getName()); + bd -> { + bd.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR); + bd.getConstructorArgumentValues().addGenericArgumentValue("\\", char.class.getName()); }); - AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean); + AutowiredArguments arguments = source.getSupplier().resolveArguments(registerBean); assertThat(arguments.toArray()).hasSize(1); assertThat(arguments.getObject(0)).isInstanceOf(Character.class).isEqualTo('\\'); } @@ -597,10 +570,9 @@ class BeanInstanceSupplierTests { void resolveIndexedArgumentsWithUserValueWithBeanReference(Source source) { this.beanFactory.registerSingleton("stringBean", "string"); RegisteredBean registerBean = source.registerBean(this.beanFactory, - beanDefinition -> beanDefinition.getConstructorArgumentValues() - .addIndexedArgumentValue(0, - new RuntimeBeanReference("stringBean"))); - AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean); + bd -> bd.getConstructorArgumentValues() + .addIndexedArgumentValue(0, new RuntimeBeanReference("stringBean"))); + AutowiredArguments arguments = source.getSupplier().resolveArguments(registerBean); assertThat(arguments.toArray()).hasSize(1); assertThat(arguments.getObject(0)).isEqualTo("string"); } @@ -609,33 +581,31 @@ class BeanInstanceSupplierTests { void resolveGenericArgumentsWithUserValueWithBeanReference(Source source) { this.beanFactory.registerSingleton("stringBean", "string"); RegisteredBean registerBean = source.registerBean(this.beanFactory, - beanDefinition -> beanDefinition.getConstructorArgumentValues() + bd -> bd.getConstructorArgumentValues() .addGenericArgumentValue(new RuntimeBeanReference("stringBean"))); - AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean); + AutowiredArguments arguments = source.getSupplier().resolveArguments(registerBean); assertThat(arguments.toArray()).hasSize(1); assertThat(arguments.getObject(0)).isEqualTo("string"); } @ParameterizedResolverTest(Sources.SINGLE_ARG) void resolveIndexedArgumentsWithUserValueWithBeanDefinition(Source source) { - AbstractBeanDefinition userValue = BeanDefinitionBuilder - .rootBeanDefinition(String.class, () -> "string").getBeanDefinition(); + AbstractBeanDefinition userValue = BeanDefinitionBuilder.rootBeanDefinition( + String.class, () -> "string").getBeanDefinition(); RegisteredBean registerBean = source.registerBean(this.beanFactory, - beanDefinition -> beanDefinition.getConstructorArgumentValues() - .addIndexedArgumentValue(0, userValue)); - AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean); + bd -> bd.getConstructorArgumentValues().addIndexedArgumentValue(0, userValue)); + AutowiredArguments arguments = source.getSupplier().resolveArguments(registerBean); assertThat(arguments.toArray()).hasSize(1); assertThat(arguments.getObject(0)).isEqualTo("string"); } @ParameterizedResolverTest(Sources.SINGLE_ARG) void resolveGenericArgumentsWithUserValueWithBeanDefinition(Source source) { - AbstractBeanDefinition userValue = BeanDefinitionBuilder - .rootBeanDefinition(String.class, () -> "string").getBeanDefinition(); + AbstractBeanDefinition userValue = BeanDefinitionBuilder.rootBeanDefinition( + String.class, () -> "string").getBeanDefinition(); RegisteredBean registerBean = source.registerBean(this.beanFactory, - beanDefinition -> beanDefinition.getConstructorArgumentValues() - .addGenericArgumentValue(userValue)); - AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean); + bd -> bd.getConstructorArgumentValues().addGenericArgumentValue(userValue)); + AutowiredArguments arguments = source.getSupplier().resolveArguments(registerBean); assertThat(arguments.toArray()).hasSize(1); assertThat(arguments.getObject(0)).isEqualTo("string"); } @@ -643,13 +613,11 @@ class BeanInstanceSupplierTests { @ParameterizedResolverTest(Sources.SINGLE_ARG) void resolveIndexedArgumentsWithUserValueThatIsAlreadyResolved(Source source) { RegisteredBean registerBean = source.registerBean(this.beanFactory); - BeanDefinition mergedBeanDefinition = this.beanFactory - .getMergedBeanDefinition("testBean"); + BeanDefinition mergedBeanDefinition = this.beanFactory.getMergedBeanDefinition("testBean"); ValueHolder valueHolder = new ValueHolder("a"); valueHolder.setConvertedValue("this is an a"); - mergedBeanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, - valueHolder); - AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean); + mergedBeanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, valueHolder); + AutowiredArguments arguments = source.getSupplier().resolveArguments(registerBean); assertThat(arguments.toArray()).hasSize(1); assertThat(arguments.getObject(0)).isEqualTo("this is an a"); } @@ -657,12 +625,11 @@ class BeanInstanceSupplierTests { @ParameterizedResolverTest(Sources.SINGLE_ARG) void resolveGenericArgumentsWithUserValueThatIsAlreadyResolved(Source source) { RegisteredBean registerBean = source.registerBean(this.beanFactory); - BeanDefinition mergedBeanDefinition = this.beanFactory - .getMergedBeanDefinition("testBean"); + BeanDefinition mergedBeanDefinition = this.beanFactory.getMergedBeanDefinition("testBean"); ValueHolder valueHolder = new ValueHolder("a"); valueHolder.setConvertedValue("this is an a"); mergedBeanDefinition.getConstructorArgumentValues().addGenericArgumentValue(valueHolder); - AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean); + AutowiredArguments arguments = source.getSupplier().resolveArguments(registerBean); assertThat(arguments.toArray()).hasSize(1); assertThat(arguments.getObject(0)).isEqualTo("this is an a"); } @@ -678,21 +645,19 @@ class BeanInstanceSupplierTests { } }; - BeanInstanceSupplier resolver = BeanInstanceSupplier - .forConstructor(String.class); + BeanInstanceSupplier resolver = BeanInstanceSupplier.forConstructor(String.class); Source source = new Source(String.class, resolver); beanFactory.registerSingleton("one", "1"); RegisteredBean registeredBean = source.registerBean(beanFactory); assertThatExceptionOfType(AssertionError.class) .isThrownBy(() -> resolver.resolveArguments(registeredBean)); - assertThat(resolver.withShortcuts("one").resolveArguments(registeredBean).toArray()) + assertThat(resolver.withShortcut("one").resolveArguments(registeredBean).toArray()) .containsExactly("1"); } @Test void resolveArgumentsRegistersDependantBeans() { - BeanInstanceSupplier resolver = BeanInstanceSupplier - .forConstructor(String.class); + BeanInstanceSupplier resolver = BeanInstanceSupplier.forConstructor(String.class); Source source = new Source(SingleArgConstructor.class, resolver); this.beanFactory.registerSingleton("one", "1"); RegisteredBean registeredBean = source.registerBean(this.beanFactory); @@ -700,6 +665,7 @@ class BeanInstanceSupplierTests { assertThat(this.beanFactory.getDependentBeans("one")).containsExactly("testBean"); } + /** * Parameterized test backed by a {@link Sources}. */ @@ -709,14 +675,13 @@ class BeanInstanceSupplierTests { @interface ParameterizedResolverTest { Sources value(); - } + /** * {@link ArgumentsProvider} delegating to the {@link Sources}. */ - static class SourcesArguments - implements ArgumentsProvider, AnnotationConsumer { + static class SourcesArguments implements ArgumentsProvider, AnnotationConsumer { private Sources source; @@ -729,9 +694,9 @@ class BeanInstanceSupplierTests { public Stream provideArguments(ExtensionContext context) { return this.source.provideArguments(context); } - } + /** * Sources for parameterized tests. */ @@ -740,11 +705,9 @@ class BeanInstanceSupplierTests { SINGLE_ARG { @Override protected void setup() { - add(SingleArgConstructor.class, BeanInstanceSupplier - .forConstructor(String.class)); - add(String.class, - BeanInstanceSupplier.forFactoryMethod( - SingleArgFactory.class, "single", String.class)); + add(SingleArgConstructor.class, BeanInstanceSupplier.forConstructor(String.class)); + add(String.class, BeanInstanceSupplier.forFactoryMethod( + SingleArgFactory.class, "single", String.class)); } }, @@ -752,13 +715,9 @@ class BeanInstanceSupplierTests { INNER_CLASS_SINGLE_ARG { @Override protected void setup() { - add(Enclosing.InnerSingleArgConstructor.class, - BeanInstanceSupplier - .forConstructor(String.class)); - add(String.class, - BeanInstanceSupplier.forFactoryMethod( - Enclosing.InnerSingleArgFactory.class, "single", - String.class)); + add(Enclosing.InnerSingleArgConstructor.class, BeanInstanceSupplier.forConstructor(String.class)); + add(String.class, BeanInstanceSupplier.forFactoryMethod( + Enclosing.InnerSingleArgFactory.class, "single", String.class)); } }, @@ -766,12 +725,9 @@ class BeanInstanceSupplierTests { ARRAY_OF_BEANS { @Override protected void setup() { - add(BeansCollectionConstructor.class, - BeanInstanceSupplier - .forConstructor(String[].class)); - add(String.class, - BeanInstanceSupplier.forFactoryMethod( - BeansCollectionFactory.class, "array", String[].class)); + add(BeansCollectionConstructor.class, BeanInstanceSupplier.forConstructor(String[].class)); + add(String.class, BeanInstanceSupplier.forFactoryMethod( + BeansCollectionFactory.class, "array", String[].class)); } }, @@ -779,12 +735,9 @@ class BeanInstanceSupplierTests { LIST_OF_BEANS { @Override protected void setup() { - add(BeansCollectionConstructor.class, - BeanInstanceSupplier - .forConstructor(List.class)); - add(String.class, - BeanInstanceSupplier.forFactoryMethod( - BeansCollectionFactory.class, "list", List.class)); + add(BeansCollectionConstructor.class, BeanInstanceSupplier.forConstructor(List.class)); + add(String.class, BeanInstanceSupplier.forFactoryMethod( + BeansCollectionFactory.class, "list", List.class)); } }, @@ -792,12 +745,9 @@ class BeanInstanceSupplierTests { SET_OF_BEANS { @Override protected void setup() { - add(BeansCollectionConstructor.class, - BeanInstanceSupplier - .forConstructor(Set.class)); - add(String.class, - BeanInstanceSupplier.forFactoryMethod( - BeansCollectionFactory.class, "set", Set.class)); + add(BeansCollectionConstructor.class, BeanInstanceSupplier.forConstructor(Set.class)); + add(String.class, BeanInstanceSupplier.forFactoryMethod( + BeansCollectionFactory.class, "set", Set.class)); } }, @@ -805,12 +755,9 @@ class BeanInstanceSupplierTests { MAP_OF_BEANS { @Override protected void setup() { - add(BeansCollectionConstructor.class, - BeanInstanceSupplier - .forConstructor(Map.class)); - add(String.class, - BeanInstanceSupplier.forFactoryMethod( - BeansCollectionFactory.class, "map", Map.class)); + add(BeansCollectionConstructor.class, BeanInstanceSupplier.forConstructor(Map.class)); + add(String.class, BeanInstanceSupplier.forFactoryMethod( + BeansCollectionFactory.class, "map", Map.class)); } }, @@ -818,14 +765,11 @@ class BeanInstanceSupplierTests { MULTI_ARGS { @Override protected void setup() { - add(MultiArgsConstructor.class, - BeanInstanceSupplier.forConstructor( - ResourceLoader.class, Environment.class, - ObjectProvider.class)); - add(String.class, - BeanInstanceSupplier.forFactoryMethod( - MultiArgsFactory.class, "multiArgs", ResourceLoader.class, - Environment.class, ObjectProvider.class)); + add(MultiArgsConstructor.class, BeanInstanceSupplier.forConstructor( + ResourceLoader.class, Environment.class, ObjectProvider.class)); + add(String.class, BeanInstanceSupplier.forFactoryMethod( + MultiArgsFactory.class, "multiArgs", ResourceLoader.class, + Environment.class, ObjectProvider.class)); } }, @@ -833,13 +777,10 @@ class BeanInstanceSupplierTests { MIXED_ARGS { @Override protected void setup() { - add(MixedArgsConstructor.class, - BeanInstanceSupplier.forConstructor( - ResourceLoader.class, String.class, Environment.class)); - add(String.class, - BeanInstanceSupplier.forFactoryMethod( - MixedArgsFactory.class, "mixedArgs", ResourceLoader.class, - String.class, Environment.class)); + add(MixedArgsConstructor.class, BeanInstanceSupplier.forConstructor( + ResourceLoader.class, String.class, Environment.class)); + add(String.class, BeanInstanceSupplier.forFactoryMethod( + MixedArgsFactory.class, "mixedArgs", ResourceLoader.class, String.class, Environment.class)); } }; @@ -853,17 +794,16 @@ class BeanInstanceSupplierTests { protected abstract void setup(); - protected final void add(Class beanClass, - BeanInstanceSupplier resolver) { - this.arguments.add(Arguments.of(new Source(beanClass, resolver))); + protected final void add(Class beanClass, BeanInstanceSupplier supplier) { + this.arguments.add(Arguments.of(new Source(beanClass, supplier))); } final Stream provideArguments(ExtensionContext context) { return this.arguments.stream(); } - } + static class BeanRegistrar { final Class beanClass; @@ -873,53 +813,50 @@ class BeanInstanceSupplierTests { } RegisteredBean registerBean(DefaultListableBeanFactory beanFactory) { - return registerBean(beanFactory, beanDefinition -> { - }); + return registerBean(beanFactory, bd -> {}); } - RegisteredBean registerBean(DefaultListableBeanFactory beanFactory, - Consumer beanDefinitionCustomizer) { + RegisteredBean registerBean(DefaultListableBeanFactory beanFactory, Consumer bdCustomizer) { String beanName = "testBean"; - RootBeanDefinition beanDefinition = new RootBeanDefinition(this.beanClass); - beanDefinition.setInstanceSupplier(() -> { + RootBeanDefinition bd = new RootBeanDefinition(this.beanClass); + bd.setInstanceSupplier(() -> { throw new BeanCurrentlyInCreationException(beanName); }); - beanDefinitionCustomizer.accept(beanDefinition); - beanFactory.registerBeanDefinition(beanName, beanDefinition); + bdCustomizer.accept(bd); + beanFactory.registerBeanDefinition(beanName, bd); return RegisteredBean.of(beanFactory, beanName); } } + static class Source extends BeanRegistrar { - private final BeanInstanceSupplier resolver; + private final BeanInstanceSupplier supplier; - public Source(Class beanClass, - BeanInstanceSupplier resolver) { + public Source(Class beanClass, BeanInstanceSupplier supplier) { super(beanClass); - this.resolver = resolver; + this.supplier = supplier; } - BeanInstanceSupplier getResolver() { - return this.resolver; + BeanInstanceSupplier getSupplier() { + return this.supplier; } Executable lookupExecutable(RegisteredBean registeredBean) { - return this.resolver.getLookup().get(registeredBean); + return this.supplier.getLookup().get(registeredBean); } @Override public String toString() { - return this.resolver.getLookup() + " with bean class " - + ClassUtils.getShortName(this.beanClass); + return this.supplier.getLookup() + " with bean class " + ClassUtils.getShortName(this.beanClass); } - } - static class NoArgConstructor { + static class NoArgConstructor { } + static class SingleArgConstructor { private final String string; @@ -931,20 +868,20 @@ class BeanInstanceSupplierTests { String getString() { return this.string; } - } + static class SingleArgFactory { String single(String s) { return s; } - } + static class Enclosing { - class InnerSingleArgConstructor { + static class InnerSingleArgConstructor { private final String string; @@ -955,39 +892,33 @@ class BeanInstanceSupplierTests { String getString() { return this.string; } - } - class InnerSingleArgFactory { + static class InnerSingleArgFactory { String single(String s) { return s; } - } - } + static class BeansCollectionConstructor { public BeansCollectionConstructor(String[] beans) { - } public BeansCollectionConstructor(List beans) { - } public BeansCollectionConstructor(Set beans) { - } public BeansCollectionConstructor(Map beans) { - } - } + static class BeansCollectionFactory { public String array(String[] beans) { @@ -1008,6 +939,7 @@ class BeanInstanceSupplierTests { } + static class MultiArgsConstructor { public MultiArgsConstructor(ResourceLoader resourceLoader, @@ -1015,51 +947,50 @@ class BeanInstanceSupplierTests { } } + static class MultiArgsFactory { - String multiArgs(ResourceLoader resourceLoader, Environment environment, - ObjectProvider provider) { + String multiArgs(ResourceLoader resourceLoader, Environment environment, ObjectProvider provider) { return "test"; } } - static class MixedArgsConstructor { - public MixedArgsConstructor(ResourceLoader resourceLoader, String test, - Environment environment) { + static class MixedArgsConstructor { + public MixedArgsConstructor(ResourceLoader resourceLoader, String test, Environment environment) { } - } + static class MixedArgsFactory { String mixedArgs(ResourceLoader resourceLoader, String test, Environment environment) { return "test"; } - } + static class CharDependency { CharDependency(char escapeChar) { } - } + interface MethodOnInterface { default String test() { return "Test"; } - } - static class MethodOnInterfaceImpl implements MethodOnInterface { + static class MethodOnInterfaceImpl implements MethodOnInterface { } + static class TestStringFactory { String test() { @@ -1067,6 +998,7 @@ class BeanInstanceSupplierTests { } } + static class AnotherTestStringFactory { String another() { diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/aot/InstanceSupplierCodeGeneratorTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/aot/InstanceSupplierCodeGeneratorTests.java index 84e5480494e..85e572cfd69 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/aot/InstanceSupplierCodeGeneratorTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/aot/InstanceSupplierCodeGeneratorTests.java @@ -122,7 +122,7 @@ class InstanceSupplierCodeGeneratorTests { NoDependencyComponent bean = getBean(beanDefinition, instanceSupplier); assertThat(bean).isInstanceOf(NoDependencyComponent.class); assertThat(compiled.getSourceFile()).contains( - "getBeanFactory().getBean(InnerComponentConfiguration.class).new NoDependencyComponent()"); + "InstanceSupplier.using(InnerComponentConfiguration.NoDependencyComponent::new"); }); assertThat(getReflectionHints().getTypeHint(NoDependencyComponent.class)) .satisfies(hasConstructorWithMode(ExecutableMode.INTROSPECT)); @@ -137,7 +137,7 @@ class InstanceSupplierCodeGeneratorTests { EnvironmentAwareComponent bean = getBean(beanDefinition, instanceSupplier); assertThat(bean).isInstanceOf(EnvironmentAwareComponent.class); assertThat(compiled.getSourceFile()).contains( - "getBeanFactory().getBean(InnerComponentConfiguration.class).new EnvironmentAwareComponent("); + "new InnerComponentConfiguration.EnvironmentAwareComponent("); }); assertThat(getReflectionHints().getTypeHint(EnvironmentAwareComponent.class)) .satisfies(hasConstructorWithMode(ExecutableMode.INTROSPECT)); @@ -182,7 +182,7 @@ class InstanceSupplierCodeGeneratorTests { assertThat(bean).isInstanceOf(String.class); assertThat(bean).isEqualTo("Hello"); assertThat(compiled.getSourceFile()).contains( - "getBeanFactory().getBean(SimpleConfiguration.class).stringBean()"); + "getBeanFactory().getBean(\"config\", SimpleConfiguration.class).stringBean()"); }); assertThat(getReflectionHints().getTypeHint(SimpleConfiguration.class)) .satisfies(hasMethodWithMode(ExecutableMode.INTROSPECT)); @@ -199,7 +199,7 @@ class InstanceSupplierCodeGeneratorTests { Object bean = getBean(beanDefinition, instanceSupplier); assertThat(bean).isInstanceOf(SimpleBean.class); assertThat(compiled.getSourceFile()).contains( - "getBeanFactory().getBean(DefaultSimpleBeanContract.class).simpleBean()"); + "getBeanFactory().getBean(\"config\", DefaultSimpleBeanContract.class).simpleBean()"); }); assertThat(getReflectionHints().getTypeHint(SimpleBeanContract.class)) .satisfies(hasMethodWithMode(ExecutableMode.INTROSPECT)); @@ -228,10 +228,8 @@ class InstanceSupplierCodeGeneratorTests { @Test void generateWhenHasStaticFactoryMethodWithNoArg() { BeanDefinition beanDefinition = BeanDefinitionBuilder - .rootBeanDefinition(Integer.class) - .setFactoryMethodOnBean("integerBean", "config").getBeanDefinition(); - this.beanFactory.registerBeanDefinition("config", BeanDefinitionBuilder - .genericBeanDefinition(SimpleConfiguration.class).getBeanDefinition()); + .rootBeanDefinition(SimpleConfiguration.class) + .setFactoryMethod("integerBean").getBeanDefinition(); compile(beanDefinition, (instanceSupplier, compiled) -> { Integer bean = getBean(beanDefinition, instanceSupplier); assertThat(bean).isInstanceOf(Integer.class); @@ -246,12 +244,10 @@ class InstanceSupplierCodeGeneratorTests { @Test void generateWhenHasStaticFactoryMethodWithArg() { RootBeanDefinition beanDefinition = (RootBeanDefinition) BeanDefinitionBuilder - .rootBeanDefinition(String.class) - .setFactoryMethodOnBean("create", "config").getBeanDefinition(); + .rootBeanDefinition(SimpleConfiguration.class) + .setFactoryMethod("create").getBeanDefinition(); beanDefinition.setResolvedFactoryMethod(ReflectionUtils .findMethod(SampleFactory.class, "create", Number.class, String.class)); - this.beanFactory.registerBeanDefinition("config", BeanDefinitionBuilder - .genericBeanDefinition(SampleFactory.class).getBeanDefinition()); this.beanFactory.registerSingleton("number", 42); this.beanFactory.registerSingleton("string", "test"); compile(beanDefinition, (instanceSupplier, compiled) -> { @@ -265,7 +261,7 @@ class InstanceSupplierCodeGeneratorTests { } @Test - void generateWhenHasStaticFactoryMethodCheckedException() { + void generateWhenHasFactoryMethodCheckedException() { BeanDefinition beanDefinition = BeanDefinitionBuilder .rootBeanDefinition(Integer.class) .setFactoryMethodOnBean("throwingIntegerBean", "config") @@ -282,6 +278,62 @@ class InstanceSupplierCodeGeneratorTests { .satisfies(hasMethodWithMode(ExecutableMode.INTROSPECT)); } + + private ReflectionHints getReflectionHints() { + return this.generationContext.getRuntimeHints().reflection(); + } + + private ThrowingConsumer hasConstructorWithMode(ExecutableMode mode) { + return hint -> assertThat(hint.constructors()).anySatisfy(hasMode(mode)); + } + + private ThrowingConsumer hasMethodWithMode(ExecutableMode mode) { + return hint -> assertThat(hint.methods()).anySatisfy(hasMode(mode)); + } + + private ThrowingConsumer hasMode(ExecutableMode mode) { + return hint -> assertThat(hint.getMode()).isEqualTo(mode); + } + + @SuppressWarnings("unchecked") + private T getBean(BeanDefinition beanDefinition, InstanceSupplier instanceSupplier) { + ((RootBeanDefinition) beanDefinition).setInstanceSupplier(instanceSupplier); + this.beanFactory.registerBeanDefinition("testBean", beanDefinition); + return (T) this.beanFactory.getBean("testBean"); + } + + private void compile(BeanDefinition beanDefinition, BiConsumer, Compiled> result) { + compile(TestCompiler.forSystem(), beanDefinition, result); + } + + private void compile(TestCompiler testCompiler, BeanDefinition beanDefinition, + BiConsumer, Compiled> result) { + + DefaultListableBeanFactory freshBeanFactory = new DefaultListableBeanFactory(this.beanFactory); + freshBeanFactory.registerBeanDefinition("testBean", beanDefinition); + RegisteredBean registeredBean = RegisteredBean.of(freshBeanFactory, "testBean"); + DeferredTypeBuilder typeBuilder = new DeferredTypeBuilder(); + GeneratedClass generateClass = this.generationContext.getGeneratedClasses().addForFeature("TestCode", typeBuilder); + InstanceSupplierCodeGenerator generator = new InstanceSupplierCodeGenerator( + this.generationContext, generateClass.getName(), + generateClass.getMethods(), false); + InstantiationDescriptor instantiationDescriptor = registeredBean.resolveInstantiationDescriptor(); + assertThat(instantiationDescriptor).isNotNull(); + CodeBlock generatedCode = generator.generateCode(registeredBean, instantiationDescriptor); + typeBuilder.set(type -> { + type.addModifiers(Modifier.PUBLIC); + type.addSuperinterface(ParameterizedTypeName.get(Supplier.class, InstanceSupplier.class)); + type.addMethod(MethodSpec.methodBuilder("get") + .addModifiers(Modifier.PUBLIC) + .returns(InstanceSupplier.class) + .addStatement("return $L", generatedCode).build()); + }); + this.generationContext.writeGeneratedContent(); + testCompiler.with(this.generationContext).compile(compiled -> result.accept( + (InstanceSupplier) compiled.getInstance(Supplier.class).get(), compiled)); + } + + @Nested @SuppressWarnings("deprecation") class DeprecationTests { @@ -335,9 +387,9 @@ class InstanceSupplierCodeGeneratorTests { assertThatNoException().isThrownBy(() -> compile(TEST_COMPILER, beanDefinition, ((instanceSupplier, compiled) -> {}))); } - } + @Nested @SuppressWarnings("removal") class DeprecationForRemovalTests { @@ -381,61 +433,6 @@ class InstanceSupplierCodeGeneratorTests { assertThatNoException().isThrownBy(() -> compile(TEST_COMPILER, beanDefinition, ((instanceSupplier, compiled) -> {}))); } - - } - - private ReflectionHints getReflectionHints() { - return this.generationContext.getRuntimeHints().reflection(); - } - - private ThrowingConsumer hasConstructorWithMode(ExecutableMode mode) { - return hint -> assertThat(hint.constructors()).anySatisfy(hasMode(mode)); - } - - private ThrowingConsumer hasMethodWithMode(ExecutableMode mode) { - return hint -> assertThat(hint.methods()).anySatisfy(hasMode(mode)); - } - - private ThrowingConsumer hasMode(ExecutableMode mode) { - return hint -> assertThat(hint.getMode()).isEqualTo(mode); - } - - @SuppressWarnings("unchecked") - private T getBean(BeanDefinition beanDefinition, InstanceSupplier instanceSupplier) { - ((RootBeanDefinition) beanDefinition).setInstanceSupplier(instanceSupplier); - this.beanFactory.registerBeanDefinition("testBean", beanDefinition); - return (T) this.beanFactory.getBean("testBean"); - } - - private void compile(BeanDefinition beanDefinition, BiConsumer, Compiled> result) { - compile(TestCompiler.forSystem(), beanDefinition, result); - } - - private void compile(TestCompiler testCompiler, BeanDefinition beanDefinition, - BiConsumer, Compiled> result) { - - DefaultListableBeanFactory freshBeanFactory = new DefaultListableBeanFactory(this.beanFactory); - freshBeanFactory.registerBeanDefinition("testBean", beanDefinition); - RegisteredBean registeredBean = RegisteredBean.of(freshBeanFactory, "testBean"); - DeferredTypeBuilder typeBuilder = new DeferredTypeBuilder(); - GeneratedClass generateClass = this.generationContext.getGeneratedClasses().addForFeature("TestCode", typeBuilder); - InstanceSupplierCodeGenerator generator = new InstanceSupplierCodeGenerator( - this.generationContext, generateClass.getName(), - generateClass.getMethods(), false); - InstantiationDescriptor instantiationDescriptor = registeredBean.resolveInstantiationDescriptor(); - assertThat(instantiationDescriptor).isNotNull(); - CodeBlock generatedCode = generator.generateCode(registeredBean, instantiationDescriptor); - typeBuilder.set(type -> { - type.addModifiers(Modifier.PUBLIC); - type.addSuperinterface(ParameterizedTypeName.get(Supplier.class, InstanceSupplier.class)); - type.addMethod(MethodSpec.methodBuilder("get") - .addModifiers(Modifier.PUBLIC) - .returns(InstanceSupplier.class) - .addStatement("return $L", generatedCode).build()); - }); - this.generationContext.writeGeneratedContent(); - testCompiler.with(this.generationContext).compile(compiled -> result.accept( - (InstanceSupplier) compiled.getInstance(Supplier.class).get(), compiled)); } } diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/support/RootBeanDefinitionTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/support/RootBeanDefinitionTests.java index d71424f76dd..edb44d2be53 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/support/RootBeanDefinitionTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/support/RootBeanDefinitionTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 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. @@ -26,6 +26,7 @@ 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; +import static org.mockito.Mockito.verifyNoInteractions; /** * Tests for {@link RootBeanDefinition}. @@ -54,7 +55,7 @@ class RootBeanDefinitionTests { beanDefinition.setResolvedFactoryMethod(method); beanDefinition.setInstanceSupplier(instanceSupplier); assertThat(beanDefinition.getResolvedFactoryMethod()).isEqualTo(method); - verify(instanceSupplier).getFactoryMethod(); + verifyNoInteractions(instanceSupplier); } @Test @@ -81,15 +82,15 @@ class RootBeanDefinitionTests { assertThat(beanDefinition.getDestroyMethodNames()).isNull(); } + static class BeanWithCloseMethod { public void close() { } - } - static class BeanWithNoDestroyMethod { + static class BeanWithNoDestroyMethod { } } diff --git a/spring-beans/src/test/kotlin/org/springframework/beans/factory/aot/InstanceSupplierCodeGeneratorKotlinTests.kt b/spring-beans/src/test/kotlin/org/springframework/beans/factory/aot/InstanceSupplierCodeGeneratorKotlinTests.kt index 451c77b37a0..2bb67793b45 100644 --- a/spring-beans/src/test/kotlin/org/springframework/beans/factory/aot/InstanceSupplierCodeGeneratorKotlinTests.kt +++ b/spring-beans/src/test/kotlin/org/springframework/beans/factory/aot/InstanceSupplierCodeGeneratorKotlinTests.kt @@ -87,7 +87,7 @@ class InstanceSupplierCodeGeneratorKotlinTests { Assertions.assertThat(bean).isInstanceOf(String::class.java) Assertions.assertThat(bean).isEqualTo("Hello") Assertions.assertThat(compiled.sourceFile).contains( - "getBeanFactory().getBean(KotlinConfiguration.class).stringBean()" + "getBeanFactory().getBean(\"config\", KotlinConfiguration.class).stringBean()" ) } Assertions.assertThat(getReflectionHints().getTypeHint(KotlinConfiguration::class.java)) diff --git a/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/factory/generator/InnerComponentConfiguration.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/factory/generator/InnerComponentConfiguration.java index 28188b2a52a..63d2eb3b74d 100644 --- a/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/factory/generator/InnerComponentConfiguration.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/factory/generator/InnerComponentConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2024 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. @@ -20,17 +20,16 @@ import org.springframework.core.env.Environment; public class InnerComponentConfiguration { - public class NoDependencyComponent { + public static class NoDependencyComponent { public NoDependencyComponent() { - } } - public class EnvironmentAwareComponent { + public static class EnvironmentAwareComponent { public EnvironmentAwareComponent(Environment environment) { - } } + } diff --git a/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/factory/generator/SimpleConfiguration.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/factory/generator/SimpleConfiguration.java index 89d459297bf..17d51ed498b 100644 --- a/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/factory/generator/SimpleConfiguration.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/factory/generator/SimpleConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2024 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. @@ -20,9 +20,6 @@ import java.io.IOException; public class SimpleConfiguration { - public SimpleConfiguration() { - } - public String stringBean() { return "Hello"; }