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

@@ -534,10 +534,9 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
Map<String, String> mappings = buildImportAwareMappings();
if (!mappings.isEmpty()) {
GeneratedMethod generatedMethod = beanFactoryInitializationCode
.getMethodGenerator()
.generateMethod("addImportAwareBeanPostProcessors")
.using(builder -> generateAddPostProcessorMethod(builder,
mappings));
.getMethods()
.add("addImportAwareBeanPostProcessors", method ->
generateAddPostProcessorMethod(method, mappings));
beanFactoryInitializationCode
.addInitializer(MethodReference.of(generatedMethod.getName()));
ResourceHints hints = generationContext.getRuntimeHints().resources();
@@ -546,14 +545,14 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
}
}
private void generateAddPostProcessorMethod(MethodSpec.Builder builder,
private void generateAddPostProcessorMethod(MethodSpec.Builder method,
Map<String, String> mappings) {
builder.addJavadoc(
method.addJavadoc(
"Add ImportAwareBeanPostProcessor to support ImportAware beans");
builder.addModifiers(Modifier.PRIVATE);
builder.addParameter(DefaultListableBeanFactory.class, BEAN_FACTORY_VARIABLE);
builder.addCode(generateAddPostProcessorCode(mappings));
method.addModifiers(Modifier.PRIVATE);
method.addParameter(DefaultListableBeanFactory.class, BEAN_FACTORY_VARIABLE);
method.addCode(generateAddPostProcessorCode(mappings));
}
private CodeBlock generateAddPostProcessorCode(Map<String, String> mappings) {

View File

@@ -16,7 +16,6 @@
package org.springframework.context.aot;
import org.springframework.aot.generate.GeneratedClass;
import org.springframework.aot.generate.GenerationContext;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
@@ -47,15 +46,11 @@ public class ApplicationContextAotGenerator {
public ClassName generateApplicationContext(GenericApplicationContext applicationContext,
GenerationContext generationContext) {
applicationContext.refreshForAotProcessing();
DefaultListableBeanFactory beanFactory = applicationContext
.getDefaultListableBeanFactory();
ApplicationContextInitializationCodeGenerator codeGenerator = new ApplicationContextInitializationCodeGenerator();
new BeanFactoryInitializationAotContributions(beanFactory).applyTo(generationContext,
codeGenerator);
GeneratedClass applicationContextInitializer = generationContext.getGeneratedClasses()
.forFeature("ApplicationContextInitializer")
.generate(codeGenerator.generateJavaFile());
return applicationContextInitializer.getName();
DefaultListableBeanFactory beanFactory = applicationContext.getDefaultListableBeanFactory();
ApplicationContextInitializationCodeGenerator codeGenerator =
new ApplicationContextInitializationCodeGenerator(generationContext);
new BeanFactoryInitializationAotContributions(beanFactory).applyTo(generationContext, codeGenerator);
return codeGenerator.getGeneratedClass().getName();
}
}

View File

@@ -18,12 +18,12 @@ package org.springframework.context.aot;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import javax.lang.model.element.Modifier;
import org.springframework.aot.generate.GeneratedClass;
import org.springframework.aot.generate.GeneratedMethods;
import org.springframework.aot.generate.MethodGenerator;
import org.springframework.aot.generate.GenerationContext;
import org.springframework.aot.generate.MethodReference;
import org.springframework.beans.factory.aot.BeanFactoryInitializationCode;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
@@ -44,45 +44,41 @@ import org.springframework.javapoet.TypeSpec;
class ApplicationContextInitializationCodeGenerator
implements BeanFactoryInitializationCode {
private static final String INITIALIZE_METHOD = "initialize";
private static final String APPLICATION_CONTEXT_VARIABLE = "applicationContext";
private final GeneratedMethods generatedMethods = new GeneratedMethods();
private final List<MethodReference> initializers = new ArrayList<>();
private final GeneratedClass generatedClass;
@Override
public MethodGenerator getMethodGenerator() {
return this.generatedMethods;
ApplicationContextInitializationCodeGenerator(GenerationContext generationContext) {
this.generatedClass = generationContext.getGeneratedClasses()
.addForFeature("ApplicationContextInitializer", this::generateType);
this.generatedClass.reserveMethodNames(INITIALIZE_METHOD);
}
@Override
public void addInitializer(MethodReference methodReference) {
this.initializers.add(methodReference);
private void generateType(TypeSpec.Builder type) {
type.addJavadoc(
"{@link $T} to restore an application context based on previous AOT processing.",
ApplicationContextInitializer.class);
type.addModifiers(Modifier.PUBLIC);
type.addSuperinterface(ParameterizedTypeName.get(
ApplicationContextInitializer.class, GenericApplicationContext.class));
type.addMethod(generateInitializeMethod());
}
Consumer<TypeSpec.Builder> generateJavaFile() {
return builder -> {
builder.addJavadoc(
"{@link $T} to restore an application context based on previous AOT processing.",
ApplicationContextInitializer.class);
builder.addModifiers(Modifier.PUBLIC);
builder.addSuperinterface(ParameterizedTypeName.get(
ApplicationContextInitializer.class, GenericApplicationContext.class));
builder.addMethod(generateInitializeMethod());
this.generatedMethods.doWithMethodSpecs(builder::addMethod);
};
}
private MethodSpec generateInitializeMethod() {
MethodSpec.Builder builder = MethodSpec.methodBuilder("initialize");
builder.addAnnotation(Override.class);
builder.addModifiers(Modifier.PUBLIC);
builder.addParameter(GenericApplicationContext.class,
MethodSpec.Builder method = MethodSpec.methodBuilder(INITIALIZE_METHOD);
method.addAnnotation(Override.class);
method.addModifiers(Modifier.PUBLIC);
method.addParameter(GenericApplicationContext.class,
APPLICATION_CONTEXT_VARIABLE);
builder.addCode(generateInitializeCode());
return builder.build();
method.addCode(generateInitializeCode());
return method.build();
}
private CodeBlock generateInitializeCode() {
@@ -93,10 +89,23 @@ class ApplicationContextInitializationCodeGenerator
builder.addStatement("$L.setAutowireCandidateResolver(new $T())",
BEAN_FACTORY_VARIABLE, ContextAnnotationAutowireCandidateResolver.class);
for (MethodReference initializer : this.initializers) {
builder.addStatement(
initializer.toInvokeCodeBlock(CodeBlock.of(BEAN_FACTORY_VARIABLE)));
builder.addStatement(initializer.toInvokeCodeBlock(CodeBlock.of(BEAN_FACTORY_VARIABLE)));
}
return builder.build();
}
GeneratedClass getGeneratedClass() {
return this.generatedClass;
}
@Override
public GeneratedMethods getMethods() {
return this.generatedClass.getMethods();
}
@Override
public void addInitializer(MethodReference methodReference) {
this.initializers.add(methodReference);
}
}