Allow MethodReference to define a more flexible signature
This commit moves MethodReference to an interface with a default implementation that relies on a MethodSpec. Such an arrangement avoid the need of specifying attributes of the method such as whether it is static or not. The resolution of the invocation block now takes an ArgumentCodeGenerator rather than the raw arguments. Doing so gives the opportunity to create more flexible signatures. See gh-29005
This commit is contained in:
@@ -25,6 +25,7 @@ import org.springframework.aot.generate.GeneratedMethod;
|
||||
import org.springframework.aot.generate.GeneratedMethods;
|
||||
import org.springframework.aot.generate.GenerationContext;
|
||||
import org.springframework.aot.generate.MethodReference;
|
||||
import org.springframework.aot.generate.MethodReference.ArgumentCodeGenerator;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.javapoet.ClassName;
|
||||
import org.springframework.javapoet.CodeBlock;
|
||||
@@ -81,9 +82,11 @@ class BeanRegistrationsAotContribution
|
||||
MethodReference beanDefinitionMethod = beanDefinitionMethodGenerator
|
||||
.generateBeanDefinitionMethod(generationContext,
|
||||
beanRegistrationsCode);
|
||||
CodeBlock methodInvocation = beanDefinitionMethod.toInvokeCodeBlock(
|
||||
ArgumentCodeGenerator.none(), beanRegistrationsCode.getClassName());
|
||||
code.addStatement("$L.registerBeanDefinition($S, $L)",
|
||||
BEAN_FACTORY_PARAMETER_NAME, beanName,
|
||||
beanDefinitionMethod.toInvokeCodeBlock());
|
||||
methodInvocation);
|
||||
});
|
||||
method.addCode(code.build());
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.util.function.Predicate;
|
||||
import org.springframework.aot.generate.AccessVisibility;
|
||||
import org.springframework.aot.generate.GenerationContext;
|
||||
import org.springframework.aot.generate.MethodReference;
|
||||
import org.springframework.aot.generate.MethodReference.ArgumentCodeGenerator;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
@@ -156,7 +157,7 @@ class DefaultBeanRegistrationCodeFragments extends BeanRegistrationCodeFragments
|
||||
MethodReference generatedMethod = methodGenerator
|
||||
.generateBeanDefinitionMethod(generationContext,
|
||||
this.beanRegistrationsCode);
|
||||
return generatedMethod.toInvokeCodeBlock();
|
||||
return generatedMethod.toInvokeCodeBlock(ArgumentCodeGenerator.none());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import org.springframework.aot.generate.AccessVisibility;
|
||||
import org.springframework.aot.generate.GeneratedMethod;
|
||||
import org.springframework.aot.generate.GeneratedMethods;
|
||||
import org.springframework.aot.generate.GenerationContext;
|
||||
import org.springframework.aot.generate.MethodReference.ArgumentCodeGenerator;
|
||||
import org.springframework.aot.hint.ExecutableMode;
|
||||
import org.springframework.beans.factory.support.InstanceSupplier;
|
||||
import org.springframework.beans.factory.support.RegisteredBean;
|
||||
@@ -297,7 +298,8 @@ class InstanceSupplierCodeGenerator {
|
||||
}
|
||||
|
||||
private CodeBlock generateReturnStatement(GeneratedMethod generatedMethod) {
|
||||
return generatedMethod.toMethodReference().toInvokeCodeBlock();
|
||||
return generatedMethod.toMethodReference().toInvokeCodeBlock(
|
||||
ArgumentCodeGenerator.none(), this.className);
|
||||
}
|
||||
|
||||
private CodeBlock generateWithGeneratorCode(boolean hasArguments, CodeBlock newInstance) {
|
||||
|
||||
@@ -24,6 +24,7 @@ import javax.lang.model.element.Modifier;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.aot.generate.MethodReference;
|
||||
import org.springframework.aot.generate.MethodReference.ArgumentCodeGenerator;
|
||||
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
|
||||
import org.springframework.aot.test.generate.TestGenerationContext;
|
||||
import org.springframework.aot.test.generate.compile.CompileWithTargetClassAccess;
|
||||
@@ -161,13 +162,16 @@ class AutowiredAnnotationBeanRegistrationAotContributionTests {
|
||||
Class<?> target = registeredBean.getBeanClass();
|
||||
MethodReference methodReference = this.beanRegistrationCode.getInstancePostProcessors().get(0);
|
||||
this.beanRegistrationCode.getTypeBuilder().set(type -> {
|
||||
CodeBlock methodInvocation = methodReference.toInvokeCodeBlock(
|
||||
ArgumentCodeGenerator.of(RegisteredBean.class, "registeredBean").and(target, "instance"),
|
||||
this.beanRegistrationCode.getClassName());
|
||||
type.addModifiers(Modifier.PUBLIC);
|
||||
type.addSuperinterface(ParameterizedTypeName.get(BiFunction.class, RegisteredBean.class, target, target));
|
||||
type.addMethod(MethodSpec.methodBuilder("apply")
|
||||
.addModifiers(Modifier.PUBLIC)
|
||||
.addParameter(RegisteredBean.class, "registeredBean")
|
||||
.addParameter(target, "instance").returns(target)
|
||||
.addStatement("return $L", methodReference.toInvokeCodeBlock(CodeBlock.of("registeredBean"), CodeBlock.of("instance")))
|
||||
.addStatement("return $L", methodInvocation)
|
||||
.build());
|
||||
|
||||
});
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.junit.jupiter.api.Test;
|
||||
import org.springframework.aot.generate.GeneratedMethod;
|
||||
import org.springframework.aot.generate.GenerationContext;
|
||||
import org.springframework.aot.generate.MethodReference;
|
||||
import org.springframework.aot.generate.MethodReference.ArgumentCodeGenerator;
|
||||
import org.springframework.aot.test.generate.TestGenerationContext;
|
||||
import org.springframework.aot.test.generate.compile.CompileWithTargetClassAccess;
|
||||
import org.springframework.aot.test.generate.compile.Compiled;
|
||||
@@ -414,12 +415,14 @@ class BeanDefinitionMethodGeneratorTests {
|
||||
private void compile(MethodReference method,
|
||||
BiConsumer<RootBeanDefinition, Compiled> result) {
|
||||
this.beanRegistrationsCode.getTypeBuilder().set(type -> {
|
||||
CodeBlock methodInvocation = method.toInvokeCodeBlock(ArgumentCodeGenerator.none(),
|
||||
this.beanRegistrationsCode.getClassName());
|
||||
type.addModifiers(Modifier.PUBLIC);
|
||||
type.addSuperinterface(ParameterizedTypeName.get(Supplier.class, BeanDefinition.class));
|
||||
type.addMethod(MethodSpec.methodBuilder("get")
|
||||
.addModifiers(Modifier.PUBLIC)
|
||||
.returns(BeanDefinition.class)
|
||||
.addCode("return $L;", method.toInvokeCodeBlock()).build());
|
||||
.addCode("return $L;", methodInvocation).build());
|
||||
});
|
||||
this.generationContext.writeGeneratedContent();
|
||||
TestCompiler.forSystem().withFiles(this.generationContext.getGeneratedFiles()).compile(compiled ->
|
||||
|
||||
@@ -31,6 +31,7 @@ import org.junit.jupiter.api.Test;
|
||||
import org.springframework.aot.generate.ClassNameGenerator;
|
||||
import org.springframework.aot.generate.GenerationContext;
|
||||
import org.springframework.aot.generate.MethodReference;
|
||||
import org.springframework.aot.generate.MethodReference.ArgumentCodeGenerator;
|
||||
import org.springframework.aot.test.generate.TestGenerationContext;
|
||||
import org.springframework.aot.test.generate.TestTarget;
|
||||
import org.springframework.aot.test.generate.compile.Compiled;
|
||||
@@ -155,11 +156,14 @@ class BeanRegistrationsAotContributionTests {
|
||||
MethodReference methodReference = this.beanFactoryInitializationCode
|
||||
.getInitializers().get(0);
|
||||
this.beanFactoryInitializationCode.getTypeBuilder().set(type -> {
|
||||
CodeBlock methodInvocation = methodReference.toInvokeCodeBlock(
|
||||
ArgumentCodeGenerator.of(DefaultListableBeanFactory.class, "beanFactory"),
|
||||
this.beanFactoryInitializationCode.getClassName());
|
||||
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")))
|
||||
.addStatement(methodInvocation)
|
||||
.build());
|
||||
});
|
||||
this.generationContext.writeGeneratedContent();
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.springframework.aot.generate.GeneratedMethods;
|
||||
import org.springframework.aot.generate.GenerationContext;
|
||||
import org.springframework.aot.generate.MethodReference;
|
||||
import org.springframework.beans.factory.aot.BeanFactoryInitializationCode;
|
||||
import org.springframework.javapoet.ClassName;
|
||||
|
||||
/**
|
||||
* Mock {@link BeanFactoryInitializationCode} implementation.
|
||||
@@ -46,6 +47,9 @@ public class MockBeanFactoryInitializationCode implements BeanFactoryInitializat
|
||||
.addForFeature("TestCode", this.typeBuilder);
|
||||
}
|
||||
|
||||
public ClassName getClassName() {
|
||||
return this.generatedClass.getName();
|
||||
}
|
||||
|
||||
public DeferredTypeBuilder getTypeBuilder() {
|
||||
return this.typeBuilder;
|
||||
|
||||
Reference in New Issue
Block a user