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:
@@ -30,7 +30,6 @@ 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;
|
||||
@@ -42,8 +41,9 @@ 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.MethodName;
|
||||
import org.springframework.aot.generate.MethodReference;
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
@@ -72,7 +72,6 @@ import org.springframework.core.PriorityOrdered;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.javapoet.CodeBlock;
|
||||
import org.springframework.javapoet.MethodSpec;
|
||||
import org.springframework.javapoet.MethodSpec.Builder;
|
||||
import org.springframework.jndi.JndiLocatorDelegate;
|
||||
import org.springframework.jndi.JndiTemplate;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -766,8 +765,6 @@ public class PersistenceAnnotationBeanPostProcessor implements InstantiationAwar
|
||||
|
||||
private static class AotContribution implements BeanRegistrationAotContribution {
|
||||
|
||||
private static final String APPLY_METHOD = "apply";
|
||||
|
||||
private static final String REGISTERED_BEAN_PARAMETER = "registeredBean";
|
||||
|
||||
private static final String INSTANCE_PARAMETER = "instance";
|
||||
@@ -788,45 +785,38 @@ public class PersistenceAnnotationBeanPostProcessor implements InstantiationAwar
|
||||
public void applyTo(GenerationContext generationContext,
|
||||
BeanRegistrationCode beanRegistrationCode) {
|
||||
GeneratedClass generatedClass = generationContext.getGeneratedClasses()
|
||||
.forFeatureComponent("PersistenceInjection", this.target).generate(type -> {
|
||||
.addForFeatureComponent("PersistenceInjection", this.target, 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(generatedClass.getName(), APPLY_METHOD));
|
||||
}
|
||||
|
||||
private Consumer<Builder> generateMethod(RuntimeHints hints, MethodGenerator methodGenerator) {
|
||||
return method -> {
|
||||
GeneratedMethod generatedMethod = generatedClass.getMethods().add("apply", 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));
|
||||
};
|
||||
method.addCode(generateMethodCode(generationContext.getRuntimeHints(), generatedClass.getMethods()));
|
||||
});
|
||||
beanRegistrationCode.addInstancePostProcessor(MethodReference
|
||||
.ofStatic(generatedClass.getName(), generatedMethod.getName()));
|
||||
}
|
||||
|
||||
private CodeBlock generateMethodCode(RuntimeHints hints,
|
||||
MethodGenerator methodGenerator) {
|
||||
CodeBlock.Builder builder = CodeBlock.builder();
|
||||
InjectionCodeGenerator injectionCodeGenerator = new InjectionCodeGenerator(
|
||||
hints);
|
||||
private CodeBlock generateMethodCode(RuntimeHints hints, GeneratedMethods generatedMethods) {
|
||||
CodeBlock.Builder code = CodeBlock.builder();
|
||||
InjectionCodeGenerator injectionCodeGenerator = new InjectionCodeGenerator(hints);
|
||||
for (InjectedElement injectedElement : this.injectedElements) {
|
||||
CodeBlock resourceToInject = getResourceToInject(methodGenerator,
|
||||
CodeBlock resourceToInject = generateResourceToInjectCode(generatedMethods,
|
||||
(PersistenceElement) injectedElement);
|
||||
builder.add(injectionCodeGenerator.generateInjectionCode(
|
||||
code.add(injectionCodeGenerator.generateInjectionCode(
|
||||
injectedElement.getMember(), INSTANCE_PARAMETER,
|
||||
resourceToInject));
|
||||
}
|
||||
builder.addStatement("return $L", INSTANCE_PARAMETER);
|
||||
return builder.build();
|
||||
code.addStatement("return $L", INSTANCE_PARAMETER);
|
||||
return code.build();
|
||||
}
|
||||
|
||||
private CodeBlock getResourceToInject(MethodGenerator methodGenerator,
|
||||
private CodeBlock generateResourceToInjectCode(GeneratedMethods generatedMethods,
|
||||
PersistenceElement injectedElement) {
|
||||
String unitName = injectedElement.unitName;
|
||||
boolean requireEntityManager = (injectedElement.type != null);
|
||||
@@ -836,40 +826,38 @@ public class PersistenceAnnotationBeanPostProcessor implements InstantiationAwar
|
||||
EntityManagerFactoryUtils.class, ListableBeanFactory.class,
|
||||
REGISTERED_BEAN_PARAMETER, unitName);
|
||||
}
|
||||
GeneratedMethod getEntityManagerMethod = methodGenerator
|
||||
.generateMethod("get", unitName, "EntityManager")
|
||||
.using(builder -> buildGetEntityManagerMethod(builder,
|
||||
injectedElement));
|
||||
return CodeBlock.of("$L($L)", getEntityManagerMethod.getName(),
|
||||
REGISTERED_BEAN_PARAMETER);
|
||||
GeneratedMethod generatedMethod = generatedMethods
|
||||
.add(MethodName.of("get", unitName, "EntityManager"), method ->
|
||||
generateGetEntityManagerMethod(method, injectedElement));
|
||||
return CodeBlock.of("$L($L)", generatedMethod.getName(), REGISTERED_BEAN_PARAMETER);
|
||||
}
|
||||
|
||||
private void buildGetEntityManagerMethod(MethodSpec.Builder builder,
|
||||
private void generateGetEntityManagerMethod(MethodSpec.Builder method,
|
||||
PersistenceElement injectedElement) {
|
||||
String unitName = injectedElement.unitName;
|
||||
Properties properties = injectedElement.properties;
|
||||
builder.addJavadoc("Get the '$L' {@link $T}",
|
||||
method.addJavadoc("Get the '$L' {@link $T}",
|
||||
(StringUtils.hasLength(unitName)) ? unitName : "default",
|
||||
EntityManager.class);
|
||||
builder.addModifiers(javax.lang.model.element.Modifier.PUBLIC,
|
||||
method.addModifiers(javax.lang.model.element.Modifier.PUBLIC,
|
||||
javax.lang.model.element.Modifier.STATIC);
|
||||
builder.returns(EntityManager.class);
|
||||
builder.addParameter(RegisteredBean.class, REGISTERED_BEAN_PARAMETER);
|
||||
builder.addStatement(
|
||||
method.returns(EntityManager.class);
|
||||
method.addParameter(RegisteredBean.class, REGISTERED_BEAN_PARAMETER);
|
||||
method.addStatement(
|
||||
"$T entityManagerFactory = $T.findEntityManagerFactory(($T) $L.getBeanFactory(), $S)",
|
||||
EntityManagerFactory.class, EntityManagerFactoryUtils.class,
|
||||
ListableBeanFactory.class, REGISTERED_BEAN_PARAMETER, unitName);
|
||||
boolean hasProperties = !CollectionUtils.isEmpty(properties);
|
||||
if (hasProperties) {
|
||||
builder.addStatement("$T properties = new Properties()",
|
||||
method.addStatement("$T properties = new Properties()",
|
||||
Properties.class);
|
||||
for (String propertyName : new TreeSet<>(
|
||||
properties.stringPropertyNames())) {
|
||||
builder.addStatement("properties.put($S, $S)", propertyName,
|
||||
method.addStatement("properties.put($S, $S)", propertyName,
|
||||
properties.getProperty(propertyName));
|
||||
}
|
||||
}
|
||||
builder.addStatement(
|
||||
method.addStatement(
|
||||
"return $T.createSharedEntityManager(entityManagerFactory, $L, $L)",
|
||||
SharedEntityManagerCreator.class,
|
||||
(hasProperties) ? "properties" : null,
|
||||
|
||||
Reference in New Issue
Block a user