From 8ef850ff91604fc1d6e7f3a32423aded0a8d0d7e Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 22 Sep 2022 14:22:17 +0200 Subject: [PATCH 1/2] Update ClassNameGenerator to work with a ClassName target This commit updates ClassNameGenerator so that it uses a ClassName for its default target. This makes sure that a target that has been generated can be used. See gh-29027 --- ...BeanRegistrationsAotContributionTests.java | 3 +- .../test/generate/TestGenerationContext.java | 12 ++++-- .../aot/test/generate/TestTarget.java | 26 ------------ .../aot/generate/ClassNameGenerator.java | 24 ++++++----- .../aot/generate/GeneratedClasses.java | 41 +++++++++++++++++-- .../aot/generate/ClassNameGeneratorTests.java | 40 +++++++++--------- .../DefaultGenerationContextTests.java | 21 +++++----- .../aot/generate/GeneratedClassesTests.java | 5 ++- .../context/aot/TestContextAotGenerator.java | 8 ++-- 9 files changed, 99 insertions(+), 81 deletions(-) delete mode 100644 spring-core-test/src/main/java/org/springframework/aot/test/generate/TestTarget.java diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanRegistrationsAotContributionTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanRegistrationsAotContributionTests.java index 592d1c665d..577631ff54 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanRegistrationsAotContributionTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanRegistrationsAotContributionTests.java @@ -33,7 +33,6 @@ 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.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.RegisteredBean; import org.springframework.beans.factory.support.RootBeanDefinition; @@ -97,7 +96,7 @@ class BeanRegistrationsAotContributionTests { @Test void applyToWhenHasNameGeneratesPrefixedFeatureName() { this.generationContext = new TestGenerationContext( - new ClassNameGenerator(TestTarget.class, "Management")); + new ClassNameGenerator(TestGenerationContext.TEST_TARGET, "Management")); this.beanFactoryInitializationCode = new MockBeanFactoryInitializationCode(this.generationContext); Map registrations = new LinkedHashMap<>(); RegisteredBean registeredBean = registerBean( diff --git a/spring-core-test/src/main/java/org/springframework/aot/test/generate/TestGenerationContext.java b/spring-core-test/src/main/java/org/springframework/aot/test/generate/TestGenerationContext.java index fa95ea3082..77b19e10a1 100644 --- a/spring-core-test/src/main/java/org/springframework/aot/test/generate/TestGenerationContext.java +++ b/spring-core-test/src/main/java/org/springframework/aot/test/generate/TestGenerationContext.java @@ -23,6 +23,7 @@ import org.springframework.aot.generate.DefaultGenerationContext; import org.springframework.aot.generate.GenerationContext; import org.springframework.aot.generate.InMemoryGeneratedFiles; import org.springframework.core.test.tools.TestCompiler; +import org.springframework.javapoet.ClassName; /** * {@link GenerationContext} test implementation that uses @@ -35,6 +36,11 @@ import org.springframework.core.test.tools.TestCompiler; */ public class TestGenerationContext extends DefaultGenerationContext implements UnaryOperator { + /** + * The default test target {@link ClassName}. + */ + public static final ClassName TEST_TARGET = ClassName.get("com.example", "TestTarget"); + /** * Create an instance using the specified {@link ClassNameGenerator}. * @param classNameGenerator the class name generator to use @@ -47,15 +53,15 @@ public class TestGenerationContext extends DefaultGenerationContext implements U * Create an instance using the specified {@code target}. * @param target the default target class to use */ - public TestGenerationContext(Class target) { + public TestGenerationContext(ClassName target) { this(new ClassNameGenerator(target)); } /** - * Create an instance using {@link TestTarget} as the {@code target}. + * Create an instance using {@link #TEST_TARGET} as the {@code target}. */ public TestGenerationContext() { - this(TestTarget.class); + this(TEST_TARGET); } diff --git a/spring-core-test/src/main/java/org/springframework/aot/test/generate/TestTarget.java b/spring-core-test/src/main/java/org/springframework/aot/test/generate/TestTarget.java deleted file mode 100644 index f63ead634e..0000000000 --- a/spring-core-test/src/main/java/org/springframework/aot/test/generate/TestTarget.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2002-2022 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.aot.test.generate; - -/** - * A default target class used by tests of code generation. - * - * @author Stephane Nicoll - * @since 6.0 - */ -public class TestTarget { -} diff --git a/spring-core/src/main/java/org/springframework/aot/generate/ClassNameGenerator.java b/spring-core/src/main/java/org/springframework/aot/generate/ClassNameGenerator.java index 80ea3dc60d..48c88041e4 100644 --- a/spring-core/src/main/java/org/springframework/aot/generate/ClassNameGenerator.java +++ b/spring-core/src/main/java/org/springframework/aot/generate/ClassNameGenerator.java @@ -27,8 +27,8 @@ import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; /** - * Generate unique class names based on a target {@link Class} and a feature - * name. + * Generate unique class names based on a target {@link ClassName} and a + * feature name. * *

This class is stateful, so the same instance should be used for all name * generation. @@ -43,7 +43,7 @@ public final class ClassNameGenerator { private static final String AOT_FEATURE = "Aot"; - private final Class defaultTarget; + private final ClassName defaultTarget; private final String featureNamePrefix; @@ -55,7 +55,7 @@ public final class ClassNameGenerator { * feature name prefix. * @param defaultTarget the default target class to use */ - public ClassNameGenerator(Class defaultTarget) { + public ClassNameGenerator(ClassName defaultTarget) { this(defaultTarget, ""); } @@ -65,11 +65,11 @@ public final class ClassNameGenerator { * @param defaultTarget the default target class to use * @param featureNamePrefix the prefix to use to qualify feature names */ - public ClassNameGenerator(Class defaultTarget, String featureNamePrefix) { + public ClassNameGenerator(ClassName defaultTarget, String featureNamePrefix) { this(defaultTarget, featureNamePrefix, new ConcurrentHashMap<>()); } - private ClassNameGenerator(Class defaultTarget, String featureNamePrefix, + private ClassNameGenerator(ClassName defaultTarget, String featureNamePrefix, Map sequenceGenerator) { Assert.notNull(defaultTarget, "'defaultTarget' must not be null"); this.defaultTarget = defaultTarget; @@ -98,16 +98,16 @@ public final class ClassNameGenerator { * {@code null} to use the main target * @return a unique generated class name */ - public ClassName generateClassName(String featureName, @Nullable Class target) { + public ClassName generateClassName(String featureName, @Nullable ClassName target) { return generateSequencedClassName(getRootName(featureName, target)); } - private String getRootName(String featureName, @Nullable Class target) { + private String getRootName(String featureName, @Nullable ClassName target) { Assert.hasLength(featureName, "'featureName' must not be empty"); featureName = clean(featureName); - Class targetToUse = (target != null ? target : this.defaultTarget); + ClassName targetToUse = (target != null ? target : this.defaultTarget); String featureNameToUse = this.featureNamePrefix + featureName; - return targetToUse.getName().replace("$", "_") + SEPARATOR + StringUtils.capitalize(featureNameToUse); + return toName(targetToUse).replace("$", "_") + SEPARATOR + StringUtils.capitalize(featureNameToUse); } private String clean(String name) { @@ -147,4 +147,8 @@ public final class ClassNameGenerator { this.sequenceGenerator); } + private static String toName(ClassName className) { + return GeneratedTypeReference.of(className).getName(); + } + } diff --git a/spring-core/src/main/java/org/springframework/aot/generate/GeneratedClasses.java b/spring-core/src/main/java/org/springframework/aot/generate/GeneratedClasses.java index 27be83e168..aa768ff406 100644 --- a/spring-core/src/main/java/org/springframework/aot/generate/GeneratedClasses.java +++ b/spring-core/src/main/java/org/springframework/aot/generate/GeneratedClasses.java @@ -99,7 +99,7 @@ public class GeneratedClasses { * @return an existing or newly generated class */ public GeneratedClass getOrAddForFeatureComponent(String featureName, - Class targetComponent, Consumer type) { + ClassName targetComponent, Consumer type) { Assert.hasLength(featureName, "'featureName' must not be empty"); Assert.notNull(targetComponent, "'targetComponent' must not be null"); @@ -111,6 +111,24 @@ public class GeneratedClasses { return generatedClass; } + /** + * Get or add a generated class for the specified {@code featureName} + * targeting the specified {@code component}. If this method has previously + * been called with the given {@code featureName}/{@code target} the + * existing class will be returned, otherwise a new class will be generated, + * otherwise a new class will be generated. + * @param featureName the name of the feature to associate with the + * generated class + * @param targetComponent the target component + * @param type a {@link Consumer} used to build the type + * @return an existing or newly generated class + */ + public GeneratedClass getOrAddForFeatureComponent(String featureName, + Class targetComponent, Consumer type) { + + return getOrAddForFeatureComponent(featureName, ClassName.get(targetComponent), type); + } + /** * Add a new generated class for the specified {@code featureName} and no * particular component. @@ -135,7 +153,7 @@ public class GeneratedClasses { * @return the newly generated class */ public GeneratedClass addForFeatureComponent(String featureName, - Class targetComponent, Consumer type) { + ClassName targetComponent, Consumer type) { Assert.hasLength(featureName, "'featureName' must not be empty"); Assert.notNull(targetComponent, "'targetComponent' must not be null"); @@ -143,8 +161,23 @@ public class GeneratedClasses { return createAndAddGeneratedClass(featureName, targetComponent, type); } + /** + * Add a new generated class for the specified {@code featureName} targeting + * the specified {@code component}. + * @param featureName the name of the feature to associate with the + * generated class + * @param targetComponent the target component + * @param type a {@link Consumer} used to build the type + * @return the newly generated class + */ + public GeneratedClass addForFeatureComponent(String featureName, + Class targetComponent, Consumer type) { + + return addForFeatureComponent(featureName, ClassName.get(targetComponent), type); + } + private GeneratedClass createAndAddGeneratedClass(String featureName, - @Nullable Class targetComponent, Consumer type) { + @Nullable ClassName targetComponent, Consumer type) { ClassName className = this.classNameGenerator.generateClassName(featureName, targetComponent); GeneratedClass generatedClass = new GeneratedClass(className, type); @@ -171,7 +204,7 @@ public class GeneratedClasses { this.classes, this.classesByOwner); } - private record Owner(String featureNamePrefix, String featureName, @Nullable Class target) { + private record Owner(String featureNamePrefix, String featureName, @Nullable ClassName target) { } } diff --git a/spring-core/src/test/java/org/springframework/aot/generate/ClassNameGeneratorTests.java b/spring-core/src/test/java/org/springframework/aot/generate/ClassNameGeneratorTests.java index de6f780178..b1867a0583 100644 --- a/spring-core/src/test/java/org/springframework/aot/generate/ClassNameGeneratorTests.java +++ b/spring-core/src/test/java/org/springframework/aot/generate/ClassNameGeneratorTests.java @@ -32,71 +32,69 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException */ class ClassNameGeneratorTests { - private final ClassNameGenerator generator = new ClassNameGenerator(Object.class); + private static final ClassName TEST_TARGET = ClassName.get("com.example", "Test"); + + private final ClassNameGenerator generator = new ClassNameGenerator(TEST_TARGET); @Test void generateClassNameWhenTargetClassIsNullUsesMainTarget() { ClassName generated = this.generator.generateClassName("test", null); - assertThat(generated).hasToString("java.lang.Object__Test"); + assertThat(generated).hasToString("com.example.Test__Test"); } @Test void generateClassNameUseFeatureNamePrefix() { - ClassName generated = new ClassNameGenerator(Object.class, "One") - .generateClassName("test", InputStream.class); + ClassName generated = new ClassNameGenerator(TEST_TARGET, "One") + .generateClassName("test", ClassName.get(InputStream.class)); assertThat(generated).hasToString("java.io.InputStream__OneTest"); } @Test void generateClassNameWithNoTextFeatureNamePrefix() { - ClassName generated = new ClassNameGenerator(Object.class, " ") - .generateClassName("test", InputStream.class); + ClassName generated = new ClassNameGenerator(TEST_TARGET, " ") + .generateClassName("test", ClassName.get(InputStream.class)); assertThat(generated).hasToString("java.io.InputStream__Test"); } @Test void generatedClassNameWhenFeatureIsEmptyThrowsException() { assertThatIllegalArgumentException() - .isThrownBy(() -> this.generator.generateClassName("", InputStream.class)) + .isThrownBy(() -> this.generator.generateClassName("", ClassName.get(InputStream.class))) .withMessage("'featureName' must not be empty"); } @Test void generatedClassNameWhenFeatureIsNotAllLettersThrowsException() { - assertThat(this.generator.generateClassName("name!", InputStream.class)) + assertThat(this.generator.generateClassName("name!", ClassName.get(InputStream.class))) .hasToString("java.io.InputStream__Name"); - assertThat(this.generator.generateClassName("1NameHere", InputStream.class)) + assertThat(this.generator.generateClassName("1NameHere", ClassName.get(InputStream.class))) .hasToString("java.io.InputStream__NameHere"); - assertThat(this.generator.generateClassName("Y0pe", InputStream.class)) + assertThat(this.generator.generateClassName("Y0pe", ClassName.get(InputStream.class))) .hasToString("java.io.InputStream__YPe"); } @Test void generateClassNameWithClassWhenLowercaseFeatureNameGeneratesName() { - ClassName generated = this.generator.generateClassName("bytes", InputStream.class); + ClassName generated = this.generator.generateClassName("bytes", ClassName.get(InputStream.class)); assertThat(generated).hasToString("java.io.InputStream__Bytes"); } @Test void generateClassNameWithClassWhenInnerClassGeneratesName() { - ClassName generated = this.generator.generateClassName("EventListener", TestBean.class); + ClassName innerBean = ClassName.get("com.example", "Test", "InnerBean"); + ClassName generated = this.generator.generateClassName("EventListener", innerBean); assertThat(generated) - .hasToString("org.springframework.aot.generate.ClassNameGeneratorTests_TestBean__EventListener"); + .hasToString("com.example.Test_InnerBean__EventListener"); } @Test void generateClassWithClassWhenMultipleCallsGeneratesSequencedName() { - ClassName generated1 = this.generator.generateClassName("bytes", InputStream.class); - ClassName generated2 = this.generator.generateClassName("bytes", InputStream.class); - ClassName generated3 = this.generator.generateClassName("bytes", InputStream.class); + ClassName generated1 = this.generator.generateClassName("bytes",ClassName.get(InputStream.class)); + ClassName generated2 = this.generator.generateClassName("bytes", ClassName.get(InputStream.class)); + ClassName generated3 = this.generator.generateClassName("bytes", ClassName.get(InputStream.class)); assertThat(generated1).hasToString("java.io.InputStream__Bytes"); assertThat(generated2).hasToString("java.io.InputStream__Bytes1"); assertThat(generated3).hasToString("java.io.InputStream__Bytes2"); } - - static class TestBean { - - } - } diff --git a/spring-core/src/test/java/org/springframework/aot/generate/DefaultGenerationContextTests.java b/spring-core/src/test/java/org/springframework/aot/generate/DefaultGenerationContextTests.java index 137f166cb8..1db14ca7d3 100644 --- a/spring-core/src/test/java/org/springframework/aot/generate/DefaultGenerationContextTests.java +++ b/spring-core/src/test/java/org/springframework/aot/generate/DefaultGenerationContextTests.java @@ -22,6 +22,7 @@ import org.junit.jupiter.api.Test; import org.springframework.aot.generate.GeneratedFiles.Kind; import org.springframework.aot.hint.RuntimeHints; +import org.springframework.javapoet.ClassName; import org.springframework.javapoet.TypeSpec; import static org.assertj.core.api.Assertions.assertThat; @@ -35,10 +36,12 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException */ class DefaultGenerationContextTests { + private static final ClassName SAMPLE_TARGET = ClassName.get("com.example", "SampleTarget"); + private static final Consumer typeSpecCustomizer = type -> {}; private final GeneratedClasses generatedClasses = new GeneratedClasses( - new ClassNameGenerator(SampleTarget.class)); + new ClassNameGenerator(SAMPLE_TARGET)); private final InMemoryGeneratedFiles generatedFiles = new InMemoryGeneratedFiles(); @@ -48,7 +51,7 @@ class DefaultGenerationContextTests { @Test void createWithOnlyGeneratedFilesCreatesContext() { DefaultGenerationContext context = new DefaultGenerationContext( - new ClassNameGenerator(SampleTarget.class), this.generatedFiles); + new ClassNameGenerator(SAMPLE_TARGET), this.generatedFiles); assertThat(context.getGeneratedFiles()).isSameAs(this.generatedFiles); assertThat(context.getRuntimeHints()).isInstanceOf(RuntimeHints.class); } @@ -109,7 +112,7 @@ class DefaultGenerationContextTests { @Test void withNameUpdateNamingConvention() { DefaultGenerationContext context = new DefaultGenerationContext( - new ClassNameGenerator(SampleTarget.class), this.generatedFiles); + new ClassNameGenerator(SAMPLE_TARGET), this.generatedFiles); GenerationContext anotherContext = context.withName("Another"); GeneratedClass generatedClass = anotherContext.getGeneratedClasses() .addForFeature("Test", typeSpecCustomizer); @@ -119,7 +122,7 @@ class DefaultGenerationContextTests { @Test void withNameKeepsTrackOfAllGeneratedFiles() { DefaultGenerationContext context = new DefaultGenerationContext( - new ClassNameGenerator(SampleTarget.class), this.generatedFiles); + new ClassNameGenerator(SAMPLE_TARGET), this.generatedFiles); context.getGeneratedClasses().addForFeature("Test", typeSpecCustomizer); GenerationContext anotherContext = context.withName("Another"); assertThat(anotherContext.getGeneratedClasses()).isNotSameAs(context.getGeneratedClasses()); @@ -133,7 +136,7 @@ class DefaultGenerationContextTests { @Test void withNameGeneratesUniqueName() { DefaultGenerationContext context = new DefaultGenerationContext( - new ClassNameGenerator(Object.class), this.generatedFiles); + new ClassNameGenerator(SAMPLE_TARGET), this.generatedFiles); context.withName("Test").getGeneratedClasses() .addForFeature("Feature", typeSpecCustomizer); context.withName("Test").getGeneratedClasses() @@ -142,11 +145,9 @@ class DefaultGenerationContextTests { .addForFeature("Feature", typeSpecCustomizer); context.writeGeneratedContent(); assertThat(this.generatedFiles.getGeneratedFiles(Kind.SOURCE)).containsOnlyKeys( - "java/lang/Object__TestFeature.java", - "java/lang/Object__Test1Feature.java", - "java/lang/Object__Test2Feature.java"); + "com/example/SampleTarget__TestFeature.java", + "com/example/SampleTarget__Test1Feature.java", + "com/example/SampleTarget__Test2Feature.java"); } - static class SampleTarget {} - } diff --git a/spring-core/src/test/java/org/springframework/aot/generate/GeneratedClassesTests.java b/spring-core/src/test/java/org/springframework/aot/generate/GeneratedClassesTests.java index 2edca07b55..df8a73c960 100644 --- a/spring-core/src/test/java/org/springframework/aot/generate/GeneratedClassesTests.java +++ b/spring-core/src/test/java/org/springframework/aot/generate/GeneratedClassesTests.java @@ -22,6 +22,7 @@ import java.util.function.Consumer; import org.junit.jupiter.api.Test; import org.springframework.aot.generate.GeneratedFiles.Kind; +import org.springframework.javapoet.ClassName; import org.springframework.javapoet.TypeSpec; import static org.assertj.core.api.Assertions.assertThat; @@ -42,7 +43,7 @@ class GeneratedClassesTests { private static final Consumer emptyTypeCustomizer = type -> {}; private final GeneratedClasses generatedClasses = new GeneratedClasses( - new ClassNameGenerator(Object.class)); + new ClassNameGenerator(ClassName.get("com.example", "Test"))); @Test void createWhenClassNameGeneratorIsNullThrowsException() { @@ -76,7 +77,7 @@ class GeneratedClassesTests { @Test void addForFeatureUsesDefaultTarget() { GeneratedClass generatedClass = this.generatedClasses.addForFeature("Test", emptyTypeCustomizer); - assertThat(generatedClass.getName()).hasToString("java.lang.Object__Test"); + assertThat(generatedClass.getName()).hasToString("com.example.Test__Test"); } @Test diff --git a/spring-test/src/main/java/org/springframework/test/context/aot/TestContextAotGenerator.java b/spring-test/src/main/java/org/springframework/test/context/aot/TestContextAotGenerator.java index ae67e17a47..004f7a597a 100644 --- a/spring-test/src/main/java/org/springframework/test/context/aot/TestContextAotGenerator.java +++ b/spring-test/src/main/java/org/springframework/test/context/aot/TestContextAotGenerator.java @@ -234,7 +234,7 @@ public class TestContextAotGenerator { } DefaultGenerationContext createGenerationContext(Class testClass) { - ClassNameGenerator classNameGenerator = new ClassNameGenerator(testClass); + ClassNameGenerator classNameGenerator = new ClassNameGenerator(ClassName.get(testClass)); DefaultGenerationContext generationContext = new DefaultGenerationContext(classNameGenerator, this.generatedFiles, this.runtimeHints); return generationContext.withName(nextTestContextId()); @@ -245,7 +245,8 @@ public class TestContextAotGenerator { } private void generateTestAotMappings(MultiValueMap> initializerClassMappings) { - ClassNameGenerator classNameGenerator = new ClassNameGenerator(AotTestContextInitializers.class); + ClassNameGenerator classNameGenerator = new ClassNameGenerator( + ClassName.get(AotTestContextInitializers.class)); DefaultGenerationContext generationContext = new DefaultGenerationContext(classNameGenerator, this.generatedFiles, this.runtimeHints); GeneratedClasses generatedClasses = generationContext.getGeneratedClasses(); @@ -258,7 +259,8 @@ public class TestContextAotGenerator { } private void generateAotTestAttributes() { - ClassNameGenerator classNameGenerator = new ClassNameGenerator(AotTestAttributes.class); + ClassNameGenerator classNameGenerator = new ClassNameGenerator( + ClassName.get(AotTestAttributes.class)); DefaultGenerationContext generationContext = new DefaultGenerationContext(classNameGenerator, this.generatedFiles, this.runtimeHints); GeneratedClasses generatedClasses = generationContext.getGeneratedClasses(); From e6aef11b0968a2416e1bf6a3c6fb39425f1904ea Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 22 Sep 2022 16:02:25 +0200 Subject: [PATCH 2/2] Allow target to be a ClassName rather than an existing Class See gh-29207 --- ...opedProxyBeanRegistrationAotProcessor.java | 5 +- .../aot/BeanDefinitionMethodGenerator.java | 4 +- .../aot/BeanRegistrationCodeFragments.java | 5 +- ...eanRegistrationCodeFragmentsDecorator.java | 3 +- .../DefaultBeanRegistrationCodeFragments.java | 5 +- ...ultBeanRegistrationCodeFragmentsTests.java | 56 ++++++++++--------- 6 files changed, 43 insertions(+), 35 deletions(-) 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 512f06e3fd..305b71ef46 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 @@ -37,6 +37,7 @@ import org.springframework.beans.factory.support.InstanceSupplier; import org.springframework.beans.factory.support.RegisteredBean; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.core.ResolvableType; +import org.springframework.javapoet.ClassName; import org.springframework.javapoet.CodeBlock; import org.springframework.lang.Nullable; @@ -108,8 +109,8 @@ class ScopedProxyBeanRegistrationAotProcessor implements BeanRegistrationAotProc } @Override - public Class getTarget(RegisteredBean registeredBean, Executable constructorOrFactoryMethod) { - return this.targetBeanDefinition.getResolvableType().toClass(); + public ClassName getTarget(RegisteredBean registeredBean, Executable constructorOrFactoryMethod) { + return ClassName.get(this.targetBeanDefinition.getResolvableType().toClass()); } @Override 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 29703c3eeb..b128333f2a 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 @@ -94,9 +94,9 @@ class BeanDefinitionMethodGenerator { registerRuntimeHintsIfNecessary(generationContext.getRuntimeHints()); BeanRegistrationCodeFragments codeFragments = getCodeFragments(generationContext, beanRegistrationsCode); - Class target = codeFragments.getTarget(this.registeredBean, + ClassName target = codeFragments.getTarget(this.registeredBean, this.constructorOrFactoryMethod); - if (!target.getName().startsWith("java.")) { + if (!target.canonicalName().startsWith("java.")) { GeneratedClass generatedClass = generationContext.getGeneratedClasses() .getOrAddForFeatureComponent("BeanDefinitions", target, type -> { type.addJavadoc("Bean definitions for {@link $T}", target); diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanRegistrationCodeFragments.java b/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanRegistrationCodeFragments.java index 9019cce7b4..d7f02a43e5 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanRegistrationCodeFragments.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanRegistrationCodeFragments.java @@ -26,6 +26,7 @@ import org.springframework.beans.factory.support.InstanceSupplier; import org.springframework.beans.factory.support.RegisteredBean; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.core.ResolvableType; +import org.springframework.javapoet.ClassName; import org.springframework.javapoet.CodeBlock; /** @@ -52,9 +53,9 @@ public interface BeanRegistrationCodeFragments { * the code. * @param registeredBean the registered bean * @param constructorOrFactoryMethod the constructor or factory method - * @return the target class + * @return the target {@link ClassName} */ - Class getTarget(RegisteredBean registeredBean, + ClassName getTarget(RegisteredBean registeredBean, Executable constructorOrFactoryMethod); /** diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanRegistrationCodeFragmentsDecorator.java b/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanRegistrationCodeFragmentsDecorator.java index 169e61bc7e..7f6251624b 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanRegistrationCodeFragmentsDecorator.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanRegistrationCodeFragmentsDecorator.java @@ -26,6 +26,7 @@ import org.springframework.aot.generate.MethodReference; import org.springframework.beans.factory.support.RegisteredBean; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.core.ResolvableType; +import org.springframework.javapoet.ClassName; import org.springframework.javapoet.CodeBlock; import org.springframework.util.Assert; @@ -51,7 +52,7 @@ public class BeanRegistrationCodeFragmentsDecorator implements BeanRegistrationC } @Override - public Class getTarget(RegisteredBean registeredBean, + public ClassName getTarget(RegisteredBean registeredBean, Executable constructorOrFactoryMethod) { return this.delegate.getTarget(registeredBean, constructorOrFactoryMethod); diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/aot/DefaultBeanRegistrationCodeFragments.java b/spring-beans/src/main/java/org/springframework/beans/factory/aot/DefaultBeanRegistrationCodeFragments.java index 0c76862915..f756f21088 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/aot/DefaultBeanRegistrationCodeFragments.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/aot/DefaultBeanRegistrationCodeFragments.java @@ -32,6 +32,7 @@ import org.springframework.beans.factory.support.InstanceSupplier; import org.springframework.beans.factory.support.RegisteredBean; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.core.ResolvableType; +import org.springframework.javapoet.ClassName; import org.springframework.javapoet.CodeBlock; import org.springframework.javapoet.ParameterizedTypeName; import org.springframework.lang.Nullable; @@ -70,7 +71,7 @@ class DefaultBeanRegistrationCodeFragments implements BeanRegistrationCodeFragme @Override - public Class getTarget(RegisteredBean registeredBean, + public ClassName getTarget(RegisteredBean registeredBean, Executable constructorOrFactoryMethod) { Class target = extractDeclaringClass(registeredBean.getBeanType(), constructorOrFactoryMethod); @@ -79,7 +80,7 @@ class DefaultBeanRegistrationCodeFragments implements BeanRegistrationCodeFragme Assert.state(parent != null, "No parent available for inner bean"); target = parent.getBeanClass(); } - return target; + return ClassName.get(target); } private Class extractDeclaringClass(ResolvableType beanType, Executable executable) { diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/aot/DefaultBeanRegistrationCodeFragmentsTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/aot/DefaultBeanRegistrationCodeFragmentsTests.java index ac53388579..64a4ecdb4f 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/aot/DefaultBeanRegistrationCodeFragmentsTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/aot/DefaultBeanRegistrationCodeFragmentsTests.java @@ -34,6 +34,7 @@ import org.springframework.beans.testfixture.beans.factory.aot.SimpleBean; import org.springframework.beans.testfixture.beans.factory.aot.SimpleBeanConfiguration; import org.springframework.beans.testfixture.beans.factory.aot.SimpleBeanFactoryBean; import org.springframework.core.ResolvableType; +import org.springframework.javapoet.ClassName; import org.springframework.util.ReflectionUtils; import static org.assertj.core.api.Assertions.assertThat; @@ -52,45 +53,45 @@ class DefaultBeanRegistrationCodeFragmentsTests { @Test void getTargetOnConstructor() { RegisteredBean registeredBean = registerTestBean(SimpleBean.class); - assertThat(createInstance(registeredBean).getTarget(registeredBean, - SimpleBean.class.getDeclaredConstructors()[0])).isEqualTo(SimpleBean.class); + assertTarget(createInstance(registeredBean).getTarget(registeredBean, + SimpleBean.class.getDeclaredConstructors()[0]), SimpleBean.class); } @Test void getTargetOnConstructorToPublicFactoryBean() { RegisteredBean registeredBean = registerTestBean(SimpleBean.class); - assertThat(createInstance(registeredBean).getTarget(registeredBean, - SimpleBeanFactoryBean.class.getDeclaredConstructors()[0])).isEqualTo(SimpleBean.class); + assertTarget(createInstance(registeredBean).getTarget(registeredBean, + SimpleBeanFactoryBean.class.getDeclaredConstructors()[0]), SimpleBean.class); } @Test void getTargetOnConstructorToPublicGenericFactoryBeanExtractTargetFromFactoryBeanType() { RegisteredBean registeredBean = registerTestBean(ResolvableType .forClassWithGenerics(GenericFactoryBean.class, SimpleBean.class)); - assertThat(createInstance(registeredBean).getTarget(registeredBean, - GenericFactoryBean.class.getDeclaredConstructors()[0])).isEqualTo(SimpleBean.class); + assertTarget(createInstance(registeredBean).getTarget(registeredBean, + GenericFactoryBean.class.getDeclaredConstructors()[0]), SimpleBean.class); } @Test void getTargetOnConstructorToPublicGenericFactoryBeanWithBoundExtractTargetFromFactoryBeanType() { RegisteredBean registeredBean = registerTestBean(ResolvableType .forClassWithGenerics(NumberFactoryBean.class, Integer.class)); - assertThat(createInstance(registeredBean).getTarget(registeredBean, - NumberFactoryBean.class.getDeclaredConstructors()[0])).isEqualTo(Integer.class); + assertTarget(createInstance(registeredBean).getTarget(registeredBean, + NumberFactoryBean.class.getDeclaredConstructors()[0]), Integer.class); } @Test void getTargetOnConstructorToPublicGenericFactoryBeanUseBeanTypeAsFallback() { RegisteredBean registeredBean = registerTestBean(SimpleBean.class); - assertThat(createInstance(registeredBean).getTarget(registeredBean, - GenericFactoryBean.class.getDeclaredConstructors()[0])).isEqualTo(SimpleBean.class); + assertTarget(createInstance(registeredBean).getTarget(registeredBean, + GenericFactoryBean.class.getDeclaredConstructors()[0]), SimpleBean.class); } @Test void getTargetOnConstructorToProtectedFactoryBean() { RegisteredBean registeredBean = registerTestBean(SimpleBean.class); - assertThat(createInstance(registeredBean).getTarget(registeredBean, - PrivilegedTestBeanFactoryBean.class.getDeclaredConstructors()[0])).isEqualTo( + assertTarget(createInstance(registeredBean).getTarget(registeredBean, + PrivilegedTestBeanFactoryBean.class.getDeclaredConstructors()[0]), PrivilegedTestBeanFactoryBean.class); } @@ -99,8 +100,8 @@ class DefaultBeanRegistrationCodeFragmentsTests { RegisteredBean registeredBean = registerTestBean(SimpleBean.class); Method method = ReflectionUtils.findMethod(SimpleBeanConfiguration.class, "simpleBean"); assertThat(method).isNotNull(); - assertThat(createInstance(registeredBean).getTarget(registeredBean, - method)).isEqualTo(SimpleBeanConfiguration.class); + assertTarget(createInstance(registeredBean).getTarget(registeredBean, method), + SimpleBeanConfiguration.class); } @Test @@ -110,16 +111,15 @@ class DefaultBeanRegistrationCodeFragmentsTests { new RootBeanDefinition(String.class)); Method method = ReflectionUtils.findMethod(getClass(), "createString"); assertThat(method).isNotNull(); - assertThat(createInstance(innerBean).getTarget(innerBean, - method)).isEqualTo(getClass()); + assertTarget(createInstance(innerBean).getTarget(innerBean, method), getClass()); } @Test void getTargetOnConstructorWithInnerBeanInJavaPackage() { RegisteredBean registeredBean = registerTestBean(SimpleBean.class); RegisteredBean innerBean = RegisteredBean.ofInnerBean(registeredBean, "innerTestBean", new RootBeanDefinition(String.class)); - assertThat(createInstance(innerBean).getTarget(innerBean, - String.class.getDeclaredConstructors()[0])).isEqualTo(SimpleBean.class); + assertTarget(createInstance(innerBean).getTarget(innerBean, + String.class.getDeclaredConstructors()[0]), SimpleBean.class); } @Test @@ -127,8 +127,8 @@ class DefaultBeanRegistrationCodeFragmentsTests { RegisteredBean registeredBean = registerTestBean(SimpleBean.class); RegisteredBean innerBean = RegisteredBean.ofInnerBean(registeredBean, "innerTestBean", new RootBeanDefinition(StringFactoryBean.class)); - assertThat(createInstance(innerBean).getTarget(innerBean, - StringFactoryBean.class.getDeclaredConstructors()[0])).isEqualTo(SimpleBean.class); + assertTarget(createInstance(innerBean).getTarget(innerBean, + StringFactoryBean.class.getDeclaredConstructors()[0]), SimpleBean.class); } @Test @@ -138,8 +138,8 @@ class DefaultBeanRegistrationCodeFragmentsTests { new RootBeanDefinition(SimpleBean.class)); Method method = ReflectionUtils.findMethod(SimpleBeanConfiguration.class, "simpleBean"); assertThat(method).isNotNull(); - assertThat(createInstance(innerBean).getTarget(innerBean, method)) - .isEqualTo(SimpleBeanConfiguration.class); + assertTarget(createInstance(innerBean).getTarget(innerBean, method), + SimpleBeanConfiguration.class); } @Test @@ -147,8 +147,8 @@ class DefaultBeanRegistrationCodeFragmentsTests { RegisteredBean registeredBean = registerTestBean(DummyFactory.class); RegisteredBean innerBean = RegisteredBean.ofInnerBean(registeredBean, "innerTestBean", new RootBeanDefinition(SimpleBean.class)); - assertThat(createInstance(innerBean).getTarget(innerBean, - SimpleBean.class.getDeclaredConstructors()[0])).isEqualTo(SimpleBean.class); + assertTarget(createInstance(innerBean).getTarget(innerBean, + SimpleBean.class.getDeclaredConstructors()[0]), SimpleBean.class); } @Test @@ -156,8 +156,12 @@ class DefaultBeanRegistrationCodeFragmentsTests { RegisteredBean registeredBean = registerTestBean(DummyFactory.class); RegisteredBean innerBean = RegisteredBean.ofInnerBean(registeredBean, "innerTestBean", new RootBeanDefinition(SimpleBean.class)); - assertThat(createInstance(innerBean).getTarget(innerBean, - SimpleBeanFactoryBean.class.getDeclaredConstructors()[0])).isEqualTo(SimpleBean.class); + assertTarget(createInstance(innerBean).getTarget(innerBean, + SimpleBeanFactoryBean.class.getDeclaredConstructors()[0]), SimpleBean.class); + } + + private void assertTarget(ClassName target, Class expected) { + assertThat(target).isEqualTo(ClassName.get(expected)); }