Harmonize generated class name conventions

This commit moves the responsibility of naming classes to the
GenerationContext. This was already largely the case before, except that
the concept of a "mainTarget" and "featureNamePrefix" was specific
to bean factory initialization contributors.

ClassNameGenerator should now be instantiated with a default target
and an optional feature name prefix. As a result, it does no longer
generate class names in the "__" package.

GeneratedClasses can now provide a new, unique, GeneratedClass or
offer a container for retrieving the same GeneratedClass based on an
identifier. This lets all contributors use this facility rather than
creating JavaFile manually. This also means that ClassNameGenerator
is no longer exposed.

Because the naming conventions are now part of the GenerationContext, it
is required to be able to retrieve a specialized version of it if a
code generation round needs to use different naming conventions. A new
withName method has been added to that effect.

Closes gh-28585
This commit is contained in:
Stephane Nicoll
2022-06-22 14:20:00 +02:00
parent b121eed753
commit 6199835d6e
31 changed files with 652 additions and 565 deletions

View File

@@ -25,7 +25,6 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.aot.generate.DefaultGenerationContext;
import org.springframework.aot.generate.GenerationContext;
import org.springframework.aot.generate.InMemoryGeneratedFiles;
import org.springframework.aot.generate.MethodReference;
import org.springframework.aot.hint.RuntimeHints;
@@ -40,6 +39,7 @@ import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.testfixture.beans.factory.aot.MockBeanRegistrationCode;
import org.springframework.core.env.Environment;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.testfixture.aot.generate.TestGenerationContext;
import org.springframework.javapoet.CodeBlock;
import org.springframework.javapoet.JavaFile;
import org.springframework.javapoet.MethodSpec;
@@ -59,7 +59,7 @@ class AutowiredAnnotationBeanRegistrationAotContributionTests {
private InMemoryGeneratedFiles generatedFiles;
private GenerationContext generationContext;
private DefaultGenerationContext generationContext;
private RuntimeHints runtimeHints;
@@ -70,7 +70,7 @@ class AutowiredAnnotationBeanRegistrationAotContributionTests {
@BeforeEach
void setup() {
this.generatedFiles = new InMemoryGeneratedFiles();
this.generationContext = new DefaultGenerationContext(this.generatedFiles);
this.generationContext = new TestGenerationContext(this.generatedFiles);
this.runtimeHints = this.generationContext.getRuntimeHints();
this.beanRegistrationCode = new MockBeanRegistrationCode();
this.beanFactory = new DefaultListableBeanFactory();
@@ -169,6 +169,7 @@ class AutowiredAnnotationBeanRegistrationAotContributionTests {
@SuppressWarnings("unchecked")
private void testCompiledResult(RegisteredBean registeredBean,
BiConsumer<BiFunction<RegisteredBean, Object, Object>, Compiled> result) {
this.generationContext.writeGeneratedContent();
JavaFile javaFile = createJavaFile(registeredBean.getBeanClass());
TestCompiler.forSystem().withFiles(this.generatedFiles).compile(javaFile::writeTo,
compiled -> result.accept(compiled.getInstance(BiFunction.class),

View File

@@ -50,6 +50,7 @@ import org.springframework.beans.testfixture.beans.TestBean;
import org.springframework.beans.testfixture.beans.factory.aot.MockBeanRegistrationsCode;
import org.springframework.core.ResolvableType;
import org.springframework.core.mock.MockSpringFactoriesLoader;
import org.springframework.core.testfixture.aot.generate.TestGenerationContext;
import org.springframework.javapoet.ClassName;
import org.springframework.javapoet.CodeBlock;
import org.springframework.javapoet.JavaFile;
@@ -80,7 +81,7 @@ class BeanDefinitionMethodGeneratorTests {
@BeforeEach
void setup() {
this.generatedFiles = new InMemoryGeneratedFiles();
this.generationContext = new DefaultGenerationContext(this.generatedFiles);
this.generationContext = new TestGenerationContext(this.generatedFiles);
this.beanFactory = new DefaultListableBeanFactory();
this.methodGeneratorFactory = new BeanDefinitionMethodGeneratorFactory(
new AotFactoriesLoader(this.beanFactory, new MockSpringFactoriesLoader()));
@@ -96,7 +97,7 @@ class BeanDefinitionMethodGeneratorTests {
this.methodGeneratorFactory, registeredBean, null,
Collections.emptyList());
MethodReference method = generator.generateBeanDefinitionMethod(
this.generationContext, "", this.beanRegistrationsCode);
this.generationContext, this.beanRegistrationsCode);
testCompiledResult(method, (actual, compiled) -> {
SourceFile sourceFile = compiled.getSourceFile(".*BeanDefinitions");
assertThat(sourceFile).contains("Get the bean definition for 'testBean'");
@@ -114,7 +115,7 @@ class BeanDefinitionMethodGeneratorTests {
this.methodGeneratorFactory, registeredBean, null,
Collections.emptyList());
MethodReference method = generator.generateBeanDefinitionMethod(
this.generationContext, "", this.beanRegistrationsCode);
this.generationContext, this.beanRegistrationsCode);
testCompiledResult(method, (actual, compiled) -> {
assertThat(actual.getResolvableType().resolve()).isEqualTo(GenericBean.class);
SourceFile sourceFile = compiled.getSourceFile(".*BeanDefinitions");
@@ -147,7 +148,7 @@ class BeanDefinitionMethodGeneratorTests {
BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator(
this.methodGeneratorFactory, registeredBean, null, aotContributions);
MethodReference method = generator.generateBeanDefinitionMethod(
this.generationContext, "", this.beanRegistrationsCode);
this.generationContext, this.beanRegistrationsCode);
testCompiledResult(method, (actual, compiled) -> {
assertThat(actual.getBeanClass()).isEqualTo(TestBean.class);
InstanceSupplier<?> supplier = (InstanceSupplier<?>) actual
@@ -173,7 +174,7 @@ class BeanDefinitionMethodGeneratorTests {
BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator(
this.methodGeneratorFactory, registeredBean, null, aotContributions);
MethodReference method = generator.generateBeanDefinitionMethod(
this.generationContext, "", this.beanRegistrationsCode);
this.generationContext, this.beanRegistrationsCode);
testCompiledResult(method, (actual, compiled) -> {
assertThat(actual.getBeanClass()).isEqualTo(TestBean.class);
SourceFile sourceFile = compiled.getSourceFile(".*BeanDefinitions");
@@ -213,7 +214,7 @@ class BeanDefinitionMethodGeneratorTests {
this.methodGeneratorFactory, registeredBean, null,
aotContributions);
MethodReference method = generator.generateBeanDefinitionMethod(
this.generationContext, "", this.beanRegistrationsCode);
this.generationContext, this.beanRegistrationsCode);
testCompiledResult(method, (actual, compiled) -> {
assertThat(actual.getAttribute("a")).isEqualTo("A");
assertThat(actual.getAttribute("b")).isNull();
@@ -246,7 +247,7 @@ class BeanDefinitionMethodGeneratorTests {
this.methodGeneratorFactory, innerBean, "testInnerBean",
Collections.emptyList());
MethodReference method = generator.generateBeanDefinitionMethod(
this.generationContext, "", this.beanRegistrationsCode);
this.generationContext, this.beanRegistrationsCode);
testCompiledResult(method, (actual, compiled) -> {
assertThat(compiled.getSourceFile(".*BeanDefinitions"))
.contains("Get the inner-bean definition for 'testInnerBean'");
@@ -267,7 +268,7 @@ class BeanDefinitionMethodGeneratorTests {
this.methodGeneratorFactory, registeredBean, null,
Collections.emptyList());
MethodReference method = generator.generateBeanDefinitionMethod(
this.generationContext, "", this.beanRegistrationsCode);
this.generationContext, this.beanRegistrationsCode);
testCompiledResult(method, (actual, compiled) -> {
RootBeanDefinition actualInnerBeanDefinition = (RootBeanDefinition) actual
.getPropertyValues().get("name");
@@ -301,7 +302,7 @@ class BeanDefinitionMethodGeneratorTests {
this.methodGeneratorFactory, registeredBean, null,
Collections.emptyList());
MethodReference method = generator.generateBeanDefinitionMethod(
this.generationContext, "", this.beanRegistrationsCode);
this.generationContext, this.beanRegistrationsCode);
testCompiledResult(method, (actual, compiled) -> {
RootBeanDefinition actualInnerBeanDefinition = (RootBeanDefinition) actual
.getConstructorArgumentValues()
@@ -334,7 +335,7 @@ class BeanDefinitionMethodGeneratorTests {
BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator(
this.methodGeneratorFactory, registeredBean, null, aotContributions);
MethodReference method = generator.generateBeanDefinitionMethod(
this.generationContext, "", this.beanRegistrationsCode);
this.generationContext, this.beanRegistrationsCode);
testCompiledResult(method, (actual, compiled) -> {
SourceFile sourceFile = compiled.getSourceFile(".*BeanDefinitions");
assertThat(sourceFile).contains("AotContributedMethod()");
@@ -351,7 +352,7 @@ class BeanDefinitionMethodGeneratorTests {
this.methodGeneratorFactory, registeredBean, null,
Collections.emptyList());
MethodReference method = generator.generateBeanDefinitionMethod(
this.generationContext, "", this.beanRegistrationsCode);
this.generationContext, this.beanRegistrationsCode);
testCompiledResult(method, (actual, compiled) -> {
DefaultListableBeanFactory freshBeanFactory = new DefaultListableBeanFactory();
freshBeanFactory.registerBeanDefinition("test", actual);

View File

@@ -29,6 +29,7 @@ import javax.lang.model.element.Modifier;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.aot.generate.ClassNameGenerator;
import org.springframework.aot.generate.DefaultGenerationContext;
import org.springframework.aot.generate.GenerationContext;
import org.springframework.aot.generate.InMemoryGeneratedFiles;
@@ -42,6 +43,8 @@ import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.testfixture.beans.TestBean;
import org.springframework.beans.testfixture.beans.factory.aot.MockBeanFactoryInitializationCode;
import org.springframework.core.mock.MockSpringFactoriesLoader;
import org.springframework.core.testfixture.aot.generate.TestGenerationContext;
import org.springframework.core.testfixture.aot.generate.TestTarget;
import org.springframework.javapoet.CodeBlock;
import org.springframework.javapoet.JavaFile;
import org.springframework.javapoet.MethodSpec;
@@ -72,7 +75,7 @@ class BeanRegistrationsAotContributionTests {
@BeforeEach
void setup() {
this.generatedFiles = new InMemoryGeneratedFiles();
this.generationContext = new DefaultGenerationContext(this.generatedFiles);
this.generationContext = new TestGenerationContext(this.generatedFiles);
this.beanFactory = new DefaultListableBeanFactory();
this.springFactoriesLoader = new MockSpringFactoriesLoader();
this.methodGeneratorFactory = new BeanDefinitionMethodGeneratorFactory(
@@ -100,7 +103,9 @@ class BeanRegistrationsAotContributionTests {
@Test
void applyToWhenHasNameGeneratesPrefixedFeatureName() {
this.beanFactoryInitializationCode = new MockBeanFactoryInitializationCode("Management");
this.generationContext = new DefaultGenerationContext(
new ClassNameGenerator(TestTarget.class, "Management"), this.generatedFiles);
this.beanFactoryInitializationCode = new MockBeanFactoryInitializationCode();
Map<String, BeanDefinitionMethodGenerator> registrations = new LinkedHashMap<>();
RegisteredBean registeredBean = registerBean(
new RootBeanDefinition(TestBean.class));
@@ -129,11 +134,11 @@ class BeanRegistrationsAotContributionTests {
@Override
MethodReference generateBeanDefinitionMethod(
GenerationContext generationContext, String featureNamePrefix,
GenerationContext generationContext,
BeanRegistrationsCode beanRegistrationsCode) {
beanRegistrationsCodes.add(beanRegistrationsCode);
return super.generateBeanDefinitionMethod(generationContext,
featureNamePrefix, beanRegistrationsCode);
beanRegistrationsCode);
}
};

View File

@@ -52,6 +52,7 @@ import org.springframework.beans.testfixture.beans.factory.generator.factory.Num
import org.springframework.beans.testfixture.beans.factory.generator.factory.SampleFactory;
import org.springframework.beans.testfixture.beans.factory.generator.injection.InjectionComponent;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.testfixture.aot.generate.TestGenerationContext;
import org.springframework.javapoet.ClassName;
import org.springframework.javapoet.CodeBlock;
import org.springframework.javapoet.JavaFile;
@@ -82,7 +83,7 @@ class InstanceSupplierCodeGeneratorTests {
@BeforeEach
void setup() {
this.generatedFiles = new InMemoryGeneratedFiles();
this.generationContext = new DefaultGenerationContext(this.generatedFiles);
this.generationContext = new TestGenerationContext(this.generatedFiles);
}