Browse Source

Allow AOT contributions to customize code fragments.

Update the `BeanRegistrationAotContribution` interface to allow
it to customize `BeanRegistrationCodeFragments`. This change
allows us to drop the `BeanRegistrationCodeFragmentsCustomizer`
interface since an `BeanRegistrationAotProcessor` can now be
used instead.

Closes gh-28557
pull/28569/head
Phillip Webb 4 years ago
parent
commit
8d79ec0b67
  1. 43
      spring-aop/src/main/java/org/springframework/aop/scope/ScopedProxyBeanRegistrationAotProcessor.java
  2. 4
      spring-aop/src/main/resources/META-INF/spring/aot.factories
  3. 4
      spring-aop/src/test/java/org/springframework/aop/scope/ScopedProxyBeanRegistrationAotProcessorTests.java
  4. 35
      spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionMethodGenerator.java
  5. 6
      spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionMethodGeneratorFactory.java
  6. 45
      spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanRegistrationAotContribution.java
  7. 45
      spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanRegistrationCodeFragmentsCustomizer.java
  8. 3
      spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanRegistrationCodeGenerator.java
  9. 10
      spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanRegistrationAotContributionTests.java
  10. 100
      spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanDefinitionMethodGeneratorTests.java
  11. 4
      spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanRegistrationsAotContributionTests.java

43
spring-aop/src/main/java/org/springframework/aop/scope/ScopedProxyBeanRegistrationCodeFragmentsCustomizer.java → spring-aop/src/main/java/org/springframework/aop/scope/ScopedProxyBeanRegistrationAotProcessor.java

@ -26,9 +26,10 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.aot.generate.GeneratedMethod; import org.springframework.aot.generate.GeneratedMethod;
import org.springframework.aot.generate.GenerationContext; import org.springframework.aot.generate.GenerationContext;
import org.springframework.beans.factory.aot.BeanRegistrationAotContribution;
import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;
import org.springframework.beans.factory.aot.BeanRegistrationCode; import org.springframework.beans.factory.aot.BeanRegistrationCode;
import org.springframework.beans.factory.aot.BeanRegistrationCodeFragments; import org.springframework.beans.factory.aot.BeanRegistrationCodeFragments;
import org.springframework.beans.factory.aot.BeanRegistrationCodeFragmentsCustomizer;
import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.support.InstanceSupplier; import org.springframework.beans.factory.support.InstanceSupplier;
@ -39,39 +40,37 @@ import org.springframework.javapoet.CodeBlock;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
/** /**
* {@link BeanRegistrationCodeFragmentsCustomizer} for * {@link BeanRegistrationAotProcessor} for {@link ScopedProxyFactoryBean}.
* {@link ScopedProxyFactoryBean}.
* *
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Phillip Webb * @author Phillip Webb
* @since 6.0 * @since 6.0
*/ */
class ScopedProxyBeanRegistrationCodeFragmentsCustomizer class ScopedProxyBeanRegistrationAotProcessor
implements BeanRegistrationCodeFragmentsCustomizer { implements BeanRegistrationAotProcessor {
private static final Log logger = LogFactory private static final Log logger = LogFactory
.getLog(ScopedProxyBeanRegistrationCodeFragmentsCustomizer.class); .getLog(ScopedProxyBeanRegistrationAotProcessor.class);
@Override @Override
public BeanRegistrationCodeFragments customizeBeanRegistrationCodeFragments( public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {
RegisteredBean registeredBean, BeanRegistrationCodeFragments codeFragments) {
Class<?> beanType = registeredBean.getBeanType().toClass(); Class<?> beanType = registeredBean.getBeanType().toClass();
if (!beanType.equals(ScopedProxyFactoryBean.class)) { if (beanType.equals(ScopedProxyFactoryBean.class)) {
return codeFragments; String targetBeanName = getTargetBeanName(
} registeredBean.getMergedBeanDefinition());
String targetBeanName = getTargetBeanName( BeanDefinition targetBeanDefinition = getTargetBeanDefinition(
registeredBean.getMergedBeanDefinition()); registeredBean.getBeanFactory(), targetBeanName);
BeanDefinition targetBeanDefinition = getTargetBeanDefinition( if (targetBeanDefinition == null) {
registeredBean.getBeanFactory(), targetBeanName); logger.warn("Could not handle " + ScopedProxyFactoryBean.class.getSimpleName()
if (targetBeanDefinition == null) { + ": no target bean definition found with name " + targetBeanName);
logger.warn("Could not handle " + ScopedProxyFactoryBean.class.getSimpleName() return null;
+ ": no target bean definition found with name " + targetBeanName); }
return codeFragments; return BeanRegistrationAotContribution.ofBeanRegistrationCodeFragmentsCustomizer(codeFragments ->
new ScopedProxyBeanRegistrationCodeFragments(codeFragments, registeredBean,
targetBeanName, targetBeanDefinition));
} }
return new ScopedProxyBeanRegistrationCodeFragments(codeFragments, registeredBean, return null;
targetBeanName, targetBeanDefinition);
} }
@Nullable @Nullable

4
spring-aop/src/main/resources/META-INF/spring/aot.factories

@ -1,2 +1,2 @@
org.springframework.beans.factory.aot.registration.BeanRegistrationCodeFragmentsCustomizer=\ org.springframework.beans.factory.aot.registration.BeanRegistrationAotProcessor=\
org.springframework.aop.scope.ScopedProxyBeanRegistrationCodeFragmentsCustomizer org.springframework.aop.scope.ScopedProxyBeanRegistrationAotProcessor

4
spring-aop/src/test/java/org/springframework/aop/scope/ScopedProxyBeanRegistrationCodeFragmentsCustomizerTests.java → spring-aop/src/test/java/org/springframework/aop/scope/ScopedProxyBeanRegistrationAotProcessorTests.java

@ -50,13 +50,13 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/** /**
* Tests for {@link ScopedProxyBeanRegistrationCodeFragmentsCustomizer}. * Tests for {@link ScopedProxyBeanRegistrationAotProcessor}.
* *
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Phillip Webb * @author Phillip Webb
* @since 6.0 * @since 6.0
*/ */
class ScopedProxyBeanRegistrationCodeFragmentsCustomizerTests { class ScopedProxyBeanRegistrationAotProcessorTests {
private DefaultListableBeanFactory beanFactory; private DefaultListableBeanFactory beanFactory;

35
spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionMethodGenerator.java

@ -56,8 +56,6 @@ class BeanDefinitionMethodGenerator {
private final List<BeanRegistrationAotContribution> aotContributions; private final List<BeanRegistrationAotContribution> aotContributions;
private final List<BeanRegistrationCodeFragmentsCustomizer> codeFragmentsCustomizers;
/** /**
* Create a new {@link BeanDefinitionMethodGenerator} instance. * Create a new {@link BeanDefinitionMethodGenerator} instance.
@ -65,13 +63,11 @@ class BeanDefinitionMethodGenerator {
* @param registeredBean the registered bean * @param registeredBean the registered bean
* @param innerBeanPropertyName the inner bean property name * @param innerBeanPropertyName the inner bean property name
* @param aotContributions the AOT contributions * @param aotContributions the AOT contributions
* @param codeFragmentsCustomizers the code fragments customizers
*/ */
BeanDefinitionMethodGenerator( BeanDefinitionMethodGenerator(
BeanDefinitionMethodGeneratorFactory methodGeneratorFactory, BeanDefinitionMethodGeneratorFactory methodGeneratorFactory,
RegisteredBean registeredBean, @Nullable String innerBeanPropertyName, RegisteredBean registeredBean, @Nullable String innerBeanPropertyName,
List<BeanRegistrationAotContribution> aotContributions, List<BeanRegistrationAotContribution> aotContributions) {
List<BeanRegistrationCodeFragmentsCustomizer> codeFragmentsCustomizers) {
this.methodGeneratorFactory = methodGeneratorFactory; this.methodGeneratorFactory = methodGeneratorFactory;
this.registeredBean = registeredBean; this.registeredBean = registeredBean;
@ -79,7 +75,6 @@ class BeanDefinitionMethodGenerator {
.resolve(registeredBean); .resolve(registeredBean);
this.innerBeanPropertyName = innerBeanPropertyName; this.innerBeanPropertyName = innerBeanPropertyName;
this.aotContributions = aotContributions; this.aotContributions = aotContributions;
this.codeFragmentsCustomizers = codeFragmentsCustomizers;
} }
/** /**
@ -92,8 +87,7 @@ class BeanDefinitionMethodGenerator {
MethodReference generateBeanDefinitionMethod(GenerationContext generationContext, MethodReference generateBeanDefinitionMethod(GenerationContext generationContext,
BeanRegistrationsCode beanRegistrationsCode) { BeanRegistrationsCode beanRegistrationsCode) {
BeanRegistrationCodeFragments codeFragments = getCodeFragments( BeanRegistrationCodeFragments codeFragments = getCodeFragments(beanRegistrationsCode);
beanRegistrationsCode);
Class<?> target = codeFragments.getTarget(this.registeredBean, Class<?> target = codeFragments.getTarget(this.registeredBean,
this.constructorOrFactoryMethod); this.constructorOrFactoryMethod);
if (!target.getName().startsWith("java.")) { if (!target.getName().startsWith("java.")) {
@ -115,7 +109,17 @@ class BeanDefinitionMethodGenerator {
Modifier.PRIVATE); Modifier.PRIVATE);
return MethodReference.ofStatic(beanRegistrationsCode.getClassName(), return MethodReference.ofStatic(beanRegistrationsCode.getClassName(),
generatedMethod.getName().toString()); generatedMethod.getName().toString());
}
private BeanRegistrationCodeFragments getCodeFragments(
BeanRegistrationsCode beanRegistrationsCode) {
BeanRegistrationCodeFragments codeFragments = new DefaultBeanRegistrationCodeFragments(
beanRegistrationsCode, this.registeredBean, this.methodGeneratorFactory);
for (BeanRegistrationAotContribution aotContribution : this.aotContributions) {
codeFragments = aotContribution.customizeBeanRegistrationCodeFragments(codeFragments);
}
return codeFragments;
} }
private GeneratedMethod generateBeanDefinitionMethod( private GeneratedMethod generateBeanDefinitionMethod(
@ -126,8 +130,7 @@ class BeanDefinitionMethodGenerator {
BeanRegistrationCodeGenerator codeGenerator = new BeanRegistrationCodeGenerator( BeanRegistrationCodeGenerator codeGenerator = new BeanRegistrationCodeGenerator(
className, methodGenerator, this.registeredBean, className, methodGenerator, this.registeredBean,
this.constructorOrFactoryMethod, codeFragments); this.constructorOrFactoryMethod, codeFragments);
GeneratedMethod method = methodGenerator.generateMethod("get", "bean", GeneratedMethod method = methodGenerator.generateMethod("get", "bean", "definition");
"definition");
this.aotContributions.forEach(aotContribution -> aotContribution this.aotContributions.forEach(aotContribution -> aotContribution
.applyTo(generationContext, codeGenerator)); .applyTo(generationContext, codeGenerator));
return method.using(builder -> { return method.using(builder -> {
@ -140,18 +143,6 @@ class BeanDefinitionMethodGenerator {
}); });
} }
private BeanRegistrationCodeFragments getCodeFragments(
BeanRegistrationsCode beanRegistrationsCode) {
BeanRegistrationCodeFragments codeFragments = new DefaultBeanRegistrationCodeFragments(
beanRegistrationsCode, this.registeredBean, this.methodGeneratorFactory);
for (BeanRegistrationCodeFragmentsCustomizer customizer : this.codeFragmentsCustomizers) {
codeFragments = customizer.customizeBeanRegistrationCodeFragments(
this.registeredBean, codeFragments);
}
return codeFragments;
}
private String getName() { private String getName() {
if (this.innerBeanPropertyName != null) { if (this.innerBeanPropertyName != null) {
return this.innerBeanPropertyName; return this.innerBeanPropertyName;

6
spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionMethodGeneratorFactory.java

@ -47,8 +47,6 @@ class BeanDefinitionMethodGeneratorFactory {
private final List<BeanRegistrationExcludeFilter> excludeFilters; private final List<BeanRegistrationExcludeFilter> excludeFilters;
private final List<BeanRegistrationCodeFragmentsCustomizer> codeGenerationCustomizers;
/** /**
* Create a new {@link BeanDefinitionMethodGeneratorFactory} backed by the * Create a new {@link BeanDefinitionMethodGeneratorFactory} backed by the
@ -67,8 +65,6 @@ class BeanDefinitionMethodGeneratorFactory {
BeanDefinitionMethodGeneratorFactory(AotFactoriesLoader loader) { BeanDefinitionMethodGeneratorFactory(AotFactoriesLoader loader) {
this.aotProcessors = loader.load(BeanRegistrationAotProcessor.class); this.aotProcessors = loader.load(BeanRegistrationAotProcessor.class);
this.excludeFilters = loader.load(BeanRegistrationExcludeFilter.class); this.excludeFilters = loader.load(BeanRegistrationExcludeFilter.class);
this.codeGenerationCustomizers = loader
.load(BeanRegistrationCodeFragmentsCustomizer.class);
} }
@ -92,7 +88,7 @@ class BeanDefinitionMethodGeneratorFactory {
List<BeanRegistrationAotContribution> contributions = getAotContributions( List<BeanRegistrationAotContribution> contributions = getAotContributions(
registeredBean); registeredBean);
return new BeanDefinitionMethodGenerator(this, registeredBean, return new BeanDefinitionMethodGenerator(this, registeredBean,
innerBeanPropertyName, contributions, this.codeGenerationCustomizers); innerBeanPropertyName, contributions);
} }
private boolean isExcluded(RegisteredBean registeredBean) { private boolean isExcluded(RegisteredBean registeredBean) {

45
spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanRegistrationAotContribution.java

@ -16,7 +16,10 @@
package org.springframework.beans.factory.aot; package org.springframework.beans.factory.aot;
import java.util.function.UnaryOperator;
import org.springframework.aot.generate.GenerationContext; import org.springframework.aot.generate.GenerationContext;
import org.springframework.util.Assert;
/** /**
* AOT contribution from a {@link BeanRegistrationAotProcessor} used to register * AOT contribution from a {@link BeanRegistrationAotProcessor} used to register
@ -29,6 +32,19 @@ import org.springframework.aot.generate.GenerationContext;
@FunctionalInterface @FunctionalInterface
public interface BeanRegistrationAotContribution { public interface BeanRegistrationAotContribution {
/**
* Customize the {@link BeanRegistrationCodeFragments} that will be used to
* generate the bean registration code. Custom code fragments can be used if
* default code generation isn't suitable.
* @param codeFragments the existing code fragments
* @return the code fragments to use, may be the original instance or a
* wrapper
*/
default BeanRegistrationCodeFragments customizeBeanRegistrationCodeFragments(
BeanRegistrationCodeFragments codeFragments) {
return codeFragments;
}
/** /**
* Apply this contribution to the given {@link BeanRegistrationCode}. * Apply this contribution to the given {@link BeanRegistrationCode}.
* @param generationContext the active generation context * @param generationContext the active generation context
@ -37,4 +53,33 @@ public interface BeanRegistrationAotContribution {
void applyTo(GenerationContext generationContext, void applyTo(GenerationContext generationContext,
BeanRegistrationCode beanRegistrationCode); BeanRegistrationCode beanRegistrationCode);
/**
* Factory method that can be used to create a
* {@link BeanRegistrationAotContribution} that applies the given
* {@link BeanRegistrationCodeFragments} customizer.
* @param beanRegistrationCodeFragmentsCustomizer the
* {@link BeanRegistrationCodeFragments} customizer
* @return a new {@link BeanRegistrationAotContribution} instance
* @see #customizeBeanRegistrationCodeFragments(BeanRegistrationCodeFragments)
*/
static BeanRegistrationAotContribution ofBeanRegistrationCodeFragmentsCustomizer(
UnaryOperator<BeanRegistrationCodeFragments> beanRegistrationCodeFragmentsCustomizer) {
Assert.notNull(beanRegistrationCodeFragmentsCustomizer,
"BeanRegistrationCodeFragmentsCustomizer must not be null");
return new BeanRegistrationAotContribution() {
@Override
public BeanRegistrationCodeFragments customizeBeanRegistrationCodeFragments(
BeanRegistrationCodeFragments codeFragments) {
return beanRegistrationCodeFragmentsCustomizer.apply(codeFragments);
}
@Override
public void applyTo(GenerationContext generationContext,
BeanRegistrationCode beanRegistrationCode) {
}
};
}
} }

45
spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanRegistrationCodeFragmentsCustomizer.java

@ -1,45 +0,0 @@
/*
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.beans.factory.aot;
import org.springframework.beans.factory.support.RegisteredBean;
/**
* Strategy factory interface that can be used to customize the
* {@link BeanRegistrationCodeFragments} that us used for a given
* {@link RegisteredBean}. This interface can be used if default code generation
* isn't suitable for specific types of {@link RegisteredBean}.
*
* @author Phillip Webb
* @since 6.0
*/
@FunctionalInterface
public interface BeanRegistrationCodeFragmentsCustomizer {
/**
* Apply this {@link BeanRegistrationCodeFragmentsCustomizer} to the given
* {@link BeanRegistrationCodeFragments code fragments generator}. The
* returned code generator my be a
* {@link BeanRegistrationCodeFragmentsWrapper wrapper} around the original.
* @param registeredBean the registered bean
* @param codeFragments the existing code fragments
* @return the code generator to use, either the original or a wrapped one;
*/
BeanRegistrationCodeFragments customizeBeanRegistrationCodeFragments(
RegisteredBean registeredBean, BeanRegistrationCodeFragments codeFragments);
}

3
spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanRegistrationCodeGenerator.java

@ -89,8 +89,7 @@ class BeanRegistrationCodeGenerator implements BeanRegistrationCode {
CodeBlock instanceSupplierCode = this.codeFragments.generateInstanceSupplierCode( CodeBlock instanceSupplierCode = this.codeFragments.generateInstanceSupplierCode(
generationContext, this, this.constructorOrFactoryMethod, generationContext, this, this.constructorOrFactoryMethod,
this.instancePostProcessors.isEmpty()); this.instancePostProcessors.isEmpty());
builder.add( builder.add(this.codeFragments.generateSetBeanInstanceSupplierCode(generationContext,
this.codeFragments.generateSetBeanInstanceSupplierCode(generationContext,
this, instanceSupplierCode, this.instancePostProcessors)); this, instanceSupplierCode, this.instancePostProcessors));
builder.add(this.codeFragments.generateReturnCode(generationContext, this)); builder.add(this.codeFragments.generateReturnCode(generationContext, this));
return builder.build(); return builder.build();

10
spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanRegistrationAotContributionTests.java

@ -182,11 +182,6 @@ class AutowiredAnnotationBeanRegistrationAotContributionTests {
private final List<MethodReference> instancePostProcessors = new ArrayList<>(); private final List<MethodReference> instancePostProcessors = new ArrayList<>();
@Override
public void addInstancePostProcessor(MethodReference methodReference) {
this.instancePostProcessors.add(methodReference);
}
@Override @Override
public ClassName getClassName() { public ClassName getClassName() {
return null; return null;
@ -197,6 +192,11 @@ class AutowiredAnnotationBeanRegistrationAotContributionTests {
return null; return null;
} }
@Override
public void addInstancePostProcessor(MethodReference methodReference) {
this.instancePostProcessors.add(methodReference);
}
} }
} }

100
spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanDefinitionMethodGeneratorTests.java

@ -96,7 +96,7 @@ class BeanDefinitionMethodGeneratorTests {
new RootBeanDefinition(TestBean.class)); new RootBeanDefinition(TestBean.class));
BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator( BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator(
this.methodGeneratorFactory, registeredBean, null, this.methodGeneratorFactory, registeredBean, null,
Collections.emptyList(), Collections.emptyList()); Collections.emptyList());
MethodReference method = generator.generateBeanDefinitionMethod( MethodReference method = generator.generateBeanDefinitionMethod(
this.generationContext, this.beanRegistrationsCode); this.generationContext, this.beanRegistrationsCode);
testCompiledResult(method, (actual, compiled) -> { testCompiledResult(method, (actual, compiled) -> {
@ -114,7 +114,7 @@ class BeanDefinitionMethodGeneratorTests {
ResolvableType.forClassWithGenerics(GenericBean.class, Integer.class))); ResolvableType.forClassWithGenerics(GenericBean.class, Integer.class)));
BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator( BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator(
this.methodGeneratorFactory, registeredBean, null, this.methodGeneratorFactory, registeredBean, null,
Collections.emptyList(), Collections.emptyList()); Collections.emptyList());
MethodReference method = generator.generateBeanDefinitionMethod( MethodReference method = generator.generateBeanDefinitionMethod(
this.generationContext, this.beanRegistrationsCode); this.generationContext, this.beanRegistrationsCode);
testCompiledResult(method, (actual, compiled) -> { testCompiledResult(method, (actual, compiled) -> {
@ -147,8 +147,7 @@ class BeanDefinitionMethodGeneratorTests {
List<BeanRegistrationAotContribution> aotContributions = Collections List<BeanRegistrationAotContribution> aotContributions = Collections
.singletonList(aotContribution); .singletonList(aotContribution);
BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator( BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator(
this.methodGeneratorFactory, registeredBean, null, aotContributions, this.methodGeneratorFactory, registeredBean, null, aotContributions);
Collections.emptyList());
MethodReference method = generator.generateBeanDefinitionMethod( MethodReference method = generator.generateBeanDefinitionMethod(
this.generationContext, this.beanRegistrationsCode); this.generationContext, this.beanRegistrationsCode);
testCompiledResult(method, (actual, compiled) -> { testCompiledResult(method, (actual, compiled) -> {
@ -166,17 +165,55 @@ class BeanDefinitionMethodGeneratorTests {
}); });
} }
@Test
void generateBeanDefinitionMethodWhenHasCodeFragmentsCustomizerGeneratesMethod() {
RegisteredBean registeredBean = registerBean(
new RootBeanDefinition(TestBean.class));
BeanRegistrationAotContribution aotContribution = BeanRegistrationAotContribution
.ofBeanRegistrationCodeFragmentsCustomizer(this::customizeBeanDefinitionCode);
List<BeanRegistrationAotContribution> aotContributions = Collections.singletonList(aotContribution);
BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator(
this.methodGeneratorFactory, registeredBean, null, aotContributions);
MethodReference method = generator.generateBeanDefinitionMethod(
this.generationContext, this.beanRegistrationsCode);
testCompiledResult(method, (actual, compiled) -> {
assertThat(actual.getBeanClass()).isEqualTo(TestBean.class);
SourceFile sourceFile = compiled.getSourceFile(".*BeanDefinitions");
assertThat(sourceFile).contains("I am custom");
});
}
private BeanRegistrationCodeFragments customizeBeanDefinitionCode(
BeanRegistrationCodeFragments codeFragments) {
return new BeanRegistrationCodeFragments(codeFragments) {
@Override
public CodeBlock generateNewBeanDefinitionCode(
GenerationContext generationContext,
ResolvableType beanType,
BeanRegistrationCode beanRegistrationCode) {
CodeBlock.Builder builder = CodeBlock.builder();
builder.addStatement("// I am custom");
builder.add(super.generateNewBeanDefinitionCode(generationContext, beanType, beanRegistrationCode));
return builder.build();
}
};
}
@Test @Test
void generateBeanDefinitionMethodWhenHasAttributeFilterGeneratesMethod() { void generateBeanDefinitionMethodWhenHasAttributeFilterGeneratesMethod() {
RootBeanDefinition beanDefinition = new RootBeanDefinition(TestBean.class); RootBeanDefinition beanDefinition = new RootBeanDefinition(TestBean.class);
beanDefinition.setAttribute("a", "A"); beanDefinition.setAttribute("a", "A");
beanDefinition.setAttribute("b", "B"); beanDefinition.setAttribute("b", "B");
RegisteredBean registeredBean = registerBean(beanDefinition); RegisteredBean registeredBean = registerBean(beanDefinition);
List<BeanRegistrationCodeFragmentsCustomizer> fragmentCustomizers = Collections BeanRegistrationAotContribution aotContribution = BeanRegistrationAotContribution
.singletonList(this::customizeWithAttributeFilter); .ofBeanRegistrationCodeFragmentsCustomizer(this::customizeAttributeFilter);
List<BeanRegistrationAotContribution> aotContributions = Collections
.singletonList(aotContribution);
BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator( BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator(
this.methodGeneratorFactory, registeredBean, null, this.methodGeneratorFactory, registeredBean, null,
Collections.emptyList(), fragmentCustomizers); aotContributions);
MethodReference method = generator.generateBeanDefinitionMethod( MethodReference method = generator.generateBeanDefinitionMethod(
this.generationContext, this.beanRegistrationsCode); this.generationContext, this.beanRegistrationsCode);
testCompiledResult(method, (actual, compiled) -> { testCompiledResult(method, (actual, compiled) -> {
@ -185,8 +222,8 @@ class BeanDefinitionMethodGeneratorTests {
}); });
} }
private BeanRegistrationCodeFragments customizeWithAttributeFilter( private BeanRegistrationCodeFragments customizeAttributeFilter(
RegisteredBean registeredBean, BeanRegistrationCodeFragments codeFragments) { BeanRegistrationCodeFragments codeFragments) {
return new BeanRegistrationCodeFragments(codeFragments) { return new BeanRegistrationCodeFragments(codeFragments) {
@Override @Override
@ -209,7 +246,7 @@ class BeanDefinitionMethodGeneratorTests {
new RootBeanDefinition(AnnotatedBean.class)); new RootBeanDefinition(AnnotatedBean.class));
BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator( BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator(
this.methodGeneratorFactory, innerBean, "testInnerBean", this.methodGeneratorFactory, innerBean, "testInnerBean",
Collections.emptyList(), Collections.emptyList()); Collections.emptyList());
MethodReference method = generator.generateBeanDefinitionMethod( MethodReference method = generator.generateBeanDefinitionMethod(
this.generationContext, this.beanRegistrationsCode); this.generationContext, this.beanRegistrationsCode);
testCompiledResult(method, (actual, compiled) -> { testCompiledResult(method, (actual, compiled) -> {
@ -230,7 +267,7 @@ class BeanDefinitionMethodGeneratorTests {
RegisteredBean registeredBean = registerBean(beanDefinition); RegisteredBean registeredBean = registerBean(beanDefinition);
BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator( BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator(
this.methodGeneratorFactory, registeredBean, null, this.methodGeneratorFactory, registeredBean, null,
Collections.emptyList(), Collections.emptyList()); Collections.emptyList());
MethodReference method = generator.generateBeanDefinitionMethod( MethodReference method = generator.generateBeanDefinitionMethod(
this.generationContext, this.beanRegistrationsCode); this.generationContext, this.beanRegistrationsCode);
testCompiledResult(method, (actual, compiled) -> { testCompiledResult(method, (actual, compiled) -> {
@ -264,7 +301,7 @@ class BeanDefinitionMethodGeneratorTests {
RegisteredBean registeredBean = registerBean(beanDefinition); RegisteredBean registeredBean = registerBean(beanDefinition);
BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator( BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator(
this.methodGeneratorFactory, registeredBean, null, this.methodGeneratorFactory, registeredBean, null,
Collections.emptyList(), Collections.emptyList()); Collections.emptyList());
MethodReference method = generator.generateBeanDefinitionMethod( MethodReference method = generator.generateBeanDefinitionMethod(
this.generationContext, this.beanRegistrationsCode); this.generationContext, this.beanRegistrationsCode);
testCompiledResult(method, (actual, compiled) -> { testCompiledResult(method, (actual, compiled) -> {
@ -297,8 +334,7 @@ class BeanDefinitionMethodGeneratorTests {
.getMethodGenerator().generateMethod("aotContributedMethod") .getMethodGenerator().generateMethod("aotContributedMethod")
.using(builder -> builder.addComment("Example Contribution"))); .using(builder -> builder.addComment("Example Contribution")));
BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator( BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator(
this.methodGeneratorFactory, registeredBean, null, aotContributions, this.methodGeneratorFactory, registeredBean, null, aotContributions);
Collections.emptyList());
MethodReference method = generator.generateBeanDefinitionMethod( MethodReference method = generator.generateBeanDefinitionMethod(
this.generationContext, this.beanRegistrationsCode); this.generationContext, this.beanRegistrationsCode);
testCompiledResult(method, (actual, compiled) -> { testCompiledResult(method, (actual, compiled) -> {
@ -308,40 +344,6 @@ class BeanDefinitionMethodGeneratorTests {
}); });
} }
@Test
void generateBeanDefinitionMethodWhenHasBeanRegistrationCodeFragmentsCustomizerReturnsCodeGeneratesMethod() {
RegisteredBean registeredBean = registerBean(
new RootBeanDefinition(TestBean.class));
List<BeanRegistrationCodeFragmentsCustomizer> codeFragmentsCustomizers = new ArrayList<>();
codeFragmentsCustomizers.add(this::customizeBeanRegistrationCodeFragments);
BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator(
this.methodGeneratorFactory, registeredBean, null,
Collections.emptyList(), codeFragmentsCustomizers);
MethodReference method = generator.generateBeanDefinitionMethod(
this.generationContext, this.beanRegistrationsCode);
testCompiledResult(method,
(actual, compiled) -> assertThat(
compiled.getSourceFile(".*BeanDefinitions"))
.contains("// Custom Code"));
}
private BeanRegistrationCodeFragments customizeBeanRegistrationCodeFragments(
RegisteredBean registeredBean, BeanRegistrationCodeFragments codeFragments) {
return new BeanRegistrationCodeFragments(codeFragments) {
@Override
public CodeBlock generateReturnCode(GenerationContext generationContext,
BeanRegistrationCode beanRegistrationCode) {
CodeBlock.Builder builder = CodeBlock.builder();
builder.addStatement("// Custom Code");
builder.add(super.generateReturnCode(generationContext,
beanRegistrationCode));
return builder.build();
}
};
}
@Test @Test
@CompileWithTargetClassAccess(classes = PackagePrivateTestBean.class) @CompileWithTargetClassAccess(classes = PackagePrivateTestBean.class)
void generateBeanDefinitionMethodWhenPackagePrivateBean() { void generateBeanDefinitionMethodWhenPackagePrivateBean() {
@ -349,7 +351,7 @@ class BeanDefinitionMethodGeneratorTests {
new RootBeanDefinition(PackagePrivateTestBean.class)); new RootBeanDefinition(PackagePrivateTestBean.class));
BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator( BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator(
this.methodGeneratorFactory, registeredBean, null, this.methodGeneratorFactory, registeredBean, null,
Collections.emptyList(), Collections.emptyList()); Collections.emptyList());
MethodReference method = generator.generateBeanDefinitionMethod( MethodReference method = generator.generateBeanDefinitionMethod(
this.generationContext, this.beanRegistrationsCode); this.generationContext, this.beanRegistrationsCode);
testCompiledResult(method, false, (actual, compiled) -> { testCompiledResult(method, false, (actual, compiled) -> {

4
spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanRegistrationsAotContributionTests.java

@ -86,7 +86,7 @@ class BeanRegistrationsAotContributionTests {
new RootBeanDefinition(TestBean.class)); new RootBeanDefinition(TestBean.class));
BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator( BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator(
this.methodGeneratorFactory, registeredBean, null, this.methodGeneratorFactory, registeredBean, null,
Collections.emptyList(), Collections.emptyList()); Collections.emptyList());
registrations.put("testBean", generator); registrations.put("testBean", generator);
BeanRegistrationsAotContribution contribution = new BeanRegistrationsAotContribution( BeanRegistrationsAotContribution contribution = new BeanRegistrationsAotContribution(
registrations); registrations);
@ -106,7 +106,7 @@ class BeanRegistrationsAotContributionTests {
new RootBeanDefinition(TestBean.class)); new RootBeanDefinition(TestBean.class));
BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator( BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator(
this.methodGeneratorFactory, registeredBean, null, this.methodGeneratorFactory, registeredBean, null,
Collections.emptyList(), Collections.emptyList()) { Collections.emptyList()) {
@Override @Override
MethodReference generateBeanDefinitionMethod( MethodReference generateBeanDefinitionMethod(

Loading…
Cancel
Save