Browse Source

Harmonize hint registration

Previously, a shortcut method for the default ExecutableMode was
provided, but we found out that the shortcut makes it harder to
determine the intent.

This commit harmonizes hints registration for types, methods, and
fields. An ExecutableMode is now mandatory to register a method or
constructor. Previous methods that infer a mode or provided a
customizer of the builder are deprecated.

Closes gh-29135
pull/29136/head
Stephane Nicoll 2 years ago
parent
commit
58a2b79699
  1. 2
      spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java
  2. 2
      spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGenerator.java
  3. 4
      spring-beans/src/main/java/org/springframework/beans/factory/aot/InstanceSupplierCodeGenerator.java
  4. 8
      spring-core-test/src/test/java/org/springframework/aot/agent/InstrumentedMethodTests.java
  5. 2
      spring-core/src/main/java/org/springframework/aot/hint/BindingReflectionHintsRegistrar.java
  6. 56
      spring-core/src/main/java/org/springframework/aot/hint/ReflectionHints.java
  7. 17
      spring-core/src/main/java/org/springframework/aot/hint/TypeHint.java
  8. 5
      spring-core/src/main/java/org/springframework/aot/hint/annotation/SimpleReflectiveProcessor.java
  9. 59
      spring-core/src/test/java/org/springframework/aot/hint/ReflectionHintsTests.java
  10. 90
      spring-core/src/test/java/org/springframework/aot/hint/TypeHintTests.java
  11. 4
      spring-core/src/test/java/org/springframework/aot/hint/predicate/ReflectionHintsPredicatesTests.java
  12. 2
      spring-core/src/test/java/org/springframework/aot/nativex/FileNativeConfigurationWriterTests.java
  13. 2
      spring-core/src/test/java/org/springframework/aot/nativex/ReflectionHintsWriterTests.java
  14. 3
      spring-orm/src/main/java/org/springframework/orm/jpa/support/InjectionCodeGenerator.java

2
spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java

@ -1007,7 +1007,7 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA @@ -1007,7 +1007,7 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
AccessVisibility visibility = AccessVisibility.forMember(method);
if (visibility == AccessVisibility.PRIVATE
|| visibility == AccessVisibility.PROTECTED) {
hints.reflection().registerMethod(method);
hints.reflection().registerMethod(method, ExecutableMode.INVOKE);
code.add(".resolveAndInvoke($L, $L)", REGISTERED_BEAN_PARAMETER,
INSTANCE_PARAMETER);
}

2
spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGenerator.java

