diff --git a/spring-aop/src/main/java/org/springframework/aop/scope/ScopedProxyBeanRegistrationAotProcessor.java b/spring-aop/src/main/java/org/springframework/aop/scope/ScopedProxyBeanRegistrationAotProcessor.java index 36d44764b158..5ad52df235b4 100644 --- a/spring-aop/src/main/java/org/springframework/aop/scope/ScopedProxyBeanRegistrationAotProcessor.java +++ b/spring-aop/src/main/java/org/springframework/aop/scope/ScopedProxyBeanRegistrationAotProcessor.java @@ -163,8 +163,8 @@ public CodeBlock generateInstanceSupplierCode(GenerationContext generationContex method.addStatement("return ($T) factory.getObject()", beanClass); }); - return CodeBlock.of("$T.of($T::$L)", InstanceSupplier.class, - beanRegistrationCode.getClassName(), generatedMethod.getName()); + return CodeBlock.of("$T.of($L)", InstanceSupplier.class, + generatedMethod.toMethodReference().toCodeBlock()); } } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java index 2154610858f0..ace0f093ac61 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java @@ -44,7 +44,6 @@ import org.springframework.aot.generate.GeneratedClass; import org.springframework.aot.generate.GeneratedMethod; import org.springframework.aot.generate.GenerationContext; -import org.springframework.aot.generate.MethodReference; import org.springframework.aot.hint.ExecutableMode; import org.springframework.aot.hint.RuntimeHints; import org.springframework.beans.BeanUtils; @@ -944,8 +943,7 @@ public void applyTo(GenerationContext generationContext, method.returns(this.target); method.addCode(generateMethodCode(generationContext.getRuntimeHints())); }); - beanRegistrationCode.addInstancePostProcessor( - MethodReference.ofStatic(generatedClass.getName(), generateMethod.getName())); + beanRegistrationCode.addInstancePostProcessor(generateMethod.toMethodReference()); if (this.candidateResolver != null) { registerHints(generationContext.getRuntimeHints()); diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionMethodGenerator.java b/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionMethodGenerator.java index 8f08985b7925..29703c3eeb52 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionMethodGenerator.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionMethodGenerator.java @@ -107,16 +107,14 @@ MethodReference generateBeanDefinitionMethod(GenerationContext generationContext GeneratedMethod generatedMethod = generateBeanDefinitionMethod( generationContext, generatedClass.getName(), generatedMethods, codeFragments, Modifier.PUBLIC); - return MethodReference.ofStatic(generatedClass.getName(), - generatedMethod.getName()); + return generatedMethod.toMethodReference(); } GeneratedMethods generatedMethods = beanRegistrationsCode.getMethods() .withPrefix(getName()); GeneratedMethod generatedMethod = generateBeanDefinitionMethod(generationContext, beanRegistrationsCode.getClassName(), generatedMethods, codeFragments, Modifier.PRIVATE); - return MethodReference.ofStatic(beanRegistrationsCode.getClassName(), - generatedMethod.getName()); + return generatedMethod.toMethodReference(); } private BeanRegistrationCodeFragments getCodeFragments(GenerationContext generationContext, diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanRegistrationsAotContribution.java b/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanRegistrationsAotContribution.java index 2dad04b877f4..fc8ca237b8b2 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanRegistrationsAotContribution.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanRegistrationsAotContribution.java @@ -65,8 +65,7 @@ public void applyTo(GenerationContext generationContext, BeanRegistrationsCodeGenerator codeGenerator = new BeanRegistrationsCodeGenerator(generatedClass); GeneratedMethod generatedMethod = codeGenerator.getMethods().add("registerBeanDefinitions", method -> generateRegisterMethod(method, generationContext, codeGenerator)); - beanFactoryInitializationCode.addInitializer( - MethodReference.of(generatedClass.getName(), generatedMethod.getName())); + beanFactoryInitializationCode.addInitializer(generatedMethod.toMethodReference()); } private void generateRegisterMethod(MethodSpec.Builder method, diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/aot/InstanceSupplierCodeGenerator.java b/spring-beans/src/main/java/org/springframework/beans/factory/aot/InstanceSupplierCodeGenerator.java index 66bba1620471..1b597a36d379 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/aot/InstanceSupplierCodeGenerator.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/aot/InstanceSupplierCodeGenerator.java @@ -296,8 +296,8 @@ private CodeBlock generateNewInstanceCodeForMethod(boolean dependsOnBean, REGISTERED_BEAN_PARAMETER_NAME, declaringClass, factoryMethodName, args); } - private CodeBlock generateReturnStatement(GeneratedMethod getInstanceMethod) { - return CodeBlock.of("$T.$L()", this.className, getInstanceMethod.getName()); + private CodeBlock generateReturnStatement(GeneratedMethod generatedMethod) { + return generatedMethod.toMethodReference().toInvokeCodeBlock(); } private CodeBlock generateWithGeneratorCode(boolean hasArguments, CodeBlock newInstance) { diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanDefinitionMethodGeneratorTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanDefinitionMethodGeneratorTests.java index 53c182ddc583..3cc278470a14 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanDefinitionMethodGeneratorTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanDefinitionMethodGeneratorTests.java @@ -129,8 +129,7 @@ void generateBeanDefinitionMethodWhenHasInstancePostProcessorGeneratesMethod() { .addParameter(RegisteredBean.class, "registeredBean") .addParameter(TestBean.class, "testBean") .returns(TestBean.class).addCode("return new $T($S);", TestBean.class, "postprocessed")); - beanRegistrationCode.addInstancePostProcessor(MethodReference.ofStatic( - beanRegistrationCode.getClassName(), generatedMethod.getName())); + beanRegistrationCode.addInstancePostProcessor(generatedMethod.toMethodReference()); }; List aotContributions = Collections .singletonList(aotContribution); @@ -167,8 +166,7 @@ void generateBeanDefinitionMethodWhenHasInstancePostProcessorAndFactoryMethodGen .addParameter(RegisteredBean.class, "registeredBean") .addParameter(TestBean.class, "testBean") .returns(TestBean.class).addCode("return new $T($S);", TestBean.class, "postprocessed")); - beanRegistrationCode.addInstancePostProcessor(MethodReference.ofStatic( - beanRegistrationCode.getClassName(), generatedMethod.getName())); + beanRegistrationCode.addInstancePostProcessor(generatedMethod.toMethodReference()); }; List aotContributions = Collections .singletonList(aotContribution); diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java index 3c2fa7381798..02db1a37c9cf 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java @@ -33,7 +33,6 @@ import org.springframework.aop.framework.autoproxy.AutoProxyUtils; import org.springframework.aot.generate.GeneratedMethod; import org.springframework.aot.generate.GenerationContext; -import org.springframework.aot.generate.MethodReference; import org.springframework.aot.hint.ResourceHints; import org.springframework.aot.hint.TypeReference; import org.springframework.beans.PropertyValues; @@ -536,7 +535,7 @@ public void applyTo(GenerationContext generationContext, .add("addImportAwareBeanPostProcessors", method -> generateAddPostProcessorMethod(method, mappings)); beanFactoryInitializationCode - .addInitializer(MethodReference.of(generatedMethod.getName())); + .addInitializer(generatedMethod.toMethodReference()); ResourceHints hints = generationContext.getRuntimeHints().resources(); mappings.forEach( (target, from) -> hints.registerType(TypeReference.of(from))); diff --git a/spring-core/src/main/java/org/springframework/aot/generate/GeneratedClass.java b/spring-core/src/main/java/org/springframework/aot/generate/GeneratedClass.java index be591208fff9..5a1bb3021876 100644 --- a/spring-core/src/main/java/org/springframework/aot/generate/GeneratedClass.java +++ b/spring-core/src/main/java/org/springframework/aot/generate/GeneratedClass.java @@ -55,7 +55,7 @@ public final class GeneratedClass { GeneratedClass(ClassName name, Consumer type) { this.name = name; this.type = type; - this.methods = new GeneratedMethods(this::generateSequencedMethodName); + this.methods = new GeneratedMethods(name, this::generateSequencedMethodName); } diff --git a/spring-core/src/main/java/org/springframework/aot/generate/GeneratedMethod.java b/spring-core/src/main/java/org/springframework/aot/generate/GeneratedMethod.java index 4d351241d0da..7247c212d0c7 100644 --- a/spring-core/src/main/java/org/springframework/aot/generate/GeneratedMethod.java +++ b/spring-core/src/main/java/org/springframework/aot/generate/GeneratedMethod.java @@ -18,6 +18,9 @@ import java.util.function.Consumer; +import javax.lang.model.element.Modifier; + +import org.springframework.javapoet.ClassName; import org.springframework.javapoet.MethodSpec; import org.springframework.util.Assert; @@ -25,11 +28,14 @@ * A generated method. * * @author Phillip Webb + * @author Stephane Nicoll * @since 6.0 * @see GeneratedMethods */ public final class GeneratedMethod { + private final ClassName className; + private final String name; private final MethodSpec methodSpec; @@ -39,12 +45,14 @@ public final class GeneratedMethod { * Create a new {@link GeneratedMethod} instance with the given name. This * constructor is package-private since names should only be generated via * {@link GeneratedMethods}. + * @param className the declaring class of the method * @param name the generated method name * @param method consumer to generate the method */ - GeneratedMethod(String name, Consumer method) { + GeneratedMethod(ClassName className, String name, Consumer method) { + this.className = className; this.name = name; - MethodSpec.Builder builder = MethodSpec.methodBuilder(getName()); + MethodSpec.Builder builder = MethodSpec.methodBuilder(this.name); method.accept(builder); this.methodSpec = builder.build(); Assert.state(this.name.equals(this.methodSpec.name), @@ -60,6 +68,16 @@ public String getName() { return this.name; } + /** + * Return a {@link MethodReference} to this generated method. + * @return a method reference + */ + public MethodReference toMethodReference() { + return (this.methodSpec.modifiers.contains(Modifier.STATIC) + ? MethodReference.ofStatic(this.className, this.name) + : MethodReference.of(this.className, this.name)); + } + /** * Return the {@link MethodSpec} for this generated method. * @return the method spec diff --git a/spring-core/src/main/java/org/springframework/aot/generate/GeneratedMethods.java b/spring-core/src/main/java/org/springframework/aot/generate/GeneratedMethods.java index e16779ab779b..0c65c37582ad 100644 --- a/spring-core/src/main/java/org/springframework/aot/generate/GeneratedMethods.java +++ b/spring-core/src/main/java/org/springframework/aot/generate/GeneratedMethods.java @@ -22,6 +22,7 @@ import java.util.function.Function; import java.util.stream.Stream; +import org.springframework.javapoet.ClassName; import org.springframework.javapoet.MethodSpec; import org.springframework.javapoet.MethodSpec.Builder; import org.springframework.util.Assert; @@ -30,11 +31,14 @@ * A managed collection of generated methods. * * @author Phillip Webb + * @author Stephane Nicoll * @since 6.0 * @see GeneratedMethod */ public class GeneratedMethods { + private final ClassName className; + private final Function methodNameGenerator; private final MethodName prefix; @@ -44,18 +48,22 @@ public class GeneratedMethods { /** * Create a new {@link GeneratedMethods} using the specified method name * generator. + * @param className the declaring class name * @param methodNameGenerator the method name generator */ - GeneratedMethods(Function methodNameGenerator) { + GeneratedMethods(ClassName className, Function methodNameGenerator) { + Assert.notNull(className, "'className' must not be null"); Assert.notNull(methodNameGenerator, "'methodNameGenerator' must not be null"); + this.className = className; this.methodNameGenerator = methodNameGenerator; this.prefix = MethodName.NONE; this.generatedMethods = new ArrayList<>(); } - private GeneratedMethods(Function methodNameGenerator, + private GeneratedMethods(ClassName className, Function methodNameGenerator, MethodName prefix, List generatedMethods) { + this.className = className; this.methodNameGenerator = methodNameGenerator; this.prefix = prefix; this.generatedMethods = generatedMethods; @@ -82,7 +90,7 @@ public GeneratedMethod add(String[] suggestedNameParts, Consumer method Assert.notNull(suggestedNameParts, "'suggestedNameParts' must not be null"); Assert.notNull(method, "'method' must not be null"); String generatedName = this.methodNameGenerator.apply(this.prefix.and(suggestedNameParts)); - GeneratedMethod generatedMethod = new GeneratedMethod(generatedName, method); + GeneratedMethod generatedMethod = new GeneratedMethod(this.className, generatedName, method); this.generatedMethods.add(generatedMethod); return generatedMethod; } @@ -90,7 +98,8 @@ public GeneratedMethod add(String[] suggestedNameParts, Consumer method public GeneratedMethods withPrefix(String prefix) { Assert.notNull(prefix, "'prefix' must not be null"); - return new GeneratedMethods(this.methodNameGenerator, this.prefix.and(prefix), this.generatedMethods); + return new GeneratedMethods(this.className, this.methodNameGenerator, + this.prefix.and(prefix), this.generatedMethods); } /** diff --git a/spring-core/src/test/java/org/springframework/aot/generate/GeneratedMethodTests.java b/spring-core/src/test/java/org/springframework/aot/generate/GeneratedMethodTests.java index f080ce8ed202..34ac962746aa 100644 --- a/spring-core/src/test/java/org/springframework/aot/generate/GeneratedMethodTests.java +++ b/spring-core/src/test/java/org/springframework/aot/generate/GeneratedMethodTests.java @@ -18,8 +18,12 @@ import java.util.function.Consumer; +import javax.lang.model.element.Modifier; + import org.junit.jupiter.api.Test; +import org.springframework.javapoet.ClassName; +import org.springframework.javapoet.CodeBlock; import org.springframework.javapoet.MethodSpec; import static org.assertj.core.api.Assertions.assertThat; @@ -29,30 +33,55 @@ * Tests for {@link GeneratedMethod}. * * @author Phillip Webb + * @author Stephane Nicoll */ class GeneratedMethodTests { - private static final Consumer methodSpecCustomizer = method -> {}; + private static final ClassName TEST_CLASS_NAME = ClassName.get("com.example", "Test"); + + private static final Consumer emptyMethod = method -> {}; private static final String NAME = "spring"; @Test void getNameReturnsName() { - GeneratedMethod generatedMethod = new GeneratedMethod(NAME, methodSpecCustomizer); + GeneratedMethod generatedMethod = new GeneratedMethod(TEST_CLASS_NAME, NAME, emptyMethod); assertThat(generatedMethod.getName()).isSameAs(NAME); } @Test void generateMethodSpecReturnsMethodSpec() { - GeneratedMethod generatedMethod = new GeneratedMethod(NAME, method -> method.addJavadoc("Test")); + GeneratedMethod generatedMethod = create(method -> method.addJavadoc("Test")); assertThat(generatedMethod.getMethodSpec().javadoc).asString().contains("Test"); } @Test void generateMethodSpecWhenMethodNameIsChangedThrowsException() { assertThatIllegalStateException().isThrownBy(() -> - new GeneratedMethod(NAME, method -> method.setName("badname")).getMethodSpec()) - .withMessage("'method' consumer must not change the generated method name"); + create(method -> method.setName("badname")).getMethodSpec()) + .withMessage("'method' consumer must not change the generated method name"); + } + + @Test + void toMethodReferenceWithInstanceMethod() { + GeneratedMethod generatedMethod = create(emptyMethod); + MethodReference methodReference = generatedMethod.toMethodReference(); + assertThat(methodReference).isNotNull(); + assertThat(methodReference.toInvokeCodeBlock("test")) + .isEqualTo(CodeBlock.of("test.spring()")); + } + + @Test + void toMethodReferenceWithStaticMethod() { + GeneratedMethod generatedMethod = create(method -> method.addModifiers(Modifier.STATIC)); + MethodReference methodReference = generatedMethod.toMethodReference(); + assertThat(methodReference).isNotNull(); + assertThat(methodReference.toInvokeCodeBlock()) + .isEqualTo(CodeBlock.of("com.example.Test.spring()")); + } + + private GeneratedMethod create(Consumer method) { + return new GeneratedMethod(TEST_CLASS_NAME, NAME, method); } } diff --git a/spring-core/src/test/java/org/springframework/aot/generate/GeneratedMethodsTests.java b/spring-core/src/test/java/org/springframework/aot/generate/GeneratedMethodsTests.java index 2ae2517e6c85..1b051f691e02 100644 --- a/spring-core/src/test/java/org/springframework/aot/generate/GeneratedMethodsTests.java +++ b/spring-core/src/test/java/org/springframework/aot/generate/GeneratedMethodsTests.java @@ -23,6 +23,7 @@ import org.junit.jupiter.api.Test; +import org.springframework.javapoet.ClassName; import org.springframework.javapoet.MethodSpec; import static org.assertj.core.api.Assertions.assertThat; @@ -32,38 +33,49 @@ * Tests for {@link GeneratedMethods}. * * @author Phillip Webb + * @author Stephane Nicoll */ class GeneratedMethodsTests { + private static final ClassName TEST_CLASS_NAME = ClassName.get("com.example", "Test"); + private static final Consumer methodSpecCustomizer = method -> {}; - private final GeneratedMethods methods = new GeneratedMethods(MethodName::toString); + private final GeneratedMethods methods = new GeneratedMethods(TEST_CLASS_NAME, MethodName::toString); + + @Test + void createWhenClassNameIsNullThrowsException() { + assertThatIllegalArgumentException().isThrownBy(() -> + new GeneratedMethods(null, MethodName::toString)) + .withMessage("'className' must not be null"); + } @Test void createWhenMethodNameGeneratorIsNullThrowsException() { - assertThatIllegalArgumentException().isThrownBy(() -> new GeneratedMethods(null)) + assertThatIllegalArgumentException().isThrownBy(() -> + new GeneratedMethods(TEST_CLASS_NAME, null)) .withMessage("'methodNameGenerator' must not be null"); } @Test void createWithExistingGeneratorUsesGenerator() { Function generator = name -> "__" + name.toString(); - GeneratedMethods methods = new GeneratedMethods(generator); + GeneratedMethods methods = new GeneratedMethods(TEST_CLASS_NAME, generator); assertThat(methods.add("test", methodSpecCustomizer).getName()).hasToString("__test"); } @Test void addWithStringNameWhenSuggestedMethodIsNullThrowsException() { assertThatIllegalArgumentException().isThrownBy(() -> - this.methods.add((String) null, methodSpecCustomizer)) - .withMessage("'suggestedName' must not be null"); + this.methods.add((String) null, methodSpecCustomizer)) + .withMessage("'suggestedName' must not be null"); } @Test void addWithStringNameWhenMethodIsNullThrowsException() { assertThatIllegalArgumentException().isThrownBy(() -> - this.methods.add("test", null)) - .withMessage("'method' must not be null"); + this.methods.add("test", null)) + .withMessage("'method' must not be null"); } @Test @@ -71,7 +83,7 @@ void addAddsMethod() { this.methods.add("springBeans", methodSpecCustomizer); this.methods.add("springContext", methodSpecCustomizer); assertThat(this.methods.stream().map(GeneratedMethod::getName).map(Object::toString)) - .containsExactly("springBeans", "springContext"); + .containsExactly("springBeans", "springContext"); } @Test diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessor.java b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessor.java index cf88dc8acbc5..e8d8fe3848b2 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessor.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessor.java @@ -99,7 +99,7 @@ public CodeBlock generateInstanceSupplierCode(GenerationContext generationContex List.class, toCodeBlock(persistenceManagedTypes.getManagedPackages())); method.addStatement("return $T.of($L, $L)", beanType, "managedClassNames", "managedPackages"); }); - return CodeBlock.of("() -> $T.$L()", beanRegistrationCode.getClassName(), generatedMethod.getName()); + return generatedMethod.toMethodReference().toCodeBlock(); } private CodeBlock toCodeBlock(List values) { diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/support/PersistenceAnnotationBeanPostProcessor.java b/spring-orm/src/main/java/org/springframework/orm/jpa/support/PersistenceAnnotationBeanPostProcessor.java index 47078596607f..abac448ac02a 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/support/PersistenceAnnotationBeanPostProcessor.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/support/PersistenceAnnotationBeanPostProcessor.java @@ -43,7 +43,6 @@ 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.hint.RuntimeHints; import org.springframework.beans.BeanUtils; import org.springframework.beans.PropertyValues; @@ -797,8 +796,7 @@ public void applyTo(GenerationContext generationContext, method.returns(this.target); method.addCode(generateMethodCode(generationContext.getRuntimeHints(), generatedClass.getMethods())); }); - beanRegistrationCode.addInstancePostProcessor(MethodReference - .ofStatic(generatedClass.getName(), generatedMethod.getName())); + beanRegistrationCode.addInstancePostProcessor(generatedMethod.toMethodReference()); } private CodeBlock generateMethodCode(RuntimeHints hints, GeneratedMethods generatedMethods) {