Migrate AOT tests to use GeneratedClasses and refine/polish AOT APIs

Migrate all AOT tests to make use of `GeneratedClasses` rather than
directly generating Java files. This commit also refines and polishes
AOT APIs to being greater consistency.

Specifically:

	- The `MethodGenerator` interface has been removed in favor of
	  working directly with `GeneratedMethods`.
	- The visibility of several constructors and methods has been
	  reduced to package-private.
	- The `using(...)` and `builder` methods have been removed in
	  favor of setting the `Consumer` callbacks directly as
	  constructor arguments.
	- Variable names for builders are now named `type` or `method`
	  depending on what they're building.

Closes gh-28831
This commit is contained in:
Phillip Webb
2022-06-23 13:48:38 -07:00
parent 4f8516e2c3
commit f2d31b7a20
51 changed files with 1255 additions and 1399 deletions

View File

@@ -39,10 +39,8 @@ import org.springframework.context.testfixture.context.generator.annotation.Impo
import org.springframework.context.testfixture.context.generator.annotation.ImportConfiguration;
import org.springframework.core.testfixture.aot.generate.TestGenerationContext;
import org.springframework.javapoet.CodeBlock;
import org.springframework.javapoet.JavaFile;
import org.springframework.javapoet.MethodSpec;
import org.springframework.javapoet.ParameterizedTypeName;
import org.springframework.javapoet.TypeSpec;
import org.springframework.lang.Nullable;
import static org.assertj.core.api.Assertions.assertThat;
@@ -56,21 +54,26 @@ import static org.assertj.core.api.Assertions.entry;
*/
class ConfigurationClassPostProcessorAotContributionTests {
private DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
private final InMemoryGeneratedFiles generatedFiles;
private InMemoryGeneratedFiles generatedFiles = new InMemoryGeneratedFiles();
private final DefaultGenerationContext generationContext;
private DefaultGenerationContext generationContext = new TestGenerationContext(
this.generatedFiles);
private final MockBeanFactoryInitializationCode beanFactoryInitializationCode;
ConfigurationClassPostProcessorAotContributionTests() {
this.generatedFiles = new InMemoryGeneratedFiles();
this.generationContext = new TestGenerationContext(this.generatedFiles);
this.beanFactoryInitializationCode = new MockBeanFactoryInitializationCode(this.generationContext);
}
private MockBeanFactoryInitializationCode beanFactoryInitializationCode = new MockBeanFactoryInitializationCode();
@Test
void applyToWhenHasImportAwareConfigurationRegistersBeanPostProcessorWithMapEntry() {
BeanFactoryInitializationAotContribution contribution = getContribution(
ImportConfiguration.class);
contribution.applyTo(this.generationContext, this.beanFactoryInitializationCode);
testCompiledResult((initializer, compiled) -> {
compile((initializer, compiled) -> {
DefaultListableBeanFactory freshBeanFactory = new DefaultListableBeanFactory();
initializer.accept(freshBeanFactory);
ImportAwareAotBeanPostProcessor postProcessor = (ImportAwareAotBeanPostProcessor) freshBeanFactory
@@ -89,8 +92,8 @@ class ConfigurationClassPostProcessorAotContributionTests {
.singleElement()
.satisfies(resourceHint -> assertThat(resourceHint.getIncludes())
.map(ResourcePatternHint::getPattern)
.containsOnly(
"org/springframework/context/testfixture/context/generator/annotation/ImportConfiguration.class"));
.containsOnly("org/springframework/context/testfixture/context/generator/annotation/"
+ "ImportConfiguration.class"));
}
@Test
@@ -100,38 +103,28 @@ class ConfigurationClassPostProcessorAotContributionTests {
@Nullable
private BeanFactoryInitializationAotContribution getContribution(Class<?> type) {
this.beanFactory.registerBeanDefinition("configuration",
new RootBeanDefinition(type));
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerBeanDefinition("configuration", new RootBeanDefinition(type));
ConfigurationClassPostProcessor postProcessor = new ConfigurationClassPostProcessor();
postProcessor.postProcessBeanFactory(this.beanFactory);
return postProcessor.processAheadOfTime(this.beanFactory);
postProcessor.postProcessBeanFactory(beanFactory);
return postProcessor.processAheadOfTime(beanFactory);
}
@SuppressWarnings("unchecked")
private void testCompiledResult(
BiConsumer<Consumer<DefaultListableBeanFactory>, Compiled> result) {
JavaFile javaFile = createJavaFile();
private void compile(BiConsumer<Consumer<DefaultListableBeanFactory>, Compiled> result) {
MethodReference methodReference = this.beanFactoryInitializationCode
.getInitializers().get(0);
this.beanFactoryInitializationCode.getTypeBuilder().set(type -> {
type.addModifiers(Modifier.PUBLIC);
type.addSuperinterface(ParameterizedTypeName.get(Consumer.class, DefaultListableBeanFactory.class));
type.addMethod(MethodSpec.methodBuilder("accept").addModifiers(Modifier.PUBLIC)
.addParameter(DefaultListableBeanFactory.class, "beanFactory")
.addStatement(methodReference.toInvokeCodeBlock(CodeBlock.of("beanFactory")))
.build());
});
this.generationContext.writeGeneratedContent();
TestCompiler.forSystem().withFiles(this.generatedFiles).compile(javaFile::writeTo,
compiled -> result.accept(compiled.getInstance(Consumer.class),
compiled));
}
private JavaFile createJavaFile() {
MethodReference methodReference = this.beanFactoryInitializationCode.getInitializers()
.get(0);
TypeSpec.Builder builder = TypeSpec.classBuilder("TestConsumer");
builder.addModifiers(Modifier.PUBLIC);
builder.addSuperinterface(ParameterizedTypeName.get(Consumer.class,
DefaultListableBeanFactory.class));
builder.addMethod(MethodSpec.methodBuilder("accept").addModifiers(Modifier.PUBLIC)
.addParameter(DefaultListableBeanFactory.class, "beanFactory")
.addStatement(
methodReference.toInvokeCodeBlock(CodeBlock.of("beanFactory")))
.build());
this.beanFactoryInitializationCode.getMethodGenerator()
.doWithMethodSpecs(builder::addMethod);
return JavaFile.builder("__", builder.build()).build();
TestCompiler.forSystem().withFiles(this.generatedFiles).compile(compiled ->
result.accept(compiled.getInstance(Consumer.class), compiled));
}
private void assertPostProcessorEntry(ImportAwareAotBeanPostProcessor postProcessor,

View File

@@ -188,14 +188,11 @@ class ApplicationContextAotGeneratorTests {
BiConsumer<ApplicationContextInitializer<GenericApplicationContext>, Compiled> result) {
ApplicationContextAotGenerator generator = new ApplicationContextAotGenerator();
InMemoryGeneratedFiles generatedFiles = new InMemoryGeneratedFiles();
DefaultGenerationContext generationContext = new TestGenerationContext(
generatedFiles);
DefaultGenerationContext generationContext = new TestGenerationContext(generatedFiles);
generator.generateApplicationContext(applicationContext, generationContext);
generationContext.writeGeneratedContent();
TestCompiler.forSystem().withFiles(generatedFiles)
.compile(compiled -> result.accept(
compiled.getInstance(ApplicationContextInitializer.class),
compiled));
TestCompiler.forSystem().withFiles(generatedFiles).compile(compiled ->
result.accept(compiled.getInstance(ApplicationContextInitializer.class), compiled));
}
private GenericApplicationContext toFreshApplicationContext(

View File

@@ -25,6 +25,7 @@ import java.lang.annotation.Target;
import org.junit.jupiter.api.Test;
import org.springframework.aot.generate.GenerationContext;
import org.springframework.aot.generate.InMemoryGeneratedFiles;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.TypeReference;
@@ -53,7 +54,7 @@ class ReflectiveProcessorBeanRegistrationAotProcessorTests {
private final ReflectiveProcessorBeanRegistrationAotProcessor processor = new ReflectiveProcessorBeanRegistrationAotProcessor();
private final GenerationContext generationContext = new TestGenerationContext();
private final GenerationContext generationContext = new TestGenerationContext(new InMemoryGeneratedFiles());
@Test
void shouldIgnoreNonAnnotatedType() {

View File

@@ -26,6 +26,7 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.aot.generate.GenerationContext;
import org.springframework.aot.generate.InMemoryGeneratedFiles;
import org.springframework.aot.hint.ResourceBundleHint;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
@@ -55,7 +56,7 @@ class RuntimeHintsBeanFactoryInitializationAotProcessorTests {
@BeforeEach
void setup() {
this.generationContext = new TestGenerationContext();
this.generationContext = new TestGenerationContext(new InMemoryGeneratedFiles());
this.generator = new ApplicationContextAotGenerator();
}