Rename BeanInstantiationContributor to Contribution

This commit polishes the contribution model where an AOT contributing
bean post processor can return a contribution, rather than a
contributor. This makes it easier to return `null` if no contribution
can be produced now that it is named this way.

See gh-28047
This commit is contained in:
Stephane Nicoll 2022-03-04 09:50:27 +01:00
parent 572d017370
commit 20b17f02a2
6 changed files with 51 additions and 52 deletions

View File

@ -57,7 +57,7 @@ import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor;
import org.springframework.beans.factory.generator.AotContributingBeanPostProcessor;
import org.springframework.beans.factory.generator.BeanInstantiationContributor;
import org.springframework.beans.factory.generator.BeanInstantiationContribution;
import org.springframework.beans.factory.generator.InjectionGenerator;
import org.springframework.beans.factory.support.LookupOverride;
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
@ -268,12 +268,12 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
}
@Override
public BeanInstantiationContributor buildAotContributor(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
public BeanInstantiationContribution contribute(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
InjectionMetadata metadata = findInjectionMetadata(beanName, beanType, beanDefinition);
Collection<InjectedElement> injectedElements = metadata.getInjectedElements();
return (!ObjectUtils.isEmpty(injectedElements)
? new AutowiredAnnotationBeanInstantiationContributor(injectedElements)
: BeanInstantiationContributor.NO_OP);
? new AutowiredAnnotationBeanInstantiationContribution(injectedElements)
: null);
}
private InjectionMetadata findInjectionMetadata(String beanName, Class<?> beanType, RootBeanDefinition beanDefinition) {
@ -821,19 +821,19 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
}
}
private static final class AutowiredAnnotationBeanInstantiationContributor implements BeanInstantiationContributor {
private static final class AutowiredAnnotationBeanInstantiationContribution implements BeanInstantiationContribution {
private final Collection<InjectedElement> injectedElements;
private final InjectionGenerator generator;
AutowiredAnnotationBeanInstantiationContributor(Collection<InjectedElement> injectedElements) {
AutowiredAnnotationBeanInstantiationContribution(Collection<InjectedElement> injectedElements) {
this.injectedElements = injectedElements;
this.generator = new InjectionGenerator();
}
@Override
public void contribute(CodeContribution contribution) {
public void applyTo(CodeContribution contribution) {
this.injectedElements.forEach(element -> {
boolean isRequired = isRequired(element);
Member member = element.getMember();

View File

@ -18,6 +18,7 @@ package org.springframework.beans.factory.generator;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.lang.Nullable;
/**
* Specialization of {@link BeanPostProcessor} that contributes to bean
@ -35,12 +36,14 @@ import org.springframework.beans.factory.support.RootBeanDefinition;
public interface AotContributingBeanPostProcessor extends BeanPostProcessor {
/**
* Build a {@link BeanInstantiationContributor} for the given bean definition.
* Contribute a {@link BeanInstantiationContribution} for the given bean definition,
* if applicable.
* @param beanDefinition the merged bean definition for the bean
* @param beanType the inferred type of the bean
* @param beanName the name of the bean
* @return the contributor to use
* @return the contribution to use or {@code null} if the bean should not be processed
*/
BeanInstantiationContributor buildAotContributor(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName);
@Nullable
BeanInstantiationContribution contribute(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName);
}

View File

@ -19,24 +19,18 @@ package org.springframework.beans.factory.generator;
import org.springframework.aot.generator.CodeContribution;
/**
* Contributor to the code that instantiates a bean following ahead of time
* A contribution to the instantiation of a bean following ahead of time
* processing.
*
* @author Stephane Nicoll
* @since 6.0
*/
@FunctionalInterface
public interface BeanInstantiationContributor {
public interface BeanInstantiationContribution {
/**
* A {@link BeanInstantiationContributor} that does not contribute anything
* to the {@link CodeContribution}.
*/
BeanInstantiationContributor NO_OP = contribution -> { };
/**
* Contribute to the specified {@link CodeContribution}.
* <p>Implementation of this interface can assume the following variables
* Contribute bean instantiation to the specified {@link CodeContribution}.
* <p>Implementations of this interface can assume the following variables
* to be accessible:
* <ul>
* <li>{@code beanFactory}: the general {@code DefaultListableBeanFactory}</li>
@ -45,6 +39,6 @@ public interface BeanInstantiationContributor {
* </ul>
* @param contribution the {@link CodeContribution} to use
*/
void contribute(CodeContribution contribution);
void applyTo(CodeContribution contribution);
}

View File

@ -36,25 +36,25 @@ import org.springframework.util.ClassUtils;
* Write the necessary statements to instantiate a bean.
*
* @author Stephane Nicoll
* @see BeanInstantiationContributor
* @see BeanInstantiationContribution
*/
class DefaultBeanInstantiationGenerator {
private final Executable instanceCreator;
private final List<BeanInstantiationContributor> contributors;
private final List<BeanInstantiationContribution> contributions;
private final InjectionGenerator injectionGenerator;
private final Options beanInstanceOptions;
DefaultBeanInstantiationGenerator(Executable instanceCreator, List<BeanInstantiationContributor> contributors) {
DefaultBeanInstantiationGenerator(Executable instanceCreator, List<BeanInstantiationContribution> contributions) {
this.instanceCreator = instanceCreator;
this.contributors = List.copyOf(contributors);
this.contributions = List.copyOf(contributions);
this.injectionGenerator = new InjectionGenerator();
this.beanInstanceOptions = Options.defaults().useReflection(member -> false)
.assignReturnType(member -> !this.contributors.isEmpty()).build();
.assignReturnType(member -> !this.contributions.isEmpty()).build();
}
/**
@ -78,7 +78,7 @@ class DefaultBeanInstantiationGenerator {
private void writeBeanInstantiation(CodeContribution contribution, Constructor<?> constructor) {
Class<?> declaringType = ClassUtils.getUserClass(constructor.getDeclaringClass());
boolean innerClass = isInnerClass(declaringType);
boolean multiStatements = !this.contributors.isEmpty();
boolean multiStatements = !this.contributions.isEmpty();
int minArgs = isInnerClass(declaringType) ? 2 : 1;
CodeBlock.Builder code = CodeBlock.builder();
// Shortcut for common case
@ -110,8 +110,8 @@ class DefaultBeanInstantiationGenerator {
contribution.statements().addStatement(code.build());
if (multiStatements) {
for (BeanInstantiationContributor contributor : this.contributors) {
contributor.contribute(contribution);
for (BeanInstantiationContribution contributor : this.contributions) {
contributor.applyTo(contribution);
}
contribution.statements().addStatement("return bean")
.add(codeBlock -> codeBlock.unindent().add("}"));
@ -127,7 +127,7 @@ class DefaultBeanInstantiationGenerator {
contribution.runtimeHints().reflection().registerMethod(method,
hint -> hint.withMode(ExecutableMode.INTROSPECT));
List<Class<?>> parameterTypes = new ArrayList<>(Arrays.asList(method.getParameterTypes()));
boolean multiStatements = !this.contributors.isEmpty();
boolean multiStatements = !this.contributions.isEmpty();
Class<?> declaringType = method.getDeclaringClass();
CodeBlock.Builder code = CodeBlock.builder();
// Shortcut for common case
@ -148,8 +148,8 @@ class DefaultBeanInstantiationGenerator {
code.add(this.injectionGenerator.writeInstantiation(method));
contribution.statements().addStatement(code.build());
if (multiStatements) {
for (BeanInstantiationContributor contributor : this.contributors) {
contributor.contribute(contribution);
for (BeanInstantiationContribution contributor : this.contributions) {
contributor.applyTo(contribution);
}
contribution.statements().addStatement("return bean")
.add(codeBlock -> codeBlock.unindent().add("}"));

View File

@ -24,11 +24,12 @@ import org.springframework.aot.hint.ExecutableMode;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.TypeReference;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessorTests.ResourceInjectionBean;
import org.springframework.beans.factory.generator.BeanInstantiationContributor;
import org.springframework.beans.factory.generator.BeanInstantiationContribution;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.testfixture.beans.TestBean;
import org.springframework.core.env.Environment;
import org.springframework.javapoet.support.CodeSnippet;
import org.springframework.lang.Nullable;
import static org.assertj.core.api.Assertions.assertThat;
@ -37,10 +38,10 @@ import static org.assertj.core.api.Assertions.assertThat;
*
* @author Stephane Nicoll
*/
class AutowiredAnnotationBeanInstantiationContributorTests {
class AutowiredAnnotationBeanInstantiationContributionTests {
@Test
void buildAotContributorWithPackageProtectedFieldInjection() {
void contributeWithPackageProtectedFieldInjection() {
CodeContribution contribution = contribute(PackageProtectedFieldInjectionSample.class);
assertThat(CodeSnippet.process(contribution.statements().toCodeBlock())).isEqualTo("""
instanceContext.field("environment", Environment.class)
@ -58,12 +59,12 @@ class AutowiredAnnotationBeanInstantiationContributorTests {
}
@Test
void buildAotContributorWithPrivateFieldInjection() {
void contributeWithPrivateFieldInjection() {
CodeContribution contribution = contribute(PrivateFieldInjectionSample.class);
assertThat(CodeSnippet.process(contribution.statements().toCodeBlock())).isEqualTo("""
instanceContext.field("environment", Environment.class)
.invoke(beanFactory, (attributes) -> {
Field environmentField = ReflectionUtils.findField(AutowiredAnnotationBeanInstantiationContributorTests.PrivateFieldInjectionSample.class, "environment", Environment.class);
Field environmentField = ReflectionUtils.findField(AutowiredAnnotationBeanInstantiationContributionTests.PrivateFieldInjectionSample.class, "environment", Environment.class);
ReflectionUtils.makeAccessible(environmentField);
ReflectionUtils.setField(environmentField, bean, attributes.get(0));
})""");
@ -79,7 +80,7 @@ class AutowiredAnnotationBeanInstantiationContributorTests {
}
@Test
void buildAotContributorWithPublicMethodInjection() {
void contributeWithPublicMethodInjection() {
CodeContribution contribution = contribute(PublicMethodInjectionSample.class);
assertThat(CodeSnippet.process(contribution.statements().toCodeBlock())).isEqualTo("""
instanceContext.method("setTestBean", TestBean.class)
@ -95,7 +96,7 @@ class AutowiredAnnotationBeanInstantiationContributorTests {
}
@Test
void buildAotContributorWithInjectionPoints() {
void contributeWithInjectionPoints() {
CodeContribution contribution = contribute(ResourceInjectionBean.class);
assertThat(CodeSnippet.process(contribution.statements().toCodeBlock())).isEqualTo("""
instanceContext.field("testBean", TestBean.class)
@ -116,23 +117,24 @@ class AutowiredAnnotationBeanInstantiationContributorTests {
}
@Test
void buildAotContributorWithoutInjectionPoints() {
BeanInstantiationContributor contributor = createAotContributor(String.class);
assertThat(contributor).isNotNull().isSameAs(BeanInstantiationContributor.NO_OP);
void contributeWithoutInjectionPoints() {
BeanInstantiationContribution contributor = createContribution(String.class);
assertThat(contributor).isNull();
}
private DefaultCodeContribution contribute(Class<?> type) {
BeanInstantiationContributor contributor = createAotContributor(type);
BeanInstantiationContribution contributor = createContribution(type);
assertThat(contributor).isNotNull();
DefaultCodeContribution contribution = new DefaultCodeContribution(new RuntimeHints());
contributor.contribute(contribution);
contributor.applyTo(contribution);
return contribution;
}
private BeanInstantiationContributor createAotContributor(Class<?> type) {
@Nullable
private BeanInstantiationContribution createContribution(Class<?> type) {
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
RootBeanDefinition beanDefinition = new RootBeanDefinition(type);
return bpp.buildAotContributor(beanDefinition, type, "test");
return bpp.contribute(beanDefinition, type, "test");
}

View File

@ -106,10 +106,10 @@ class DefaultBeanInstantiationGeneratorTests {
}
@Test
void generateUsingNoArgConstructorAndContributorsDoesNotUseMethodReference() {
void generateUsingNoArgConstructorAndContributionsDoesNotUseMethodReference() {
CodeContribution contribution = generate(SimpleConfiguration.class.getDeclaredConstructors()[0],
contrib -> contrib.statements().add(CodeBlock.of("// hello\n")),
BeanInstantiationContributor.NO_OP);
contrib -> {});
assertThat(code(contribution)).isEqualTo("""
(instanceContext) -> {
SimpleConfiguration bean = new SimpleConfiguration();
@ -119,7 +119,7 @@ class DefaultBeanInstantiationGeneratorTests {
}
@Test
void generateUsingContributorsRegisterHints() {
void generateUsingContributionsRegisterHints() {
CodeContribution contribution = generate(SimpleConfiguration.class.getDeclaredConstructors()[0],
contrib -> {
contrib.statements().add(CodeBlock.of("// hello\n"));
@ -170,7 +170,7 @@ class DefaultBeanInstantiationGeneratorTests {
}
@Test
void generateUsingMethodAndContributors() {
void generateUsingMethodAndContributions() {
CodeContribution contribution = generate(method(SimpleConfiguration.class, "stringBean"),
contrib -> {
contrib.statements().add(CodeBlock.of("// hello\n"));
@ -240,9 +240,9 @@ class DefaultBeanInstantiationGeneratorTests {
}
private CodeContribution generate(Executable executable,
BeanInstantiationContributor... beanInstantiationContributors) {
BeanInstantiationContribution... beanInstantiationContributions) {
DefaultBeanInstantiationGenerator generator = new DefaultBeanInstantiationGenerator(executable,
Arrays.asList(beanInstantiationContributors));
Arrays.asList(beanInstantiationContributions));
return generator.generateBeanInstantiation(new RuntimeHints());
}