Adapt to Spring Framework API change
This commit adapts to API changes in Spring Framework, see spring-projects/spring-framework#31117 Previously, the "autowired" executable to use for a bean was always resolved, even if a custom code fragment didn't really need it. This is key for binding of immutable configuration properties as we use an instance supplier for it. This changes means that the workaround added in maintenance releases can be removed. See gh-37337
This commit is contained in:
@@ -16,8 +16,6 @@
|
||||
|
||||
package org.springframework.boot.autoconfigure.flyway;
|
||||
|
||||
import java.lang.reflect.Executable;
|
||||
|
||||
import javax.lang.model.element.Modifier;
|
||||
|
||||
import org.springframework.aot.generate.GeneratedMethod;
|
||||
@@ -58,8 +56,7 @@ class ResourceProviderCustomizerBeanRegistrationAotProcessor implements BeanRegi
|
||||
|
||||
@Override
|
||||
public CodeBlock generateInstanceSupplierCode(GenerationContext generationContext,
|
||||
BeanRegistrationCode beanRegistrationCode, Executable constructorOrFactoryMethod,
|
||||
boolean allowDirectSupplierShortcut) {
|
||||
BeanRegistrationCode beanRegistrationCode, boolean allowDirectSupplierShortcut) {
|
||||
GeneratedMethod generatedMethod = beanRegistrationCode.getMethods().add("getInstance", (method) -> {
|
||||
method.addJavadoc("Get the bean instance for '$L'.", this.registeredBean.getBeanName());
|
||||
method.addModifiers(Modifier.PRIVATE, Modifier.STATIC);
|
||||
|
||||
@@ -16,18 +16,14 @@
|
||||
|
||||
package org.springframework.boot.context.properties;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.aot.generate.GenerationContext;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution;
|
||||
import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor;
|
||||
import org.springframework.beans.factory.aot.BeanFactoryInitializationCode;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor;
|
||||
import org.springframework.boot.context.properties.bind.BindConstructorProvider;
|
||||
import org.springframework.boot.context.properties.bind.BindMethod;
|
||||
import org.springframework.boot.context.properties.bind.Bindable;
|
||||
import org.springframework.boot.context.properties.bind.BindableRuntimeHintsRegistrar;
|
||||
@@ -47,7 +43,6 @@ class ConfigurationPropertiesBeanFactoryInitializationAotProcessor implements Be
|
||||
@Override
|
||||
public ConfigurationPropertiesReflectionHintsContribution processAheadOfTime(
|
||||
ConfigurableListableBeanFactory beanFactory) {
|
||||
beanFactory.addBeanPostProcessor(new BindConstructorAwareBeanPostProcessor(beanFactory));
|
||||
String[] beanNames = beanFactory.getBeanNamesForAnnotation(ConfigurationProperties.class);
|
||||
List<Bindable<?>> bindables = new ArrayList<>();
|
||||
for (String beanName : beanNames) {
|
||||
@@ -63,37 +58,6 @@ class ConfigurationPropertiesBeanFactoryInitializationAotProcessor implements Be
|
||||
return (!bindables.isEmpty()) ? new ConfigurationPropertiesReflectionHintsContribution(bindables) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link SmartInstantiationAwareBeanPostProcessor} implementation to work around
|
||||
* framework's constructor resolver for immutable configuration properties.
|
||||
* <p>
|
||||
* Constructor binding supports multiple constructors as long as one is identified as
|
||||
* the candidate for binding. Unfortunately, framework is not aware of such feature
|
||||
* and attempts to resolve the autowired constructor to use.
|
||||
*/
|
||||
static class BindConstructorAwareBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {
|
||||
|
||||
private final ConfigurableListableBeanFactory beanFactory;
|
||||
|
||||
BindConstructorAwareBeanPostProcessor(ConfigurableListableBeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName)
|
||||
throws BeansException {
|
||||
BindMethod bindMethod = BindMethodAttribute.get(this.beanFactory, beanName);
|
||||
if (bindMethod != null && bindMethod == BindMethod.VALUE_OBJECT) {
|
||||
Constructor<?> bindConstructor = BindConstructorProvider.DEFAULT.getBindConstructor(beanClass, false);
|
||||
if (bindConstructor != null) {
|
||||
return new Constructor<?>[] { bindConstructor };
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static final class ConfigurationPropertiesReflectionHintsContribution
|
||||
implements BeanFactoryInitializationAotContribution {
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.boot.context.properties;
|
||||
|
||||
import java.lang.reflect.Executable;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import javax.lang.model.element.Modifier;
|
||||
@@ -34,6 +33,7 @@ import org.springframework.beans.factory.support.InstanceSupplier;
|
||||
import org.springframework.beans.factory.support.RegisteredBean;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.boot.context.properties.bind.BindMethod;
|
||||
import org.springframework.javapoet.ClassName;
|
||||
import org.springframework.javapoet.CodeBlock;
|
||||
|
||||
/**
|
||||
@@ -80,10 +80,14 @@ class ConfigurationPropertiesBeanRegistrationAotProcessor implements BeanRegistr
|
||||
beanDefinition, attributeFilter.or(BindMethodAttribute.NAME::equals));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassName getTarget(RegisteredBean registeredBean) {
|
||||
return ClassName.get(this.registeredBean.getBeanClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeBlock generateInstanceSupplierCode(GenerationContext generationContext,
|
||||
BeanRegistrationCode beanRegistrationCode, Executable constructorOrFactoryMethod,
|
||||
boolean allowDirectSupplierShortcut) {
|
||||
BeanRegistrationCode beanRegistrationCode, boolean allowDirectSupplierShortcut) {
|
||||
GeneratedMethod generatedMethod = beanRegistrationCode.getMethods().add("getInstance", (method) -> {
|
||||
Class<?> beanClass = this.registeredBean.getBeanClass();
|
||||
method.addJavadoc("Get the bean instance for '$L'.", this.registeredBean.getBeanName())
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.boot.jackson;
|
||||
|
||||
import java.lang.reflect.Executable;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -33,6 +32,7 @@ import org.springframework.beans.factory.aot.BeanRegistrationCode;
|
||||
import org.springframework.beans.factory.aot.BeanRegistrationCodeFragments;
|
||||
import org.springframework.beans.factory.aot.BeanRegistrationCodeFragmentsDecorator;
|
||||
import org.springframework.beans.factory.support.RegisteredBean;
|
||||
import org.springframework.javapoet.ClassName;
|
||||
import org.springframework.javapoet.CodeBlock;
|
||||
|
||||
/**
|
||||
@@ -54,6 +54,8 @@ class JsonMixinModuleEntriesBeanRegistrationAotProcessor implements BeanRegistra
|
||||
|
||||
static class AotContribution extends BeanRegistrationCodeFragmentsDecorator {
|
||||
|
||||
private static final Class<?> BEAN_TYPE = JsonMixinModuleEntries.class;
|
||||
|
||||
private final RegisteredBean registeredBean;
|
||||
|
||||
private final ClassLoader classLoader;
|
||||
@@ -64,18 +66,21 @@ class JsonMixinModuleEntriesBeanRegistrationAotProcessor implements BeanRegistra
|
||||
this.classLoader = registeredBean.getBeanFactory().getBeanClassLoader();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassName getTarget(RegisteredBean registeredBean) {
|
||||
return ClassName.get(BEAN_TYPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeBlock generateInstanceSupplierCode(GenerationContext generationContext,
|
||||
BeanRegistrationCode beanRegistrationCode, Executable constructorOrFactoryMethod,
|
||||
boolean allowDirectSupplierShortcut) {
|
||||
BeanRegistrationCode beanRegistrationCode, boolean allowDirectSupplierShortcut) {
|
||||
JsonMixinModuleEntries entries = this.registeredBean.getBeanFactory()
|
||||
.getBean(this.registeredBean.getBeanName(), JsonMixinModuleEntries.class);
|
||||
contributeHints(generationContext.getRuntimeHints(), entries);
|
||||
GeneratedMethod generatedMethod = beanRegistrationCode.getMethods().add("getInstance", (method) -> {
|
||||
Class<?> beanType = JsonMixinModuleEntries.class;
|
||||
method.addJavadoc("Get the bean instance for '$L'.", this.registeredBean.getBeanName());
|
||||
method.addModifiers(Modifier.PRIVATE, Modifier.STATIC);
|
||||
method.returns(beanType);
|
||||
method.returns(BEAN_TYPE);
|
||||
CodeBlock.Builder code = CodeBlock.builder();
|
||||
code.add("return $T.create(", JsonMixinModuleEntries.class).beginControlFlow("(mixins) ->");
|
||||
entries.doWithEntry(this.classLoader, (type, mixin) -> addEntryCode(code, type, mixin));
|
||||
|
||||
Reference in New Issue
Block a user