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
This commit is contained in:
parent
aef5143642
commit
d6e4bd7c90
|
@ -113,26 +113,34 @@ class BeanDefinitionPropertiesCodeGenerator {
|
||||||
|
|
||||||
CodeBlock generateCode(RootBeanDefinition beanDefinition) {
|
CodeBlock generateCode(RootBeanDefinition beanDefinition) {
|
||||||
CodeBlock.Builder code = CodeBlock.builder();
|
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,
|
addStatementForValue(code, beanDefinition, BeanDefinition::getScope,
|
||||||
this::hasScope, "$L.setScope($S)");
|
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,
|
addStatementForValue(code, beanDefinition, BeanDefinition::getDependsOn,
|
||||||
this::hasDependsOn, "$L.setDependsOn($L)", this::toStringVarArgs);
|
this::hasDependsOn, "$L.setDependsOn($L)", this::toStringVarArgs);
|
||||||
addStatementForValue(code, beanDefinition, BeanDefinition::isAutowireCandidate,
|
addStatementForValue(code, beanDefinition, BeanDefinition::isAutowireCandidate,
|
||||||
"$L.setAutowireCandidate($L)");
|
"$L.setAutowireCandidate($L)");
|
||||||
addStatementForValue(code, beanDefinition, BeanDefinition::getRole,
|
addStatementForValue(code, beanDefinition, AbstractBeanDefinition::isDefaultCandidate,
|
||||||
this::hasRole, "$L.setRole($L)", this::toRole);
|
"$L.setDefaultCandidate($L)");
|
||||||
addStatementForValue(code, beanDefinition, AbstractBeanDefinition::getLazyInit,
|
addStatementForValue(code, beanDefinition, BeanDefinition::isPrimary,
|
||||||
"$L.setLazyInit($L)");
|
"$L.setPrimary($L)");
|
||||||
|
addStatementForValue(code, beanDefinition, BeanDefinition::isFallback,
|
||||||
|
"$L.setFallback($L)");
|
||||||
addStatementForValue(code, beanDefinition, AbstractBeanDefinition::isSynthetic,
|
addStatementForValue(code, beanDefinition, AbstractBeanDefinition::isSynthetic,
|
||||||
"$L.setSynthetic($L)");
|
"$L.setSynthetic($L)");
|
||||||
|
addStatementForValue(code, beanDefinition, BeanDefinition::getRole,
|
||||||
|
this::hasRole, "$L.setRole($L)", this::toRole);
|
||||||
addInitDestroyMethods(code, beanDefinition, beanDefinition.getInitMethodNames(),
|
addInitDestroyMethods(code, beanDefinition, beanDefinition.getInitMethodNames(),
|
||||||
"$L.setInitMethodNames($L)");
|
"$L.setInitMethodNames($L)");
|
||||||
addInitDestroyMethods(code, beanDefinition, beanDefinition.getDestroyMethodNames(),
|
addInitDestroyMethods(code, beanDefinition, beanDefinition.getDestroyMethodNames(),
|
||||||
"$L.setDestroyMethodNames($L)");
|
"$L.setDestroyMethodNames($L)");
|
||||||
|
if (beanDefinition.getFactoryBeanName() != null) {
|
||||||
|
addStatementForValue(code, beanDefinition, BeanDefinition::getFactoryBeanName,
|
||||||
|
"$L.setFactoryBeanName(\"$L\")");
|
||||||
|
}
|
||||||
addConstructorArgumentValues(code, beanDefinition);
|
addConstructorArgumentValues(code, beanDefinition);
|
||||||
addPropertyValues(code, beanDefinition);
|
addPropertyValues(code, beanDefinition);
|
||||||
addAttributes(code, beanDefinition);
|
addAttributes(code, beanDefinition);
|
||||||
|
@ -142,6 +150,7 @@ class BeanDefinitionPropertiesCodeGenerator {
|
||||||
|
|
||||||
private void addInitDestroyMethods(Builder code, AbstractBeanDefinition beanDefinition,
|
private void addInitDestroyMethods(Builder code, AbstractBeanDefinition beanDefinition,
|
||||||
@Nullable String[] methodNames, String format) {
|
@Nullable String[] methodNames, String format) {
|
||||||
|
|
||||||
// For Publisher-based destroy methods
|
// For Publisher-based destroy methods
|
||||||
this.hints.reflection().registerType(TypeReference.of("org.reactivestreams.Publisher"));
|
this.hints.reflection().registerType(TypeReference.of("org.reactivestreams.Publisher"));
|
||||||
if (!ObjectUtils.isEmpty(methodNames)) {
|
if (!ObjectUtils.isEmpty(methodNames)) {
|
||||||
|
@ -210,7 +219,6 @@ class BeanDefinitionPropertiesCodeGenerator {
|
||||||
else if (valueHolder.getType() != null) {
|
else if (valueHolder.getType() != null) {
|
||||||
code.addStatement("$L.getConstructorArgumentValues().addGenericArgumentValue($L, $S)",
|
code.addStatement("$L.getConstructorArgumentValues().addGenericArgumentValue($L, $S)",
|
||||||
BEAN_DEFINITION_VARIABLE, valueCode, valueHolder.getType());
|
BEAN_DEFINITION_VARIABLE, valueCode, valueHolder.getType());
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
code.addStatement("$L.getConstructorArgumentValues().addGenericArgumentValue($L)",
|
code.addStatement("$L.getConstructorArgumentValues().addGenericArgumentValue($L)",
|
||||||
|
@ -224,7 +232,8 @@ class BeanDefinitionPropertiesCodeGenerator {
|
||||||
MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
|
MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
|
||||||
if (!propertyValues.isEmpty()) {
|
if (!propertyValues.isEmpty()) {
|
||||||
Class<?> infrastructureType = getInfrastructureType(beanDefinition);
|
Class<?> infrastructureType = getInfrastructureType(beanDefinition);
|
||||||
Map<String, Method> writeMethods = (infrastructureType != Object.class) ? getWriteMethods(infrastructureType) : Collections.emptyMap();
|
Map<String, Method> writeMethods = (infrastructureType != Object.class ?
|
||||||
|
getWriteMethods(infrastructureType) : Collections.emptyMap());
|
||||||
for (PropertyValue propertyValue : propertyValues) {
|
for (PropertyValue propertyValue : propertyValues) {
|
||||||
String name = propertyValue.getName();
|
String name = propertyValue.getName();
|
||||||
CodeBlock valueCode = generateValue(name, propertyValue.getValue());
|
CodeBlock valueCode = generateValue(name, propertyValue.getValue());
|
||||||
|
@ -266,8 +275,8 @@ class BeanDefinitionPropertiesCodeGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
private CodeBlock generateValue(@Nullable String name, @Nullable Object value) {
|
private CodeBlock generateValue(@Nullable String name, @Nullable Object value) {
|
||||||
|
PropertyNamesStack.push(name);
|
||||||
try {
|
try {
|
||||||
PropertyNamesStack.push(name);
|
|
||||||
return this.valueCodeGenerator.generateCode(value);
|
return this.valueCodeGenerator.generateCode(value);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
@ -308,8 +317,7 @@ class BeanDefinitionPropertiesCodeGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasScope(String defaultValue, String actualValue) {
|
private boolean hasScope(String defaultValue, String actualValue) {
|
||||||
return StringUtils.hasText(actualValue) &&
|
return (StringUtils.hasText(actualValue) && !ConfigurableBeanFactory.SCOPE_SINGLETON.equals(actualValue));
|
||||||
!ConfigurableBeanFactory.SCOPE_SINGLETON.equals(actualValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasDependsOn(String[] defaultValue, String[] actualValue) {
|
private boolean hasDependsOn(String[] defaultValue, String[] actualValue) {
|
||||||
|
@ -335,8 +343,7 @@ class BeanDefinitionPropertiesCodeGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
private <B extends BeanDefinition, T> void addStatementForValue(
|
private <B extends BeanDefinition, T> void addStatementForValue(
|
||||||
CodeBlock.Builder code, BeanDefinition beanDefinition,
|
CodeBlock.Builder code, BeanDefinition beanDefinition, Function<B, T> getter, String format) {
|
||||||
Function<B, T> getter, String format) {
|
|
||||||
|
|
||||||
addStatementForValue(code, beanDefinition, getter,
|
addStatementForValue(code, beanDefinition, getter,
|
||||||
(defaultValue, actualValue) -> !Objects.equals(defaultValue, actualValue), format);
|
(defaultValue, actualValue) -> !Objects.equals(defaultValue, actualValue), format);
|
||||||
|
@ -351,9 +358,8 @@ class BeanDefinitionPropertiesCodeGenerator {
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private <B extends BeanDefinition, T> void addStatementForValue(
|
private <B extends BeanDefinition, T> void addStatementForValue(
|
||||||
CodeBlock.Builder code, BeanDefinition beanDefinition,
|
CodeBlock.Builder code, BeanDefinition beanDefinition, Function<B, T> getter,
|
||||||
Function<B, T> getter, BiPredicate<T, T> filter, String format,
|
BiPredicate<T, T> filter, String format, Function<T, Object> formatter) {
|
||||||
Function<T, Object> formatter) {
|
|
||||||
|
|
||||||
T defaultValue = getter.apply((B) DEFAULT_BEAN_DEFINITION);
|
T defaultValue = getter.apply((B) DEFAULT_BEAN_DEFINITION);
|
||||||
T actualValue = getter.apply((B) beanDefinition);
|
T actualValue = getter.apply((B) beanDefinition);
|
||||||
|
@ -363,9 +369,8 @@ class BeanDefinitionPropertiesCodeGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cast the specified {@code valueCode} to the specified {@code castType} if
|
* Cast the specified {@code valueCode} to the specified {@code castType} if the
|
||||||
* the {@code castNecessary} is {@code true}. Otherwise return the valueCode
|
* {@code castNecessary} is {@code true}. Otherwise, return the valueCode as-is.
|
||||||
* as is.
|
|
||||||
* @param castNecessary whether a cast is necessary
|
* @param castNecessary whether a cast is necessary
|
||||||
* @param castType the type to cast to
|
* @param castType the type to cast to
|
||||||
* @param valueCode the code for the value
|
* @param valueCode the code for the value
|
||||||
|
|
|
@ -32,9 +32,7 @@ import org.springframework.beans.BeanInstantiationException;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
import org.springframework.beans.TypeConverter;
|
import org.springframework.beans.TypeConverter;
|
||||||
import org.springframework.beans.factory.BeanFactory;
|
|
||||||
import org.springframework.beans.factory.UnsatisfiedDependencyException;
|
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;
|
||||||
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
|
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
|
||||||
import org.springframework.beans.factory.config.DependencyDescriptor;
|
import org.springframework.beans.factory.config.DependencyDescriptor;
|
||||||
|
@ -49,7 +47,6 @@ import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
import org.springframework.util.ObjectUtils;
|
|
||||||
import org.springframework.util.ReflectionUtils;
|
import org.springframework.util.ReflectionUtils;
|
||||||
import org.springframework.util.function.ThrowingBiFunction;
|
import org.springframework.util.function.ThrowingBiFunction;
|
||||||
import org.springframework.util.function.ThrowingFunction;
|
import org.springframework.util.function.ThrowingFunction;
|
||||||
|
@ -79,6 +76,7 @@ import org.springframework.util.function.ThrowingSupplier;
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
* @author Stephane Nicoll
|
* @author Stephane Nicoll
|
||||||
|
* @author Juergen Hoeller
|
||||||
* @since 6.0
|
* @since 6.0
|
||||||
* @param <T> the type of instance supplied by this supplier
|
* @param <T> the type of instance supplied by this supplier
|
||||||
* @see AutowiredArguments
|
* @see AutowiredArguments
|
||||||
|
@ -88,19 +86,24 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
||||||
private final ExecutableLookup lookup;
|
private final ExecutableLookup lookup;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private final ThrowingBiFunction<RegisteredBean, AutowiredArguments, T> generator;
|
private final ThrowingFunction<RegisteredBean, T> generatorWithoutArguments;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private final String[] shortcuts;
|
private final ThrowingBiFunction<RegisteredBean, AutowiredArguments, T> generatorWithArguments;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private final String[] shortcutBeanNames;
|
||||||
|
|
||||||
|
|
||||||
private BeanInstanceSupplier(ExecutableLookup lookup,
|
private BeanInstanceSupplier(ExecutableLookup lookup,
|
||||||
@Nullable ThrowingBiFunction<RegisteredBean, AutowiredArguments, T> generator,
|
@Nullable ThrowingFunction<RegisteredBean, T> generatorWithoutArguments,
|
||||||
@Nullable String[] shortcuts) {
|
@Nullable ThrowingBiFunction<RegisteredBean, AutowiredArguments, T> generatorWithArguments,
|
||||||
|
@Nullable String[] shortcutBeanNames) {
|
||||||
|
|
||||||
this.lookup = lookup;
|
this.lookup = lookup;
|
||||||
this.generator = generator;
|
this.generatorWithoutArguments = generatorWithoutArguments;
|
||||||
this.shortcuts = shortcuts;
|
this.generatorWithArguments = generatorWithArguments;
|
||||||
|
this.shortcutBeanNames = shortcutBeanNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -114,7 +117,7 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
||||||
public static <T> BeanInstanceSupplier<T> forConstructor(Class<?>... parameterTypes) {
|
public static <T> BeanInstanceSupplier<T> forConstructor(Class<?>... parameterTypes) {
|
||||||
Assert.notNull(parameterTypes, "'parameterTypes' must not be null");
|
Assert.notNull(parameterTypes, "'parameterTypes' must not be null");
|
||||||
Assert.noNullElements(parameterTypes, "'parameterTypes' must not contain null elements");
|
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<T> extends AutowiredElementResolver impl
|
||||||
Assert.noNullElements(parameterTypes, "'parameterTypes' must not contain null elements");
|
Assert.noNullElements(parameterTypes, "'parameterTypes' must not contain null elements");
|
||||||
return new BeanInstanceSupplier<>(
|
return new BeanInstanceSupplier<>(
|
||||||
new FactoryMethodLookup(declaringClass, methodName, parameterTypes),
|
new FactoryMethodLookup(declaringClass, methodName, parameterTypes),
|
||||||
null, null);
|
null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -151,11 +154,9 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
||||||
* instantiate the underlying bean
|
* instantiate the underlying bean
|
||||||
* @return a new {@link BeanInstanceSupplier} instance with the specified generator
|
* @return a new {@link BeanInstanceSupplier} instance with the specified generator
|
||||||
*/
|
*/
|
||||||
public BeanInstanceSupplier<T> withGenerator(
|
public BeanInstanceSupplier<T> withGenerator(ThrowingBiFunction<RegisteredBean, AutowiredArguments, T> generator) {
|
||||||
ThrowingBiFunction<RegisteredBean, AutowiredArguments, T> generator) {
|
|
||||||
|
|
||||||
Assert.notNull(generator, "'generator' must not be null");
|
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<T> extends AutowiredElementResolver impl
|
||||||
*/
|
*/
|
||||||
public BeanInstanceSupplier<T> withGenerator(ThrowingFunction<RegisteredBean, T> generator) {
|
public BeanInstanceSupplier<T> withGenerator(ThrowingFunction<RegisteredBean, T> generator) {
|
||||||
Assert.notNull(generator, "'generator' must not be null");
|
Assert.notNull(generator, "'generator' must not be null");
|
||||||
return new BeanInstanceSupplier<>(this.lookup,
|
return new BeanInstanceSupplier<>(this.lookup, generator, null, this.shortcutBeanNames);
|
||||||
(registeredBean, args) -> generator.apply(registeredBean), this.shortcuts);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -181,50 +181,83 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
||||||
@Deprecated(since = "6.0.11", forRemoval = true)
|
@Deprecated(since = "6.0.11", forRemoval = true)
|
||||||
public BeanInstanceSupplier<T> withGenerator(ThrowingSupplier<T> generator) {
|
public BeanInstanceSupplier<T> withGenerator(ThrowingSupplier<T> generator) {
|
||||||
Assert.notNull(generator, "'generator' must not be null");
|
Assert.notNull(generator, "'generator' must not be null");
|
||||||
return new BeanInstanceSupplier<>(this.lookup,
|
return new BeanInstanceSupplier<>(this.lookup, registeredBean -> generator.get(),
|
||||||
(registeredBean, args) -> generator.get(), this.shortcuts);
|
null, this.shortcutBeanNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a new {@link BeanInstanceSupplier} instance
|
* Return a new {@link BeanInstanceSupplier} instance
|
||||||
* that uses direct bean name injection shortcuts for specific parameters.
|
* that uses direct bean name injection shortcuts for specific parameters.
|
||||||
* @param beanNames the bean names to use as shortcuts (aligned with the
|
* @deprecated in favor of {@link #withShortcut(String...)}
|
||||||
* constructor or factory method parameters)
|
|
||||||
* @return a new {@link BeanInstanceSupplier} instance
|
|
||||||
* that uses the shortcuts
|
|
||||||
*/
|
*/
|
||||||
|
@Deprecated(since = "6.2", forRemoval = true)
|
||||||
public BeanInstanceSupplier<T> withShortcuts(String... beanNames) {
|
public BeanInstanceSupplier<T> 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<T> withShortcut(String... beanNames) {
|
||||||
|
return new BeanInstanceSupplier<>(
|
||||||
|
this.lookup, this.generatorWithoutArguments, this.generatorWithArguments, beanNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public T get(RegisteredBean registeredBean) throws Exception {
|
public T get(RegisteredBean registeredBean) {
|
||||||
Assert.notNull(registeredBean, "'registeredBean' must not be null");
|
Assert.notNull(registeredBean, "'registeredBean' must not be null");
|
||||||
Executable executable = this.lookup.get(registeredBean);
|
if (this.generatorWithoutArguments != null) {
|
||||||
AutowiredArguments arguments = resolveArguments(registeredBean, executable);
|
Executable executable = getFactoryMethodForGenerator();
|
||||||
if (this.generator != null) {
|
return invokeBeanSupplier(executable, () -> this.generatorWithoutArguments.apply(registeredBean));
|
||||||
return invokeBeanSupplier(executable, () -> this.generator.apply(registeredBean, arguments));
|
}
|
||||||
|
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 invokeBeanSupplier(executable,
|
|
||||||
() -> instantiate(registeredBean.getBeanFactory(), executable, arguments.toArray()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private T invokeBeanSupplier(Executable executable, ThrowingSupplier<T> beanSupplier) {
|
|
||||||
if (!(executable instanceof Method method)) {
|
|
||||||
return beanSupplier.get();
|
|
||||||
}
|
|
||||||
return SimpleInstantiationStrategy.instantiateWithFactoryMethod(method, beanSupplier::get);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
@Override
|
||||||
|
@Nullable
|
||||||
public Method getFactoryMethod() {
|
public Method getFactoryMethod() {
|
||||||
|
// Cached factory method retrieval for qualifier introspection etc.
|
||||||
if (this.lookup instanceof FactoryMethodLookup factoryMethodLookup) {
|
if (this.lookup instanceof FactoryMethodLookup factoryMethodLookup) {
|
||||||
return factoryMethodLookup.get();
|
return factoryMethodLookup.get();
|
||||||
}
|
}
|
||||||
return null;
|
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<T> beanSupplier) {
|
||||||
|
if (executable instanceof Method method) {
|
||||||
|
return SimpleInstantiationStrategy.instantiateWithFactoryMethod(method, beanSupplier);
|
||||||
|
}
|
||||||
|
return beanSupplier.get();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve arguments for the specified registered bean.
|
* Resolve arguments for the specified registered bean.
|
||||||
* @param registeredBean the registered bean
|
* @param registeredBean the registered bean
|
||||||
|
@ -236,26 +269,22 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
||||||
}
|
}
|
||||||
|
|
||||||
private AutowiredArguments resolveArguments(RegisteredBean registeredBean, Executable executable) {
|
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();
|
int parameterCount = executable.getParameterCount();
|
||||||
Object[] resolved = new Object[parameterCount - startIndex];
|
Object[] resolved = new Object[parameterCount];
|
||||||
Assert.isTrue(this.shortcuts == null || this.shortcuts.length == resolved.length,
|
Assert.isTrue(this.shortcutBeanNames == null || this.shortcutBeanNames.length == resolved.length,
|
||||||
() -> "'shortcuts' must contain " + resolved.length + " elements");
|
() -> "'shortcuts' must contain " + resolved.length + " elements");
|
||||||
|
|
||||||
ValueHolder[] argumentValues = resolveArgumentValues(registeredBean, executable);
|
ValueHolder[] argumentValues = resolveArgumentValues(registeredBean, executable);
|
||||||
Set<String> autowiredBeanNames = new LinkedHashSet<>(resolved.length * 2);
|
Set<String> 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);
|
MethodParameter parameter = getMethodParameter(executable, i);
|
||||||
DependencyDescriptor descriptor = new DependencyDescriptor(parameter, true);
|
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) {
|
if (shortcut != null) {
|
||||||
descriptor = new ShortcutDependencyDescriptor(descriptor, shortcut);
|
descriptor = new ShortcutDependencyDescriptor(descriptor, shortcut);
|
||||||
}
|
}
|
||||||
ValueHolder argumentValue = argumentValues[i];
|
ValueHolder argumentValue = argumentValues[i];
|
||||||
resolved[i - startIndex] = resolveAutowiredArgument(
|
resolved[i] = resolveAutowiredArgument(
|
||||||
registeredBean, descriptor, argumentValue, autowiredBeanNames);
|
registeredBean, descriptor, argumentValue, autowiredBeanNames);
|
||||||
}
|
}
|
||||||
registerDependentBeans(registeredBean.getBeanFactory(), registeredBean.getBeanName(), autowiredBeanNames);
|
registerDependentBeans(registeredBean.getBeanFactory(), registeredBean.getBeanName(), autowiredBeanNames);
|
||||||
|
@ -339,62 +368,30 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
private Object instantiate(RegisteredBean registeredBean, Executable executable, Object[] args) {
|
||||||
private T instantiate(ConfigurableBeanFactory beanFactory, Executable executable, Object[] args) {
|
|
||||||
if (executable instanceof Constructor<?> constructor) {
|
if (executable instanceof Constructor<?> constructor) {
|
||||||
try {
|
return BeanUtils.instantiateClass(constructor, args);
|
||||||
return (T) instantiate(constructor, args);
|
|
||||||
}
|
|
||||||
catch (Exception ex) {
|
|
||||||
throw new BeanInstantiationException(constructor, ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (executable instanceof Method method) {
|
if (executable instanceof Method method) {
|
||||||
try {
|
Object target = null;
|
||||||
return (T) instantiate(beanFactory, method, args);
|
String factoryBeanName = registeredBean.getMergedBeanDefinition().getFactoryBeanName();
|
||||||
|
if (factoryBeanName != null) {
|
||||||
|
target = registeredBean.getBeanFactory().getBean(factoryBeanName, method.getDeclaringClass());
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
else if (!Modifier.isStatic(method.getModifiers())) {
|
||||||
|
throw new IllegalStateException("Cannot invoke instance method without factoryBeanName: " + method);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
ReflectionUtils.makeAccessible(method);
|
||||||
|
return method.invoke(target, args);
|
||||||
|
}
|
||||||
|
catch (Throwable ex) {
|
||||||
throw new BeanInstantiationException(method, ex.getMessage(), ex);
|
throw new BeanInstantiationException(method, ex.getMessage(), ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new IllegalStateException("Unsupported executable " + executable.getClass().getName());
|
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) {
|
private static String toCommaSeparatedNames(Class<?>... parameterTypes) {
|
||||||
return Arrays.stream(parameterTypes).map(Class::getName).collect(Collectors.joining(", "));
|
return Arrays.stream(parameterTypes).map(Class::getName).collect(Collectors.joining(", "));
|
||||||
|
@ -423,12 +420,9 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Executable get(RegisteredBean registeredBean) {
|
public Executable get(RegisteredBean registeredBean) {
|
||||||
Class<?> beanClass = registeredBean.getBeanClass();
|
Class<?> beanClass = registeredBean.getMergedBeanDefinition().getBeanClass();
|
||||||
try {
|
try {
|
||||||
Class<?>[] actualParameterTypes = (!ClassUtils.isInnerClass(beanClass)) ?
|
return beanClass.getDeclaredConstructor(this.parameterTypes);
|
||||||
this.parameterTypes : ObjectUtils.addObjectToArray(
|
|
||||||
this.parameterTypes, beanClass.getEnclosingClass(), 0);
|
|
||||||
return beanClass.getDeclaredConstructor(actualParameterTypes);
|
|
||||||
}
|
}
|
||||||
catch (NoSuchMethodException ex) {
|
catch (NoSuchMethodException ex) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
|
@ -454,6 +448,9 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
||||||
|
|
||||||
private final Class<?>[] parameterTypes;
|
private final Class<?>[] parameterTypes;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private volatile Method resolvedMethod;
|
||||||
|
|
||||||
FactoryMethodLookup(Class<?> declaringClass, String methodName, Class<?>[] parameterTypes) {
|
FactoryMethodLookup(Class<?> declaringClass, String methodName, Class<?>[] parameterTypes) {
|
||||||
this.declaringClass = declaringClass;
|
this.declaringClass = declaringClass;
|
||||||
this.methodName = methodName;
|
this.methodName = methodName;
|
||||||
|
@ -466,8 +463,13 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
||||||
}
|
}
|
||||||
|
|
||||||
Method get() {
|
Method get() {
|
||||||
Method method = ReflectionUtils.findMethod(this.declaringClass, this.methodName, this.parameterTypes);
|
Method method = this.resolvedMethod;
|
||||||
Assert.notNull(method, () -> "%s cannot be found".formatted(this));
|
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;
|
return method;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -123,7 +123,7 @@ class DefaultBeanRegistrationCodeFragments implements BeanRegistrationCodeFragme
|
||||||
|
|
||||||
CodeBlock.Builder code = CodeBlock.builder();
|
CodeBlock.Builder code = CodeBlock.builder();
|
||||||
RootBeanDefinition mbd = this.registeredBean.getMergedBeanDefinition();
|
RootBeanDefinition mbd = this.registeredBean.getMergedBeanDefinition();
|
||||||
Class<?> beanClass = (mbd.hasBeanClass() ? ClassUtils.getUserClass(mbd.getBeanClass()) : null);
|
Class<?> beanClass = (mbd.hasBeanClass() ? mbd.getBeanClass() : null);
|
||||||
CodeBlock beanClassCode = generateBeanClassCode(
|
CodeBlock beanClassCode = generateBeanClassCode(
|
||||||
beanRegistrationCode.getClassName().packageName(),
|
beanRegistrationCode.getClassName().packageName(),
|
||||||
(beanClass != null ? beanClass : beanType.toClass()));
|
(beanClass != null ? beanClass : beanType.toClass()));
|
||||||
|
@ -158,7 +158,7 @@ class DefaultBeanRegistrationCodeFragments implements BeanRegistrationCodeFragme
|
||||||
if (beanClass != null && this.registeredBean.getMergedBeanDefinition().getFactoryMethodName() != null) {
|
if (beanClass != null && this.registeredBean.getMergedBeanDefinition().getFactoryMethodName() != null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return (beanClass != null && !beanType.toClass().equals(beanClass));
|
return (beanClass != null && !beanType.toClass().equals(ClassUtils.getUserClass(beanClass)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -20,7 +20,6 @@ import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.Executable;
|
import java.lang.reflect.Executable;
|
||||||
import java.lang.reflect.Member;
|
import java.lang.reflect.Member;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Modifier;
|
|
||||||
import java.lang.reflect.Parameter;
|
import java.lang.reflect.Parameter;
|
||||||
import java.lang.reflect.Proxy;
|
import java.lang.reflect.Proxy;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
@ -55,6 +54,7 @@ import org.springframework.javapoet.CodeBlock;
|
||||||
import org.springframework.javapoet.CodeBlock.Builder;
|
import org.springframework.javapoet.CodeBlock.Builder;
|
||||||
import org.springframework.javapoet.MethodSpec;
|
import org.springframework.javapoet.MethodSpec;
|
||||||
import org.springframework.javapoet.ParameterizedTypeName;
|
import org.springframework.javapoet.ParameterizedTypeName;
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
import org.springframework.util.function.ThrowingSupplier;
|
import org.springframework.util.function.ThrowingSupplier;
|
||||||
|
|
||||||
|
@ -83,9 +83,8 @@ public class InstanceSupplierCodeGenerator {
|
||||||
|
|
||||||
private static final String ARGS_PARAMETER_NAME = "args";
|
private static final String ARGS_PARAMETER_NAME = "args";
|
||||||
|
|
||||||
private static final javax.lang.model.element.Modifier[] PRIVATE_STATIC = {
|
private static final javax.lang.model.element.Modifier[] PRIVATE_STATIC =
|
||||||
javax.lang.model.element.Modifier.PRIVATE,
|
{javax.lang.model.element.Modifier.PRIVATE, javax.lang.model.element.Modifier.STATIC};
|
||||||
javax.lang.model.element.Modifier.STATIC };
|
|
||||||
|
|
||||||
private static final CodeBlock NO_ARGS = CodeBlock.of("");
|
private static final CodeBlock NO_ARGS = CodeBlock.of("");
|
||||||
|
|
||||||
|
@ -165,28 +164,26 @@ public class InstanceSupplierCodeGenerator {
|
||||||
String beanName = registeredBean.getBeanName();
|
String beanName = registeredBean.getBeanName();
|
||||||
Class<?> beanClass = registeredBean.getBeanClass();
|
Class<?> beanClass = registeredBean.getBeanClass();
|
||||||
Class<?> declaringClass = constructor.getDeclaringClass();
|
Class<?> declaringClass = constructor.getDeclaringClass();
|
||||||
boolean dependsOnBean = ClassUtils.isInnerClass(declaringClass);
|
|
||||||
|
|
||||||
Visibility accessVisibility = getAccessVisibility(registeredBean, constructor);
|
Visibility accessVisibility = getAccessVisibility(registeredBean, constructor);
|
||||||
if (KotlinDetector.isKotlinReflectPresent() && KotlinDelegate.hasConstructorWithOptionalParameter(beanClass)) {
|
if (KotlinDetector.isKotlinReflectPresent() && KotlinDelegate.hasConstructorWithOptionalParameter(beanClass)) {
|
||||||
return generateCodeForInaccessibleConstructor(beanName, beanClass, constructor,
|
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) {
|
else if (accessVisibility != Visibility.PRIVATE) {
|
||||||
return generateCodeForAccessibleConstructor(beanName, beanClass, constructor,
|
return generateCodeForAccessibleConstructor(beanName, beanClass, constructor, declaringClass);
|
||||||
dependsOnBean, declaringClass);
|
|
||||||
}
|
}
|
||||||
return generateCodeForInaccessibleConstructor(beanName, beanClass, constructor, dependsOnBean,
|
return generateCodeForInaccessibleConstructor(beanName, beanClass, constructor,
|
||||||
hints -> hints.registerConstructor(constructor, ExecutableMode.INVOKE));
|
hints -> hints.registerConstructor(constructor, ExecutableMode.INVOKE));
|
||||||
}
|
}
|
||||||
|
|
||||||
private CodeBlock generateCodeForAccessibleConstructor(String beanName, Class<?> beanClass,
|
private CodeBlock generateCodeForAccessibleConstructor(String beanName, Class<?> beanClass,
|
||||||
Constructor<?> constructor, boolean dependsOnBean, Class<?> declaringClass) {
|
Constructor<?> constructor, Class<?> declaringClass) {
|
||||||
|
|
||||||
this.generationContext.getRuntimeHints().reflection().registerConstructor(
|
this.generationContext.getRuntimeHints().reflection().registerConstructor(
|
||||||
constructor, ExecutableMode.INTROSPECT);
|
constructor, ExecutableMode.INTROSPECT);
|
||||||
|
|
||||||
if (!dependsOnBean && constructor.getParameterCount() == 0) {
|
if (constructor.getParameterCount() == 0) {
|
||||||
if (!this.allowDirectSupplierShortcut) {
|
if (!this.allowDirectSupplierShortcut) {
|
||||||
return CodeBlock.of("$T.using($T::new)", InstanceSupplier.class, declaringClass);
|
return CodeBlock.of("$T.using($T::new)", InstanceSupplier.class, declaringClass);
|
||||||
}
|
}
|
||||||
|
@ -197,13 +194,13 @@ public class InstanceSupplierCodeGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
GeneratedMethod generatedMethod = generateGetInstanceSupplierMethod(method ->
|
GeneratedMethod generatedMethod = generateGetInstanceSupplierMethod(method ->
|
||||||
buildGetInstanceMethodForConstructor(method, beanName, beanClass, constructor,
|
buildGetInstanceMethodForConstructor(
|
||||||
declaringClass, dependsOnBean, PRIVATE_STATIC));
|
method, beanName, beanClass, constructor, declaringClass, PRIVATE_STATIC));
|
||||||
return generateReturnStatement(generatedMethod);
|
return generateReturnStatement(generatedMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CodeBlock generateCodeForInaccessibleConstructor(String beanName, Class<?> beanClass,
|
private CodeBlock generateCodeForInaccessibleConstructor(String beanName, Class<?> beanClass,
|
||||||
Constructor<?> constructor, boolean dependsOnBean, Consumer<ReflectionHints> hints) {
|
Constructor<?> constructor, Consumer<ReflectionHints> hints) {
|
||||||
|
|
||||||
CodeWarnings codeWarnings = new CodeWarnings();
|
CodeWarnings codeWarnings = new CodeWarnings();
|
||||||
codeWarnings.detectDeprecation(beanClass, constructor)
|
codeWarnings.detectDeprecation(beanClass, constructor)
|
||||||
|
@ -215,8 +212,7 @@ public class InstanceSupplierCodeGenerator {
|
||||||
method.addModifiers(PRIVATE_STATIC);
|
method.addModifiers(PRIVATE_STATIC);
|
||||||
codeWarnings.suppress(method);
|
codeWarnings.suppress(method);
|
||||||
method.returns(ParameterizedTypeName.get(BeanInstanceSupplier.class, beanClass));
|
method.returns(ParameterizedTypeName.get(BeanInstanceSupplier.class, beanClass));
|
||||||
int parameterOffset = (!dependsOnBean) ? 0 : 1;
|
method.addStatement(generateResolverForConstructor(beanClass, constructor));
|
||||||
method.addStatement(generateResolverForConstructor(beanClass, constructor, parameterOffset));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return generateReturnStatement(generatedMethod);
|
return generateReturnStatement(generatedMethod);
|
||||||
|
@ -224,7 +220,7 @@ public class InstanceSupplierCodeGenerator {
|
||||||
|
|
||||||
private void buildGetInstanceMethodForConstructor(MethodSpec.Builder method,
|
private void buildGetInstanceMethodForConstructor(MethodSpec.Builder method,
|
||||||
String beanName, Class<?> beanClass, Constructor<?> constructor, Class<?> declaringClass,
|
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 codeWarnings = new CodeWarnings();
|
||||||
codeWarnings.detectDeprecation(beanClass, constructor, declaringClass)
|
codeWarnings.detectDeprecation(beanClass, constructor, declaringClass)
|
||||||
|
@ -234,72 +230,58 @@ public class InstanceSupplierCodeGenerator {
|
||||||
codeWarnings.suppress(method);
|
codeWarnings.suppress(method);
|
||||||
method.returns(ParameterizedTypeName.get(BeanInstanceSupplier.class, beanClass));
|
method.returns(ParameterizedTypeName.get(BeanInstanceSupplier.class, beanClass));
|
||||||
|
|
||||||
int parameterOffset = (!dependsOnBean) ? 0 : 1;
|
|
||||||
CodeBlock.Builder code = CodeBlock.builder();
|
CodeBlock.Builder code = CodeBlock.builder();
|
||||||
code.add(generateResolverForConstructor(beanClass, constructor, parameterOffset));
|
code.add(generateResolverForConstructor(beanClass, constructor));
|
||||||
boolean hasArguments = constructor.getParameterCount() > 0;
|
boolean hasArguments = constructor.getParameterCount() > 0;
|
||||||
|
|
||||||
CodeBlock arguments = hasArguments ?
|
CodeBlock arguments = hasArguments ?
|
||||||
new AutowiredArgumentsCodeGenerator(declaringClass, constructor)
|
new AutowiredArgumentsCodeGenerator(declaringClass, constructor)
|
||||||
.generateCode(constructor.getParameterTypes(), parameterOffset)
|
.generateCode(constructor.getParameterTypes())
|
||||||
: NO_ARGS;
|
: NO_ARGS;
|
||||||
|
|
||||||
CodeBlock newInstance = generateNewInstanceCodeForConstructor(dependsOnBean, declaringClass, arguments);
|
CodeBlock newInstance = generateNewInstanceCodeForConstructor(declaringClass, arguments);
|
||||||
code.add(generateWithGeneratorCode(hasArguments, newInstance));
|
code.add(generateWithGeneratorCode(hasArguments, newInstance));
|
||||||
method.addStatement(code.build());
|
method.addStatement(code.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
private CodeBlock generateResolverForConstructor(Class<?> beanClass,
|
private CodeBlock generateResolverForConstructor(Class<?> beanClass, Constructor<?> constructor) {
|
||||||
Constructor<?> constructor, int parameterOffset) {
|
CodeBlock parameterTypes = generateParameterTypesCode(constructor.getParameterTypes());
|
||||||
|
|
||||||
CodeBlock parameterTypes = generateParameterTypesCode(constructor.getParameterTypes(), parameterOffset);
|
|
||||||
return CodeBlock.of("return $T.<$T>forConstructor($L)", BeanInstanceSupplier.class, beanClass, parameterTypes);
|
return CodeBlock.of("return $T.<$T>forConstructor($L)", BeanInstanceSupplier.class, beanClass, parameterTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CodeBlock generateNewInstanceCodeForConstructor(boolean dependsOnBean,
|
private CodeBlock generateNewInstanceCodeForConstructor(Class<?> declaringClass, CodeBlock args) {
|
||||||
Class<?> declaringClass, CodeBlock args) {
|
return CodeBlock.of("new $T($L)", declaringClass, 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 generateCodeForFactoryMethod(RegisteredBean registeredBean, Method factoryMethod, Class<?> targetClass) {
|
private CodeBlock generateCodeForFactoryMethod(
|
||||||
String beanName = registeredBean.getBeanName();
|
RegisteredBean registeredBean, Method factoryMethod, Class<?> targetClass) {
|
||||||
Class<?> targetClassToUse = ClassUtils.getUserClass(targetClass);
|
|
||||||
boolean dependsOnBean = !Modifier.isStatic(factoryMethod.getModifiers());
|
|
||||||
|
|
||||||
Visibility accessVisibility = getAccessVisibility(registeredBean, factoryMethod);
|
Visibility accessVisibility = getAccessVisibility(registeredBean, factoryMethod);
|
||||||
if (accessVisibility != Visibility.PRIVATE) {
|
if (accessVisibility != Visibility.PRIVATE) {
|
||||||
return generateCodeForAccessibleFactoryMethod(
|
return generateCodeForAccessibleFactoryMethod(registeredBean.getBeanName(), factoryMethod, targetClass,
|
||||||
beanName, factoryMethod, targetClassToUse, dependsOnBean);
|
registeredBean.getMergedBeanDefinition().getFactoryBeanName());
|
||||||
}
|
}
|
||||||
return generateCodeForInaccessibleFactoryMethod(beanName, factoryMethod, targetClassToUse);
|
return generateCodeForInaccessibleFactoryMethod(registeredBean.getBeanName(), factoryMethod, targetClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CodeBlock generateCodeForAccessibleFactoryMethod(String beanName,
|
private CodeBlock generateCodeForAccessibleFactoryMethod(String beanName,
|
||||||
Method factoryMethod, Class<?> targetClass, boolean dependsOnBean) {
|
Method factoryMethod, Class<?> targetClass, @Nullable String factoryBeanName) {
|
||||||
|
|
||||||
this.generationContext.getRuntimeHints().reflection().registerMethod(
|
this.generationContext.getRuntimeHints().reflection().registerMethod(factoryMethod, ExecutableMode.INTROSPECT);
|
||||||
factoryMethod, ExecutableMode.INTROSPECT);
|
|
||||||
|
|
||||||
if (!dependsOnBean && factoryMethod.getParameterCount() == 0) {
|
if (factoryBeanName == null && factoryMethod.getParameterCount() == 0) {
|
||||||
Class<?> suppliedType = ClassUtils.resolvePrimitiveIfNecessary(factoryMethod.getReturnType());
|
Class<?> suppliedType = ClassUtils.resolvePrimitiveIfNecessary(factoryMethod.getReturnType());
|
||||||
CodeBlock.Builder code = CodeBlock.builder();
|
CodeBlock.Builder code = CodeBlock.builder();
|
||||||
code.add("$T.<$T>forFactoryMethod($T.class, $S)", BeanInstanceSupplier.class,
|
code.add("$T.<$T>forFactoryMethod($T.class, $S)", BeanInstanceSupplier.class,
|
||||||
suppliedType, targetClass, factoryMethod.getName());
|
suppliedType, targetClass, factoryMethod.getName());
|
||||||
code.add(".withGenerator(($L) -> $T.$L())", REGISTERED_BEAN_PARAMETER_NAME,
|
code.add(".withGenerator(($L) -> $T.$L())", REGISTERED_BEAN_PARAMETER_NAME,
|
||||||
targetClass, factoryMethod.getName());
|
ClassUtils.getUserClass(targetClass), factoryMethod.getName());
|
||||||
return code.build();
|
return code.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
GeneratedMethod getInstanceMethod = generateGetInstanceSupplierMethod(method ->
|
GeneratedMethod getInstanceMethod = generateGetInstanceSupplierMethod(method ->
|
||||||
buildGetInstanceMethodForFactoryMethod(method, beanName, factoryMethod,
|
buildGetInstanceMethodForFactoryMethod(method, beanName, factoryMethod,
|
||||||
targetClass, dependsOnBean, PRIVATE_STATIC));
|
targetClass, factoryBeanName, PRIVATE_STATIC));
|
||||||
return generateReturnStatement(getInstanceMethod);
|
return generateReturnStatement(getInstanceMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,12 +302,12 @@ public class InstanceSupplierCodeGenerator {
|
||||||
|
|
||||||
private void buildGetInstanceMethodForFactoryMethod(MethodSpec.Builder method,
|
private void buildGetInstanceMethodForFactoryMethod(MethodSpec.Builder method,
|
||||||
String beanName, Method factoryMethod, Class<?> targetClass,
|
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();
|
String factoryMethodName = factoryMethod.getName();
|
||||||
Class<?> suppliedType = ClassUtils.resolvePrimitiveIfNecessary(factoryMethod.getReturnType());
|
Class<?> suppliedType = ClassUtils.resolvePrimitiveIfNecessary(factoryMethod.getReturnType());
|
||||||
CodeWarnings codeWarnings = new CodeWarnings();
|
CodeWarnings codeWarnings = new CodeWarnings();
|
||||||
codeWarnings.detectDeprecation(targetClass, factoryMethod, suppliedType)
|
codeWarnings.detectDeprecation(ClassUtils.getUserClass(targetClass), factoryMethod, suppliedType)
|
||||||
.detectDeprecation(Arrays.stream(factoryMethod.getParameters()).map(Parameter::getType));
|
.detectDeprecation(Arrays.stream(factoryMethod.getParameters()).map(Parameter::getType));
|
||||||
|
|
||||||
method.addJavadoc("Get the bean instance supplier for '$L'.", beanName);
|
method.addJavadoc("Get the bean instance supplier for '$L'.", beanName);
|
||||||
|
@ -339,12 +321,12 @@ public class InstanceSupplierCodeGenerator {
|
||||||
|
|
||||||
boolean hasArguments = factoryMethod.getParameterCount() > 0;
|
boolean hasArguments = factoryMethod.getParameterCount() > 0;
|
||||||
CodeBlock arguments = hasArguments ?
|
CodeBlock arguments = hasArguments ?
|
||||||
new AutowiredArgumentsCodeGenerator(targetClass, factoryMethod)
|
new AutowiredArgumentsCodeGenerator(ClassUtils.getUserClass(targetClass), factoryMethod)
|
||||||
.generateCode(factoryMethod.getParameterTypes())
|
.generateCode(factoryMethod.getParameterTypes())
|
||||||
: NO_ARGS;
|
: NO_ARGS;
|
||||||
|
|
||||||
CodeBlock newInstance = generateNewInstanceCodeForMethod(
|
CodeBlock newInstance = generateNewInstanceCodeForMethod(
|
||||||
dependsOnBean, targetClass, factoryMethodName, arguments);
|
factoryBeanName, ClassUtils.getUserClass(targetClass), factoryMethodName, arguments);
|
||||||
code.add(generateWithGeneratorCode(hasArguments, newInstance));
|
code.add(generateWithGeneratorCode(hasArguments, newInstance));
|
||||||
method.addStatement(code.build());
|
method.addStatement(code.build());
|
||||||
}
|
}
|
||||||
|
@ -357,19 +339,19 @@ public class InstanceSupplierCodeGenerator {
|
||||||
BeanInstanceSupplier.class, suppliedType, targetClass, factoryMethodName);
|
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)",
|
return CodeBlock.of("return $T.<$T>forFactoryMethod($T.class, $S, $L)",
|
||||||
BeanInstanceSupplier.class, suppliedType, targetClass, factoryMethodName, parameterTypes);
|
BeanInstanceSupplier.class, suppliedType, targetClass, factoryMethodName, parameterTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CodeBlock generateNewInstanceCodeForMethod(boolean dependsOnBean,
|
private CodeBlock generateNewInstanceCodeForMethod(@Nullable String factoryBeanName,
|
||||||
Class<?> targetClass, String factoryMethodName, CodeBlock args) {
|
Class<?> targetClass, String factoryMethodName, CodeBlock args) {
|
||||||
|
|
||||||
if (!dependsOnBean) {
|
if (factoryBeanName == null) {
|
||||||
return CodeBlock.of("$T.$L($L)", targetClass, factoryMethodName, args);
|
return CodeBlock.of("$T.$L($L)", targetClass, factoryMethodName, args);
|
||||||
}
|
}
|
||||||
return CodeBlock.of("$L.getBeanFactory().getBean($T.class).$L($L)",
|
return CodeBlock.of("$L.getBeanFactory().getBean(\"$L\", $T.class).$L($L)",
|
||||||
REGISTERED_BEAN_PARAMETER_NAME, targetClass, factoryMethodName, args);
|
REGISTERED_BEAN_PARAMETER_NAME, factoryBeanName, targetClass, factoryMethodName, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CodeBlock generateReturnStatement(GeneratedMethod generatedMethod) {
|
private CodeBlock generateReturnStatement(GeneratedMethod generatedMethod) {
|
||||||
|
@ -395,10 +377,10 @@ public class InstanceSupplierCodeGenerator {
|
||||||
return AccessControl.lowest(beanTypeAccessControl, memberAccessControl).getVisibility();
|
return AccessControl.lowest(beanTypeAccessControl, memberAccessControl).getVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
private CodeBlock generateParameterTypesCode(Class<?>[] parameterTypes, int offset) {
|
private CodeBlock generateParameterTypesCode(Class<?>[] parameterTypes) {
|
||||||
CodeBlock.Builder code = CodeBlock.builder();
|
CodeBlock.Builder code = CodeBlock.builder();
|
||||||
for (int i = offset; i < parameterTypes.length; i++) {
|
for (int i = 0; i < parameterTypes.length; i++) {
|
||||||
code.add(i != offset ? ", " : "");
|
code.add(i > 0 ? ", " : "");
|
||||||
code.add("$T.class", parameterTypes[i]);
|
code.add("$T.class", parameterTypes[i]);
|
||||||
}
|
}
|
||||||
return code.build();
|
return code.build();
|
||||||
|
|
|
@ -375,7 +375,7 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
|
||||||
if (returnType != null) {
|
if (returnType != null) {
|
||||||
return returnType;
|
return returnType;
|
||||||
}
|
}
|
||||||
Method factoryMethod = this.factoryMethodToIntrospect;
|
Method factoryMethod = getResolvedFactoryMethod();
|
||||||
if (factoryMethod != null) {
|
if (factoryMethod != null) {
|
||||||
return ResolvableType.forMethodReturnType(factoryMethod);
|
return ResolvableType.forMethodReturnType(factoryMethod);
|
||||||
}
|
}
|
||||||
|
@ -453,17 +453,12 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
public Method getResolvedFactoryMethod() {
|
public Method getResolvedFactoryMethod() {
|
||||||
return this.factoryMethodToIntrospect;
|
Method factoryMethod = this.factoryMethodToIntrospect;
|
||||||
}
|
if (factoryMethod == null &&
|
||||||
|
getInstanceSupplier() instanceof InstanceSupplier<?> instanceSupplier) {
|
||||||
@Override
|
factoryMethod = instanceSupplier.getFactoryMethod();
|
||||||
public void setInstanceSupplier(@Nullable Supplier<?> supplier) {
|
|
||||||
super.setInstanceSupplier(supplier);
|
|
||||||
Method factoryMethod = (supplier instanceof InstanceSupplier<?> instanceSupplier ?
|
|
||||||
instanceSupplier.getFactoryMethod() : null);
|
|
||||||
if (factoryMethod != null) {
|
|
||||||
setResolvedFactoryMethod(factoryMethod);
|
|
||||||
}
|
}
|
||||||
|
return factoryMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -19,6 +19,7 @@ package org.springframework.beans.factory.support;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.springframework.beans.BeanInstantiationException;
|
import org.springframework.beans.BeanInstantiationException;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
|
@ -27,7 +28,6 @@ import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.ReflectionUtils;
|
import org.springframework.util.ReflectionUtils;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
import org.springframework.util.function.ThrowingSupplier;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple object instantiation strategy for use in a BeanFactory.
|
* Simple object instantiation strategy for use in a BeanFactory.
|
||||||
|
@ -60,7 +60,7 @@ public class SimpleInstantiationStrategy implements InstantiationStrategy {
|
||||||
* the current value, if any.
|
* the current value, if any.
|
||||||
* @param method the factory method currently being invoked or {@code null}
|
* @param method the factory method currently being invoked or {@code null}
|
||||||
* @since 6.0
|
* @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)
|
@Deprecated(since = "6.2", forRemoval = true)
|
||||||
public static void setCurrentlyInvokedFactoryMethod(@Nullable Method method) {
|
public static void setCurrentlyInvokedFactoryMethod(@Nullable Method method) {
|
||||||
|
@ -81,7 +81,7 @@ public class SimpleInstantiationStrategy implements InstantiationStrategy {
|
||||||
* @return the result of the instance supplier
|
* @return the result of the instance supplier
|
||||||
* @since 6.2
|
* @since 6.2
|
||||||
*/
|
*/
|
||||||
public static <T> T instantiateWithFactoryMethod(Method method, ThrowingSupplier<T> instanceSupplier) {
|
public static <T> T instantiateWithFactoryMethod(Method method, Supplier<T> instanceSupplier) {
|
||||||
Method priorInvokedFactoryMethod = currentlyInvokedFactoryMethod.get();
|
Method priorInvokedFactoryMethod = currentlyInvokedFactoryMethod.get();
|
||||||
try {
|
try {
|
||||||
currentlyInvokedFactoryMethod.set(method);
|
currentlyInvokedFactoryMethod.set(method);
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -122,7 +122,7 @@ class InstanceSupplierCodeGeneratorTests {
|
||||||
NoDependencyComponent bean = getBean(beanDefinition, instanceSupplier);
|
NoDependencyComponent bean = getBean(beanDefinition, instanceSupplier);
|
||||||
assertThat(bean).isInstanceOf(NoDependencyComponent.class);
|
assertThat(bean).isInstanceOf(NoDependencyComponent.class);
|
||||||
assertThat(compiled.getSourceFile()).contains(
|
assertThat(compiled.getSourceFile()).contains(
|
||||||
"getBeanFactory().getBean(InnerComponentConfiguration.class).new NoDependencyComponent()");
|
"InstanceSupplier.using(InnerComponentConfiguration.NoDependencyComponent::new");
|
||||||
});
|
});
|
||||||
assertThat(getReflectionHints().getTypeHint(NoDependencyComponent.class))
|
assertThat(getReflectionHints().getTypeHint(NoDependencyComponent.class))
|
||||||
.satisfies(hasConstructorWithMode(ExecutableMode.INTROSPECT));
|
.satisfies(hasConstructorWithMode(ExecutableMode.INTROSPECT));
|
||||||
|
@ -137,7 +137,7 @@ class InstanceSupplierCodeGeneratorTests {
|
||||||
EnvironmentAwareComponent bean = getBean(beanDefinition, instanceSupplier);
|
EnvironmentAwareComponent bean = getBean(beanDefinition, instanceSupplier);
|
||||||
assertThat(bean).isInstanceOf(EnvironmentAwareComponent.class);
|
assertThat(bean).isInstanceOf(EnvironmentAwareComponent.class);
|
||||||
assertThat(compiled.getSourceFile()).contains(
|
assertThat(compiled.getSourceFile()).contains(
|
||||||
"getBeanFactory().getBean(InnerComponentConfiguration.class).new EnvironmentAwareComponent(");
|
"new InnerComponentConfiguration.EnvironmentAwareComponent(");
|
||||||
});
|
});
|
||||||
assertThat(getReflectionHints().getTypeHint(EnvironmentAwareComponent.class))
|
assertThat(getReflectionHints().getTypeHint(EnvironmentAwareComponent.class))
|
||||||
.satisfies(hasConstructorWithMode(ExecutableMode.INTROSPECT));
|
.satisfies(hasConstructorWithMode(ExecutableMode.INTROSPECT));
|
||||||
|
@ -182,7 +182,7 @@ class InstanceSupplierCodeGeneratorTests {
|
||||||
assertThat(bean).isInstanceOf(String.class);
|
assertThat(bean).isInstanceOf(String.class);
|
||||||
assertThat(bean).isEqualTo("Hello");
|
assertThat(bean).isEqualTo("Hello");
|
||||||
assertThat(compiled.getSourceFile()).contains(
|
assertThat(compiled.getSourceFile()).contains(
|
||||||
"getBeanFactory().getBean(SimpleConfiguration.class).stringBean()");
|
"getBeanFactory().getBean(\"config\", SimpleConfiguration.class).stringBean()");
|
||||||
});
|
});
|
||||||
assertThat(getReflectionHints().getTypeHint(SimpleConfiguration.class))
|
assertThat(getReflectionHints().getTypeHint(SimpleConfiguration.class))
|
||||||
.satisfies(hasMethodWithMode(ExecutableMode.INTROSPECT));
|
.satisfies(hasMethodWithMode(ExecutableMode.INTROSPECT));
|
||||||
|
@ -199,7 +199,7 @@ class InstanceSupplierCodeGeneratorTests {
|
||||||
Object bean = getBean(beanDefinition, instanceSupplier);
|
Object bean = getBean(beanDefinition, instanceSupplier);
|
||||||
assertThat(bean).isInstanceOf(SimpleBean.class);
|
assertThat(bean).isInstanceOf(SimpleBean.class);
|
||||||
assertThat(compiled.getSourceFile()).contains(
|
assertThat(compiled.getSourceFile()).contains(
|
||||||
"getBeanFactory().getBean(DefaultSimpleBeanContract.class).simpleBean()");
|
"getBeanFactory().getBean(\"config\", DefaultSimpleBeanContract.class).simpleBean()");
|
||||||
});
|
});
|
||||||
assertThat(getReflectionHints().getTypeHint(SimpleBeanContract.class))
|
assertThat(getReflectionHints().getTypeHint(SimpleBeanContract.class))
|
||||||
.satisfies(hasMethodWithMode(ExecutableMode.INTROSPECT));
|
.satisfies(hasMethodWithMode(ExecutableMode.INTROSPECT));
|
||||||
|
@ -228,10 +228,8 @@ class InstanceSupplierCodeGeneratorTests {
|
||||||
@Test
|
@Test
|
||||||
void generateWhenHasStaticFactoryMethodWithNoArg() {
|
void generateWhenHasStaticFactoryMethodWithNoArg() {
|
||||||
BeanDefinition beanDefinition = BeanDefinitionBuilder
|
BeanDefinition beanDefinition = BeanDefinitionBuilder
|
||||||
.rootBeanDefinition(Integer.class)
|
.rootBeanDefinition(SimpleConfiguration.class)
|
||||||
.setFactoryMethodOnBean("integerBean", "config").getBeanDefinition();
|
.setFactoryMethod("integerBean").getBeanDefinition();
|
||||||
this.beanFactory.registerBeanDefinition("config", BeanDefinitionBuilder
|
|
||||||
.genericBeanDefinition(SimpleConfiguration.class).getBeanDefinition());
|
|
||||||
compile(beanDefinition, (instanceSupplier, compiled) -> {
|
compile(beanDefinition, (instanceSupplier, compiled) -> {
|
||||||
Integer bean = getBean(beanDefinition, instanceSupplier);
|
Integer bean = getBean(beanDefinition, instanceSupplier);
|
||||||
assertThat(bean).isInstanceOf(Integer.class);
|
assertThat(bean).isInstanceOf(Integer.class);
|
||||||
|
@ -246,12 +244,10 @@ class InstanceSupplierCodeGeneratorTests {
|
||||||
@Test
|
@Test
|
||||||
void generateWhenHasStaticFactoryMethodWithArg() {
|
void generateWhenHasStaticFactoryMethodWithArg() {
|
||||||
RootBeanDefinition beanDefinition = (RootBeanDefinition) BeanDefinitionBuilder
|
RootBeanDefinition beanDefinition = (RootBeanDefinition) BeanDefinitionBuilder
|
||||||
.rootBeanDefinition(String.class)
|
.rootBeanDefinition(SimpleConfiguration.class)
|
||||||
.setFactoryMethodOnBean("create", "config").getBeanDefinition();
|
.setFactoryMethod("create").getBeanDefinition();
|
||||||
beanDefinition.setResolvedFactoryMethod(ReflectionUtils
|
beanDefinition.setResolvedFactoryMethod(ReflectionUtils
|
||||||
.findMethod(SampleFactory.class, "create", Number.class, String.class));
|
.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("number", 42);
|
||||||
this.beanFactory.registerSingleton("string", "test");
|
this.beanFactory.registerSingleton("string", "test");
|
||||||
compile(beanDefinition, (instanceSupplier, compiled) -> {
|
compile(beanDefinition, (instanceSupplier, compiled) -> {
|
||||||
|
@ -265,7 +261,7 @@ class InstanceSupplierCodeGeneratorTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void generateWhenHasStaticFactoryMethodCheckedException() {
|
void generateWhenHasFactoryMethodCheckedException() {
|
||||||
BeanDefinition beanDefinition = BeanDefinitionBuilder
|
BeanDefinition beanDefinition = BeanDefinitionBuilder
|
||||||
.rootBeanDefinition(Integer.class)
|
.rootBeanDefinition(Integer.class)
|
||||||
.setFactoryMethodOnBean("throwingIntegerBean", "config")
|
.setFactoryMethodOnBean("throwingIntegerBean", "config")
|
||||||
|
@ -282,107 +278,6 @@ class InstanceSupplierCodeGeneratorTests {
|
||||||
.satisfies(hasMethodWithMode(ExecutableMode.INTROSPECT));
|
.satisfies(hasMethodWithMode(ExecutableMode.INTROSPECT));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nested
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
class DeprecationTests {
|
|
||||||
|
|
||||||
private static final TestCompiler TEST_COMPILER = TestCompiler.forSystem()
|
|
||||||
.withCompilerOptions("-Xlint:all", "-Xlint:-rawtypes", "-Werror");
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Disabled("Need to move to a separate method so that the warning can be suppressed")
|
|
||||||
void generateWhenTargetClassIsDeprecated() {
|
|
||||||
compileAndCheckWarnings(new RootBeanDefinition(DeprecatedBean.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void generateWhenTargetConstructorIsDeprecated() {
|
|
||||||
compileAndCheckWarnings(new RootBeanDefinition(DeprecatedConstructor.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void generateWhenTargetFactoryMethodIsDeprecated() {
|
|
||||||
BeanDefinition beanDefinition = BeanDefinitionBuilder
|
|
||||||
.rootBeanDefinition(String.class)
|
|
||||||
.setFactoryMethodOnBean("deprecatedString", "config").getBeanDefinition();
|
|
||||||
beanFactory.registerBeanDefinition("config", BeanDefinitionBuilder
|
|
||||||
.genericBeanDefinition(DeprecatedMemberConfiguration.class).getBeanDefinition());
|
|
||||||
compileAndCheckWarnings(beanDefinition);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void generateWhenTargetFactoryMethodParameterIsDeprecated() {
|
|
||||||
BeanDefinition beanDefinition = BeanDefinitionBuilder
|
|
||||||
.rootBeanDefinition(String.class)
|
|
||||||
.setFactoryMethodOnBean("deprecatedParameter", "config").getBeanDefinition();
|
|
||||||
beanFactory.registerBeanDefinition("config", BeanDefinitionBuilder
|
|
||||||
.genericBeanDefinition(DeprecatedMemberConfiguration.class).getBeanDefinition());
|
|
||||||
beanFactory.registerBeanDefinition("parameter", new RootBeanDefinition(DeprecatedBean.class));
|
|
||||||
compileAndCheckWarnings(beanDefinition);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void generateWhenTargetFactoryMethodReturnTypeIsDeprecated() {
|
|
||||||
BeanDefinition beanDefinition = BeanDefinitionBuilder
|
|
||||||
.rootBeanDefinition(DeprecatedBean.class)
|
|
||||||
.setFactoryMethodOnBean("deprecatedReturnType", "config").getBeanDefinition();
|
|
||||||
beanFactory.registerBeanDefinition("config", BeanDefinitionBuilder
|
|
||||||
.genericBeanDefinition(DeprecatedMemberConfiguration.class).getBeanDefinition());
|
|
||||||
compileAndCheckWarnings(beanDefinition);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void compileAndCheckWarnings(BeanDefinition beanDefinition) {
|
|
||||||
assertThatNoException().isThrownBy(() -> compile(TEST_COMPILER, beanDefinition,
|
|
||||||
((instanceSupplier, compiled) -> {})));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nested
|
|
||||||
@SuppressWarnings("removal")
|
|
||||||
class DeprecationForRemovalTests {
|
|
||||||
|
|
||||||
private static final TestCompiler TEST_COMPILER = TestCompiler.forSystem()
|
|
||||||
.withCompilerOptions("-Xlint:all", "-Xlint:-rawtypes", "-Werror");
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Disabled("Need to move to a separate method so that the warning can be suppressed")
|
|
||||||
void generateWhenTargetClassIsDeprecatedForRemoval() {
|
|
||||||
compileAndCheckWarnings(new RootBeanDefinition(DeprecatedForRemovalBean.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void generateWhenTargetConstructorIsDeprecatedForRemoval() {
|
|
||||||
compileAndCheckWarnings(new RootBeanDefinition(DeprecatedForRemovalConstructor.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void generateWhenTargetFactoryMethodIsDeprecatedForRemoval() {
|
|
||||||
BeanDefinition beanDefinition = BeanDefinitionBuilder
|
|
||||||
.rootBeanDefinition(String.class)
|
|
||||||
.setFactoryMethodOnBean("deprecatedString", "config").getBeanDefinition();
|
|
||||||
beanFactory.registerBeanDefinition("config", BeanDefinitionBuilder
|
|
||||||
.genericBeanDefinition(DeprecatedForRemovalMemberConfiguration.class).getBeanDefinition());
|
|
||||||
compileAndCheckWarnings(beanDefinition);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void generateWhenTargetFactoryMethodParameterIsDeprecatedForRemoval() {
|
|
||||||
BeanDefinition beanDefinition = BeanDefinitionBuilder
|
|
||||||
.rootBeanDefinition(String.class)
|
|
||||||
.setFactoryMethodOnBean("deprecatedParameter", "config").getBeanDefinition();
|
|
||||||
beanFactory.registerBeanDefinition("config", BeanDefinitionBuilder
|
|
||||||
.genericBeanDefinition(DeprecatedForRemovalMemberConfiguration.class).getBeanDefinition());
|
|
||||||
beanFactory.registerBeanDefinition("parameter", new RootBeanDefinition(DeprecatedForRemovalBean.class));
|
|
||||||
compileAndCheckWarnings(beanDefinition);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void compileAndCheckWarnings(BeanDefinition beanDefinition) {
|
|
||||||
assertThatNoException().isThrownBy(() -> compile(TEST_COMPILER, beanDefinition,
|
|
||||||
((instanceSupplier, compiled) -> {})));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private ReflectionHints getReflectionHints() {
|
private ReflectionHints getReflectionHints() {
|
||||||
return this.generationContext.getRuntimeHints().reflection();
|
return this.generationContext.getRuntimeHints().reflection();
|
||||||
|
@ -438,4 +333,106 @@ class InstanceSupplierCodeGeneratorTests {
|
||||||
(InstanceSupplier<?>) compiled.getInstance(Supplier.class).get(), compiled));
|
(InstanceSupplier<?>) compiled.getInstance(Supplier.class).get(), compiled));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
class DeprecationTests {
|
||||||
|
|
||||||
|
private static final TestCompiler TEST_COMPILER = TestCompiler.forSystem()
|
||||||
|
.withCompilerOptions("-Xlint:all", "-Xlint:-rawtypes", "-Werror");
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Disabled("Need to move to a separate method so that the warning can be suppressed")
|
||||||
|
void generateWhenTargetClassIsDeprecated() {
|
||||||
|
compileAndCheckWarnings(new RootBeanDefinition(DeprecatedBean.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void generateWhenTargetConstructorIsDeprecated() {
|
||||||
|
compileAndCheckWarnings(new RootBeanDefinition(DeprecatedConstructor.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void generateWhenTargetFactoryMethodIsDeprecated() {
|
||||||
|
BeanDefinition beanDefinition = BeanDefinitionBuilder
|
||||||
|
.rootBeanDefinition(String.class)
|
||||||
|
.setFactoryMethodOnBean("deprecatedString", "config").getBeanDefinition();
|
||||||
|
beanFactory.registerBeanDefinition("config", BeanDefinitionBuilder
|
||||||
|
.genericBeanDefinition(DeprecatedMemberConfiguration.class).getBeanDefinition());
|
||||||
|
compileAndCheckWarnings(beanDefinition);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void generateWhenTargetFactoryMethodParameterIsDeprecated() {
|
||||||
|
BeanDefinition beanDefinition = BeanDefinitionBuilder
|
||||||
|
.rootBeanDefinition(String.class)
|
||||||
|
.setFactoryMethodOnBean("deprecatedParameter", "config").getBeanDefinition();
|
||||||
|
beanFactory.registerBeanDefinition("config", BeanDefinitionBuilder
|
||||||
|
.genericBeanDefinition(DeprecatedMemberConfiguration.class).getBeanDefinition());
|
||||||
|
beanFactory.registerBeanDefinition("parameter", new RootBeanDefinition(DeprecatedBean.class));
|
||||||
|
compileAndCheckWarnings(beanDefinition);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void generateWhenTargetFactoryMethodReturnTypeIsDeprecated() {
|
||||||
|
BeanDefinition beanDefinition = BeanDefinitionBuilder
|
||||||
|
.rootBeanDefinition(DeprecatedBean.class)
|
||||||
|
.setFactoryMethodOnBean("deprecatedReturnType", "config").getBeanDefinition();
|
||||||
|
beanFactory.registerBeanDefinition("config", BeanDefinitionBuilder
|
||||||
|
.genericBeanDefinition(DeprecatedMemberConfiguration.class).getBeanDefinition());
|
||||||
|
compileAndCheckWarnings(beanDefinition);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void compileAndCheckWarnings(BeanDefinition beanDefinition) {
|
||||||
|
assertThatNoException().isThrownBy(() -> compile(TEST_COMPILER, beanDefinition,
|
||||||
|
((instanceSupplier, compiled) -> {})));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@SuppressWarnings("removal")
|
||||||
|
class DeprecationForRemovalTests {
|
||||||
|
|
||||||
|
private static final TestCompiler TEST_COMPILER = TestCompiler.forSystem()
|
||||||
|
.withCompilerOptions("-Xlint:all", "-Xlint:-rawtypes", "-Werror");
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Disabled("Need to move to a separate method so that the warning can be suppressed")
|
||||||
|
void generateWhenTargetClassIsDeprecatedForRemoval() {
|
||||||
|
compileAndCheckWarnings(new RootBeanDefinition(DeprecatedForRemovalBean.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void generateWhenTargetConstructorIsDeprecatedForRemoval() {
|
||||||
|
compileAndCheckWarnings(new RootBeanDefinition(DeprecatedForRemovalConstructor.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void generateWhenTargetFactoryMethodIsDeprecatedForRemoval() {
|
||||||
|
BeanDefinition beanDefinition = BeanDefinitionBuilder
|
||||||
|
.rootBeanDefinition(String.class)
|
||||||
|
.setFactoryMethodOnBean("deprecatedString", "config").getBeanDefinition();
|
||||||
|
beanFactory.registerBeanDefinition("config", BeanDefinitionBuilder
|
||||||
|
.genericBeanDefinition(DeprecatedForRemovalMemberConfiguration.class).getBeanDefinition());
|
||||||
|
compileAndCheckWarnings(beanDefinition);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void generateWhenTargetFactoryMethodParameterIsDeprecatedForRemoval() {
|
||||||
|
BeanDefinition beanDefinition = BeanDefinitionBuilder
|
||||||
|
.rootBeanDefinition(String.class)
|
||||||
|
.setFactoryMethodOnBean("deprecatedParameter", "config").getBeanDefinition();
|
||||||
|
beanFactory.registerBeanDefinition("config", BeanDefinitionBuilder
|
||||||
|
.genericBeanDefinition(DeprecatedForRemovalMemberConfiguration.class).getBeanDefinition());
|
||||||
|
beanFactory.registerBeanDefinition("parameter", new RootBeanDefinition(DeprecatedForRemovalBean.class));
|
||||||
|
compileAndCheckWarnings(beanDefinition);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void compileAndCheckWarnings(BeanDefinition beanDefinition) {
|
||||||
|
assertThatNoException().isThrownBy(() -> compile(TEST_COMPILER, beanDefinition,
|
||||||
|
((instanceSupplier, compiled) -> {})));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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.BDDMockito.given;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.verifyNoInteractions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link RootBeanDefinition}.
|
* Tests for {@link RootBeanDefinition}.
|
||||||
|
@ -54,7 +55,7 @@ class RootBeanDefinitionTests {
|
||||||
beanDefinition.setResolvedFactoryMethod(method);
|
beanDefinition.setResolvedFactoryMethod(method);
|
||||||
beanDefinition.setInstanceSupplier(instanceSupplier);
|
beanDefinition.setInstanceSupplier(instanceSupplier);
|
||||||
assertThat(beanDefinition.getResolvedFactoryMethod()).isEqualTo(method);
|
assertThat(beanDefinition.getResolvedFactoryMethod()).isEqualTo(method);
|
||||||
verify(instanceSupplier).getFactoryMethod();
|
verifyNoInteractions(instanceSupplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -81,15 +82,15 @@ class RootBeanDefinitionTests {
|
||||||
assertThat(beanDefinition.getDestroyMethodNames()).isNull();
|
assertThat(beanDefinition.getDestroyMethodNames()).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static class BeanWithCloseMethod {
|
static class BeanWithCloseMethod {
|
||||||
|
|
||||||
public void close() {
|
public void close() {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static class BeanWithNoDestroyMethod {
|
|
||||||
|
|
||||||
|
static class BeanWithNoDestroyMethod {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,7 +87,7 @@ class InstanceSupplierCodeGeneratorKotlinTests {
|
||||||
Assertions.assertThat(bean).isInstanceOf(String::class.java)
|
Assertions.assertThat(bean).isInstanceOf(String::class.java)
|
||||||
Assertions.assertThat(bean).isEqualTo("Hello")
|
Assertions.assertThat(bean).isEqualTo("Hello")
|
||||||
Assertions.assertThat(compiled.sourceFile).contains(
|
Assertions.assertThat(compiled.sourceFile).contains(
|
||||||
"getBeanFactory().getBean(KotlinConfiguration.class).stringBean()"
|
"getBeanFactory().getBean(\"config\", KotlinConfiguration.class).stringBean()"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Assertions.assertThat<TypeHint?>(getReflectionHints().getTypeHint(KotlinConfiguration::class.java))
|
Assertions.assertThat<TypeHint?>(getReflectionHints().getTypeHint(KotlinConfiguration::class.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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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 InnerComponentConfiguration {
|
||||||
|
|
||||||
public class NoDependencyComponent {
|
public static class NoDependencyComponent {
|
||||||
|
|
||||||
public NoDependencyComponent() {
|
public NoDependencyComponent() {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class EnvironmentAwareComponent {
|
public static class EnvironmentAwareComponent {
|
||||||
|
|
||||||
public EnvironmentAwareComponent(Environment environment) {
|
public EnvironmentAwareComponent(Environment environment) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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 class SimpleConfiguration {
|
||||||
|
|
||||||
public SimpleConfiguration() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public String stringBean() {
|
public String stringBean() {
|
||||||
return "Hello";
|
return "Hello";
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue