Skip to content

Commit 71362c9

Browse files
committed
Revisit RuntimeHints API
The `RuntimeHints` API mainly reflects what is needed to write GraalVM reachability metadata. The latest GraalVM version simplified its format. This commit applies relevant simplifications as parts of it are not needed anymore. The new metadata format implies methods, constructors and fields introspection as soon as a reflection hint is registered for a type. As a result, `ExecutableMode.INTROSPECT`, and all `MemberCategory` values except `MemberCategory.INVOKE_*` are being deprecated. They have no replacement, as registering a type hint is enough. In practice, it is enough to replace this: ``` hints.reflection().registerType(MyType.class, MemberCategory.DECLARED_FIELDS); ``` By this: ``` hints.reflection().registerType(MyType.class); ``` As for `MemberCategory.PUBLIC_FIELDS` and `MemberCategory.DECLARED_FIELDS`, values were replaced by `INVOKE_PUBLIC_FIELDS` and `INVOKE_DECLARED_FIELDS` to make their original intent clearer and align with the rest of the API. Note, if you were using those values for reflection only, you can safely remove those hints in favor of a simple type hint. See gh-33847
1 parent fec2ed5 commit 71362c9

12 files changed

+172
-146
lines changed

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

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -30,7 +30,10 @@ public enum ExecutableMode {
3030

3131
/**
3232
* Only retrieving the {@link Executable} and its metadata is required.
33+
* @deprecated with no replacement since introspection is included
34+
* when {@link ReflectionHints#registerType(Class, MemberCategory...) adding a reflection hint for a type}.
3335
*/
36+
@Deprecated(since= "7.0", forRemoval = true)
3437
INTROSPECT,
3538

3639
/**

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

+45-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -32,32 +32,62 @@
3232
public enum MemberCategory {
3333

3434
/**
35-
* A category that represents public {@linkplain Field fields}.
35+
* A category that represents introspection on public {@linkplain Field fields}.
36+
* @deprecated with no replacement since introspection is included
37+
* when {@link ReflectionHints#registerType(Class, MemberCategory...) adding a reflection hint for a type}.
38+
* Use {@link #INVOKE_PUBLIC_FIELDS} if getting/setting field values is required.
3639
* @see Class#getFields()
3740
*/
41+
@Deprecated(since = "7.0", forRemoval = true)
3842
PUBLIC_FIELDS,
3943

4044
/**
41-
* A category that represents {@linkplain Class#getDeclaredFields() declared
45+
* A category that represents introspection on {@linkplain Class#getDeclaredFields() declared
4246
* fields}: all fields defined by the class but not inherited fields.
47+
* @deprecated with no replacement since introspection is included
48+
* when {@link ReflectionHints#registerType(Class, MemberCategory...) adding a reflection hint for a type}.
49+
* Use {@link #INVOKE_DECLARED_FIELDS} if getting/setting field values is required.
4350
* @see Class#getDeclaredFields()
4451
*/
52+
@Deprecated(since = "7.0", forRemoval = true)
4553
DECLARED_FIELDS,
4654

55+
/**
56+
* A category that represents getting/setting values on public {@linkplain Field fields}.
57+
* @see Field#get(Object)
58+
* @see Field#set(Object, Object)
59+
* @since 7.0
60+
*/
61+
INVOKE_PUBLIC_FIELDS,
62+
63+
/**
64+
* A category that represents getting/setting values on declared {@linkplain Field fields}.
65+
* @see Field#get(Object)
66+
* @see Field#set(Object, Object)
67+
* @since 7.0
68+
*/
69+
INVOKE_DECLARED_FIELDS,
70+
4771
/**
4872
* A category that defines public {@linkplain Constructor constructors} can
4973
* be introspected but not invoked.
74+
* @deprecated with no replacement since introspection is included
75+
* when {@link ReflectionHints#registerType(Class, MemberCategory...) adding a reflection hint for a type}.
5076
* @see Class#getConstructors()
5177
* @see ExecutableMode#INTROSPECT
5278
*/
79+
@Deprecated(since = "7.0", forRemoval = true)
5380
INTROSPECT_PUBLIC_CONSTRUCTORS,
5481

5582
/**
5683
* A category that defines {@linkplain Class#getDeclaredConstructors() all
5784
* constructors} can be introspected but not invoked.
85+
* @deprecated with no replacement since introspection is included
86+
* when {@link ReflectionHints#registerType(Class, MemberCategory...) adding a reflection hint for a type}.
5887
* @see Class#getDeclaredConstructors()
5988
* @see ExecutableMode#INTROSPECT
6089
*/
90+
@Deprecated(since = "7.0", forRemoval = true)
6191
INTROSPECT_DECLARED_CONSTRUCTORS,
6292

6393
/**
@@ -79,17 +109,23 @@ public enum MemberCategory {
79109
/**
80110
* A category that defines public {@linkplain Method methods}, including
81111
* inherited ones, can be introspected but not invoked.
112+
* @deprecated with no replacement since introspection is added by default
113+
* when {@link ReflectionHints#registerType(Class, MemberCategory...) adding a reflection hint for a type}.
82114
* @see Class#getMethods()
83115
* @see ExecutableMode#INTROSPECT
84116
*/
117+
@Deprecated(since = "7.0", forRemoval = true)
85118
INTROSPECT_PUBLIC_METHODS,
86119

87120
/**
88121
* A category that defines {@linkplain Class#getDeclaredMethods() all
89122
* methods}, excluding inherited ones, can be introspected but not invoked.
123+
* @deprecated with no replacement since introspection is added by default
124+
* when {@link ReflectionHints#registerType(Class, MemberCategory...) adding a reflection hint for a type}.
90125
* @see Class#getDeclaredMethods()
91126
* @see ExecutableMode#INTROSPECT
92127
*/
128+
@Deprecated(since = "7.0", forRemoval = true)
93129
INTROSPECT_DECLARED_METHODS,
94130

95131
/**
@@ -114,7 +150,10 @@ public enum MemberCategory {
114150
* <p>Contrary to other categories, this does not register any particular
115151
* reflection for inner classes but rather makes sure they are available
116152
* via a call to {@link Class#getClasses}.
153+
* @deprecated with no replacement since introspection is included
154+
* when {@link ReflectionHints#registerType(Class, MemberCategory...) adding a reflection hint for a type}.
117155
*/
156+
@Deprecated(since = "7.0", forRemoval = true)
118157
PUBLIC_CLASSES,
119158

120159
/**
@@ -123,7 +162,10 @@ public enum MemberCategory {
123162
* <p>Contrary to other categories, this does not register any particular
124163
* reflection for inner classes but rather makes sure they are available
125164
* via a call to {@link Class#getDeclaredClasses}.
165+
* @deprecated with no replacement since introspection is included
166+
* when {@link ReflectionHints#registerType(Class, MemberCategory...) adding a reflection hint for a type}.
126167
*/
168+
@Deprecated(since = "7.0", forRemoval = true)
127169
DECLARED_CLASSES
128170

129171
}