@ -145,7 +145,7 @@ class BeanDefinitionPropertiesCodeGenerator { @@ -145,7 +145,7 @@ class BeanDefinitionPropertiesCodeGenerator {
private void addInitDestroyHint(Class<?> beanUserClass, String methodName) {
Method method = ReflectionUtils.findMethod(beanUserClass, methodName);
if (method != null) {
this.hints.reflection().registerMethod(method);
this.hints.reflection().registerMethod(method, ExecutableMode.INVOKE);
}
}

4
spring-beans/src/main/java/org/springframework/beans/factory/aot/InstanceSupplierCodeGenerator.java

@ -147,7 +147,7 @@ class InstanceSupplierCodeGenerator { @@ -147,7 +147,7 @@ class InstanceSupplierCodeGenerator {
Class<?> beanClass, Constructor<?> constructor, boolean dependsOnBean) {
this.generationContext.getRuntimeHints().reflection()
.registerConstructor(constructor);
.registerConstructor(constructor, ExecutableMode.INVOKE);
GeneratedMethod generatedMethod = generateGetInstanceSupplierMethod(method -> {
method.addJavadoc("Get the bean instance supplier for '$L'.", beanName);
method.addModifiers(PRIVATE_STATIC);
@ -240,7 +240,7 @@ class InstanceSupplierCodeGenerator { @@ -240,7 +240,7 @@ class InstanceSupplierCodeGenerator {
Method factoryMethod, Class<?> declaringClass) {
this.generationContext.getRuntimeHints().reflection()
.registerMethod(factoryMethod);
.registerMethod(factoryMethod, ExecutableMode.INVOKE);
GeneratedMethod getInstanceMethod = generateGetInstanceSupplierMethod(method -> {
method.addJavadoc("Get the bean instance supplier for '$L'.", beanName);
method.addModifiers(PRIVATE_STATIC);

8
spring-core-test/src/test/java/org/springframework/aot/agent/InstrumentedMethodTests.java

@ -194,7 +194,7 @@ class InstrumentedMethodTests { @@ -194,7 +194,7 @@ class InstrumentedMethodTests {
@Test
void classGetConstructorsShouldMatchConstructorReflectionHint() throws Exception {
hints.reflection().registerConstructor(String.class.getConstructor());
hints.reflection().registerConstructor(String.class.getConstructor(), ExecutableMode.INVOKE);
assertThatInvocationMatches(InstrumentedMethod.CLASS_GETCONSTRUCTORS, this.stringGetConstructors);
}
@ -250,7 +250,7 @@ class InstrumentedMethodTests { @@ -250,7 +250,7 @@ class InstrumentedMethodTests {
@Test
void classGetDeclaredConstructorsShouldMatchConstructorReflectionHint() throws Exception {
hints.reflection().registerConstructor(String.class.getConstructor());
hints.reflection().registerConstructor(String.class.getConstructor(), ExecutableMode.INVOKE);
assertThatInvocationMatches(InstrumentedMethod.CLASS_GETDECLAREDCONSTRUCTORS, this.stringGetDeclaredConstructors);
}
@ -350,7 +350,7 @@ class InstrumentedMethodTests { @@ -350,7 +350,7 @@ class InstrumentedMethodTests {
@Test
void classGetDeclaredMethodsShouldMatchMethodReflectionHint() throws Exception {
hints.reflection().registerMethod(String.class.getMethod("toString"));
hints.reflection().registerMethod(String.class.getMethod("toString"), ExecutableMode.INVOKE);
assertThatInvocationMatches(InstrumentedMethod.CLASS_GETDECLAREDMETHODS, this.stringGetScaleMethod);
}
@ -392,7 +392,7 @@ class InstrumentedMethodTests { @@ -392,7 +392,7 @@ class InstrumentedMethodTests {
@Test
void classGetMethodsShouldMatchMethodReflectionHint() throws Exception {
hints.reflection().registerMethod(String.class.getMethod("toString"));
hints.reflection().registerMethod(String.class.getMethod("toString"), ExecutableMode.INVOKE);
assertThatInvocationMatches(InstrumentedMethod.CLASS_GETMETHODS, this.stringGetMethods);
}

2
spring-core/src/main/java/org/springframework/aot/hint/BindingReflectionHintsRegistrar.java

@ -145,7 +145,7 @@ public class BindingReflectionHintsRegistrar { @@ -145,7 +145,7 @@ public class BindingReflectionHintsRegistrar {
Class<?> companionClass = ClassUtils.resolveClassName(companionClassName, null);
Method serializerMethod = ClassUtils.getMethodIfAvailable(companionClass, "serializer");
if (serializerMethod != null) {
hints.registerMethod(serializerMethod);
hints.registerMethod(serializerMethod, ExecutableMode.INVOKE);
}
}
}

56
spring-core/src/main/java/org/springframework/aot/hint/ReflectionHints.java

@ -36,6 +36,8 @@ import org.springframework.util.ClassUtils; @@ -36,6 +36,8 @@ import org.springframework.util.ClassUtils;
* Gather the need for reflection at runtime.
*
* @author Stephane Nicoll
* @author Phillip Webb
* @author Andy Wilkinson
* @since 6.0
*/
public class ReflectionHints {
@ -79,6 +81,7 @@ public class ReflectionHints { @@ -79,6 +81,7 @@ public class ReflectionHints {
* @param type the type to customize
* @param typeHint a builder to further customize hints for that type
* @return {@code this}, to facilitate method chaining
* @see #registerType(TypeReference, MemberCategory...)
*/
public ReflectionHints registerType(TypeReference type, Consumer<TypeHint.Builder> typeHint) {
Builder builder = this.types.computeIfAbsent(type, TypeHint.Builder::new);
@ -93,29 +96,30 @@ public class ReflectionHints { @@ -93,29 +96,30 @@ public class ReflectionHints {
* @param memberCategories the member categories to apply
* @return {@code this}, to facilitate method chaining
*/
public ReflectionHints registerType(Class<?> type, MemberCategory... memberCategories) {
return registerType(TypeReference.of(type), memberCategories);
public ReflectionHints registerType(TypeReference type, MemberCategory... memberCategories) {
return registerType(type, TypeHint.builtWith(memberCategories));
}
/**
* Register or customize reflection hints for the specified type
* using the specified {@link MemberCategory MemberCategories}.
* Register or customize reflection hints for the specified type.
* @param type the type to customize
* @param memberCategories the member categories to apply
* @param typeHint a builder to further customize hints for that type
* @return {@code this}, to facilitate method chaining
* @see #registerType(Class, MemberCategory...)
*/
public ReflectionHints registerType(TypeReference type , MemberCategory... memberCategories) {
return registerType(type, TypeHint.builtWith(memberCategories));
public ReflectionHints registerType(Class<?> type, Consumer<TypeHint.Builder> typeHint) {
return registerType(TypeReference.of(type), typeHint);
}
/**
* Register or customize reflection hints for the specified type.
* Register or customize reflection hints for the specified type
* using the specified {@link MemberCategory MemberCategories}.
* @param type the type to customize
* @param typeHint a builder to further customize hints for that type
* @param memberCategories the member categories to apply
* @return {@code this}, to facilitate method chaining
*/
public ReflectionHints registerType(Class<?> type, Consumer<TypeHint.Builder> typeHint) {
return registerType(TypeReference.of(type), typeHint);
public ReflectionHints registerType(Class<?> type, MemberCategory... memberCategories) {
return registerType(TypeReference.of(type), memberCategories);
}
/**
@ -125,6 +129,7 @@ public class ReflectionHints { @@ -125,6 +129,7 @@ public class ReflectionHints {
* @param typeName the type to customize
* @param typeHint a builder to further customize hints for that type
* @return {@code this}, to facilitate method chaining
* @see #registerTypeIfPresent(ClassLoader, String, MemberCategory...)
*/
public ReflectionHints registerTypeIfPresent(@Nullable ClassLoader classLoader,
String typeName, Consumer<TypeHint.Builder> typeHint) {
@ -134,6 +139,19 @@ public class ReflectionHints { @@ -134,6 +139,19 @@ public class ReflectionHints {
return this;
}
/**
* Register or customize reflection hints for the specified type if it
* is available using the specified {@link ClassLoader}.
* @param classLoader the classloader to use to check if the type is present
* @param typeName the type to customize
* @param memberCategories the member categories to apply
* @return {@code this}, to facilitate method chaining
*/
public ReflectionHints registerTypeIfPresent(@Nullable ClassLoader classLoader,
String typeName, MemberCategory... memberCategories) {
return registerTypeIfPresent(classLoader, typeName, TypeHint.builtWith(memberCategories));
}
/**
* Register or customize reflection hints for the types defined by the
* specified list of {@link TypeReference type references}. The specified
@ -162,7 +180,9 @@ public class ReflectionHints { @@ -162,7 +180,9 @@ public class ReflectionHints {
* enabling {@link ExecutableMode#INVOKE}.
* @param constructor the constructor that requires reflection
* @return {@code this}, to facilitate method chaining
* @deprecated in favor of {@link #registerConstructor(Constructor, ExecutableMode)}
*/
@Deprecated
public ReflectionHints registerConstructor(Constructor<?> constructor) {
return registerConstructor(constructor, ExecutableMode.INVOKE);
}
@ -175,7 +195,8 @@ public class ReflectionHints { @@ -175,7 +195,8 @@ public class ReflectionHints {
* @return {@code this}, to facilitate method chaining
*/
public ReflectionHints registerConstructor(Constructor<?> constructor, ExecutableMode mode) {
return registerConstructor(constructor, ExecutableHint.builtWith(mode));
return registerType(TypeReference.of(constructor.getDeclaringClass()),
typeHint -> typeHint.withConstructor(mapParameters(constructor), mode));
}
/**
@ -183,8 +204,10 @@ public class ReflectionHints { @@ -183,8 +204,10 @@ public class ReflectionHints {
* @param constructor the constructor that requires reflection
* @param constructorHint a builder to further customize the hints of this
* constructor
* @return {@code this}, to facilitate method chaining
* @return {@code this}, to facilitate method chaining`
* @deprecated in favor of {@link #registerConstructor(Constructor, ExecutableMode)}
*/
@Deprecated
public ReflectionHints registerConstructor(Constructor<?> constructor, Consumer<ExecutableHint.Builder> constructorHint) {
return registerType(TypeReference.of(constructor.getDeclaringClass()),
typeHint -> typeHint.withConstructor(mapParameters(constructor), constructorHint));
@ -195,7 +218,9 @@ public class ReflectionHints { @@ -195,7 +218,9 @@ public class ReflectionHints {
* enabling {@link ExecutableMode#INVOKE}.
* @param method the method that requires reflection
* @return {@code this}, to facilitate method chaining
* @deprecated in favor of {@link #registerMethod(Method, ExecutableMode)}
*/
@Deprecated
public ReflectionHints registerMethod(Method method) {
return registerMethod(method, ExecutableMode.INVOKE);
}
@ -208,7 +233,8 @@ public class ReflectionHints { @@ -208,7 +233,8 @@ public class ReflectionHints {
* @return {@code this}, to facilitate method chaining
*/
public ReflectionHints registerMethod(Method method, ExecutableMode mode) {
return registerMethod(method, ExecutableHint.builtWith(mode));
return registerType(TypeReference.of(method.getDeclaringClass()),
typeHint -> typeHint.withMethod(method.getName(), mapParameters(method), mode));
}
/**
@ -216,7 +242,9 @@ public class ReflectionHints { @@ -216,7 +242,9 @@ public class ReflectionHints {
* @param method the method that requires reflection
* @param methodHint a builder to further customize the hints of this method
* @return {@code this}, to facilitate method chaining
* @deprecated in favor of {@link #registerMethod(Method, ExecutableMode)}
*/
@Deprecated
public ReflectionHints registerMethod(Method method, Consumer<ExecutableHint.Builder> methodHint) {
return registerType(TypeReference.of(method.getDeclaringClass()),
typeHint -> typeHint.withMethod(method.getName(), mapParameters(method), methodHint));

17
spring-core/src/main/java/org/springframework/aot/hint/TypeHint.java

@ -35,6 +35,8 @@ import org.springframework.util.Assert; @@ -35,6 +35,8 @@ import org.springframework.util.Assert;
* A hint that describes the need for reflection on a type.
*
* @author Stephane Nicoll
* @author Phillip Webb
* @author Andy Wilkinson
* @since 6.0
*/
public final class TypeHint implements ConditionalHint {
@ -199,7 +201,9 @@ public final class TypeHint implements ConditionalHint { @@ -199,7 +201,9 @@ public final class TypeHint implements ConditionalHint {
* parameter types, enabling {@link ExecutableMode#INVOKE}.
* @param parameterTypes the parameter types of the constructor
* @return {@code this}, to facilitate method chaining
* @deprecated in favor of {@link #withConstructor(List, ExecutableMode)}
*/
@Deprecated
public Builder withConstructor(List<TypeReference> parameterTypes) {
return withConstructor(parameterTypes, ExecutableMode.INVOKE);
}
@ -222,8 +226,11 @@ public final class TypeHint implements ConditionalHint { @@ -222,8 +226,11 @@ public final class TypeHint implements ConditionalHint {
* @param constructorHint a builder to further customize the hints of this
* constructor
* @return {@code this}, to facilitate method chaining
* @deprecated in favor of {@link #withConstructor(List, ExecutableMode)}
*/
public Builder withConstructor(List<TypeReference> parameterTypes, Consumer<ExecutableHint.Builder> constructorHint) {
@Deprecated
public Builder withConstructor(List<TypeReference> parameterTypes,
Consumer<ExecutableHint.Builder> constructorHint) {
ExecutableKey key = new ExecutableKey("<init>", parameterTypes);
ExecutableHint.Builder builder = this.constructors.computeIfAbsent(key,
k -> ExecutableHint.ofConstructor(parameterTypes));
@ -237,7 +244,9 @@ public final class TypeHint implements ConditionalHint { @@ -237,7 +244,9 @@ public final class TypeHint implements ConditionalHint {
* @param name the name of the method
* @param parameterTypes the parameter types of the constructor
* @return {@code this}, to facilitate method chaining
* @deprecated in favor of {@link #withMethod(String, List, ExecutableMode)}
*/
@Deprecated
public Builder withMethod(String name, List<TypeReference> parameterTypes) {
return withMethod(name, parameterTypes, ExecutableMode.INVOKE);
}
@ -261,8 +270,11 @@ public final class TypeHint implements ConditionalHint { @@ -261,8 +270,11 @@ public final class TypeHint implements ConditionalHint {
* @param parameterTypes the parameter types of the constructor
* @param methodHint a builder to further customize the hints of this method
* @return {@code this}, to facilitate method chaining
* @deprecated in favor of {@link #withMethod(String, List, ExecutableMode)}
*/
public Builder withMethod(String name, List<TypeReference> parameterTypes, Consumer<ExecutableHint.Builder> methodHint) {
@Deprecated
public Builder withMethod(String name, List<TypeReference> parameterTypes,
Consumer<ExecutableHint.Builder> methodHint) {
ExecutableKey key = new ExecutableKey(name, parameterTypes);
ExecutableHint.Builder builder = this.methods.computeIfAbsent(key,
k -> ExecutableHint.ofMethod(name, parameterTypes));
@ -274,6 +286,7 @@ public final class TypeHint implements ConditionalHint { @@ -274,6 +286,7 @@ public final class TypeHint implements ConditionalHint {
* Adds the specified {@linkplain MemberCategory member categories}.
* @param memberCategories the categories to apply
* @return {@code this}, to facilitate method chaining
* @see TypeHint#builtWith(MemberCategory...)
*/
public Builder withMembers(MemberCategory... memberCategories) {
this.memberCategories.addAll(Arrays.asList(memberCategories));

5
spring-core/src/main/java/org/springframework/aot/hint/annotation/SimpleReflectiveProcessor.java

@ -21,6 +21,7 @@ import java.lang.reflect.Constructor; @@ -21,6 +21,7 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import org.springframework.aot.hint.ExecutableMode;
import org.springframework.aot.hint.ReflectionHints;
/**
@ -64,7 +65,7 @@ public class SimpleReflectiveProcessor implements ReflectiveProcessor { @@ -64,7 +65,7 @@ public class SimpleReflectiveProcessor implements ReflectiveProcessor {
* @param constructor the constructor to process
*/
protected void registerConstructorHint(ReflectionHints hints, Constructor<?> constructor) {
hints.registerConstructor(constructor);
hints.registerConstructor(constructor, ExecutableMode.INVOKE);
}
/**
@ -82,7 +83,7 @@ public class SimpleReflectiveProcessor implements ReflectiveProcessor { @@ -82,7 +83,7 @@ public class SimpleReflectiveProcessor implements ReflectiveProcessor {
* @param method the method to process
*/
protected void registerMethodHint(ReflectionHints hints, Method method) {
hints.registerMethod(method);
hints.registerMethod(method, ExecutableMode.INVOKE);
}
}

59
spring-core/src/test/java/org/springframework/aot/hint/ReflectionHintsTests.java

@ -16,6 +16,7 @@ @@ -16,6 +16,7 @@
package org.springframework.aot.hint;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.function.Consumer;
@ -48,8 +49,7 @@ class ReflectionHintsTests { @@ -48,8 +49,7 @@ class ReflectionHintsTests {
@Test
void registerTypeIfPresentRegistersExistingClass() {
this.reflectionHints.registerTypeIfPresent(null, String.class.getName(),
hint -> hint.withMembers(MemberCategory.DECLARED_FIELDS));
this.reflectionHints.registerTypeIfPresent(null, String.class.getName(), MemberCategory.DECLARED_FIELDS);
assertThat(this.reflectionHints.typeHints()).singleElement().satisfies(
typeWithMemberCategories(String.class, MemberCategory.DECLARED_FIELDS));
}
@ -144,15 +144,6 @@ class ReflectionHintsTests { @@ -144,15 +144,6 @@ class ReflectionHintsTests {
@Test
void registerConstructor() {
this.reflectionHints.registerConstructor(TestType.class.getDeclaredConstructors()[0]);
assertTestTypeConstructorHint(constructorHint -> {
assertThat(constructorHint.getParameterTypes()).isEmpty();
assertThat(constructorHint.getMode()).isEqualTo(ExecutableMode.INVOKE);
});
}
@Test
void registerConstructorWithMode() {
this.reflectionHints.registerConstructor(
TestType.class.getDeclaredConstructors()[0], ExecutableMode.INTROSPECT);
assertTestTypeConstructorHint(constructorHint -> {
@ -162,25 +153,16 @@ class ReflectionHintsTests { @@ -162,25 +153,16 @@ class ReflectionHintsTests {
}
@Test
void registerConstructorWithEmptyCustomizerAppliesConsistentDefault() {
this.reflectionHints.registerConstructor(TestType.class.getDeclaredConstructors()[0],
constructorHint -> {});
void registerConstructorTwiceUpdatesExistingEntry() {
Constructor<?> constructor = TestType.class.getDeclaredConstructors()[0];
this.reflectionHints.registerConstructor(constructor, ExecutableMode.INTROSPECT);
this.reflectionHints.registerConstructor(constructor, ExecutableMode.INVOKE);
assertTestTypeConstructorHint(constructorHint -> {
assertThat(constructorHint.getParameterTypes()).isEmpty();
assertThat(constructorHint.getMode()).isEqualTo(ExecutableMode.INVOKE);
});
}
@Test
void registerConstructorWithCustomizerAppliesCustomization() {
this.reflectionHints.registerConstructor(TestType.class.getDeclaredConstructors()[0],
constructorHint -> constructorHint.withMode(ExecutableMode.INTROSPECT));
assertTestTypeConstructorHint(constructorHint -> {
assertThat(constructorHint.getParameterTypes()).isEmpty();
assertThat(constructorHint.getMode()).isEqualTo(ExecutableMode.INTROSPECT);
});
}
private void assertTestTypeConstructorHint(Consumer<ExecutableHint> constructorHint) {
assertThat(this.reflectionHints.typeHints()).singleElement().satisfies(typeHint -> {
assertThat(typeHint.getMemberCategories()).isEmpty();
@ -194,18 +176,6 @@ class ReflectionHintsTests { @@ -194,18 +176,6 @@ class ReflectionHintsTests {
@Test
void registerMethod() {
Method method = ReflectionUtils.findMethod(TestType.class, "setName", String.class);
assertThat(method).isNotNull();
this.reflectionHints.registerMethod(method);
assertTestTypeMethodHints(methodHint -> {
assertThat(methodHint.getName()).isEqualTo("setName");
assertThat(methodHint.getParameterTypes()).containsOnly(TypeReference.of(String.class));
assertThat(methodHint.getMode()).isEqualTo(ExecutableMode.INVOKE);
});
}
@Test
void registerMethodWithMode() {
Method method = ReflectionUtils.findMethod(TestType.class, "setName", String.class);
assertThat(method).isNotNull();
this.reflectionHints.registerMethod(method, ExecutableMode.INTROSPECT);
@ -217,10 +187,11 @@ class ReflectionHintsTests { @@ -217,10 +187,11 @@ class ReflectionHintsTests {
}
@Test
void registerMethodWithEmptyCustomizerAppliesConsistentDefault() {
void registerMethodTwiceUpdatesExistingEntry() {
Method method = ReflectionUtils.findMethod(TestType.class, "setName", String.class);
assertThat(method).isNotNull();
this.reflectionHints.registerMethod(method, methodHint -> {});
this.reflectionHints.registerMethod(method, ExecutableMode.INTROSPECT);
this.reflectionHints.registerMethod(method, ExecutableMode.INVOKE);
assertTestTypeMethodHints(methodHint -> {
assertThat(methodHint.getName()).isEqualTo("setName");
assertThat(methodHint.getParameterTypes()).containsOnly(TypeReference.of(String.class));
@ -228,18 +199,6 @@ class ReflectionHintsTests { @@ -228,18 +199,6 @@ class ReflectionHintsTests {
});
}
@Test
void registerMethodWithCustomizerAppliesCustomization() {
Method method = ReflectionUtils.findMethod(TestType.class, "setName", String.class);
assertThat(method).isNotNull();
this.reflectionHints.registerMethod(method, methodHint -> methodHint.withMode(ExecutableMode.INTROSPECT));
assertTestTypeMethodHints(methodHint -> {
assertThat(methodHint.getName()).isEqualTo("setName");
assertThat(methodHint.getParameterTypes()).containsOnly(TypeReference.of(String.class));
assertThat(methodHint.getMode()).isEqualTo(ExecutableMode.INTROSPECT);
});
}
private void assertTestTypeMethodHints(Consumer<ExecutableHint> methodHint) {
assertThat(this.reflectionHints.typeHints()).singleElement().satisfies(typeHint -> {
assertThat(typeHint.getType().getCanonicalName()).isEqualTo(TestType.class.getCanonicalName());

90
spring-core/src/test/java/org/springframework/aot/hint/TypeHintTests.java

@ -70,16 +70,6 @@ class TypeHintTests { @@ -70,16 +70,6 @@ class TypeHintTests {
@Test
void createWithConstructor() {
List<TypeReference> parameterTypes = TypeReference.listOf(byte[].class, int.class);
assertConstructorHint(TypeHint.of(TypeReference.of(String.class))
.withConstructor(parameterTypes), constructorHint -> {
assertThat(constructorHint.getParameterTypes()).containsOnlyOnceElementsOf(parameterTypes);
assertThat(constructorHint.getMode()).isEqualTo(ExecutableMode.INVOKE);
});
}
@Test
void createWithConstructorAndMode() {
List<TypeReference> parameterTypes = TypeReference.listOf(byte[].class, int.class);
assertConstructorHint(TypeHint.of(TypeReference.of(String.class))
.withConstructor(parameterTypes, ExecutableMode.INTROSPECT), constructorHint -> {
@ -89,45 +79,22 @@ class TypeHintTests { @@ -89,45 +79,22 @@ class TypeHintTests {
}
@Test
void createWithConstructorAndEmptyCustomizerAppliesConsistentDefault() {
List<TypeReference> parameterTypes = TypeReference.listOf(byte[].class, int.class);
assertConstructorHint(TypeHint.of(TypeReference.of(String.class))
.withConstructor(parameterTypes, constructorHint -> {}), constructorHint -> {
assertThat(constructorHint.getParameterTypes()).containsOnlyOnceElementsOf(parameterTypes);
assertThat(constructorHint.getMode()).isEqualTo(ExecutableMode.INVOKE);
});
}
@Test
void createWithConstructorAndCustomizerAppliesCustomization() {
List<TypeReference> parameterTypes = TypeReference.listOf(byte[].class, int.class);
assertConstructorHint(TypeHint.of(TypeReference.of(String.class))
.withConstructor(parameterTypes, constructorHint ->
constructorHint.withMode(ExecutableMode.INTROSPECT)), constructorHint -> {
assertThat(constructorHint.getParameterTypes()).containsOnlyOnceElementsOf(parameterTypes);
assertThat(constructorHint.getMode()).isEqualTo(ExecutableMode.INTROSPECT);
});
}
@Test
void createConstructorReuseBuilder() {
void createWithConstructorWithSameConstructorUpdatesEntry() {
List<TypeReference> parameterTypes = TypeReference.listOf(byte[].class, int.class);
Builder builder = TypeHint.of(TypeReference.of(String.class))
.withConstructor(parameterTypes, ExecutableMode.INTROSPECT);
assertConstructorHint(builder.withConstructor(parameterTypes, constructorHint ->
constructorHint.withMode(ExecutableMode.INVOKE)), constructorHint -> {
assertConstructorHint(builder.withConstructor(parameterTypes, ExecutableMode.INVOKE), constructorHint -> {
assertThat(constructorHint.getParameterTypes()).containsExactlyElementsOf(parameterTypes);
assertThat(constructorHint.getMode()).isEqualTo(ExecutableMode.INVOKE);
});
}
@Test
void createConstructorReuseBuilderAndApplyExecutableModePrecedence() {
void createWithConstructorAndSameConstructorAppliesExecutableModePrecedence() {
List<TypeReference> parameterTypes = TypeReference.listOf(byte[].class, int.class);
Builder builder = TypeHint.of(TypeReference.of(String.class)).withConstructor(parameterTypes,
constructorHint -> constructorHint.withMode(ExecutableMode.INVOKE));
assertConstructorHint(builder.withConstructor(parameterTypes, constructorHint ->
constructorHint.withMode(ExecutableMode.INTROSPECT)), constructorHint -> {
Builder builder = TypeHint.of(TypeReference.of(String.class))
.withConstructor(parameterTypes, ExecutableMode.INVOKE);
assertConstructorHint(builder.withConstructor(parameterTypes, ExecutableMode.INTROSPECT), constructorHint -> {
assertThat(constructorHint.getParameterTypes()).containsExactlyElementsOf(parameterTypes);
assertThat(constructorHint.getMode()).isEqualTo(ExecutableMode.INVOKE);
});
@ -143,17 +110,6 @@ class TypeHintTests { @@ -143,17 +110,6 @@ class TypeHintTests {
@Test
void createWithMethod() {
List<TypeReference> parameterTypes = List.of(TypeReference.of(char[].class));
assertMethodHint(TypeHint.of(TypeReference.of(String.class))
.withMethod("valueOf", parameterTypes), methodHint -> {
assertThat(methodHint.getName()).isEqualTo("valueOf");
assertThat(methodHint.getParameterTypes()).containsExactlyElementsOf(parameterTypes);
assertThat(methodHint.getMode()).isEqualTo(ExecutableMode.INVOKE);
});
}
@Test
void createWithMethodAndMode() {
List<TypeReference> parameterTypes = List.of(TypeReference.of(char[].class));
assertMethodHint(TypeHint.of(TypeReference.of(String.class))
.withMethod("valueOf", parameterTypes, ExecutableMode.INTROSPECT), methodHint -> {
@ -164,36 +120,11 @@ class TypeHintTests { @@ -164,36 +120,11 @@ class TypeHintTests {
}
@Test
void createWithMethodAndEmptyCustomizerAppliesConsistentDefault() {
List<TypeReference> parameterTypes = List.of(TypeReference.of(char[].class));
assertMethodHint(TypeHint.of(TypeReference.of(String.class))
.withMethod("valueOf", parameterTypes, methodHint -> {}), methodHint -> {
assertThat(methodHint.getName()).isEqualTo("valueOf");
assertThat(methodHint.getParameterTypes()).containsExactlyElementsOf(parameterTypes);
assertThat(methodHint.getMode()).isEqualTo(ExecutableMode.INVOKE);
});
}
@Test
void createWithMethodAndCustomizerAppliesCustomization() {
List<TypeReference> parameterTypes = List.of(TypeReference.of(char[].class));
assertMethodHint(TypeHint.of(TypeReference.of(String.class))
.withMethod("valueOf", parameterTypes, methodHint ->
methodHint.withMode(ExecutableMode.INTROSPECT)), methodHint -> {
assertThat(methodHint.getName()).isEqualTo("valueOf");
assertThat(methodHint.getParameterTypes()).containsExactlyElementsOf(parameterTypes);
assertThat(methodHint.getMode()).isEqualTo(ExecutableMode.INTROSPECT);
});
}
@Test
void createWithMethodReuseBuilder() {
void createWithMethodWithSameMethodUpdatesEntry() {
List<TypeReference> parameterTypes = TypeReference.listOf(char[].class);
Builder builder = TypeHint.of(TypeReference.of(String.class))
.withMethod("valueOf", parameterTypes, ExecutableMode.INTROSPECT);
assertMethodHint(builder.withMethod("valueOf", parameterTypes,
methodHint -> methodHint.withMode(ExecutableMode.INVOKE)), methodHint -> {
assertMethodHint(builder.withMethod("valueOf", parameterTypes, ExecutableMode.INVOKE), methodHint -> {
assertThat(methodHint.getName()).isEqualTo("valueOf");
assertThat(methodHint.getParameterTypes()).containsExactlyElementsOf(parameterTypes);
assertThat(methodHint.getMode()).isEqualTo(ExecutableMode.INVOKE);
@ -201,12 +132,11 @@ class TypeHintTests { @@ -201,12 +132,11 @@ class TypeHintTests {
}
@Test
void createWithMethodReuseBuilderAndApplyExecutableModePrecedence() {
void createWithMethodAndSameMethodAppliesExecutableModePrecedence() {
List<TypeReference> parameterTypes = TypeReference.listOf(char[].class);
Builder builder = TypeHint.of(TypeReference.of(String.class))
.withMethod("valueOf", parameterTypes, ExecutableMode.INVOKE);
assertMethodHint(builder.withMethod("valueOf", parameterTypes,
methodHint -> methodHint.withMode(ExecutableMode.INTROSPECT)), methodHint -> {
assertMethodHint(builder.withMethod("valueOf", parameterTypes, ExecutableMode.INTROSPECT), methodHint -> {
assertThat(methodHint.getName()).isEqualTo("valueOf");
assertThat(methodHint.getParameterTypes()).containsExactlyElementsOf(parameterTypes);
assertThat(methodHint.getMode()).isEqualTo(ExecutableMode.INVOKE);

4
spring-core/src/test/java/org/springframework/aot/hint/predicate/ReflectionHintsPredicatesTests.java

@ -303,7 +303,7 @@ class ReflectionHintsPredicatesTests { @@ -303,7 +303,7 @@ class ReflectionHintsPredicatesTests {
@Test
void reflectionOnAnyConstructorMatchesConstructorReflection() {
runtimeHints.reflection().registerConstructor(publicConstructor);
runtimeHints.reflection().registerConstructor(publicConstructor, ExecutableMode.INVOKE);
assertPredicateMatches(reflection.onType(SampleClass.class).withAnyConstructor());
}
@ -458,7 +458,7 @@ class ReflectionHintsPredicatesTests { @@ -458,7 +458,7 @@ class ReflectionHintsPredicatesTests {
@Test
void reflectionOnAnyMethodMatchesMethodReflection() {
runtimeHints.reflection().registerMethod(publicMethod);
runtimeHints.reflection().registerMethod(publicMethod, ExecutableMode.INVOKE);
assertPredicateMatches(reflection.onType(SampleClass.class).withAnyMethod());
}

2
spring-core/src/test/java/org/springframework/aot/nativex/FileNativeConfigurationWriterTests.java

@ -109,7 +109,7 @@ public class FileNativeConfigurationWriterTests { @@ -109,7 +109,7 @@ public class FileNativeConfigurationWriterTests {
.withField("DEFAULT_CHARSET")
.withField("defaultCharset")
.withConstructor(TypeReference.listOf(List.class, boolean.class, MimeType.class), ExecutableMode.INTROSPECT)
.withMethod("setDefaultCharset", TypeReference.listOf(Charset.class))
.withMethod("setDefaultCharset", TypeReference.listOf(Charset.class), ExecutableMode.INVOKE)
.withMethod("getDefaultCharset", Collections.emptyList(), ExecutableMode.INTROSPECT));
generator.write(hints);
assertEquals("""

2
spring-core/src/test/java/org/springframework/aot/nativex/ReflectionHintsWriterTests.java

@ -60,7 +60,7 @@ public class ReflectionHintsWriterTests { @@ -60,7 +60,7 @@ public class ReflectionHintsWriterTests {
.withField("DEFAULT_CHARSET")
.withField("defaultCharset")
.withConstructor(TypeReference.listOf(List.class, boolean.class, MimeType.class), ExecutableMode.INTROSPECT)
.withMethod("setDefaultCharset", List.of(TypeReference.of(Charset.class)))
.withMethod("setDefaultCharset", List.of(TypeReference.of(Charset.class)), ExecutableMode.INVOKE)
.withMethod("getDefaultCharset", Collections.emptyList(), ExecutableMode.INTROSPECT));
assertEquals("""
[

3
spring-orm/src/main/java/org/springframework/orm/jpa/support/InjectionCodeGenerator.java

@ -21,6 +21,7 @@ import java.lang.reflect.Member; @@ -21,6 +21,7 @@ import java.lang.reflect.Member;
import java.lang.reflect.Method;
import org.springframework.aot.generate.AccessVisibility;
import org.springframework.aot.hint.ExecutableMode;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.javapoet.CodeBlock;
import org.springframework.util.Assert;
@ -97,7 +98,7 @@ class InjectionCodeGenerator { @@ -97,7 +98,7 @@ class InjectionCodeGenerator {
AccessVisibility visibility = AccessVisibility.forMember(method);
if (visibility == AccessVisibility.PRIVATE
|| visibility == AccessVisibility.PROTECTED) {
this.hints.reflection().registerMethod(method);
this.hints.reflection().registerMethod(method, ExecutableMode.INVOKE);
code.addStatement("$T method = $T.findMethod($T.class, $S, $T.class)",
Method.class, ReflectionUtils.class, method.getDeclaringClass(),
method.getName(), method.getParameterTypes()[0]);

Loading…
Cancel
Save