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.
This commit is contained in:
Stephane Nicoll 2022-08-18 06:52:34 +02:00
parent 4556895e6e
commit d6afa8df2d
11 changed files with 158 additions and 124 deletions

View File

@ -24,6 +24,7 @@ import org.apache.commons.logging.LogFactory;
import org.quartz.SchedulerConfigException; import org.quartz.SchedulerConfigException;
import org.quartz.spi.ThreadPool; import org.quartz.spi.ThreadPool;
import org.springframework.aot.hint.annotation.Reflective;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.util.Assert; import org.springframework.util.Assert;
@ -45,10 +46,12 @@ public class LocalTaskExecutorThreadPool implements ThreadPool {
@Override @Override
@Reflective
public void setInstanceId(String schedInstId) { public void setInstanceId(String schedInstId) {
} }
@Override @Override
@Reflective
public void setInstanceName(String schedName) { public void setInstanceName(String schedName) {
} }

View File

@ -16,12 +16,14 @@
package org.springframework.scheduling.quartz; 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.MemberCategory;
import org.springframework.aot.hint.RuntimeHints; import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar; import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.TypeHint.Builder;
import org.springframework.aot.hint.TypeReference; import org.springframework.aot.hint.TypeReference;
import org.springframework.aot.hint.annotation.ReflectiveRuntimeHintsRegistrar;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
/** /**
@ -29,36 +31,29 @@ import org.springframework.util.ClassUtils;
* reflection entries are registered. * reflection entries are registered.
* *
* @author Sebastien Deleuze * @author Sebastien Deleuze
* @author Stephane Nicoll
* @since 6.0 * @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 @Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) { public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
if (ClassUtils.isPresent(SCHEDULER_FACTORY_CLASS_NAME, classLoader)) { if (!ClassUtils.isPresent(SCHEDULER_FACTORY_CLASS_NAME, classLoader)) {
hints.reflection().registerType(TypeReference.of(SCHEDULER_FACTORY_CLASS_NAME), return;
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));
} }
Consumer<Builder> 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);
} }
} }

View File

@ -121,7 +121,7 @@ class InstrumentedMethodTests {
this.stringGetConstructor = RecordedInvocation.of(InstrumentedMethod.CLASS_GETCONSTRUCTOR) this.stringGetConstructor = RecordedInvocation.of(InstrumentedMethod.CLASS_GETCONSTRUCTOR)
.onInstance(String.class).withArgument(new Class[0]).returnValue(String.class.getConstructor()).build(); .onInstance(String.class).withArgument(new Class[0]).returnValue(String.class.getConstructor()).build();
this.stringGetDeclaredConstructor = RecordedInvocation.of(InstrumentedMethod.CLASS_GETDECLAREDCONSTRUCTOR) 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(); .returnValue(String.class.getDeclaredConstructor(byte[].class, byte.class)).build();
} }
@ -201,15 +201,15 @@ class InstrumentedMethodTests {
@Test @Test
void classGetDeclaredConstructorShouldMatchInstrospectConstructorHint() { void classGetDeclaredConstructorShouldMatchInstrospectConstructorHint() {
List<TypeReference> parameterTypes = List.of(TypeReference.of(byte[].class), TypeReference.of(byte.class)); hints.reflection().registerType(String.class, typeHint -> typeHint.withConstructor(TypeReference.listOf(byte[].class, byte.class),
hints.reflection().registerType(String.class, typeHint -> typeHint.withConstructor(parameterTypes, constructorHint -> constructorHint.setModes(ExecutableMode.INTROSPECT))); constructorHint -> constructorHint.setModes(ExecutableMode.INTROSPECT)));
assertThatInvocationMatches(InstrumentedMethod.CLASS_GETDECLAREDCONSTRUCTOR, this.stringGetDeclaredConstructor); assertThatInvocationMatches(InstrumentedMethod.CLASS_GETDECLAREDCONSTRUCTOR, this.stringGetDeclaredConstructor);
} }
@Test @Test
void classGetDeclaredConstructorShouldMatchInvokeConstructorHint() { void classGetDeclaredConstructorShouldMatchInvokeConstructorHint() {
List<TypeReference> parameterTypes = List.of(TypeReference.of(byte[].class), TypeReference.of(byte.class)); hints.reflection().registerType(String.class, typeHint -> typeHint.withConstructor(TypeReference.listOf(byte[].class, byte.class),
hints.reflection().registerType(String.class, typeHint -> typeHint.withConstructor(parameterTypes, constructorHint -> constructorHint.setModes(ExecutableMode.INVOKE))); constructorHint -> constructorHint.setModes(ExecutableMode.INVOKE)));
assertThatInvocationMatches(InstrumentedMethod.CLASS_GETDECLAREDCONSTRUCTOR, this.stringGetDeclaredConstructor); assertThatInvocationMatches(InstrumentedMethod.CLASS_GETDECLAREDCONSTRUCTOR, this.stringGetDeclaredConstructor);
} }
@ -265,33 +265,33 @@ class InstrumentedMethodTests {
.onInstance(String.class).withArguments("toString", new Class[0]) .onInstance(String.class).withArguments("toString", new Class[0])
.returnValue(String.class.getMethod("toString")).build(); .returnValue(String.class.getMethod("toString")).build();
this.stringGetScaleMethod = RecordedInvocation.of(InstrumentedMethod.CLASS_GETDECLAREDMETHOD) 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(); .returnValue(String.class.getDeclaredMethod("scale", int.class, float.class)).build();
} }
@Test @Test
void classGetDeclaredMethodShouldMatchIntrospectDeclaredMethodsHint() throws NoSuchMethodException { void classGetDeclaredMethodShouldMatchIntrospectDeclaredMethodsHint() {
hints.reflection().registerType(String.class, typeHint -> typeHint.withMembers(MemberCategory.INTROSPECT_DECLARED_METHODS)); hints.reflection().registerType(String.class, typeHint -> typeHint.withMembers(MemberCategory.INTROSPECT_DECLARED_METHODS));
assertThatInvocationMatches(InstrumentedMethod.CLASS_GETDECLAREDMETHOD, this.stringGetScaleMethod); assertThatInvocationMatches(InstrumentedMethod.CLASS_GETDECLAREDMETHOD, this.stringGetScaleMethod);
} }
@Test @Test
void classGetDeclaredMethodShouldNotMatchIntrospectPublicMethodsHint() throws NoSuchMethodException { void classGetDeclaredMethodShouldNotMatchIntrospectPublicMethodsHint() {
hints.reflection().registerType(String.class, typeHint -> typeHint.withMembers(MemberCategory.INTROSPECT_PUBLIC_METHODS)); hints.reflection().registerType(String.class, typeHint -> typeHint.withMembers(MemberCategory.INTROSPECT_PUBLIC_METHODS));
assertThatInvocationDoesNotMatch(InstrumentedMethod.CLASS_GETDECLAREDMETHOD, this.stringGetScaleMethod); assertThatInvocationDoesNotMatch(InstrumentedMethod.CLASS_GETDECLAREDMETHOD, this.stringGetScaleMethod);
} }
@Test @Test
void classGetDeclaredMethodShouldMatchIntrospectMethodHint() throws NoSuchMethodException { void classGetDeclaredMethodShouldMatchIntrospectMethodHint() {
List<TypeReference> parameterTypes = List.of(TypeReference.of(int.class), TypeReference.of(float.class)); List<TypeReference> parameterTypes = TypeReference.listOf(int.class, float.class);
hints.reflection().registerType(String.class, typeHint -> hints.reflection().registerType(String.class, typeHint ->
typeHint.withMethod("scale", parameterTypes, methodHint -> methodHint.withMode(ExecutableMode.INTROSPECT))); typeHint.withMethod("scale", parameterTypes, methodHint -> methodHint.withMode(ExecutableMode.INTROSPECT)));
assertThatInvocationMatches(InstrumentedMethod.CLASS_GETDECLAREDMETHOD, this.stringGetScaleMethod); assertThatInvocationMatches(InstrumentedMethod.CLASS_GETDECLAREDMETHOD, this.stringGetScaleMethod);
} }
@Test @Test
void classGetDeclaredMethodShouldMatchInvokeMethodHint() throws NoSuchMethodException { void classGetDeclaredMethodShouldMatchInvokeMethodHint() {
List<TypeReference> parameterTypes = List.of(TypeReference.of(int.class), TypeReference.of(float.class)); List<TypeReference> parameterTypes = TypeReference.listOf(int.class, float.class);
hints.reflection().registerType(String.class, typeHint -> hints.reflection().registerType(String.class, typeHint ->
typeHint.withMethod("scale", parameterTypes, methodHint -> methodHint.withMode(ExecutableMode.INVOKE))); typeHint.withMethod("scale", parameterTypes, methodHint -> methodHint.withMode(ExecutableMode.INVOKE)));
assertThatInvocationMatches(InstrumentedMethod.CLASS_GETDECLAREDMETHOD, this.stringGetScaleMethod); assertThatInvocationMatches(InstrumentedMethod.CLASS_GETDECLAREDMETHOD, this.stringGetScaleMethod);
@ -383,7 +383,7 @@ class InstrumentedMethodTests {
} }
@Test @Test
void classGetMethodShouldMatchInvokeMethodHint() throws Exception { void classGetMethodShouldMatchInvokeMethodHint() {
hints.reflection().registerType(String.class, typeHint -> hints.reflection().registerType(String.class, typeHint ->
typeHint.withMethod("toString", Collections.emptyList(), methodHint -> methodHint.setModes(ExecutableMode.INVOKE))); typeHint.withMethod("toString", Collections.emptyList(), methodHint -> methodHint.setModes(ExecutableMode.INVOKE)));
assertThatInvocationMatches(InstrumentedMethod.CLASS_GETMETHOD, this.stringGetToStringMethod); assertThatInvocationMatches(InstrumentedMethod.CLASS_GETMETHOD, this.stringGetToStringMethod);
@ -410,9 +410,9 @@ class InstrumentedMethodTests {
@Test @Test
void methodInvokeShouldMatchInvokeHintOnMethod() throws NoSuchMethodException { void methodInvokeShouldMatchInvokeHintOnMethod() throws NoSuchMethodException {
RecordedInvocation invocation = RecordedInvocation.of(InstrumentedMethod.METHOD_INVOKE) 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", 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); assertThatInvocationMatches(InstrumentedMethod.METHOD_INVOKE, invocation);
} }
@ -600,8 +600,8 @@ class InstrumentedMethodTests {
@BeforeEach @BeforeEach
void setup() { void setup() {
this.newProxyInstance = RecordedInvocation.of(InstrumentedMethod.PROXY_NEWPROXYINSTANCE) this.newProxyInstance = RecordedInvocation.of(InstrumentedMethod.PROXY_NEWPROXYINSTANCE)
.withArguments(ClassLoader.getSystemClassLoader(), new Class[] {AutoCloseable.class, Comparator.class}, 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)) .returnValue(Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[] { AutoCloseable.class, Comparator.class }, (proxy, method, args) -> null))
.build(); .build();
} }

View File

@ -16,6 +16,9 @@
package org.springframework.aot.hint; package org.springframework.aot.hint;
import java.util.Arrays;
import java.util.List;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
/** /**
@ -81,4 +84,14 @@ public interface TypeReference {
return SimpleTypeReference.of(className); 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<TypeReference> listOf(Class<?>... types) {
return Arrays.stream(types).map(TypeReference::of).toList();
}
} }

View File

@ -19,7 +19,6 @@ package org.springframework.aot.hint;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.stream.Stream;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -109,8 +108,8 @@ class ReflectionHintsTests {
@Test @Test
void registerTypesApplyTheSameHints() { void registerTypesApplyTheSameHints() {
this.reflectionHints.registerTypes(Stream.of(Integer.class, String.class, Double.class) this.reflectionHints.registerTypes(TypeReference.listOf(Integer.class, String.class, Double.class),
.map(TypeReference::of).toList(), hint -> hint.withMembers(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS)); hint -> hint.withMembers(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS));
assertThat(this.reflectionHints.typeHints()) assertThat(this.reflectionHints.typeHints())
.anySatisfy( .anySatisfy(
typeWithMemberCategories(Integer.class, MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS)) typeWithMemberCategories(Integer.class, MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS))

View File

@ -82,7 +82,7 @@ class TypeHintTests {
@Test @Test
void createWithConstructor() { void createWithConstructor() {
List<TypeReference> parameterTypes = List.of(TypeReference.of(byte[].class), TypeReference.of(int.class)); List<TypeReference> parameterTypes = TypeReference.listOf(byte[].class, int.class);
TypeHint hint = TypeHint.of(TypeReference.of(String.class)).withConstructor(parameterTypes, TypeHint hint = TypeHint.of(TypeReference.of(String.class)).withConstructor(parameterTypes,
constructorHint -> constructorHint.withMode(ExecutableMode.INVOKE)).build(); constructorHint -> constructorHint.withMode(ExecutableMode.INVOKE)).build();
assertThat(hint.constructors()).singleElement().satisfies(constructorHint -> { assertThat(hint.constructors()).singleElement().satisfies(constructorHint -> {
@ -93,7 +93,7 @@ class TypeHintTests {
@Test @Test
void createConstructorReuseBuilder() { void createConstructorReuseBuilder() {
List<TypeReference> parameterTypes = List.of(TypeReference.of(byte[].class), TypeReference.of(int.class)); List<TypeReference> parameterTypes = TypeReference.listOf(byte[].class, int.class);
Builder builder = TypeHint.of(TypeReference.of(String.class)).withConstructor(parameterTypes, Builder builder = TypeHint.of(TypeReference.of(String.class)).withConstructor(parameterTypes,
constructorHint -> constructorHint.withMode(ExecutableMode.INVOKE)); constructorHint -> constructorHint.withMode(ExecutableMode.INVOKE));
TypeHint hint = builder.withConstructor(parameterTypes, constructorHint -> TypeHint hint = builder.withConstructor(parameterTypes, constructorHint ->
@ -118,7 +118,7 @@ class TypeHintTests {
@Test @Test
void createWithMethodReuseBuilder() { void createWithMethodReuseBuilder() {
List<TypeReference> parameterTypes = List.of(TypeReference.of(char[].class)); List<TypeReference> parameterTypes = TypeReference.listOf(char[].class);
Builder builder = TypeHint.of(TypeReference.of(String.class)).withMethod("valueOf", parameterTypes, Builder builder = TypeHint.of(TypeReference.of(String.class)).withMethod("valueOf", parameterTypes,
methodHint -> methodHint.withMode(ExecutableMode.INVOKE)); methodHint -> methodHint.withMode(ExecutableMode.INVOKE));
TypeHint hint = builder.withMethod("valueOf", parameterTypes, TypeHint hint = builder.withMethod("valueOf", parameterTypes,

View File

@ -19,7 +19,6 @@ package org.springframework.aot.hint.predicate;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.util.Collections; import java.util.Collections;
import java.util.List;
import java.util.function.Predicate; import java.util.function.Predicate;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
@ -66,41 +65,44 @@ class ReflectionHintsPredicatesTests {
@Test @Test
void reflectionOnClassShouldMatchIntrospection() { void reflectionOnClassShouldMatchIntrospection() {
runtimeHints.reflection().registerType(SampleClass.class, builder -> { runtimeHints.reflection().registerType(SampleClass.class, builder -> {});
});
assertPredicateMatches(reflection.onType(SampleClass.class)); assertPredicateMatches(reflection.onType(SampleClass.class));
} }
@Test @Test
void reflectionOnTypeReferenceShouldMatchIntrospection() { void reflectionOnTypeReferenceShouldMatchIntrospection() {
runtimeHints.reflection().registerType(SampleClass.class, builder -> { runtimeHints.reflection().registerType(SampleClass.class, builder -> {});
});
assertPredicateMatches(reflection.onType(TypeReference.of(SampleClass.class))); assertPredicateMatches(reflection.onType(TypeReference.of(SampleClass.class)));
} }
@Test @Test
void reflectionOnDifferentClassShouldNotMatchIntrospection() { void reflectionOnDifferentClassShouldNotMatchIntrospection() {
runtimeHints.reflection().registerType(Integer.class, builder -> { runtimeHints.reflection().registerType(Integer.class, builder -> {});
});
assertPredicateDoesNotMatch(reflection.onType(TypeReference.of(SampleClass.class))); assertPredicateDoesNotMatch(reflection.onType(TypeReference.of(SampleClass.class)));
} }
@Test @Test
void typeWithMemberCategoryFailsWithNullCategory() { void typeWithMemberCategoryFailsWithNullCategory() {
runtimeHints.reflection().registerType(SampleClass.class, builder -> builder.withMembers(MemberCategory.INTROSPECT_PUBLIC_METHODS)); runtimeHints.reflection().registerType(SampleClass.class, builder ->
assertThatIllegalArgumentException().isThrownBy(() -> reflection.onType(SampleClass.class).withMemberCategory(null)); builder.withMembers(MemberCategory.INTROSPECT_PUBLIC_METHODS));
assertThatIllegalArgumentException().isThrownBy(() ->
reflection.onType(SampleClass.class).withMemberCategory(null));
} }
@Test @Test
void typeWithMemberCategoryMatchesCategory() { void typeWithMemberCategoryMatchesCategory() {
runtimeHints.reflection().registerType(SampleClass.class, builder -> builder.withMembers(MemberCategory.INTROSPECT_PUBLIC_METHODS)); runtimeHints.reflection().registerType(SampleClass.class,
assertPredicateMatches(reflection.onType(SampleClass.class).withMemberCategory(MemberCategory.INTROSPECT_PUBLIC_METHODS)); builder -> builder.withMembers(MemberCategory.INTROSPECT_PUBLIC_METHODS));
assertPredicateMatches(reflection.onType(SampleClass.class)
.withMemberCategory(MemberCategory.INTROSPECT_PUBLIC_METHODS));
} }
@Test @Test
void typeWithMemberCategoryDoesNotMatchOtherCategory() { void typeWithMemberCategoryDoesNotMatchOtherCategory() {
runtimeHints.reflection().registerType(SampleClass.class, builder -> builder.withMembers(MemberCategory.INTROSPECT_PUBLIC_METHODS)); runtimeHints.reflection().registerType(SampleClass.class,
assertPredicateDoesNotMatch(reflection.onType(SampleClass.class).withMemberCategory(MemberCategory.INVOKE_PUBLIC_METHODS)); builder -> builder.withMembers(MemberCategory.INTROSPECT_PUBLIC_METHODS));
assertPredicateDoesNotMatch(reflection.onType(SampleClass.class)
.withMemberCategory(MemberCategory.INVOKE_PUBLIC_METHODS));
} }
@Test @Test
@ -120,20 +122,26 @@ class ReflectionHintsPredicatesTests {
@Test @Test
void typeWithAnyMemberCategoryFailsWithNullCategories() { void typeWithAnyMemberCategoryFailsWithNullCategories() {
runtimeHints.reflection().registerType(SampleClass.class, builder -> builder.withMembers(MemberCategory.INTROSPECT_PUBLIC_METHODS)); runtimeHints.reflection().registerType(SampleClass.class, builder ->
assertThatIllegalArgumentException().isThrownBy(() -> reflection.onType(SampleClass.class).withAnyMemberCategory(new MemberCategory[0])); builder.withMembers(MemberCategory.INTROSPECT_PUBLIC_METHODS));
assertThatIllegalArgumentException().isThrownBy(() ->
reflection.onType(SampleClass.class).withAnyMemberCategory(new MemberCategory[0]));
} }
@Test @Test
void typeWithAnyMemberCategoryMatchesCategory() { void typeWithAnyMemberCategoryMatchesCategory() {
runtimeHints.reflection().registerType(SampleClass.class, builder -> builder.withMembers(MemberCategory.INTROSPECT_PUBLIC_METHODS, MemberCategory.INVOKE_PUBLIC_METHODS)); runtimeHints.reflection().registerType(SampleClass.class,
assertPredicateMatches(reflection.onType(SampleClass.class).withAnyMemberCategory(MemberCategory.INTROSPECT_PUBLIC_METHODS)); builder -> builder.withMembers(MemberCategory.INTROSPECT_PUBLIC_METHODS, MemberCategory.INVOKE_PUBLIC_METHODS));
assertPredicateMatches(reflection.onType(SampleClass.class)
.withAnyMemberCategory(MemberCategory.INTROSPECT_PUBLIC_METHODS));
} }
@Test @Test
void typeWithAnyMemberCategoryDoesNotMatchOtherCategory() { void typeWithAnyMemberCategoryDoesNotMatchOtherCategory() {
runtimeHints.reflection().registerType(SampleClass.class, builder -> builder.withMembers(MemberCategory.INTROSPECT_PUBLIC_METHODS, MemberCategory.INVOKE_PUBLIC_METHODS)); runtimeHints.reflection().registerType(SampleClass.class,
assertPredicateDoesNotMatch(reflection.onType(SampleClass.class).withAnyMemberCategory(MemberCategory.INVOKE_DECLARED_METHODS)); 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 @Test
void constructorIntrospectionMatchesConstructorHint() { 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()); assertPredicateMatches(reflection.onConstructor(publicConstructor).introspect());
} }
@Test @Test
void constructorIntrospectionMatchesIntrospectPublicConstructors() { 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()); assertPredicateMatches(reflection.onConstructor(publicConstructor).introspect());
} }
@Test @Test
void constructorIntrospectionMatchesInvokePublicConstructors() { 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()); assertPredicateMatches(reflection.onConstructor(publicConstructor).introspect());
} }
@Test @Test
void constructorIntrospectionMatchesIntrospectDeclaredConstructors() { 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()); assertPredicateMatches(reflection.onConstructor(publicConstructor).introspect());
} }
@Test @Test
void constructorIntrospectionMatchesInvokeDeclaredConstructors() { 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()); assertPredicateMatches(reflection.onConstructor(publicConstructor).introspect());
} }
@Test @Test
void constructorInvocationDoesNotMatchConstructorHint() { 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()); assertPredicateDoesNotMatch(reflection.onConstructor(publicConstructor).invoke());
} }
@Test @Test
void constructorInvocationMatchesConstructorInvocationHint() { 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()); assertPredicateMatches(reflection.onConstructor(publicConstructor).invoke());
} }
@Test @Test
void constructorInvocationDoesNotMatchIntrospectPublicConstructors() { 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()); assertPredicateDoesNotMatch(reflection.onConstructor(publicConstructor).invoke());
} }
@Test @Test
void constructorInvocationMatchesInvokePublicConstructors() { 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()); assertPredicateMatches(reflection.onConstructor(publicConstructor).invoke());
} }
@Test @Test
void constructorInvocationDoesNotMatchIntrospectDeclaredConstructors() { 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()); assertPredicateDoesNotMatch(reflection.onConstructor(publicConstructor).invoke());
} }
@Test @Test
void constructorInvocationMatchesInvokeDeclaredConstructors() { 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()); assertPredicateMatches(reflection.onConstructor(publicConstructor).invoke());
} }
@Test @Test
void privateConstructorIntrospectionMatchesConstructorHint() { void privateConstructorIntrospectionMatchesConstructorHint() {
List<TypeReference> parameterTypes = Collections.singletonList(TypeReference.of(String.class)); runtimeHints.reflection().registerType(SampleClass.class, typeHint ->
runtimeHints.reflection().registerType(SampleClass.class, typeHint -> typeHint.withConstructor(parameterTypes, constructorHint -> { typeHint.withConstructor(TypeReference.listOf(String.class), constructorHint -> {}));
}));
assertPredicateMatches(reflection.onConstructor(privateConstructor).introspect()); assertPredicateMatches(reflection.onConstructor(privateConstructor).introspect());
} }
@Test @Test
void privateConstructorIntrospectionDoesNotMatchIntrospectPublicConstructors() { 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()); assertPredicateDoesNotMatch(reflection.onConstructor(privateConstructor).introspect());
} }
@Test @Test
void privateConstructorIntrospectionDoesNotMatchInvokePublicConstructors() { 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()); assertPredicateDoesNotMatch(reflection.onConstructor(privateConstructor).introspect());
} }
@Test @Test
void privateConstructorIntrospectionMatchesIntrospectDeclaredConstructors() { 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()); assertPredicateMatches(reflection.onConstructor(privateConstructor).introspect());
} }
@Test @Test
void privateConstructorIntrospectionMatchesInvokeDeclaredConstructors() { 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()); assertPredicateMatches(reflection.onConstructor(privateConstructor).introspect());
} }
@Test @Test
void privateConstructorInvocationDoesNotMatchConstructorHint() { void privateConstructorInvocationDoesNotMatchConstructorHint() {
List<TypeReference> parameterTypes = Collections.singletonList(TypeReference.of(String.class)); runtimeHints.reflection().registerType(SampleClass.class, typeHint ->
runtimeHints.reflection().registerType(SampleClass.class, typeHint -> typeHint.withConstructor(parameterTypes, constructorHint -> { typeHint.withConstructor(TypeReference.listOf(String.class), constructorHint -> {}));
}));
assertPredicateDoesNotMatch(reflection.onConstructor(privateConstructor).invoke()); assertPredicateDoesNotMatch(reflection.onConstructor(privateConstructor).invoke());
} }
@Test @Test
void privateConstructorInvocationMatchesConstructorInvocationHint() { void privateConstructorInvocationMatchesConstructorInvocationHint() {
List<TypeReference> parameterTypes = Collections.singletonList(TypeReference.of(String.class)); runtimeHints.reflection().registerType(SampleClass.class, typeHint ->
runtimeHints.reflection().registerType(SampleClass.class, typeHint -> typeHint.withConstructor(parameterTypes, constructorHint -> constructorHint.withMode(ExecutableMode.INVOKE))); typeHint.withConstructor(TypeReference.listOf(String.class),
constructorHint -> constructorHint.withMode(ExecutableMode.INVOKE)));
assertPredicateMatches(reflection.onConstructor(privateConstructor).invoke()); assertPredicateMatches(reflection.onConstructor(privateConstructor).invoke());
} }
@Test @Test
void privateConstructorInvocationDoesNotMatchIntrospectPublicConstructors() { 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()); assertPredicateDoesNotMatch(reflection.onConstructor(privateConstructor).invoke());
} }
@Test @Test
void privateConstructorInvocationDoesNotMatchInvokePublicConstructors() { 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()); assertPredicateDoesNotMatch(reflection.onConstructor(privateConstructor).invoke());
} }
@Test @Test
void privateConstructorInvocationDoesNotMatchIntrospectDeclaredConstructors() { 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()); assertPredicateDoesNotMatch(reflection.onConstructor(privateConstructor).invoke());
} }
@Test @Test
void privateConstructorInvocationMatchesInvokeDeclaredConstructors() { 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()); assertPredicateMatches(reflection.onConstructor(privateConstructor).invoke());
} }
@ -460,7 +485,7 @@ class ReflectionHintsPredicatesTests {
@Test @Test
void fieldWriteReflectionMatchesFieldHintWithWrite() { void fieldWriteReflectionMatchesFieldHintWithWrite() {
runtimeHints.reflection().registerType(SampleClass.class, typeHint -> 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()); assertPredicateMatches(reflection.onField(SampleClass.class, "publicField").allowWrite());
} }

View File

@ -111,9 +111,9 @@ public class FileNativeConfigurationWriterTests {
fieldBuilder.allowWrite(true); fieldBuilder.allowWrite(true);
fieldBuilder.allowUnsafeAccess(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)) 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 -> .withMethod("getDefaultCharset", Collections.emptyList(), constructorHint ->
constructorHint.withMode(ExecutableMode.INTROSPECT)); constructorHint.withMode(ExecutableMode.INTROSPECT));
}); });

View File

@ -63,7 +63,7 @@ public class ReflectionHintsWriterTests {
fieldBuilder.allowWrite(true); fieldBuilder.allowWrite(true);
fieldBuilder.allowUnsafeAccess(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)) constructorHint.withMode(ExecutableMode.INTROSPECT))
.withMethod("setDefaultCharset", List.of(TypeReference.of(Charset.class)), ctorBuilder -> {}) .withMethod("setDefaultCharset", List.of(TypeReference.of(Charset.class)), ctorBuilder -> {})
.withMethod("getDefaultCharset", Collections.emptyList(), constructorHint -> .withMethod("getDefaultCharset", Collections.emptyList(), constructorHint ->
@ -119,8 +119,8 @@ public class ReflectionHintsWriterTests {
@Test @Test
void queriedMethods() throws JSONException { void queriedMethods() throws JSONException {
ReflectionHints hints = new ReflectionHints(); ReflectionHints hints = new ReflectionHints();
hints.registerType(Integer.class, builder -> builder.withMethod("parseInt", List.of(TypeReference.of(String.class)), hints.registerType(Integer.class, builder -> builder.withMethod("parseInt",
b -> b.withMode(ExecutableMode.INTROSPECT))); TypeReference.listOf(String.class), b -> b.withMode(ExecutableMode.INTROSPECT)));
assertEquals(""" assertEquals("""
[ [
@ -140,8 +140,8 @@ public class ReflectionHintsWriterTests {
@Test @Test
void methods() throws JSONException { void methods() throws JSONException {
ReflectionHints hints = new ReflectionHints(); ReflectionHints hints = new ReflectionHints();
hints.registerType(Integer.class, builder -> builder.withMethod("parseInt", List.of(TypeReference.of(String.class)), hints.registerType(Integer.class, builder -> builder.withMethod("parseInt",
b -> b.withMode(ExecutableMode.INVOKE))); TypeReference.listOf(String.class), b -> b.withMode(ExecutableMode.INVOKE)));
assertEquals(""" assertEquals("""
[ [
@ -161,8 +161,8 @@ public class ReflectionHintsWriterTests {
@Test @Test
void methodWithInnerClassParameter() throws JSONException { void methodWithInnerClassParameter() throws JSONException {
ReflectionHints hints = new ReflectionHints(); ReflectionHints hints = new ReflectionHints();
hints.registerType(Integer.class, builder -> builder.withMethod("test", List.of(TypeReference.of(Inner.class)), hints.registerType(Integer.class, builder -> builder.withMethod("test",
b -> b.withMode(ExecutableMode.INVOKE))); TypeReference.listOf(Inner.class), b -> b.withMode(ExecutableMode.INVOKE)));
assertEquals(""" assertEquals("""
[ [
@ -182,10 +182,10 @@ public class ReflectionHintsWriterTests {
@Test @Test
void methodAndQueriedMethods() throws JSONException { void methodAndQueriedMethods() throws JSONException {
ReflectionHints hints = new ReflectionHints(); ReflectionHints hints = new ReflectionHints();
hints.registerType(Integer.class, builder -> builder.withMethod("parseInt", List.of(TypeReference.of(String.class)), hints.registerType(Integer.class, builder -> builder.withMethod("parseInt",
b -> b.withMode(ExecutableMode.INVOKE))); TypeReference.listOf(String.class), b -> b.withMode(ExecutableMode.INVOKE)));
hints.registerType(Integer.class, builder -> builder.withMethod("parseInt", List.of(TypeReference.of(String.class)), hints.registerType(Integer.class, builder -> builder.withMethod("parseInt",
b -> b.withMode(ExecutableMode.INTROSPECT))); TypeReference.listOf(String.class), b -> b.withMode(ExecutableMode.INTROSPECT)));
assertEquals(""" assertEquals("""
[ [

View File

@ -16,8 +16,6 @@
package org.springframework.transaction.annotation; package org.springframework.transaction.annotation;
import java.util.List;
import org.springframework.aot.hint.MemberCategory; import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints; import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar; import org.springframework.aot.hint.RuntimeHintsRegistrar;
@ -38,11 +36,8 @@ class TransactionRuntimeHints implements RuntimeHintsRegistrar {
@Override @Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) { public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
RuntimeHintsUtils.registerSynthesizedAnnotation(hints, Transactional.class); RuntimeHintsUtils.registerSynthesizedAnnotation(hints, Transactional.class);
hints.reflection() hints.reflection().registerTypes(TypeReference.listOf(
.registerTypes(List.of( Isolation.class, Propagation.class, TransactionDefinition.class),
TypeReference.of(Isolation.class), builder -> builder.withMembers(MemberCategory.DECLARED_FIELDS));
TypeReference.of(Propagation.class),
TypeReference.of(TransactionDefinition.class)),
builder -> builder.withMembers(MemberCategory.DECLARED_FIELDS));
} }
} }

View File

@ -16,9 +16,12 @@
package org.springframework.http.codec; package org.springframework.http.codec;
import java.util.function.Consumer;
import org.springframework.aot.hint.MemberCategory; import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints; import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar; import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.TypeHint.Builder;
import org.springframework.aot.hint.TypeReference; import org.springframework.aot.hint.TypeReference;
import org.springframework.http.codec.support.DefaultClientCodecConfigurer; import org.springframework.http.codec.support.DefaultClientCodecConfigurer;
import org.springframework.http.codec.support.DefaultServerCodecConfigurer; import org.springframework.http.codec.support.DefaultServerCodecConfigurer;
@ -29,20 +32,21 @@ import org.springframework.lang.Nullable;
* implementations listed in {@code CodecConfigurer.properties}. * implementations listed in {@code CodecConfigurer.properties}.
* *
* @author Sebastien Deleuze * @author Sebastien Deleuze
* @author Stephane Nicoll
* @since 6.0 * @since 6.0
*/ */
class CodecConfigurerRuntimeHints implements RuntimeHintsRegistrar { class CodecConfigurerRuntimeHints implements RuntimeHintsRegistrar {
private static final Consumer<Builder> CODEC_HINT = type -> type
.onReachableType(TypeReference.of(CodecConfigurerFactory.class))
.withMembers(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS);
@Override @Override
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) { public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
hints.resources().registerPattern("org/springframework/http/codec/CodecConfigurer.properties"); hints.resources().registerPattern("org/springframework/http/codec/CodecConfigurer.properties");
registerType(hints, DefaultClientCodecConfigurer.class); hints.reflection().registerTypes(TypeReference.listOf(
registerType(hints, DefaultServerCodecConfigurer.class); 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));
}
} }