Update runtime hints predicates after GraalVM changes

As of gh-33847, method and field introspection is included by default
when a type is registered for reflection.
Many methods in ReflectionHintsPredicates are now mostly useless as their
default behavior checks for introspection.

This commit deprecates those methods and promotes instead invocation
variants. During the upgrade, developers should replace it for an
`onType` check if only reflection is required. If they were checking for
invocation, they should use the new 'onXInvocation` method.

Closes gh-34239
This commit is contained in:
Brian Clozel
2025-01-13 15:34:34 +01:00
parent 6be811119e
commit d28c0396c9
24 changed files with 224 additions and 177 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -254,7 +254,7 @@ class BindingReflectionHintsRegistrarTests {
@Test
void registerTypeForSerializationWithRecordWithProperty() {
bindingRegistrar.registerReflectionHints(this.hints.reflection(), SampleRecordWithProperty.class);
assertThat(RuntimeHintsPredicates.reflection().onMethod(SampleRecordWithProperty.class, "getNameProperty"))
assertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(SampleRecordWithProperty.class, "getNameProperty"))
.accepts(this.hints);
}
@@ -267,18 +267,18 @@ class BindingReflectionHintsRegistrarTests {
@Test
void registerTypeForJacksonAnnotations() {
bindingRegistrar.registerReflectionHints(this.hints.reflection(), SampleClassWithJsonProperty.class);
assertThat(RuntimeHintsPredicates.reflection().onField(SampleClassWithJsonProperty.class, "privateField"))
assertThat(RuntimeHintsPredicates.reflection().onFieldInvocation(SampleClassWithJsonProperty.class, "privateField"))
.accepts(this.hints);
assertThat(RuntimeHintsPredicates.reflection().onMethod(SampleClassWithJsonProperty.class, "packagePrivateMethod").invoke())
assertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(SampleClassWithJsonProperty.class, "packagePrivateMethod"))
.accepts(this.hints);
}
@Test
void registerTypeForInheritedJacksonAnnotations() {
bindingRegistrar.registerReflectionHints(this.hints.reflection(), SampleClassWithInheritedJsonProperty.class);
assertThat(RuntimeHintsPredicates.reflection().onField(SampleClassWithJsonProperty.class, "privateField"))
assertThat(RuntimeHintsPredicates.reflection().onFieldInvocation(SampleClassWithJsonProperty.class, "privateField"))
.accepts(this.hints);
assertThat(RuntimeHintsPredicates.reflection().onMethod(SampleClassWithJsonProperty.class, "packagePrivateMethod").invoke())
assertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(SampleClassWithJsonProperty.class, "packagePrivateMethod"))
.accepts(this.hints);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -152,7 +152,7 @@ class ReflectiveRuntimeHintsRegistrarTests {
void shouldInvokeCustomProcessor() {
process(SampleCustomProcessor.class);
assertThat(RuntimeHintsPredicates.reflection()
.onMethod(SampleCustomProcessor.class, "managed")).accepts(this.runtimeHints);
.onMethodInvocation(SampleCustomProcessor.class, "managed")).accepts(this.runtimeHints);
assertThat(RuntimeHintsPredicates.reflection().onType(String.class)
.withMemberCategory(MemberCategory.INVOKE_DECLARED_METHODS)).accepts(this.runtimeHints);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -41,7 +41,7 @@ class RegisterReflectionForBindingProcessorTests {
processor.registerReflectionHints(hints.reflection(), ClassLevelAnnotatedBean.class);
assertThat(RuntimeHintsPredicates.reflection().onType(SampleClassWithGetter.class)).accepts(hints);
assertThat(RuntimeHintsPredicates.reflection().onType(String.class)).accepts(hints);
assertThat(RuntimeHintsPredicates.reflection().onMethod(SampleClassWithGetter.class, "getName")).accepts(hints);
assertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(SampleClassWithGetter.class, "getName")).accepts(hints);
}
@Test
@@ -49,7 +49,7 @@ class RegisterReflectionForBindingProcessorTests {
processor.registerReflectionHints(hints.reflection(), MethodLevelAnnotatedBean.class.getMethod("method"));
assertThat(RuntimeHintsPredicates.reflection().onType(SampleClassWithGetter.class)).accepts(hints);
assertThat(RuntimeHintsPredicates.reflection().onType(String.class)).accepts(hints);
assertThat(RuntimeHintsPredicates.reflection().onMethod(SampleClassWithGetter.class, "getName")).accepts(hints);
assertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(SampleClassWithGetter.class, "getName")).accepts(hints);
}
@Test
@@ -57,7 +57,7 @@ class RegisterReflectionForBindingProcessorTests {
processor.registerReflectionHints(hints.reflection(), SampleClassWithoutAnnotationAttribute.class);
assertThat(RuntimeHintsPredicates.reflection().onType(SampleClassWithoutAnnotationAttribute.class)).accepts(hints);
assertThat(RuntimeHintsPredicates.reflection().onType(String.class)).accepts(hints);
assertThat(RuntimeHintsPredicates.reflection().onMethod(SampleClassWithoutAnnotationAttribute.class, "getName")).accepts(hints);
assertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(SampleClassWithoutAnnotationAttribute.class, "getName")).accepts(hints);
}
@Test

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -156,147 +156,80 @@ class ReflectionHintsPredicatesTests {
@Nested
class ReflectionOnConstructor {
@Test
void constructorIntrospectionDoesNotMatchMissingHint() {
assertPredicateDoesNotMatch(reflection.onConstructor(publicConstructor).introspect());
}
@Test
void constructorIntrospectionMatchesTypeHint() {
runtimeHints.reflection().registerType(SampleClass.class);
assertPredicateMatches(reflection.onConstructor(publicConstructor).introspect());
}
@Test
void constructorIntrospectionMatchesConstructorHint() {
runtimeHints.reflection().registerType(SampleClass.class, typeHint ->
typeHint.withConstructor(Collections.emptyList(), ExecutableMode.INTROSPECT));
assertPredicateMatches(reflection.onConstructor(publicConstructor).introspect());
}
@Test
void constructorIntrospectionMatchesIntrospectPublicConstructors() {
runtimeHints.reflection().registerType(SampleClass.class, MemberCategory.INTROSPECT_PUBLIC_CONSTRUCTORS);
assertPredicateMatches(reflection.onConstructor(publicConstructor).introspect());
}
@Test
void constructorIntrospectionMatchesInvokePublicConstructors() {
runtimeHints.reflection().registerType(SampleClass.class, MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS);
assertPredicateMatches(reflection.onConstructor(publicConstructor).introspect());
}
@Test
void constructorIntrospectionMatchesIntrospectDeclaredConstructors() {
runtimeHints.reflection().registerType(SampleClass.class, MemberCategory.INTROSPECT_DECLARED_CONSTRUCTORS);
assertPredicateMatches(reflection.onConstructor(publicConstructor).introspect());
}
@Test
void constructorIntrospectionMatchesInvokeDeclaredConstructors() {
runtimeHints.reflection().registerType(SampleClass.class, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);
assertPredicateMatches(reflection.onConstructor(publicConstructor).introspect());
}
@Test
void constructorInvocationDoesNotMatchConstructorHint() {
runtimeHints.reflection().registerType(SampleClass.class, typeHint -> typeHint.
withConstructor(Collections.emptyList(), ExecutableMode.INTROSPECT));
assertPredicateDoesNotMatch(reflection.onConstructor(publicConstructor).invoke());
assertPredicateDoesNotMatch(reflection.onConstructorInvocation(publicConstructor));
}
@Test
void constructorInvocationMatchesConstructorInvocationHint() {
runtimeHints.reflection().registerType(SampleClass.class, typeHint -> typeHint.
withConstructor(Collections.emptyList(), ExecutableMode.INVOKE));
assertPredicateMatches(reflection.onConstructor(publicConstructor).invoke());
assertPredicateMatches(reflection.onConstructorInvocation(publicConstructor));
}
@Test
void constructorInvocationDoesNotMatchIntrospectPublicConstructors() {
runtimeHints.reflection().registerType(SampleClass.class, MemberCategory.INTROSPECT_PUBLIC_CONSTRUCTORS);
assertPredicateDoesNotMatch(reflection.onConstructor(publicConstructor).invoke());
assertPredicateDoesNotMatch(reflection.onConstructorInvocation(publicConstructor));
}
@Test
void constructorInvocationMatchesInvokePublicConstructors() {
runtimeHints.reflection().registerType(SampleClass.class, MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS);
assertPredicateMatches(reflection.onConstructor(publicConstructor).invoke());
assertPredicateMatches(reflection.onConstructorInvocation(publicConstructor));
}
@Test
void constructorInvocationDoesNotMatchIntrospectDeclaredConstructors() {
runtimeHints.reflection().registerType(SampleClass.class, MemberCategory.INTROSPECT_DECLARED_CONSTRUCTORS);
assertPredicateDoesNotMatch(reflection.onConstructor(publicConstructor).invoke());
assertPredicateDoesNotMatch(reflection.onConstructorInvocation(publicConstructor));
}
@Test
void constructorInvocationMatchesInvokeDeclaredConstructors() {
runtimeHints.reflection().registerType(SampleClass.class, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);
assertPredicateMatches(reflection.onConstructor(publicConstructor).invoke());
}
@Test
void privateConstructorIntrospectionMatchesTypeHint() {
runtimeHints.reflection().registerType(SampleClass.class);
assertPredicateMatches(reflection.onConstructor(privateConstructor).introspect());
}
@Test
void privateConstructorIntrospectionMatchesConstructorHint() {
runtimeHints.reflection().registerType(SampleClass.class, typeHint ->
typeHint.withConstructor(TypeReference.listOf(String.class), ExecutableMode.INTROSPECT));
assertPredicateMatches(reflection.onConstructor(privateConstructor).introspect());
}
@Test
void privateConstructorIntrospectionMatchesIntrospectDeclaredConstructors() {
runtimeHints.reflection().registerType(SampleClass.class, MemberCategory.INTROSPECT_DECLARED_CONSTRUCTORS);
assertPredicateMatches(reflection.onConstructor(privateConstructor).introspect());
}
@Test
void privateConstructorIntrospectionMatchesInvokeDeclaredConstructors() {
runtimeHints.reflection().registerType(SampleClass.class, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);
assertPredicateMatches(reflection.onConstructor(privateConstructor).introspect());
assertPredicateMatches(reflection.onConstructorInvocation(publicConstructor));
}
@Test
void privateConstructorInvocationDoesNotMatchConstructorHint() {
runtimeHints.reflection().registerType(SampleClass.class, typeHint ->
typeHint.withConstructor(TypeReference.listOf(String.class), ExecutableMode.INTROSPECT));
assertPredicateDoesNotMatch(reflection.onConstructor(privateConstructor).invoke());
assertPredicateDoesNotMatch(reflection.onConstructorInvocation(privateConstructor));
}
@Test
void privateConstructorInvocationMatchesConstructorInvocationHint() {
runtimeHints.reflection().registerType(SampleClass.class, typeHint ->
typeHint.withConstructor(TypeReference.listOf(String.class), ExecutableMode.INVOKE));
assertPredicateMatches(reflection.onConstructor(privateConstructor).invoke());
assertPredicateMatches(reflection.onConstructorInvocation(privateConstructor));
}
@Test
void privateConstructorInvocationDoesNotMatchIntrospectPublicConstructors() {
runtimeHints.reflection().registerType(SampleClass.class, MemberCategory.INTROSPECT_PUBLIC_CONSTRUCTORS);
assertPredicateDoesNotMatch(reflection.onConstructor(privateConstructor).invoke());
assertPredicateDoesNotMatch(reflection.onConstructorInvocation(privateConstructor));
}
@Test
void privateConstructorInvocationDoesNotMatchInvokePublicConstructors() {
runtimeHints.reflection().registerType(SampleClass.class, MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS);
assertPredicateDoesNotMatch(reflection.onConstructor(privateConstructor).invoke());
assertPredicateDoesNotMatch(reflection.onConstructorInvocation(privateConstructor));
}
@Test
void privateConstructorInvocationDoesNotMatchIntrospectDeclaredConstructors() {
runtimeHints.reflection().registerType(SampleClass.class, MemberCategory.INTROSPECT_DECLARED_CONSTRUCTORS);
assertPredicateDoesNotMatch(reflection.onConstructor(privateConstructor).invoke());
assertPredicateDoesNotMatch(reflection.onConstructorInvocation(privateConstructor));
}
@Test
void privateConstructorInvocationMatchesInvokeDeclaredConstructors() {
runtimeHints.reflection().registerType(SampleClass.class, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);
assertPredicateMatches(reflection.onConstructor(privateConstructor).invoke());
assertPredicateMatches(reflection.onConstructorInvocation(privateConstructor));
}
}
@@ -448,7 +381,7 @@ class ReflectionHintsPredicatesTests {
@Test
void shouldFailForUnknownClass() {
assertThatThrownBy(() -> reflection.onField("com.example.DoesNotExist", "missingField"))
assertThatThrownBy(() -> reflection.onFieldInvocation("com.example.DoesNotExist", "missingField"))
.isInstanceOf(ClassNotFoundException.class);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -49,13 +49,13 @@ class ObjectToObjectConverterRuntimeHintsTests {
@Test
void javaSqlDateHasHints() throws NoSuchMethodException {
assertThat(RuntimeHintsPredicates.reflection().onMethod(java.sql.Date.class, "toLocalDate")).accepts(this.hints);
assertThat(RuntimeHintsPredicates.reflection().onMethod(java.sql.Date.class.getMethod("valueOf", LocalDate.class))).accepts(this.hints);
assertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(java.sql.Date.class, "toLocalDate")).accepts(this.hints);
assertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(java.sql.Date.class.getMethod("valueOf", LocalDate.class))).accepts(this.hints);
}
@Test
void uriHasHints() throws NoSuchMethodException {
assertThat(RuntimeHintsPredicates.reflection().onConstructor(URI.class.getConstructor(String.class))).accepts(this.hints);
assertThat(RuntimeHintsPredicates.reflection().onType(URI.class)).accepts(this.hints);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -65,14 +65,14 @@ class BindingReflectionHintsRegistrarKotlinTests {
@Test
fun `Register reflection hints for Kotlin data class`() {
bindingRegistrar.registerReflectionHints(hints.reflection(), SampleDataClass::class.java)
assertThat(RuntimeHintsPredicates.reflection().onMethod(SampleDataClass::class.java, "component1")).accepts(hints)
assertThat(RuntimeHintsPredicates.reflection().onMethod(SampleDataClass::class.java, "copy")).accepts(hints)
assertThat(RuntimeHintsPredicates.reflection().onMethod(SampleDataClass::class.java, "getName")).accepts(hints)
assertThat(RuntimeHintsPredicates.reflection().onMethod(SampleDataClass::class.java, "isNonNullable")).accepts(hints)
assertThat(RuntimeHintsPredicates.reflection().onMethod(SampleDataClass::class.java, "isNullable")).accepts(hints)
assertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(SampleDataClass::class.java, "component1")).accepts(hints)
assertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(SampleDataClass::class.java, "copy")).accepts(hints)
assertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(SampleDataClass::class.java, "getName")).accepts(hints)
assertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(SampleDataClass::class.java, "isNonNullable")).accepts(hints)
assertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(SampleDataClass::class.java, "isNullable")).accepts(hints)
val copyDefault: Method = SampleDataClass::class.java.getMethod("copy\$default", SampleDataClass::class.java,
String::class.java, Boolean::class.javaPrimitiveType, Boolean::class.javaObjectType, Int::class.java, Object::class.java)
assertThat(RuntimeHintsPredicates.reflection().onMethod(copyDefault)).accepts(hints)
assertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(copyDefault)).accepts(hints)
}
@Test