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 ace0f093ac6..92dec61c232 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 @@ -1007,7 +1007,7 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA AccessVisibility visibility = AccessVisibility.forMember(method); if (visibility == AccessVisibility.PRIVATE || visibility == AccessVisibility.PROTECTED) { - hints.reflection().registerMethod(method); + hints.reflection().registerMethod(method, ExecutableMode.INVOKE); code.add(".resolveAndInvoke($L, $L)", REGISTERED_BEAN_PARAMETER, INSTANCE_PARAMETER); } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGenerator.java b/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGenerator.java index 39380e784d3..cef034888c7 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGenerator.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGenerator.java @@ -145,7 +145,7 @@ class BeanDefinitionPropertiesCodeGenerator { private void addInitDestroyHint(Class beanUserClass, String methodName) { Method method = ReflectionUtils.findMethod(beanUserClass, methodName); if (method != null) { - this.hints.reflection().registerMethod(method); + this.hints.reflection().registerMethod(method, ExecutableMode.INVOKE); } } 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 e6cb5df84f1..217ac0f1e8f 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 @@ -147,7 +147,7 @@ class InstanceSupplierCodeGenerator { Class beanClass, Constructor constructor, boolean dependsOnBean) { this.generationContext.getRuntimeHints().reflection() - .registerConstructor(constructor); + .registerConstructor(constructor, ExecutableMode.INVOKE); GeneratedMethod generatedMethod = generateGetInstanceSupplierMethod(method -> { method.addJavadoc("Get the bean instance supplier for '$L'.", beanName); method.addModifiers(PRIVATE_STATIC); @@ -240,7 +240,7 @@ class InstanceSupplierCodeGenerator { Method factoryMethod, Class declaringClass) { this.generationContext.getRuntimeHints().reflection() - .registerMethod(factoryMethod); + .registerMethod(factoryMethod, ExecutableMode.INVOKE); GeneratedMethod getInstanceMethod = generateGetInstanceSupplierMethod(method -> { method.addJavadoc("Get the bean instance supplier for '$L'.", beanName); method.addModifiers(PRIVATE_STATIC); diff --git a/spring-core-test/src/test/java/org/springframework/aot/agent/InstrumentedMethodTests.java b/spring-core-test/src/test/java/org/springframework/aot/agent/InstrumentedMethodTests.java index 0a3863a08c9..6b989174d3f 100644 --- a/spring-core-test/src/test/java/org/springframework/aot/agent/InstrumentedMethodTests.java +++ b/spring-core-test/src/test/java/org/springframework/aot/agent/InstrumentedMethodTests.java @@ -194,7 +194,7 @@ class InstrumentedMethodTests { @Test void classGetConstructorsShouldMatchConstructorReflectionHint() throws Exception { - hints.reflection().registerConstructor(String.class.getConstructor()); + hints.reflection().registerConstructor(String.class.getConstructor(), ExecutableMode.INVOKE); assertThatInvocationMatches(InstrumentedMethod.CLASS_GETCONSTRUCTORS, this.stringGetConstructors); } @@ -250,7 +250,7 @@ class InstrumentedMethodTests { @Test void classGetDeclaredConstructorsShouldMatchConstructorReflectionHint() throws Exception { - hints.reflection().registerConstructor(String.class.getConstructor()); + hints.reflection().registerConstructor(String.class.getConstructor(), ExecutableMode.INVOKE); assertThatInvocationMatches(InstrumentedMethod.CLASS_GETDECLAREDCONSTRUCTORS, this.stringGetDeclaredConstructors); } @@ -350,7 +350,7 @@ class InstrumentedMethodTests { @Test void classGetDeclaredMethodsShouldMatchMethodReflectionHint() throws Exception { - hints.reflection().registerMethod(String.class.getMethod("toString")); + hints.reflection().registerMethod(String.class.getMethod("toString"), ExecutableMode.INVOKE); assertThatInvocationMatches(InstrumentedMethod.CLASS_GETDECLAREDMETHODS, this.stringGetScaleMethod); } @@ -392,7 +392,7 @@ class InstrumentedMethodTests { @Test void classGetMethodsShouldMatchMethodReflectionHint() throws Exception { - hints.reflection().registerMethod(String.class.getMethod("toString")); + hints.reflection().registerMethod(String.class.getMethod("toString"), ExecutableMode.INVOKE); assertThatInvocationMatches(InstrumentedMethod.CLASS_GETMETHODS, this.stringGetMethods); } diff --git a/spring-core/src/main/java/org/springframework/aot/hint/BindingReflectionHintsRegistrar.java b/spring-core/src/main/java/org/springframework/aot/hint/BindingReflectionHintsRegistrar.java index 35b4b5993d9..4c560eb9163 100644 --- a/spring-core/src/main/java/org/springframework/aot/hint/BindingReflectionHintsRegistrar.java +++ b/spring-core/src/main/java/org/springframework/aot/hint/BindingReflectionHintsRegistrar.java @@ -145,7 +145,7 @@ public class BindingReflectionHintsRegistrar { Class companionClass = ClassUtils.resolveClassName(companionClassName, null); Method serializerMethod = ClassUtils.getMethodIfAvailable(companionClass, "serializer"); if (serializerMethod != null) { - hints.registerMethod(serializerMethod); + hints.registerMethod(serializerMethod, ExecutableMode.INVOKE); } } } diff --git a/spring-core/src/main/java/org/springframework/aot/hint/ReflectionHints.java b/spring-core/src/main/java/org/springframework/aot/hint/ReflectionHints.java index e70e9d94cca..7cf337a0c0a 100644 --- a/spring-core/src/main/java/org/springframework/aot/hint/ReflectionHints.java +++ b/spring-core/src/main/java/org/springframework/aot/hint/ReflectionHints.java @@ -36,6 +36,8 @@ import org.springframework.util.ClassUtils; * Gather the need for reflection at runtime. * * @author Stephane Nicoll + * @author Phillip Webb + * @author Andy Wilkinson * @since 6.0 */ public class ReflectionHints { @@ -79,6 +81,7 @@ public class ReflectionHints { * @param type the type to customize * @param typeHint a builder to further customize hints for that type * @return {@code this}, to facilitate method chaining + * @see #registerType(TypeReference, MemberCategory...) */ public ReflectionHints registerType(TypeReference type, Consumer typeHint) { Builder builder = this.types.computeIfAbsent(type, TypeHint.Builder::new); @@ -93,8 +96,19 @@ public class ReflectionHints { * @param memberCategories the member categories to apply * @return {@code this}, to facilitate method chaining */ - public ReflectionHints registerType(Class type, MemberCategory... memberCategories) { - return registerType(TypeReference.of(type), memberCategories); + public ReflectionHints registerType(TypeReference type, MemberCategory... memberCategories) { + return registerType(type, TypeHint.builtWith(memberCategories)); + } + + /** + * Register or customize reflection hints for the specified type. + * @param type the type to customize + * @param typeHint a builder to further customize hints for that type + * @return {@code this}, to facilitate method chaining + * @see #registerType(Class, MemberCategory...) + */ + public ReflectionHints registerType(Class type, Consumer typeHint) { + return registerType(TypeReference.of(type), typeHint); } /** @@ -104,18 +118,8 @@ public class ReflectionHints { * @param memberCategories the member categories to apply * @return {@code this}, to facilitate method chaining */ - public ReflectionHints registerType(TypeReference type , MemberCategory... memberCategories) { - return registerType(type, TypeHint.builtWith(memberCategories)); - } - - /** - * Register or customize reflection hints for the specified type. - * @param type the type to customize - * @param typeHint a builder to further customize hints for that type - * @return {@code this}, to facilitate method chaining - */ - public ReflectionHints registerType(Class type, Consumer typeHint) { - return registerType(TypeReference.of(type), typeHint); + public ReflectionHints registerType(Class type, MemberCategory... memberCategories) { + return registerType(TypeReference.of(type), memberCategories); } /** @@ -125,6 +129,7 @@ public class ReflectionHints { * @param typeName the type to customize * @param typeHint a builder to further customize hints for that type * @return {@code this}, to facilitate method chaining + * @see #registerTypeIfPresent(ClassLoader, String, MemberCategory...) */ public ReflectionHints registerTypeIfPresent(@Nullable ClassLoader classLoader, String typeName, Consumer typeHint) { @@ -134,6 +139,19 @@ public class ReflectionHints { return this; } + /** + * Register or customize reflection hints for the specified type if it + * is available using the specified {@link ClassLoader}. + * @param classLoader the classloader to use to check if the type is present + * @param typeName the type to customize + * @param memberCategories the member categories to apply + * @return {@code this}, to facilitate method chaining + */ + public ReflectionHints registerTypeIfPresent(@Nullable ClassLoader classLoader, + String typeName, MemberCategory... memberCategories) { + return registerTypeIfPresent(classLoader, typeName, TypeHint.builtWith(memberCategories)); + } + /** * Register or customize reflection hints for the types defined by the * specified list of {@link TypeReference type references}. The specified @@ -162,7 +180,9 @@ public class ReflectionHints { * enabling {@link ExecutableMode#INVOKE}. * @param constructor the constructor that requires reflection * @return {@code this}, to facilitate method chaining + * @deprecated in favor of {@link #registerConstructor(Constructor, ExecutableMode)} */ + @Deprecated public ReflectionHints registerConstructor(Constructor constructor) { return registerConstructor(constructor, ExecutableMode.INVOKE); } @@ -175,7 +195,8 @@ public class ReflectionHints { * @return {@code this}, to facilitate method chaining */ public ReflectionHints registerConstructor(Constructor constructor, ExecutableMode mode) { - return registerConstructor(constructor, ExecutableHint.builtWith(mode)); + return registerType(TypeReference.of(constructor.getDeclaringClass()), + typeHint -> typeHint.withConstructor(mapParameters(constructor), mode)); } /** @@ -183,8 +204,10 @@ public class ReflectionHints { * @param constructor the constructor that requires reflection * @param constructorHint a builder to further customize the hints of this * constructor - * @return {@code this}, to facilitate method chaining + * @return {@code this}, to facilitate method chaining` + * @deprecated in favor of {@link #registerConstructor(Constructor, ExecutableMode)} */ + @Deprecated public ReflectionHints registerConstructor(Constructor constructor, Consumer constructorHint) { return registerType(TypeReference.of(constructor.getDeclaringClass()), typeHint -> typeHint.withConstructor(mapParameters(constructor), constructorHint)); @@ -195,7 +218,9 @@ public class ReflectionHints { * enabling {@link ExecutableMode#INVOKE}. * @param method the method that requires reflection * @return {@code this}, to facilitate method chaining + * @deprecated in favor of {@link #registerMethod(Method, ExecutableMode)} */ + @Deprecated public ReflectionHints registerMethod(Method method) { return registerMethod(method, ExecutableMode.INVOKE); } @@ -208,7 +233,8 @@ public class ReflectionHints { * @return {@code this}, to facilitate method chaining */ public ReflectionHints registerMethod(Method method, ExecutableMode mode) { - return registerMethod(method, ExecutableHint.builtWith(mode)); + return registerType(TypeReference.of(method.getDeclaringClass()), + typeHint -> typeHint.withMethod(method.getName(), mapParameters(method), mode)); } /** @@ -216,7 +242,9 @@ public class ReflectionHints { * @param method the method that requires reflection * @param methodHint a builder to further customize the hints of this method * @return {@code this}, to facilitate method chaining + * @deprecated in favor of {@link #registerMethod(Method, ExecutableMode)} */ + @Deprecated public ReflectionHints registerMethod(Method method, Consumer methodHint) { return registerType(TypeReference.of(method.getDeclaringClass()), typeHint -> typeHint.withMethod(method.getName(), mapParameters(method), methodHint)); diff --git a/spring-core/src/main/java/org/springframework/aot/hint/TypeHint.java b/spring-core/src/main/java/org/springframework/aot/hint/TypeHint.java index f660ad3a3c5..191fe5fdefd 100644 --- a/spring-core/src/main/java/org/springframework/aot/hint/TypeHint.java +++ b/spring-core/src/main/java/org/springframework/aot/hint/TypeHint.java @@ -35,6 +35,8 @@ import org.springframework.util.Assert; * A hint that describes the need for reflection on a type. * * @author Stephane Nicoll + * @author Phillip Webb + * @author Andy Wilkinson * @since 6.0 */ public final class TypeHint implements ConditionalHint { @@ -199,7 +201,9 @@ public final class TypeHint implements ConditionalHint { * parameter types, enabling {@link ExecutableMode#INVOKE}. * @param parameterTypes the parameter types of the constructor * @return {@code this}, to facilitate method chaining + * @deprecated in favor of {@link #withConstructor(List, ExecutableMode)} */ + @Deprecated public Builder withConstructor(List parameterTypes) { return withConstructor(parameterTypes, ExecutableMode.INVOKE); } @@ -222,8 +226,11 @@ public final class TypeHint implements ConditionalHint { * @param constructorHint a builder to further customize the hints of this * constructor * @return {@code this}, to facilitate method chaining + * @deprecated in favor of {@link #withConstructor(List, ExecutableMode)} */ - public Builder withConstructor(List parameterTypes, Consumer constructorHint) { + @Deprecated + public Builder withConstructor(List parameterTypes, + Consumer constructorHint) { ExecutableKey key = new ExecutableKey("", parameterTypes); ExecutableHint.Builder builder = this.constructors.computeIfAbsent(key, k -> ExecutableHint.ofConstructor(parameterTypes)); @@ -237,7 +244,9 @@ public final class TypeHint implements ConditionalHint { * @param name the name of the method * @param parameterTypes the parameter types of the constructor * @return {@code this}, to facilitate method chaining + * @deprecated in favor of {@link #withMethod(String, List, ExecutableMode)} */ + @Deprecated public Builder withMethod(String name, List parameterTypes) { return withMethod(name, parameterTypes, ExecutableMode.INVOKE); } @@ -261,8 +270,11 @@ public final class TypeHint implements ConditionalHint { * @param parameterTypes the parameter types of the constructor * @param methodHint a builder to further customize the hints of this method * @return {@code this}, to facilitate method chaining + * @deprecated in favor of {@link #withMethod(String, List, ExecutableMode)} */ - public Builder withMethod(String name, List parameterTypes, Consumer methodHint) { + @Deprecated + public Builder withMethod(String name, List parameterTypes, + Consumer methodHint) { ExecutableKey key = new ExecutableKey(name, parameterTypes); ExecutableHint.Builder builder = this.methods.computeIfAbsent(key, k -> ExecutableHint.ofMethod(name, parameterTypes)); @@ -274,6 +286,7 @@ public final class TypeHint implements ConditionalHint { * Adds the specified {@linkplain MemberCategory member categories}. * @param memberCategories the categories to apply * @return {@code this}, to facilitate method chaining + * @see TypeHint#builtWith(MemberCategory...) */ public Builder withMembers(MemberCategory... memberCategories) { this.memberCategories.addAll(Arrays.asList(memberCategories)); diff --git a/spring-core/src/main/java/org/springframework/aot/hint/annotation/SimpleReflectiveProcessor.java b/spring-core/src/main/java/org/springframework/aot/hint/annotation/SimpleReflectiveProcessor.java index 974981d4106..949f97ca1d9 100644 --- a/spring-core/src/main/java/org/springframework/aot/hint/annotation/SimpleReflectiveProcessor.java +++ b/spring-core/src/main/java/org/springframework/aot/hint/annotation/SimpleReflectiveProcessor.java @@ -21,6 +21,7 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; +import org.springframework.aot.hint.ExecutableMode; import org.springframework.aot.hint.ReflectionHints; /** @@ -64,7 +65,7 @@ public class SimpleReflectiveProcessor implements ReflectiveProcessor { * @param constructor the constructor to process */ protected void registerConstructorHint(ReflectionHints hints, Constructor constructor) { - hints.registerConstructor(constructor); + hints.registerConstructor(constructor, ExecutableMode.INVOKE); } /** @@ -82,7 +83,7 @@ public class SimpleReflectiveProcessor implements ReflectiveProcessor { * @param method the method to process */ protected void registerMethodHint(ReflectionHints hints, Method method) { - hints.registerMethod(method); + hints.registerMethod(method, ExecutableMode.INVOKE); } } diff --git a/spring-core/src/test/java/org/springframework/aot/hint/ReflectionHintsTests.java b/spring-core/src/test/java/org/springframework/aot/hint/ReflectionHintsTests.java index b585609a06d..7f0749c9d15 100644 --- a/spring-core/src/test/java/org/springframework/aot/hint/ReflectionHintsTests.java +++ b/spring-core/src/test/java/org/springframework/aot/hint/ReflectionHintsTests.java @@ -16,6 +16,7 @@ package org.springframework.aot.hint; +import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.function.Consumer; @@ -48,8 +49,7 @@ class ReflectionHintsTests { @Test void registerTypeIfPresentRegistersExistingClass() { - this.reflectionHints.registerTypeIfPresent(null, String.class.getName(), - hint -> hint.withMembers(MemberCategory.DECLARED_FIELDS)); + this.reflectionHints.registerTypeIfPresent(null, String.class.getName(), MemberCategory.DECLARED_FIELDS); assertThat(this.reflectionHints.typeHints()).singleElement().satisfies( typeWithMemberCategories(String.class, MemberCategory.DECLARED_FIELDS)); } @@ -144,15 +144,6 @@ class ReflectionHintsTests { @Test void registerConstructor() { - this.reflectionHints.registerConstructor(TestType.class.getDeclaredConstructors()[0]); - assertTestTypeConstructorHint(constructorHint -> { - assertThat(constructorHint.getParameterTypes()).isEmpty(); - assertThat(constructorHint.getMode()).isEqualTo(ExecutableMode.INVOKE); - }); - } - - @Test - void registerConstructorWithMode() { this.reflectionHints.registerConstructor( TestType.class.getDeclaredConstructors()[0], ExecutableMode.INTROSPECT); assertTestTypeConstructorHint(constructorHint -> { @@ -162,25 +153,16 @@ class ReflectionHintsTests { } @Test - void registerConstructorWithEmptyCustomizerAppliesConsistentDefault() { - this.reflectionHints.registerConstructor(TestType.class.getDeclaredConstructors()[0], - constructorHint -> {}); + void registerConstructorTwiceUpdatesExistingEntry() { + Constructor constructor = TestType.class.getDeclaredConstructors()[0]; + this.reflectionHints.registerConstructor(constructor, ExecutableMode.INTROSPECT); + this.reflectionHints.registerConstructor(constructor, ExecutableMode.INVOKE); assertTestTypeConstructorHint(constructorHint -> { assertThat(constructorHint.getParameterTypes()).isEmpty(); assertThat(constructorHint.getMode()).isEqualTo(ExecutableMode.INVOKE); }); } - @Test - void registerConstructorWithCustomizerAppliesCustomization() { - this.reflectionHints.registerConstructor(TestType.class.getDeclaredConstructors()[0], - constructorHint -> constructorHint.withMode(ExecutableMode.INTROSPECT)); - assertTestTypeConstructorHint(constructorHint -> { - assertThat(constructorHint.getParameterTypes()).isEmpty(); - assertThat(constructorHint.getMode()).isEqualTo(ExecutableMode.INTROSPECT); - }); - } - private void assertTestTypeConstructorHint(Consumer constructorHint) { assertThat(this.reflectionHints.typeHints()).singleElement().satisfies(typeHint -> { assertThat(typeHint.getMemberCategories()).isEmpty(); @@ -194,18 +176,6 @@ class ReflectionHintsTests { @Test void registerMethod() { - Method method = ReflectionUtils.findMethod(TestType.class, "setName", String.class); - assertThat(method).isNotNull(); - this.reflectionHints.registerMethod(method); - assertTestTypeMethodHints(methodHint -> { - assertThat(methodHint.getName()).isEqualTo("setName"); - assertThat(methodHint.getParameterTypes()).containsOnly(TypeReference.of(String.class)); - assertThat(methodHint.getMode()).isEqualTo(ExecutableMode.INVOKE); - }); - } - - @Test - void registerMethodWithMode() { Method method = ReflectionUtils.findMethod(TestType.class, "setName", String.class); assertThat(method).isNotNull(); this.reflectionHints.registerMethod(method, ExecutableMode.INTROSPECT); @@ -217,10 +187,11 @@ class ReflectionHintsTests { } @Test - void registerMethodWithEmptyCustomizerAppliesConsistentDefault() { + void registerMethodTwiceUpdatesExistingEntry() { Method method = ReflectionUtils.findMethod(TestType.class, "setName", String.class); assertThat(method).isNotNull(); - this.reflectionHints.registerMethod(method, methodHint -> {}); + this.reflectionHints.registerMethod(method, ExecutableMode.INTROSPECT); + this.reflectionHints.registerMethod(method, ExecutableMode.INVOKE); assertTestTypeMethodHints(methodHint -> { assertThat(methodHint.getName()).isEqualTo("setName"); assertThat(methodHint.getParameterTypes()).containsOnly(TypeReference.of(String.class)); @@ -228,18 +199,6 @@ class ReflectionHintsTests { }); } - @Test - void registerMethodWithCustomizerAppliesCustomization() { - Method method = ReflectionUtils.findMethod(TestType.class, "setName", String.class); - assertThat(method).isNotNull(); - this.reflectionHints.registerMethod(method, methodHint -> methodHint.withMode(ExecutableMode.INTROSPECT)); - assertTestTypeMethodHints(methodHint -> { - assertThat(methodHint.getName()).isEqualTo("setName"); - assertThat(methodHint.getParameterTypes()).containsOnly(TypeReference.of(String.class)); - assertThat(methodHint.getMode()).isEqualTo(ExecutableMode.INTROSPECT); - }); - } - private void assertTestTypeMethodHints(Consumer methodHint) { assertThat(this.reflectionHints.typeHints()).singleElement().satisfies(typeHint -> { assertThat(typeHint.getType().getCanonicalName()).isEqualTo(TestType.class.getCanonicalName()); diff --git a/spring-core/src/test/java/org/springframework/aot/hint/TypeHintTests.java b/spring-core/src/test/java/org/springframework/aot/hint/TypeHintTests.java index c0f57435623..5c84ec93bbc 100644 --- a/spring-core/src/test/java/org/springframework/aot/hint/TypeHintTests.java +++ b/spring-core/src/test/java/org/springframework/aot/hint/TypeHintTests.java @@ -70,16 +70,6 @@ class TypeHintTests { @Test void createWithConstructor() { - List parameterTypes = TypeReference.listOf(byte[].class, int.class); - assertConstructorHint(TypeHint.of(TypeReference.of(String.class)) - .withConstructor(parameterTypes), constructorHint -> { - assertThat(constructorHint.getParameterTypes()).containsOnlyOnceElementsOf(parameterTypes); - assertThat(constructorHint.getMode()).isEqualTo(ExecutableMode.INVOKE); - }); - } - - @Test - void createWithConstructorAndMode() { List parameterTypes = TypeReference.listOf(byte[].class, int.class); assertConstructorHint(TypeHint.of(TypeReference.of(String.class)) .withConstructor(parameterTypes, ExecutableMode.INTROSPECT), constructorHint -> { @@ -89,45 +79,22 @@ class TypeHintTests { } @Test - void createWithConstructorAndEmptyCustomizerAppliesConsistentDefault() { - List parameterTypes = TypeReference.listOf(byte[].class, int.class); - assertConstructorHint(TypeHint.of(TypeReference.of(String.class)) - .withConstructor(parameterTypes, constructorHint -> {}), constructorHint -> { - assertThat(constructorHint.getParameterTypes()).containsOnlyOnceElementsOf(parameterTypes); - assertThat(constructorHint.getMode()).isEqualTo(ExecutableMode.INVOKE); - }); - } - - @Test - void createWithConstructorAndCustomizerAppliesCustomization() { - List parameterTypes = TypeReference.listOf(byte[].class, int.class); - assertConstructorHint(TypeHint.of(TypeReference.of(String.class)) - .withConstructor(parameterTypes, constructorHint -> - constructorHint.withMode(ExecutableMode.INTROSPECT)), constructorHint -> { - assertThat(constructorHint.getParameterTypes()).containsOnlyOnceElementsOf(parameterTypes); - assertThat(constructorHint.getMode()).isEqualTo(ExecutableMode.INTROSPECT); - }); - } - - @Test - void createConstructorReuseBuilder() { + void createWithConstructorWithSameConstructorUpdatesEntry() { List parameterTypes = TypeReference.listOf(byte[].class, int.class); Builder builder = TypeHint.of(TypeReference.of(String.class)) .withConstructor(parameterTypes, ExecutableMode.INTROSPECT); - assertConstructorHint(builder.withConstructor(parameterTypes, constructorHint -> - constructorHint.withMode(ExecutableMode.INVOKE)), constructorHint -> { + assertConstructorHint(builder.withConstructor(parameterTypes, ExecutableMode.INVOKE), constructorHint -> { assertThat(constructorHint.getParameterTypes()).containsExactlyElementsOf(parameterTypes); assertThat(constructorHint.getMode()).isEqualTo(ExecutableMode.INVOKE); }); } @Test - void createConstructorReuseBuilderAndApplyExecutableModePrecedence() { + void createWithConstructorAndSameConstructorAppliesExecutableModePrecedence() { List parameterTypes = TypeReference.listOf(byte[].class, int.class); - Builder builder = TypeHint.of(TypeReference.of(String.class)).withConstructor(parameterTypes, - constructorHint -> constructorHint.withMode(ExecutableMode.INVOKE)); - assertConstructorHint(builder.withConstructor(parameterTypes, constructorHint -> - constructorHint.withMode(ExecutableMode.INTROSPECT)), constructorHint -> { + Builder builder = TypeHint.of(TypeReference.of(String.class)) + .withConstructor(parameterTypes, ExecutableMode.INVOKE); + assertConstructorHint(builder.withConstructor(parameterTypes, ExecutableMode.INTROSPECT), constructorHint -> { assertThat(constructorHint.getParameterTypes()).containsExactlyElementsOf(parameterTypes); assertThat(constructorHint.getMode()).isEqualTo(ExecutableMode.INVOKE); }); @@ -143,17 +110,6 @@ class TypeHintTests { @Test void createWithMethod() { - List parameterTypes = List.of(TypeReference.of(char[].class)); - assertMethodHint(TypeHint.of(TypeReference.of(String.class)) - .withMethod("valueOf", parameterTypes), methodHint -> { - assertThat(methodHint.getName()).isEqualTo("valueOf"); - assertThat(methodHint.getParameterTypes()).containsExactlyElementsOf(parameterTypes); - assertThat(methodHint.getMode()).isEqualTo(ExecutableMode.INVOKE); - }); - } - - @Test - void createWithMethodAndMode() { List parameterTypes = List.of(TypeReference.of(char[].class)); assertMethodHint(TypeHint.of(TypeReference.of(String.class)) .withMethod("valueOf", parameterTypes, ExecutableMode.INTROSPECT), methodHint -> { @@ -164,36 +120,11 @@ class TypeHintTests { } @Test - void createWithMethodAndEmptyCustomizerAppliesConsistentDefault() { - List parameterTypes = List.of(TypeReference.of(char[].class)); - assertMethodHint(TypeHint.of(TypeReference.of(String.class)) - .withMethod("valueOf", parameterTypes, methodHint -> {}), methodHint -> { - assertThat(methodHint.getName()).isEqualTo("valueOf"); - assertThat(methodHint.getParameterTypes()).containsExactlyElementsOf(parameterTypes); - assertThat(methodHint.getMode()).isEqualTo(ExecutableMode.INVOKE); - }); - } - - @Test - void createWithMethodAndCustomizerAppliesCustomization() { - List parameterTypes = List.of(TypeReference.of(char[].class)); - assertMethodHint(TypeHint.of(TypeReference.of(String.class)) - .withMethod("valueOf", parameterTypes, methodHint -> - methodHint.withMode(ExecutableMode.INTROSPECT)), methodHint -> { - assertThat(methodHint.getName()).isEqualTo("valueOf"); - assertThat(methodHint.getParameterTypes()).containsExactlyElementsOf(parameterTypes); - assertThat(methodHint.getMode()).isEqualTo(ExecutableMode.INTROSPECT); - }); - } - - - @Test - void createWithMethodReuseBuilder() { + void createWithMethodWithSameMethodUpdatesEntry() { List parameterTypes = TypeReference.listOf(char[].class); Builder builder = TypeHint.of(TypeReference.of(String.class)) .withMethod("valueOf", parameterTypes, ExecutableMode.INTROSPECT); - assertMethodHint(builder.withMethod("valueOf", parameterTypes, - methodHint -> methodHint.withMode(ExecutableMode.INVOKE)), methodHint -> { + assertMethodHint(builder.withMethod("valueOf", parameterTypes, ExecutableMode.INVOKE), methodHint -> { assertThat(methodHint.getName()).isEqualTo("valueOf"); assertThat(methodHint.getParameterTypes()).containsExactlyElementsOf(parameterTypes); assertThat(methodHint.getMode()).isEqualTo(ExecutableMode.INVOKE); @@ -201,12 +132,11 @@ class TypeHintTests { } @Test - void createWithMethodReuseBuilderAndApplyExecutableModePrecedence() { + void createWithMethodAndSameMethodAppliesExecutableModePrecedence() { List parameterTypes = TypeReference.listOf(char[].class); Builder builder = TypeHint.of(TypeReference.of(String.class)) .withMethod("valueOf", parameterTypes, ExecutableMode.INVOKE); - assertMethodHint(builder.withMethod("valueOf", parameterTypes, - methodHint -> methodHint.withMode(ExecutableMode.INTROSPECT)), methodHint -> { + assertMethodHint(builder.withMethod("valueOf", parameterTypes, ExecutableMode.INTROSPECT), methodHint -> { assertThat(methodHint.getName()).isEqualTo("valueOf"); assertThat(methodHint.getParameterTypes()).containsExactlyElementsOf(parameterTypes); assertThat(methodHint.getMode()).isEqualTo(ExecutableMode.INVOKE); diff --git a/spring-core/src/test/java/org/springframework/aot/hint/predicate/ReflectionHintsPredicatesTests.java b/spring-core/src/test/java/org/springframework/aot/hint/predicate/ReflectionHintsPredicatesTests.java index ade56f2d0d5..2b8ebf338de 100644 --- a/spring-core/src/test/java/org/springframework/aot/hint/predicate/ReflectionHintsPredicatesTests.java +++ b/spring-core/src/test/java/org/springframework/aot/hint/predicate/ReflectionHintsPredicatesTests.java @@ -303,7 +303,7 @@ class ReflectionHintsPredicatesTests { @Test void reflectionOnAnyConstructorMatchesConstructorReflection() { - runtimeHints.reflection().registerConstructor(publicConstructor); + runtimeHints.reflection().registerConstructor(publicConstructor, ExecutableMode.INVOKE); assertPredicateMatches(reflection.onType(SampleClass.class).withAnyConstructor()); } @@ -458,7 +458,7 @@ class ReflectionHintsPredicatesTests { @Test void reflectionOnAnyMethodMatchesMethodReflection() { - runtimeHints.reflection().registerMethod(publicMethod); + runtimeHints.reflection().registerMethod(publicMethod, ExecutableMode.INVOKE); assertPredicateMatches(reflection.onType(SampleClass.class).withAnyMethod()); } diff --git a/spring-core/src/test/java/org/springframework/aot/nativex/FileNativeConfigurationWriterTests.java b/spring-core/src/test/java/org/springframework/aot/nativex/FileNativeConfigurationWriterTests.java index 2668180fa88..238ed1293cf 100644 --- a/spring-core/src/test/java/org/springframework/aot/nativex/FileNativeConfigurationWriterTests.java +++ b/spring-core/src/test/java/org/springframework/aot/nativex/FileNativeConfigurationWriterTests.java @@ -109,7 +109,7 @@ public class FileNativeConfigurationWriterTests { .withField("DEFAULT_CHARSET") .withField("defaultCharset") .withConstructor(TypeReference.listOf(List.class, boolean.class, MimeType.class), ExecutableMode.INTROSPECT) - .withMethod("setDefaultCharset", TypeReference.listOf(Charset.class)) + .withMethod("setDefaultCharset", TypeReference.listOf(Charset.class), ExecutableMode.INVOKE) .withMethod("getDefaultCharset", Collections.emptyList(), ExecutableMode.INTROSPECT)); generator.write(hints); assertEquals(""" diff --git a/spring-core/src/test/java/org/springframework/aot/nativex/ReflectionHintsWriterTests.java b/spring-core/src/test/java/org/springframework/aot/nativex/ReflectionHintsWriterTests.java index 0aa8bce1332..9aff60ece09 100644 --- a/spring-core/src/test/java/org/springframework/aot/nativex/ReflectionHintsWriterTests.java +++ b/spring-core/src/test/java/org/springframework/aot/nativex/ReflectionHintsWriterTests.java @@ -60,7 +60,7 @@ public class ReflectionHintsWriterTests { .withField("DEFAULT_CHARSET") .withField("defaultCharset") .withConstructor(TypeReference.listOf(List.class, boolean.class, MimeType.class), ExecutableMode.INTROSPECT) - .withMethod("setDefaultCharset", List.of(TypeReference.of(Charset.class))) + .withMethod("setDefaultCharset", List.of(TypeReference.of(Charset.class)), ExecutableMode.INVOKE) .withMethod("getDefaultCharset", Collections.emptyList(), ExecutableMode.INTROSPECT)); assertEquals(""" [ diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/support/InjectionCodeGenerator.java b/spring-orm/src/main/java/org/springframework/orm/jpa/support/InjectionCodeGenerator.java index e7e294d3838..3121df3dd18 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/support/InjectionCodeGenerator.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/support/InjectionCodeGenerator.java @@ -21,6 +21,7 @@ import java.lang.reflect.Member; import java.lang.reflect.Method; import org.springframework.aot.generate.AccessVisibility; +import org.springframework.aot.hint.ExecutableMode; import org.springframework.aot.hint.RuntimeHints; import org.springframework.javapoet.CodeBlock; import org.springframework.util.Assert; @@ -97,7 +98,7 @@ class InjectionCodeGenerator { AccessVisibility visibility = AccessVisibility.forMember(method); if (visibility == AccessVisibility.PRIVATE || visibility == AccessVisibility.PROTECTED) { - this.hints.reflection().registerMethod(method); + this.hints.reflection().registerMethod(method, ExecutableMode.INVOKE); code.addStatement("$T method = $T.findMethod($T.class, $S, $T.class)", Method.class, ReflectionUtils.class, method.getDeclaringClass(), method.getName(), method.getParameterTypes()[0]);