From d6e4bd7c90d239ba2db37b47d913ac461b5c72b9 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 24 Sep 2024 18:59:08 +0200 Subject: [PATCH] Resolve AOT factory method target by bean name and reduce reflective method exposure Includes consistent withShortcut naming and consistent bean definition flag exposure. Removes support for inner classes in alignment with standard core container behavior. Closes gh-32834 --- ...BeanDefinitionPropertiesCodeGenerator.java | 47 +- .../factory/aot/BeanInstanceSupplier.java | 200 ++++---- .../DefaultBeanRegistrationCodeFragments.java | 4 +- .../aot/InstanceSupplierCodeGenerator.java | 102 ++-- .../factory/support/RootBeanDefinition.java | 17 +- .../support/SimpleInstantiationStrategy.java | 6 +- .../aot/BeanInstanceSupplierTests.java | 448 ++++++++---------- .../InstanceSupplierCodeGeneratorTests.java | 135 +++--- .../support/RootBeanDefinitionTests.java | 9 +- ...nstanceSupplierCodeGeneratorKotlinTests.kt | 2 +- .../InnerComponentConfiguration.java | 9 +- .../generator/SimpleConfiguration.java | 5 +- 12 files changed, 447 insertions(+), 537 deletions(-) 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"; }