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

@@ -30,6 +30,7 @@ import java.util.Map;
import java.util.Properties;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
@@ -39,11 +40,10 @@ import jakarta.persistence.PersistenceProperty;
import jakarta.persistence.PersistenceUnit;
import jakarta.persistence.SynchronizationType;
import org.springframework.aot.generate.GeneratedClass;
import org.springframework.aot.generate.GeneratedMethod;
import org.springframework.aot.generate.GeneratedMethods;
import org.springframework.aot.generate.GenerationContext;
import org.springframework.aot.generate.MethodGenerator;
import org.springframework.aot.generate.MethodNameGenerator;
import org.springframework.aot.generate.MethodReference;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.beans.BeanUtils;
@@ -70,11 +70,9 @@ import org.springframework.core.BridgeMethodResolver;
import org.springframework.core.Ordered;
import org.springframework.core.PriorityOrdered;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.javapoet.ClassName;
import org.springframework.javapoet.CodeBlock;
import org.springframework.javapoet.JavaFile;
import org.springframework.javapoet.MethodSpec;
import org.springframework.javapoet.TypeSpec;
import org.springframework.javapoet.MethodSpec.Builder;
import org.springframework.jndi.JndiLocatorDelegate;
import org.springframework.jndi.JndiTemplate;
import org.springframework.lang.Nullable;
@@ -789,34 +787,27 @@ public class PersistenceAnnotationBeanPostProcessor implements InstantiationAwar
@Override
public void applyTo(GenerationContext generationContext,
BeanRegistrationCode beanRegistrationCode) {
ClassName className = generationContext.getClassNameGenerator()
.generateClassName(this.target, "PersistenceInjection");
TypeSpec.Builder classBuilder = TypeSpec.classBuilder(className);
classBuilder.addJavadoc("Persistence injection for {@link $T}.", this.target);
classBuilder.addModifiers(javax.lang.model.element.Modifier.PUBLIC);
GeneratedMethods methods = new GeneratedMethods(
new MethodNameGenerator(APPLY_METHOD));
classBuilder.addMethod(generateMethod(generationContext.getRuntimeHints(),
className, methods));
methods.doWithMethodSpecs(classBuilder::addMethod);
JavaFile javaFile = JavaFile
.builder(className.packageName(), classBuilder.build()).build();
generationContext.getGeneratedFiles().addSourceFile(javaFile);
GeneratedClass generatedClass = generationContext.getGeneratedClasses()
.forFeatureComponent("PersistenceInjection", this.target).generate(type -> {
type.addJavadoc("Persistence injection for {@link $T}.", this.target);
type.addModifiers(javax.lang.model.element.Modifier.PUBLIC);
});
generatedClass.getMethodGenerator().generateMethod(APPLY_METHOD)
.using(generateMethod(generationContext.getRuntimeHints(), generatedClass.getMethodGenerator()));
beanRegistrationCode.addInstancePostProcessor(
MethodReference.ofStatic(className, APPLY_METHOD));
MethodReference.ofStatic(generatedClass.getName(), APPLY_METHOD));
}
private MethodSpec generateMethod(RuntimeHints hints, ClassName className,
MethodGenerator methodGenerator) {
MethodSpec.Builder builder = MethodSpec.methodBuilder(APPLY_METHOD);
builder.addJavadoc("Apply the persistence injection.");
builder.addModifiers(javax.lang.model.element.Modifier.PUBLIC,
javax.lang.model.element.Modifier.STATIC);
builder.addParameter(RegisteredBean.class, REGISTERED_BEAN_PARAMETER);
builder.addParameter(this.target, INSTANCE_PARAMETER);
builder.returns(this.target);
builder.addCode(generateMethodCode(hints, methodGenerator));
return builder.build();
private Consumer<Builder> generateMethod(RuntimeHints hints, MethodGenerator methodGenerator) {
return method -> {
method.addJavadoc("Apply the persistence injection.");
method.addModifiers(javax.lang.model.element.Modifier.PUBLIC,
javax.lang.model.element.Modifier.STATIC);
method.addParameter(RegisteredBean.class, REGISTERED_BEAN_PARAMETER);
method.addParameter(this.target, INSTANCE_PARAMETER);
method.returns(this.target);
method.addCode(generateMethodCode(hints, methodGenerator));
};
}
private CodeBlock generateMethodCode(RuntimeHints hints,

View File

@@ -43,6 +43,7 @@ import org.springframework.beans.factory.aot.BeanRegistrationCode;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RegisteredBean;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.core.testfixture.aot.generate.TestGenerationContext;
import org.springframework.util.ReflectionUtils;
import static org.assertj.core.api.Assertions.assertThat;
@@ -67,7 +68,7 @@ class PersistenceAnnotationBeanPostProcessorAotContributionTests {
void setup() {
this.beanFactory = new DefaultListableBeanFactory();
this.generatedFiles = new InMemoryGeneratedFiles();
this.generationContext = new DefaultGenerationContext(generatedFiles);
this.generationContext = new TestGenerationContext(generatedFiles);
}
@Test
@@ -183,6 +184,7 @@ class PersistenceAnnotationBeanPostProcessorAotContributionTests {
.processAheadOfTime(registeredBean);
BeanRegistrationCode beanRegistrationCode = mock(BeanRegistrationCode.class);
contribution.applyTo(generationContext, beanRegistrationCode);
generationContext.writeGeneratedContent();
TestCompiler.forSystem().withFiles(generatedFiles)
.compile(compiled -> result.accept(new Invoker(compiled), compiled));
}