spring-core/src/main/java/org/springframework/aot/hint/predicate/ReflectionHintsPredicates.java

+46-58
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ public Predicate<RuntimeHints> withAnyMemberCategory(MemberCategory... memberCat
255255
}
256256

257257

258+
@SuppressWarnings("removal")
258259
public abstract static class ExecutableHintPredicate<T extends Executable> implements Predicate<RuntimeHints> {
259260

260261
protected final T executable;
@@ -299,6 +300,7 @@ static boolean includes(ExecutableHint hint, String name,
299300
}
300301

301302

303+
@SuppressWarnings("removal")
302304
public static class ConstructorHintPredicate extends ExecutableHintPredicate<Constructor<?>> {
303305

304306
ConstructorHintPredicate(Constructor<?> constructor) {
@@ -308,28 +310,17 @@ public static class ConstructorHintPredicate extends ExecutableHintPredicate<Con
308310
@Override
309311
public boolean test(RuntimeHints runtimeHints) {
310312
return (new TypeHintPredicate(TypeReference.of(this.executable.getDeclaringClass()))
311-
.withAnyMemberCategory(getPublicMemberCategories())
312-
.and(hints -> Modifier.isPublic(this.executable.getModifiers())))
313-
.or(new TypeHintPredicate(TypeReference.of(this.executable.getDeclaringClass())).withAnyMemberCategory(getDeclaredMemberCategories()))
313+
.and(hints -> this.executableMode == ExecutableMode.INTROSPECT))
314+
.or(new TypeHintPredicate(TypeReference.of(this.executable.getDeclaringClass()))
315+
.withMemberCategory(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS)
316+
.and(hints -> Modifier.isPublic(this.executable.getModifiers()))
317+
.and(hints -> this.executableMode == ExecutableMode.INVOKE))
318+
.or(new TypeHintPredicate(TypeReference.of(this.executable.getDeclaringClass()))
319+
.withMemberCategory(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)
320+
.and(hints -> this.executableMode == ExecutableMode.INVOKE))
314321
.or(exactMatch()).test(runtimeHints);
315322
}
316323

317-
MemberCategory[] getPublicMemberCategories() {
318-
if (this.executableMode == ExecutableMode.INTROSPECT) {
319-
return new MemberCategory[] { MemberCategory.INTROSPECT_PUBLIC_CONSTRUCTORS,
320-
MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS };
321-
}
322-
return new MemberCategory[] { MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS };
323-
}
324-
325-
MemberCategory[] getDeclaredMemberCategories() {
326-
if (this.executableMode == ExecutableMode.INTROSPECT) {
327-
return new MemberCategory[] { MemberCategory.INTROSPECT_DECLARED_CONSTRUCTORS,
328-
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS };
329-
}
330-
return new MemberCategory[] { MemberCategory.INVOKE_DECLARED_CONSTRUCTORS };
331-
}
332-
333324
@Override
334325
Predicate<RuntimeHints> exactMatch() {
335326
return hints -> {
@@ -343,6 +334,7 @@ Predicate<RuntimeHints> exactMatch() {
343334
}
344335

345336

337+
@SuppressWarnings("removal")
346338
public static class MethodHintPredicate extends ExecutableHintPredicate<Method> {
347339

348340
MethodHintPredicate(Method method) {
@@ -352,31 +344,18 @@ public static class MethodHintPredicate extends ExecutableHintPredicate<Method>
352344
@Override
353345
public boolean test(RuntimeHints runtimeHints) {
354346
return (new TypeHintPredicate(TypeReference.of(this.executable.getDeclaringClass()))
355-
.withAnyMemberCategory(getPublicMemberCategories())
356-
.and(hints -> Modifier.isPublic(this.executable.getModifiers())))
357-
.or(new TypeHintPredicate(TypeReference.of(this.executable.getDeclaringClass()))
358-
.withAnyMemberCategory(getDeclaredMemberCategories())
359-
.and(hints -> !Modifier.isPublic(this.executable.getModifiers())))
347+
.and(hints -> this.executableMode == ExecutableMode.INTROSPECT))
348+
.or((new TypeHintPredicate(TypeReference.of(this.executable.getDeclaringClass()))
349+
.withMemberCategory(MemberCategory.INVOKE_PUBLIC_METHODS)
350+
.and(hints -> Modifier.isPublic(this.executable.getModifiers()))
351+
.and(hints -> this.executableMode == ExecutableMode.INVOKE)))
352+
.or((new TypeHintPredicate(TypeReference.of(this.executable.getDeclaringClass()))
353+
.withMemberCategory(MemberCategory.INVOKE_DECLARED_METHODS)
354+
.and(hints -> !Modifier.isPublic(this.executable.getModifiers()))
355+
.and(hints -> this.executableMode == ExecutableMode.INVOKE)))
360356
.or(exactMatch()).test(runtimeHints);
361357
}
362358

363-
MemberCategory[] getPublicMemberCategories() {
364-
if (this.executableMode == ExecutableMode.INTROSPECT) {
365-
return new MemberCategory[] { MemberCategory.INTROSPECT_PUBLIC_METHODS,
366-
MemberCategory.INVOKE_PUBLIC_METHODS };
367-
}
368-
return new MemberCategory[] { MemberCategory.INVOKE_PUBLIC_METHODS };
369-
}
370-
371-
MemberCategory[] getDeclaredMemberCategories() {
372-
373-
if (this.executableMode == ExecutableMode.INTROSPECT) {
374-
return new MemberCategory[] { MemberCategory.INTROSPECT_DECLARED_METHODS,
375-
MemberCategory.INVOKE_DECLARED_METHODS };
376-
}
377-
return new MemberCategory[] { MemberCategory.INVOKE_DECLARED_METHODS };
378-
}
379-
380359
@Override
381360
Predicate<RuntimeHints> exactMatch() {
382361
return hints -> {
@@ -394,31 +373,40 @@ public static class FieldHintPredicate implements Predicate<RuntimeHints> {
394373

395374
private final Field field;
396375

376+
@Nullable
377+
private ExecutableMode executableMode;
378+
397379
FieldHintPredicate(Field field) {
398380
this.field = field;
399381
}
400382

383+
/**
384+
* Refine the current predicate to only match if an invocation hint is registered for this field.
385+
* @return the refined {@link RuntimeHints} predicate
386+
* @since 7.0
387+
*/
388+
public FieldHintPredicate invocation() {
389+
this.executableMode = ExecutableMode.INVOKE;
390+
return this;
391+
}
392+
401393
@Override
402394
public boolean test(RuntimeHints runtimeHints) {
403395
TypeHint typeHint = runtimeHints.reflection().getTypeHint(this.field.getDeclaringClass());
404-
if (typeHint == null) {
405-
return false;
406-
}
407-
return memberCategoryMatch(typeHint) || exactMatch(typeHint);
408-
}
409-
410-
private boolean memberCategoryMatch(TypeHint typeHint) {
411-
if (Modifier.isPublic(this.field.getModifiers())) {
412-
return typeHint.getMemberCategories().contains(MemberCategory.PUBLIC_FIELDS);
396+
if (typeHint != null) {
397+
if (this.executableMode == ExecutableMode.INVOKE) {
398+
if (Modifier.isPublic(this.field.getModifiers())) {
399+
return typeHint.getMemberCategories().contains(MemberCategory.INVOKE_PUBLIC_FIELDS);
400+
}
401+
else {
402+
return typeHint.getMemberCategories().contains(MemberCategory.INVOKE_DECLARED_FIELDS);
403+
}
404+
}
405+
else {
406+
return true;
407+
}
413408
}
414-
else {
415-
return typeHint.getMemberCategories().contains(MemberCategory.DECLARED_FIELDS);
416-
}
417-
}
418-
419-
private boolean exactMatch(TypeHint typeHint) {
420-
return typeHint.fields().anyMatch(fieldHint ->
421-
this.field.getName().equals(fieldHint.getName()));
409+
return false;
422410
}
423411
}
424412

spring-core/src/main/java/org/springframework/aot/hint/predicate/ResourceHintsPredicates.java

+7-16
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,13 @@
1919
import java.util.ArrayList;
2020
import java.util.List;
2121
import java.util.function.Predicate;
22-
import java.util.regex.Pattern;
2322

2423
import org.springframework.aot.hint.ResourceHints;
2524
import org.springframework.aot.hint.ResourcePatternHint;
2625
import org.springframework.aot.hint.RuntimeHints;
2726
import org.springframework.aot.hint.TypeReference;
27+
import org.springframework.util.AntPathMatcher;
2828
import org.springframework.util.Assert;
29-
import org.springframework.util.ConcurrentLruCache;
3029

3130
/**
3231
* Generator of {@link ResourceHints} predicates, testing whether the given hints
@@ -39,7 +38,7 @@
3938
*/
4039
public class ResourceHintsPredicates {
4140

42-
private static final ConcurrentLruCache<ResourcePatternHint, Pattern> CACHED_RESOURCE_PATTERNS = new ConcurrentLruCache<>(32, ResourcePatternHint::toRegex);
41+
private static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();
4342

4443
ResourceHintsPredicates() {
4544
}
@@ -100,26 +99,18 @@ public Predicate<RuntimeHints> forResource(String resourceName) {
10099
return hints -> {
101100
AggregatedResourcePatternHints aggregatedResourcePatternHints = AggregatedResourcePatternHints.of(
102101
hints.resources());
103-
boolean isExcluded = aggregatedResourcePatternHints.excludes().stream().anyMatch(excluded ->
104-
CACHED_RESOURCE_PATTERNS.get(excluded).matcher(resourceNameToUse).matches());
105-
if (isExcluded) {
106-
return false;
107-
}
108102
return aggregatedResourcePatternHints.includes().stream().anyMatch(included ->
109-
CACHED_RESOURCE_PATTERNS.get(included).matcher(resourceNameToUse).matches());
103+
PATH_MATCHER.match(included.getPattern(), resourceNameToUse));
110104
};
111105
}
112106

113-
private record AggregatedResourcePatternHints(List<ResourcePatternHint> includes, List<ResourcePatternHint> excludes) {
107+
private record AggregatedResourcePatternHints(List<ResourcePatternHint> includes) {
114108

115109
static AggregatedResourcePatternHints of(ResourceHints resourceHints) {
116110
List<ResourcePatternHint> includes = new ArrayList<>();
117-
List<ResourcePatternHint> excludes = new ArrayList<>();
118-
resourceHints.resourcePatternHints().forEach(resourcePatternHint -> {
119-
includes.addAll(resourcePatternHint.getIncludes());
120-
excludes.addAll(resourcePatternHint.getExcludes());
121-
});
122-
return new AggregatedResourcePatternHints(includes, excludes);
111+
resourceHints.resourcePatternHints().forEach(resourcePatternHint ->
112+
includes.addAll(resourcePatternHint.getIncludes()));
113+
return new AggregatedResourcePatternHints(includes);
123114
}
124115

125116
}

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

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
* @author Phillip Webb
2929
* @since 6.0
3030
*/
31+
@SuppressWarnings("removal")
3132
class ExecutableHintTests {
3233

3334
@Test

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
2525
*
2626
* @author Stephane Nicoll
2727
*/
28+
@SuppressWarnings("removal")
2829
class ExecutableModeTests {
2930

3031
@Test

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

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
* @author Stephane Nicoll
3838
* @author Sebastien Deleuze
3939
*/
40+
@SuppressWarnings("removal")
4041
class ReflectionHintsTests {
4142

4243
private final ReflectionHints reflectionHints = new ReflectionHints();

0 commit comments

Comments
 (0)