From d6afa8df2d541a9d8cf26a1d67becd66841a5fd0 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 18 Aug 2022 06:52:34 +0200 Subject: [PATCH] Improve registration of the same hint for multiple classes Based on the feedback in #28977 an easy way to create a list of type references based on a vararg of classes is helpful when registering the same hints for several types. --- .../quartz/LocalTaskExecutorThreadPool.java | 3 + .../SchedulerFactoryBeanRuntimeHints.java | 43 +++--- .../aot/agent/InstrumentedMethodTests.java | 34 ++--- .../aot/hint/TypeReference.java | 13 ++ .../aot/hint/ReflectionHintsTests.java | 5 +- .../aot/hint/TypeHintTests.java | 6 +- .../ReflectionHintsPredicatesTests.java | 123 +++++++++++------- .../FileNativeConfigurationWriterTests.java | 4 +- .../nativex/ReflectionHintsWriterTests.java | 22 ++-- .../annotation/TransactionRuntimeHints.java | 11 +- .../codec/CodecConfigurerRuntimeHints.java | 18 ++- 11 files changed, 158 insertions(+), 124 deletions(-) diff --git a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/LocalTaskExecutorThreadPool.java b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/LocalTaskExecutorThreadPool.java index 42af660341b..624b72cdc24 100644 --- a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/LocalTaskExecutorThreadPool.java +++ b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/LocalTaskExecutorThreadPool.java @@ -24,6 +24,7 @@ import org.apache.commons.logging.LogFactory; import org.quartz.SchedulerConfigException; import org.quartz.spi.ThreadPool; +import org.springframework.aot.hint.annotation.Reflective; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -45,10 +46,12 @@ public class LocalTaskExecutorThreadPool implements ThreadPool { @Override + @Reflective public void setInstanceId(String schedInstId) { } @Override + @Reflective public void setInstanceName(String schedName) { } diff --git a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBeanRuntimeHints.java b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBeanRuntimeHints.java index 044031ea8a7..dc8a8ace11e 100644 --- a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBeanRuntimeHints.java +++ b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBeanRuntimeHints.java @@ -16,12 +16,14 @@ package org.springframework.scheduling.quartz; -import java.util.List; +import java.util.function.Consumer; import org.springframework.aot.hint.MemberCategory; import org.springframework.aot.hint.RuntimeHints; import org.springframework.aot.hint.RuntimeHintsRegistrar; +import org.springframework.aot.hint.TypeHint.Builder; import org.springframework.aot.hint.TypeReference; +import org.springframework.aot.hint.annotation.ReflectiveRuntimeHintsRegistrar; import org.springframework.util.ClassUtils; /** @@ -29,36 +31,29 @@ import org.springframework.util.ClassUtils; * reflection entries are registered. * * @author Sebastien Deleuze + * @author Stephane Nicoll * @since 6.0 */ -public class SchedulerFactoryBeanRuntimeHints implements RuntimeHintsRegistrar { +class SchedulerFactoryBeanRuntimeHints implements RuntimeHintsRegistrar { - private static String SCHEDULER_FACTORY_CLASS_NAME = "org.quartz.impl.StdSchedulerFactory"; + private static final String SCHEDULER_FACTORY_CLASS_NAME = "org.quartz.impl.StdSchedulerFactory"; - private static TypeReference FACTORY_BEAN_TYPE_REFERENCE = TypeReference.of(SchedulerFactoryBean.class); + private static final TypeReference FACTORY_BEAN_TYPE_REFERENCE = TypeReference.of(SchedulerFactoryBean.class); + + private final ReflectiveRuntimeHintsRegistrar reflectiveRegistrar = new ReflectiveRuntimeHintsRegistrar(); @Override public void registerHints(RuntimeHints hints, ClassLoader classLoader) { - if (ClassUtils.isPresent(SCHEDULER_FACTORY_CLASS_NAME, classLoader)) { - hints.reflection().registerType(TypeReference.of(SCHEDULER_FACTORY_CLASS_NAME), - builder -> builder - .withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS) - .onReachableType(FACTORY_BEAN_TYPE_REFERENCE)); - hints.reflection().registerType(ResourceLoaderClassLoadHelper.class, - builder -> builder - .withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS) - .onReachableType(FACTORY_BEAN_TYPE_REFERENCE)); - hints.reflection().registerType(LocalTaskExecutorThreadPool.class, - builder -> builder - .withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS) - .withMethod("setInstanceId", List.of(TypeReference.of(String.class)), b -> {}) - .withMethod("setInstanceName", List.of(TypeReference.of(String.class)), b -> {}) - .onReachableType(FACTORY_BEAN_TYPE_REFERENCE)); - hints.reflection().registerType(LocalDataSourceJobStore.class, - builder -> builder - .withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS) - .onReachableType(FACTORY_BEAN_TYPE_REFERENCE)); - + if (!ClassUtils.isPresent(SCHEDULER_FACTORY_CLASS_NAME, classLoader)) { + return; } + Consumer typeHint = type -> type + .withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS) + .onReachableType(FACTORY_BEAN_TYPE_REFERENCE); + hints.reflection() + .registerType(TypeReference.of(SCHEDULER_FACTORY_CLASS_NAME), typeHint) + .registerTypes(TypeReference.listOf(ResourceLoaderClassLoadHelper.class, + LocalTaskExecutorThreadPool.class, LocalDataSourceJobStore.class), typeHint); + this.reflectiveRegistrar.registerRuntimeHints(hints, LocalTaskExecutorThreadPool.class); } } 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 7f7d78197d9..483638bf675 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 @@ -121,7 +121,7 @@ class InstrumentedMethodTests { this.stringGetConstructor = RecordedInvocation.of(InstrumentedMethod.CLASS_GETCONSTRUCTOR) .onInstance(String.class).withArgument(new Class[0]).returnValue(String.class.getConstructor()).build(); this.stringGetDeclaredConstructor = RecordedInvocation.of(InstrumentedMethod.CLASS_GETDECLAREDCONSTRUCTOR) - .onInstance(String.class).withArgument(new Class[] {byte[].class, byte.class}) + .onInstance(String.class).withArgument(new Class[] { byte[].class, byte.class }) .returnValue(String.class.getDeclaredConstructor(byte[].class, byte.class)).build(); } @@ -201,15 +201,15 @@ class InstrumentedMethodTests { @Test void classGetDeclaredConstructorShouldMatchInstrospectConstructorHint() { - List parameterTypes = List.of(TypeReference.of(byte[].class), TypeReference.of(byte.class)); - hints.reflection().registerType(String.class, typeHint -> typeHint.withConstructor(parameterTypes, constructorHint -> constructorHint.setModes(ExecutableMode.INTROSPECT))); + hints.reflection().registerType(String.class, typeHint -> typeHint.withConstructor(TypeReference.listOf(byte[].class, byte.class), + constructorHint -> constructorHint.setModes(ExecutableMode.INTROSPECT))); assertThatInvocationMatches(InstrumentedMethod.CLASS_GETDECLAREDCONSTRUCTOR, this.stringGetDeclaredConstructor); } @Test void classGetDeclaredConstructorShouldMatchInvokeConstructorHint() { - List parameterTypes = List.of(TypeReference.of(byte[].class), TypeReference.of(byte.class)); - hints.reflection().registerType(String.class, typeHint -> typeHint.withConstructor(parameterTypes, constructorHint -> constructorHint.setModes(ExecutableMode.INVOKE))); + hints.reflection().registerType(String.class, typeHint -> typeHint.withConstructor(TypeReference.listOf(byte[].class, byte.class), + constructorHint -> constructorHint.setModes(ExecutableMode.INVOKE))); assertThatInvocationMatches(InstrumentedMethod.CLASS_GETDECLAREDCONSTRUCTOR, this.stringGetDeclaredConstructor); } @@ -265,33 +265,33 @@ class InstrumentedMethodTests { .onInstance(String.class).withArguments("toString", new Class[0]) .returnValue(String.class.getMethod("toString")).build(); this.stringGetScaleMethod = RecordedInvocation.of(InstrumentedMethod.CLASS_GETDECLAREDMETHOD) - .onInstance(String.class).withArguments("scale", new Class[] {int.class, float.class}) + .onInstance(String.class).withArguments("scale", new Class[] { int.class, float.class }) .returnValue(String.class.getDeclaredMethod("scale", int.class, float.class)).build(); } @Test - void classGetDeclaredMethodShouldMatchIntrospectDeclaredMethodsHint() throws NoSuchMethodException { + void classGetDeclaredMethodShouldMatchIntrospectDeclaredMethodsHint() { hints.reflection().registerType(String.class, typeHint -> typeHint.withMembers(MemberCategory.INTROSPECT_DECLARED_METHODS)); assertThatInvocationMatches(InstrumentedMethod.CLASS_GETDECLAREDMETHOD, this.stringGetScaleMethod); } @Test - void classGetDeclaredMethodShouldNotMatchIntrospectPublicMethodsHint() throws NoSuchMethodException { + void classGetDeclaredMethodShouldNotMatchIntrospectPublicMethodsHint() { hints.reflection().registerType(String.class, typeHint -> typeHint.withMembers(MemberCategory.INTROSPECT_PUBLIC_METHODS)); assertThatInvocationDoesNotMatch(InstrumentedMethod.CLASS_GETDECLAREDMETHOD, this.stringGetScaleMethod); } @Test - void classGetDeclaredMethodShouldMatchIntrospectMethodHint() throws NoSuchMethodException { - List parameterTypes = List.of(TypeReference.of(int.class), TypeReference.of(float.class)); + void classGetDeclaredMethodShouldMatchIntrospectMethodHint() { + List parameterTypes = TypeReference.listOf(int.class, float.class); hints.reflection().registerType(String.class, typeHint -> typeHint.withMethod("scale", parameterTypes, methodHint -> methodHint.withMode(ExecutableMode.INTROSPECT))); assertThatInvocationMatches(InstrumentedMethod.CLASS_GETDECLAREDMETHOD, this.stringGetScaleMethod); } @Test - void classGetDeclaredMethodShouldMatchInvokeMethodHint() throws NoSuchMethodException { - List parameterTypes = List.of(TypeReference.of(int.class), TypeReference.of(float.class)); + void classGetDeclaredMethodShouldMatchInvokeMethodHint() { + List parameterTypes = TypeReference.listOf(int.class, float.class); hints.reflection().registerType(String.class, typeHint -> typeHint.withMethod("scale", parameterTypes, methodHint -> methodHint.withMode(ExecutableMode.INVOKE))); assertThatInvocationMatches(InstrumentedMethod.CLASS_GETDECLAREDMETHOD, this.stringGetScaleMethod); @@ -383,7 +383,7 @@ class InstrumentedMethodTests { } @Test - void classGetMethodShouldMatchInvokeMethodHint() throws Exception { + void classGetMethodShouldMatchInvokeMethodHint() { hints.reflection().registerType(String.class, typeHint -> typeHint.withMethod("toString", Collections.emptyList(), methodHint -> methodHint.setModes(ExecutableMode.INVOKE))); assertThatInvocationMatches(InstrumentedMethod.CLASS_GETMETHOD, this.stringGetToStringMethod); @@ -410,9 +410,9 @@ class InstrumentedMethodTests { @Test void methodInvokeShouldMatchInvokeHintOnMethod() throws NoSuchMethodException { RecordedInvocation invocation = RecordedInvocation.of(InstrumentedMethod.METHOD_INVOKE) - .onInstance(String.class.getMethod("startsWith", String.class)).withArguments("testString", new Object[] {"test"}).build(); + .onInstance(String.class.getMethod("startsWith", String.class)).withArguments("testString", new Object[] { "test" }).build(); hints.reflection().registerType(String.class, typeHint -> typeHint.withMethod("startsWith", - List.of(TypeReference.of(String.class)), methodHint -> methodHint.withMode(ExecutableMode.INVOKE))); + TypeReference.listOf(String.class), methodHint -> methodHint.withMode(ExecutableMode.INVOKE))); assertThatInvocationMatches(InstrumentedMethod.METHOD_INVOKE, invocation); } @@ -600,8 +600,8 @@ class InstrumentedMethodTests { @BeforeEach void setup() { this.newProxyInstance = RecordedInvocation.of(InstrumentedMethod.PROXY_NEWPROXYINSTANCE) - .withArguments(ClassLoader.getSystemClassLoader(), new Class[] {AutoCloseable.class, Comparator.class}, null) - .returnValue(Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[] {AutoCloseable.class, Comparator.class}, (proxy, method, args) -> null)) + .withArguments(ClassLoader.getSystemClassLoader(), new Class[] { AutoCloseable.class, Comparator.class }, null) + .returnValue(Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[] { AutoCloseable.class, Comparator.class }, (proxy, method, args) -> null)) .build(); } diff --git a/spring-core/src/main/java/org/springframework/aot/hint/TypeReference.java b/spring-core/src/main/java/org/springframework/aot/hint/TypeReference.java index 2fcf62fb8cb..38008cf3ef0 100644 --- a/spring-core/src/main/java/org/springframework/aot/hint/TypeReference.java +++ b/spring-core/src/main/java/org/springframework/aot/hint/TypeReference.java @@ -16,6 +16,9 @@ package org.springframework.aot.hint; +import java.util.Arrays; +import java.util.List; + import org.springframework.lang.Nullable; /** @@ -81,4 +84,14 @@ public interface TypeReference { return SimpleTypeReference.of(className); } + /** + * Create a list of {@link TypeReference type references} mapped by the specified + * types. + * @param types the types to map + * @return a list of type references + */ + static List listOf(Class... types) { + return Arrays.stream(types).map(TypeReference::of).toList(); + } + } 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 f4206130a58..68458881dde 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 @@ -19,7 +19,6 @@ package org.springframework.aot.hint; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.function.Consumer; -import java.util.stream.Stream; import org.junit.jupiter.api.Test; @@ -109,8 +108,8 @@ class ReflectionHintsTests { @Test void registerTypesApplyTheSameHints() { - this.reflectionHints.registerTypes(Stream.of(Integer.class, String.class, Double.class) - .map(TypeReference::of).toList(), hint -> hint.withMembers(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS)); + this.reflectionHints.registerTypes(TypeReference.listOf(Integer.class, String.class, Double.class), + hint -> hint.withMembers(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS)); assertThat(this.reflectionHints.typeHints()) .anySatisfy( typeWithMemberCategories(Integer.class, MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS)) 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 d6922c26bd7..e781352c523 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 @@ -82,7 +82,7 @@ class TypeHintTests { @Test void createWithConstructor() { - List parameterTypes = List.of(TypeReference.of(byte[].class), TypeReference.of(int.class)); + List parameterTypes = TypeReference.listOf(byte[].class, int.class); TypeHint hint = TypeHint.of(TypeReference.of(String.class)).withConstructor(parameterTypes, constructorHint -> constructorHint.withMode(ExecutableMode.INVOKE)).build(); assertThat(hint.constructors()).singleElement().satisfies(constructorHint -> { @@ -93,7 +93,7 @@ class TypeHintTests { @Test void createConstructorReuseBuilder() { - List parameterTypes = List.of(TypeReference.of(byte[].class), TypeReference.of(int.class)); + List parameterTypes = TypeReference.listOf(byte[].class, int.class); Builder builder = TypeHint.of(TypeReference.of(String.class)).withConstructor(parameterTypes, constructorHint -> constructorHint.withMode(ExecutableMode.INVOKE)); TypeHint hint = builder.withConstructor(parameterTypes, constructorHint -> @@ -118,7 +118,7 @@ class TypeHintTests { @Test void createWithMethodReuseBuilder() { - List parameterTypes = List.of(TypeReference.of(char[].class)); + List parameterTypes = TypeReference.listOf(char[].class); Builder builder = TypeHint.of(TypeReference.of(String.class)).withMethod("valueOf", parameterTypes, methodHint -> methodHint.withMode(ExecutableMode.INVOKE)); TypeHint hint = builder.withMethod("valueOf", parameterTypes, 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 9366438227a..d3390fe15b4 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 @@ -19,7 +19,6 @@ package org.springframework.aot.hint.predicate; import java.lang.reflect.Constructor; import java.util.Collections; -import java.util.List; import java.util.function.Predicate; import org.junit.jupiter.api.BeforeAll; @@ -66,41 +65,44 @@ class ReflectionHintsPredicatesTests { @Test void reflectionOnClassShouldMatchIntrospection() { - runtimeHints.reflection().registerType(SampleClass.class, builder -> { - }); + runtimeHints.reflection().registerType(SampleClass.class, builder -> {}); assertPredicateMatches(reflection.onType(SampleClass.class)); } @Test void reflectionOnTypeReferenceShouldMatchIntrospection() { - runtimeHints.reflection().registerType(SampleClass.class, builder -> { - }); + runtimeHints.reflection().registerType(SampleClass.class, builder -> {}); assertPredicateMatches(reflection.onType(TypeReference.of(SampleClass.class))); } @Test void reflectionOnDifferentClassShouldNotMatchIntrospection() { - runtimeHints.reflection().registerType(Integer.class, builder -> { - }); + runtimeHints.reflection().registerType(Integer.class, builder -> {}); assertPredicateDoesNotMatch(reflection.onType(TypeReference.of(SampleClass.class))); } @Test void typeWithMemberCategoryFailsWithNullCategory() { - runtimeHints.reflection().registerType(SampleClass.class, builder -> builder.withMembers(MemberCategory.INTROSPECT_PUBLIC_METHODS)); - assertThatIllegalArgumentException().isThrownBy(() -> reflection.onType(SampleClass.class).withMemberCategory(null)); + runtimeHints.reflection().registerType(SampleClass.class, builder -> + builder.withMembers(MemberCategory.INTROSPECT_PUBLIC_METHODS)); + assertThatIllegalArgumentException().isThrownBy(() -> + reflection.onType(SampleClass.class).withMemberCategory(null)); } @Test void typeWithMemberCategoryMatchesCategory() { - runtimeHints.reflection().registerType(SampleClass.class, builder -> builder.withMembers(MemberCategory.INTROSPECT_PUBLIC_METHODS)); - assertPredicateMatches(reflection.onType(SampleClass.class).withMemberCategory(MemberCategory.INTROSPECT_PUBLIC_METHODS)); + runtimeHints.reflection().registerType(SampleClass.class, + builder -> builder.withMembers(MemberCategory.INTROSPECT_PUBLIC_METHODS)); + assertPredicateMatches(reflection.onType(SampleClass.class) + .withMemberCategory(MemberCategory.INTROSPECT_PUBLIC_METHODS)); } @Test void typeWithMemberCategoryDoesNotMatchOtherCategory() { - runtimeHints.reflection().registerType(SampleClass.class, builder -> builder.withMembers(MemberCategory.INTROSPECT_PUBLIC_METHODS)); - assertPredicateDoesNotMatch(reflection.onType(SampleClass.class).withMemberCategory(MemberCategory.INVOKE_PUBLIC_METHODS)); + runtimeHints.reflection().registerType(SampleClass.class, + builder -> builder.withMembers(MemberCategory.INTROSPECT_PUBLIC_METHODS)); + assertPredicateDoesNotMatch(reflection.onType(SampleClass.class) + .withMemberCategory(MemberCategory.INVOKE_PUBLIC_METHODS)); } @Test @@ -120,20 +122,26 @@ class ReflectionHintsPredicatesTests { @Test void typeWithAnyMemberCategoryFailsWithNullCategories() { - runtimeHints.reflection().registerType(SampleClass.class, builder -> builder.withMembers(MemberCategory.INTROSPECT_PUBLIC_METHODS)); - assertThatIllegalArgumentException().isThrownBy(() -> reflection.onType(SampleClass.class).withAnyMemberCategory(new MemberCategory[0])); + runtimeHints.reflection().registerType(SampleClass.class, builder -> + builder.withMembers(MemberCategory.INTROSPECT_PUBLIC_METHODS)); + assertThatIllegalArgumentException().isThrownBy(() -> + reflection.onType(SampleClass.class).withAnyMemberCategory(new MemberCategory[0])); } @Test void typeWithAnyMemberCategoryMatchesCategory() { - runtimeHints.reflection().registerType(SampleClass.class, builder -> builder.withMembers(MemberCategory.INTROSPECT_PUBLIC_METHODS, MemberCategory.INVOKE_PUBLIC_METHODS)); - assertPredicateMatches(reflection.onType(SampleClass.class).withAnyMemberCategory(MemberCategory.INTROSPECT_PUBLIC_METHODS)); + runtimeHints.reflection().registerType(SampleClass.class, + builder -> builder.withMembers(MemberCategory.INTROSPECT_PUBLIC_METHODS, MemberCategory.INVOKE_PUBLIC_METHODS)); + assertPredicateMatches(reflection.onType(SampleClass.class) + .withAnyMemberCategory(MemberCategory.INTROSPECT_PUBLIC_METHODS)); } @Test void typeWithAnyMemberCategoryDoesNotMatchOtherCategory() { - runtimeHints.reflection().registerType(SampleClass.class, builder -> builder.withMembers(MemberCategory.INTROSPECT_PUBLIC_METHODS, MemberCategory.INVOKE_PUBLIC_METHODS)); - assertPredicateDoesNotMatch(reflection.onType(SampleClass.class).withAnyMemberCategory(MemberCategory.INVOKE_DECLARED_METHODS)); + runtimeHints.reflection().registerType(SampleClass.class, + builder -> builder.withMembers(MemberCategory.INTROSPECT_PUBLIC_METHODS, MemberCategory.INVOKE_PUBLIC_METHODS)); + assertPredicateDoesNotMatch(reflection.onType(SampleClass.class) + .withAnyMemberCategory(MemberCategory.INVOKE_DECLARED_METHODS)); } } @@ -148,140 +156,157 @@ class ReflectionHintsPredicatesTests { @Test void constructorIntrospectionMatchesConstructorHint() { - runtimeHints.reflection().registerType(SampleClass.class, typeHint -> typeHint.withConstructor(Collections.emptyList(), constructorHint -> { - })); + runtimeHints.reflection().registerType(SampleClass.class, typeHint -> + typeHint.withConstructor(Collections.emptyList(), constructorHint -> {})); assertPredicateMatches(reflection.onConstructor(publicConstructor).introspect()); } @Test void constructorIntrospectionMatchesIntrospectPublicConstructors() { - runtimeHints.reflection().registerType(SampleClass.class, typeHint -> typeHint.withMembers(MemberCategory.INTROSPECT_PUBLIC_CONSTRUCTORS)); + runtimeHints.reflection().registerType(SampleClass.class, typeHint -> + typeHint.withMembers(MemberCategory.INTROSPECT_PUBLIC_CONSTRUCTORS)); assertPredicateMatches(reflection.onConstructor(publicConstructor).introspect()); } @Test void constructorIntrospectionMatchesInvokePublicConstructors() { - runtimeHints.reflection().registerType(SampleClass.class, typeHint -> typeHint.withMembers(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS)); + runtimeHints.reflection().registerType(SampleClass.class, typeHint -> + typeHint.withMembers(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS)); assertPredicateMatches(reflection.onConstructor(publicConstructor).introspect()); } @Test void constructorIntrospectionMatchesIntrospectDeclaredConstructors() { - runtimeHints.reflection().registerType(SampleClass.class, typeHint -> typeHint.withMembers(MemberCategory.INTROSPECT_DECLARED_CONSTRUCTORS)); + runtimeHints.reflection().registerType(SampleClass.class, typeHint -> + typeHint.withMembers(MemberCategory.INTROSPECT_DECLARED_CONSTRUCTORS)); assertPredicateMatches(reflection.onConstructor(publicConstructor).introspect()); } @Test void constructorIntrospectionMatchesInvokeDeclaredConstructors() { - runtimeHints.reflection().registerType(SampleClass.class, typeHint -> typeHint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)); + runtimeHints.reflection().registerType(SampleClass.class, typeHint -> + typeHint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)); assertPredicateMatches(reflection.onConstructor(publicConstructor).introspect()); } @Test void constructorInvocationDoesNotMatchConstructorHint() { - runtimeHints.reflection().registerType(SampleClass.class, typeHint -> typeHint.withConstructor(Collections.emptyList(), constructorHint -> { - })); + runtimeHints.reflection().registerType(SampleClass.class, typeHint -> typeHint. + withConstructor(Collections.emptyList(), constructorHint -> {})); assertPredicateDoesNotMatch(reflection.onConstructor(publicConstructor).invoke()); } @Test void constructorInvocationMatchesConstructorInvocationHint() { - runtimeHints.reflection().registerType(SampleClass.class, typeHint -> typeHint.withConstructor(Collections.emptyList(), constructorHint -> constructorHint.withMode(ExecutableMode.INVOKE))); + runtimeHints.reflection().registerType(SampleClass.class, typeHint -> typeHint. + withConstructor(Collections.emptyList(), constructorHint -> + constructorHint.withMode(ExecutableMode.INVOKE))); assertPredicateMatches(reflection.onConstructor(publicConstructor).invoke()); } @Test void constructorInvocationDoesNotMatchIntrospectPublicConstructors() { - runtimeHints.reflection().registerType(SampleClass.class, typeHint -> typeHint.withMembers(MemberCategory.INTROSPECT_PUBLIC_CONSTRUCTORS)); + runtimeHints.reflection().registerType(SampleClass.class, typeHint -> + typeHint.withMembers(MemberCategory.INTROSPECT_PUBLIC_CONSTRUCTORS)); assertPredicateDoesNotMatch(reflection.onConstructor(publicConstructor).invoke()); } @Test void constructorInvocationMatchesInvokePublicConstructors() { - runtimeHints.reflection().registerType(SampleClass.class, typeHint -> typeHint.withMembers(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS)); + runtimeHints.reflection().registerType(SampleClass.class, typeHint -> + typeHint.withMembers(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS)); assertPredicateMatches(reflection.onConstructor(publicConstructor).invoke()); } @Test void constructorInvocationDoesNotMatchIntrospectDeclaredConstructors() { - runtimeHints.reflection().registerType(SampleClass.class, typeHint -> typeHint.withMembers(MemberCategory.INTROSPECT_DECLARED_CONSTRUCTORS)); + runtimeHints.reflection().registerType(SampleClass.class, typeHint -> + typeHint.withMembers(MemberCategory.INTROSPECT_DECLARED_CONSTRUCTORS)); assertPredicateDoesNotMatch(reflection.onConstructor(publicConstructor).invoke()); } @Test void constructorInvocationMatchesInvokeDeclaredConstructors() { - runtimeHints.reflection().registerType(SampleClass.class, typeHint -> typeHint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)); + runtimeHints.reflection().registerType(SampleClass.class, typeHint -> + typeHint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)); assertPredicateMatches(reflection.onConstructor(publicConstructor).invoke()); } @Test void privateConstructorIntrospectionMatchesConstructorHint() { - List parameterTypes = Collections.singletonList(TypeReference.of(String.class)); - runtimeHints.reflection().registerType(SampleClass.class, typeHint -> typeHint.withConstructor(parameterTypes, constructorHint -> { - })); + runtimeHints.reflection().registerType(SampleClass.class, typeHint -> + typeHint.withConstructor(TypeReference.listOf(String.class), constructorHint -> {})); assertPredicateMatches(reflection.onConstructor(privateConstructor).introspect()); } @Test void privateConstructorIntrospectionDoesNotMatchIntrospectPublicConstructors() { - runtimeHints.reflection().registerType(SampleClass.class, typeHint -> typeHint.withMembers(MemberCategory.INTROSPECT_PUBLIC_CONSTRUCTORS)); + runtimeHints.reflection().registerType(SampleClass.class, typeHint -> + typeHint.withMembers(MemberCategory.INTROSPECT_PUBLIC_CONSTRUCTORS)); assertPredicateDoesNotMatch(reflection.onConstructor(privateConstructor).introspect()); } @Test void privateConstructorIntrospectionDoesNotMatchInvokePublicConstructors() { - runtimeHints.reflection().registerType(SampleClass.class, typeHint -> typeHint.withMembers(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS)); + runtimeHints.reflection().registerType(SampleClass.class, typeHint -> + typeHint.withMembers(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS)); assertPredicateDoesNotMatch(reflection.onConstructor(privateConstructor).introspect()); } @Test void privateConstructorIntrospectionMatchesIntrospectDeclaredConstructors() { - runtimeHints.reflection().registerType(SampleClass.class, typeHint -> typeHint.withMembers(MemberCategory.INTROSPECT_DECLARED_CONSTRUCTORS)); + runtimeHints.reflection().registerType(SampleClass.class, typeHint -> + typeHint.withMembers(MemberCategory.INTROSPECT_DECLARED_CONSTRUCTORS)); assertPredicateMatches(reflection.onConstructor(privateConstructor).introspect()); } @Test void privateConstructorIntrospectionMatchesInvokeDeclaredConstructors() { - runtimeHints.reflection().registerType(SampleClass.class, typeHint -> typeHint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)); + runtimeHints.reflection().registerType(SampleClass.class, typeHint -> + typeHint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)); assertPredicateMatches(reflection.onConstructor(privateConstructor).introspect()); } @Test void privateConstructorInvocationDoesNotMatchConstructorHint() { - List parameterTypes = Collections.singletonList(TypeReference.of(String.class)); - runtimeHints.reflection().registerType(SampleClass.class, typeHint -> typeHint.withConstructor(parameterTypes, constructorHint -> { - })); + runtimeHints.reflection().registerType(SampleClass.class, typeHint -> + typeHint.withConstructor(TypeReference.listOf(String.class), constructorHint -> {})); assertPredicateDoesNotMatch(reflection.onConstructor(privateConstructor).invoke()); } @Test void privateConstructorInvocationMatchesConstructorInvocationHint() { - List parameterTypes = Collections.singletonList(TypeReference.of(String.class)); - runtimeHints.reflection().registerType(SampleClass.class, typeHint -> typeHint.withConstructor(parameterTypes, constructorHint -> constructorHint.withMode(ExecutableMode.INVOKE))); + runtimeHints.reflection().registerType(SampleClass.class, typeHint -> + typeHint.withConstructor(TypeReference.listOf(String.class), + constructorHint -> constructorHint.withMode(ExecutableMode.INVOKE))); assertPredicateMatches(reflection.onConstructor(privateConstructor).invoke()); } @Test void privateConstructorInvocationDoesNotMatchIntrospectPublicConstructors() { - runtimeHints.reflection().registerType(SampleClass.class, typeHint -> typeHint.withMembers(MemberCategory.INTROSPECT_PUBLIC_CONSTRUCTORS)); + runtimeHints.reflection().registerType(SampleClass.class, typeHint -> + typeHint.withMembers(MemberCategory.INTROSPECT_PUBLIC_CONSTRUCTORS)); assertPredicateDoesNotMatch(reflection.onConstructor(privateConstructor).invoke()); } @Test void privateConstructorInvocationDoesNotMatchInvokePublicConstructors() { - runtimeHints.reflection().registerType(SampleClass.class, typeHint -> typeHint.withMembers(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS)); + runtimeHints.reflection().registerType(SampleClass.class, typeHint -> + typeHint.withMembers(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS)); assertPredicateDoesNotMatch(reflection.onConstructor(privateConstructor).invoke()); } @Test void privateConstructorInvocationDoesNotMatchIntrospectDeclaredConstructors() { - runtimeHints.reflection().registerType(SampleClass.class, typeHint -> typeHint.withMembers(MemberCategory.INTROSPECT_DECLARED_CONSTRUCTORS)); + runtimeHints.reflection().registerType(SampleClass.class, typeHint -> + typeHint.withMembers(MemberCategory.INTROSPECT_DECLARED_CONSTRUCTORS)); assertPredicateDoesNotMatch(reflection.onConstructor(privateConstructor).invoke()); } @Test void privateConstructorInvocationMatchesInvokeDeclaredConstructors() { - runtimeHints.reflection().registerType(SampleClass.class, typeHint -> typeHint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)); + runtimeHints.reflection().registerType(SampleClass.class, typeHint -> + typeHint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)); assertPredicateMatches(reflection.onConstructor(privateConstructor).invoke()); } @@ -460,7 +485,7 @@ class ReflectionHintsPredicatesTests { @Test void fieldWriteReflectionMatchesFieldHintWithWrite() { runtimeHints.reflection().registerType(SampleClass.class, typeHint -> - typeHint.withField("publicField", fieldHint -> fieldHint.allowWrite(true))); + typeHint.withField("publicField", fieldHint -> fieldHint.allowWrite(true))); assertPredicateMatches(reflection.onField(SampleClass.class, "publicField").allowWrite()); } 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 6afb2861a96..dc77407689a 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 @@ -111,9 +111,9 @@ public class FileNativeConfigurationWriterTests { fieldBuilder.allowWrite(true); fieldBuilder.allowUnsafeAccess(true); }) - .withConstructor(List.of(TypeReference.of(List.class), TypeReference.of(boolean.class), TypeReference.of(MimeType.class)), constructorHint -> + .withConstructor(TypeReference.listOf(List.class, boolean.class, MimeType.class), constructorHint -> constructorHint.withMode(ExecutableMode.INTROSPECT)) - .withMethod("setDefaultCharset", List.of(TypeReference.of(Charset.class)), ctorBuilder -> {}) + .withMethod("setDefaultCharset", TypeReference.listOf(Charset.class), ctorBuilder -> {}) .withMethod("getDefaultCharset", Collections.emptyList(), constructorHint -> constructorHint.withMode(ExecutableMode.INTROSPECT)); }); 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 6091690872a..9060f5b0afa 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 @@ -63,7 +63,7 @@ public class ReflectionHintsWriterTests { fieldBuilder.allowWrite(true); fieldBuilder.allowUnsafeAccess(true); }) - .withConstructor(List.of(TypeReference.of(List.class), TypeReference.of(boolean.class), TypeReference.of(MimeType.class)), constructorHint -> + .withConstructor(TypeReference.listOf(List.class, boolean.class, MimeType.class), constructorHint -> constructorHint.withMode(ExecutableMode.INTROSPECT)) .withMethod("setDefaultCharset", List.of(TypeReference.of(Charset.class)), ctorBuilder -> {}) .withMethod("getDefaultCharset", Collections.emptyList(), constructorHint -> @@ -119,8 +119,8 @@ public class ReflectionHintsWriterTests { @Test void queriedMethods() throws JSONException { ReflectionHints hints = new ReflectionHints(); - hints.registerType(Integer.class, builder -> builder.withMethod("parseInt", List.of(TypeReference.of(String.class)), - b -> b.withMode(ExecutableMode.INTROSPECT))); + hints.registerType(Integer.class, builder -> builder.withMethod("parseInt", + TypeReference.listOf(String.class), b -> b.withMode(ExecutableMode.INTROSPECT))); assertEquals(""" [ @@ -140,8 +140,8 @@ public class ReflectionHintsWriterTests { @Test void methods() throws JSONException { ReflectionHints hints = new ReflectionHints(); - hints.registerType(Integer.class, builder -> builder.withMethod("parseInt", List.of(TypeReference.of(String.class)), - b -> b.withMode(ExecutableMode.INVOKE))); + hints.registerType(Integer.class, builder -> builder.withMethod("parseInt", + TypeReference.listOf(String.class), b -> b.withMode(ExecutableMode.INVOKE))); assertEquals(""" [ @@ -161,8 +161,8 @@ public class ReflectionHintsWriterTests { @Test void methodWithInnerClassParameter() throws JSONException { ReflectionHints hints = new ReflectionHints(); - hints.registerType(Integer.class, builder -> builder.withMethod("test", List.of(TypeReference.of(Inner.class)), - b -> b.withMode(ExecutableMode.INVOKE))); + hints.registerType(Integer.class, builder -> builder.withMethod("test", + TypeReference.listOf(Inner.class), b -> b.withMode(ExecutableMode.INVOKE))); assertEquals(""" [ @@ -182,10 +182,10 @@ public class ReflectionHintsWriterTests { @Test void methodAndQueriedMethods() throws JSONException { ReflectionHints hints = new ReflectionHints(); - hints.registerType(Integer.class, builder -> builder.withMethod("parseInt", List.of(TypeReference.of(String.class)), - b -> b.withMode(ExecutableMode.INVOKE))); - hints.registerType(Integer.class, builder -> builder.withMethod("parseInt", List.of(TypeReference.of(String.class)), - b -> b.withMode(ExecutableMode.INTROSPECT))); + hints.registerType(Integer.class, builder -> builder.withMethod("parseInt", + TypeReference.listOf(String.class), b -> b.withMode(ExecutableMode.INVOKE))); + hints.registerType(Integer.class, builder -> builder.withMethod("parseInt", + TypeReference.listOf(String.class), b -> b.withMode(ExecutableMode.INTROSPECT))); assertEquals(""" [ diff --git a/spring-tx/src/main/java/org/springframework/transaction/annotation/TransactionRuntimeHints.java b/spring-tx/src/main/java/org/springframework/transaction/annotation/TransactionRuntimeHints.java index 8f6ad94bd9d..d3bc9ffedf0 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/annotation/TransactionRuntimeHints.java +++ b/spring-tx/src/main/java/org/springframework/transaction/annotation/TransactionRuntimeHints.java @@ -16,8 +16,6 @@ package org.springframework.transaction.annotation; -import java.util.List; - import org.springframework.aot.hint.MemberCategory; import org.springframework.aot.hint.RuntimeHints; import org.springframework.aot.hint.RuntimeHintsRegistrar; @@ -38,11 +36,8 @@ class TransactionRuntimeHints implements RuntimeHintsRegistrar { @Override public void registerHints(RuntimeHints hints, ClassLoader classLoader) { RuntimeHintsUtils.registerSynthesizedAnnotation(hints, Transactional.class); - hints.reflection() - .registerTypes(List.of( - TypeReference.of(Isolation.class), - TypeReference.of(Propagation.class), - TypeReference.of(TransactionDefinition.class)), - builder -> builder.withMembers(MemberCategory.DECLARED_FIELDS)); + hints.reflection().registerTypes(TypeReference.listOf( + Isolation.class, Propagation.class, TransactionDefinition.class), + builder -> builder.withMembers(MemberCategory.DECLARED_FIELDS)); } } diff --git a/spring-web/src/main/java/org/springframework/http/codec/CodecConfigurerRuntimeHints.java b/spring-web/src/main/java/org/springframework/http/codec/CodecConfigurerRuntimeHints.java index aefcea7340b..3040f552fe0 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/CodecConfigurerRuntimeHints.java +++ b/spring-web/src/main/java/org/springframework/http/codec/CodecConfigurerRuntimeHints.java @@ -16,9 +16,12 @@ package org.springframework.http.codec; +import java.util.function.Consumer; + import org.springframework.aot.hint.MemberCategory; import org.springframework.aot.hint.RuntimeHints; import org.springframework.aot.hint.RuntimeHintsRegistrar; +import org.springframework.aot.hint.TypeHint.Builder; import org.springframework.aot.hint.TypeReference; import org.springframework.http.codec.support.DefaultClientCodecConfigurer; import org.springframework.http.codec.support.DefaultServerCodecConfigurer; @@ -29,20 +32,21 @@ import org.springframework.lang.Nullable; * implementations listed in {@code CodecConfigurer.properties}. * * @author Sebastien Deleuze + * @author Stephane Nicoll * @since 6.0 */ class CodecConfigurerRuntimeHints implements RuntimeHintsRegistrar { + private static final Consumer CODEC_HINT = type -> type + .onReachableType(TypeReference.of(CodecConfigurerFactory.class)) + .withMembers(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS); + @Override public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) { hints.resources().registerPattern("org/springframework/http/codec/CodecConfigurer.properties"); - registerType(hints, DefaultClientCodecConfigurer.class); - registerType(hints, DefaultServerCodecConfigurer.class); + hints.reflection().registerTypes(TypeReference.listOf( + DefaultClientCodecConfigurer.class, DefaultServerCodecConfigurer.class), + CODEC_HINT); } - private void registerType(RuntimeHints hints, Class type) { - hints.reflection().registerType(type, builder -> - builder.onReachableType(TypeReference.of(CodecConfigurerFactory.class)) - .withMembers(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS)); - } }