Skip to content

Commit 0759129

Browse files
committed
Deprecate RuntimeHintsAgent Java agent
This Java agent has been designed to instrument specific JDK calls for reflective introspection and invocations. This is useful for testing runtime hints in integration tests. As of GraalVM 23, there is a new VM option that does this in a much more efficient and precise fashion. Developers can use the `-XX:MissingRegistrationReportingMode` with the "Warn" or "Exit" value. The option will look for reachability metadata and emit logs in "Warn" mode or immediately exit the application with in "Exit" mode. This commit deprecates the `RuntimeHintsAgent` in favor of this new, more reliable option. See gh-33847
1 parent 71362c9 commit 0759129

File tree

4 files changed

+76
-287
lines changed

4 files changed

+76
-287
lines changed

spring-core-test/src/main/java/org/springframework/aot/agent/InstrumentedMethod.java

+15-40
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.
@@ -20,13 +20,11 @@
2020
import java.lang.reflect.Field;
2121
import java.lang.reflect.InvocationHandler;
2222
import java.lang.reflect.Method;
23-
import java.lang.reflect.Modifier;
2423
import java.lang.reflect.Proxy;
2524
import java.util.ResourceBundle;
2625
import java.util.function.Function;
2726
import java.util.function.Predicate;
2827

29-
import org.springframework.aot.hint.MemberCategory;
3028
import org.springframework.aot.hint.RuntimeHints;
3129
import org.springframework.aot.hint.TypeReference;
3230
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
@@ -67,8 +65,7 @@ enum InstrumentedMethod {
6765
CLASS_GETCLASSES(Class.class, "getClasses", HintType.REFLECTION,
6866
invocation -> {
6967
Class<?> thisClass = invocation.getInstance();
70-
return reflection().onType(TypeReference.of(thisClass))
71-
.withAnyMemberCategory(MemberCategory.DECLARED_CLASSES, MemberCategory.PUBLIC_CLASSES);
68+
return reflection().onType(TypeReference.of(thisClass));
7269
}
7370
),
7471

@@ -81,7 +78,7 @@ enum InstrumentedMethod {
8178
if (constructor == null) {
8279
return runtimeHints -> false;
8380
}
84-
return reflection().onConstructor(constructor).introspect();
81+
return reflection().onType(constructor.getDeclaringClass());
8582
}
8683
),
8784

@@ -91,9 +88,7 @@ enum InstrumentedMethod {
9188
CLASS_GETCONSTRUCTORS(Class.class, "getConstructors", HintType.REFLECTION,
9289
invocation -> {
9390
Class<?> thisClass = invocation.getInstance();
94-
return reflection().onType(TypeReference.of(thisClass)).withAnyMemberCategory(
95-
MemberCategory.INTROSPECT_PUBLIC_CONSTRUCTORS, MemberCategory.INTROSPECT_DECLARED_CONSTRUCTORS,
96-
MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);
91+
return reflection().onType(TypeReference.of(thisClass));
9792
}
9893
),
9994

@@ -103,7 +98,7 @@ enum InstrumentedMethod {
10398
CLASS_GETDECLAREDCLASSES(Class.class, "getDeclaredClasses", HintType.REFLECTION,
10499
invocation -> {
105100
Class<?> thisClass = invocation.getInstance();
106-
return reflection().onType(TypeReference.of(thisClass)).withMemberCategory(MemberCategory.DECLARED_CLASSES);
101+
return reflection().onType(TypeReference.of(thisClass));
107102
}
108103
),
109104

@@ -116,9 +111,7 @@ enum InstrumentedMethod {
116111
if (constructor == null) {
117112
return runtimeHints -> false;
118113
}
119-
TypeReference thisType = invocation.getInstanceTypeReference();
120-
return reflection().onType(thisType).withMemberCategory(MemberCategory.INTROSPECT_DECLARED_CONSTRUCTORS)
121-
.or(reflection().onConstructor(constructor).introspect());
114+
return reflection().onType(constructor.getDeclaringClass());
122115
}
123116
),
124117

@@ -128,8 +121,7 @@ enum InstrumentedMethod {
128121
CLASS_GETDECLAREDCONSTRUCTORS(Class.class, "getDeclaredConstructors", HintType.REFLECTION,
129122
invocation -> {
130123
Class<?> thisClass = invocation.getInstance();
131-
return reflection().onType(TypeReference.of(thisClass))
132-
.withAnyMemberCategory(MemberCategory.INTROSPECT_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);
124+
return reflection().onType(TypeReference.of(thisClass));
133125
}),
134126

135127
/**
@@ -141,9 +133,7 @@ enum InstrumentedMethod {
141133
if (field == null) {
142134
return runtimeHints -> false;
143135
}
144-
TypeReference thisType = invocation.getInstanceTypeReference();
145-
return reflection().onType(thisType).withMemberCategory(MemberCategory.DECLARED_FIELDS)
146-
.or(reflection().onField(field));
136+
return reflection().onType(field.getDeclaringClass());
147137
}
148138
),
149139

@@ -153,7 +143,7 @@ enum InstrumentedMethod {
153143
CLASS_GETDECLAREDFIELDS(Class.class, "getDeclaredFields", HintType.REFLECTION,
154144
invocation -> {
155145
Class<?> thisClass = invocation.getInstance();
156-
return reflection().onType(TypeReference.of(thisClass)).withMemberCategory(MemberCategory.DECLARED_FIELDS);
146+
return reflection().onType(TypeReference.of(thisClass));
157147
}
158148
),
159149

@@ -166,10 +156,7 @@ enum InstrumentedMethod {
166156
if (method == null) {
167157
return runtimeHints -> false;
168158
}
169-
TypeReference thisType = invocation.getInstanceTypeReference();
170-
return reflection().onType(thisType)
171-
.withAnyMemberCategory(MemberCategory.INTROSPECT_DECLARED_METHODS, MemberCategory.INVOKE_DECLARED_METHODS)
172-
.or(reflection().onMethod(method).introspect());
159+
return reflection().onType(method.getDeclaringClass());
173160
}
174161
),
175162

@@ -179,8 +166,7 @@ enum InstrumentedMethod {
179166
CLASS_GETDECLAREDMETHODS(Class.class, "getDeclaredMethods", HintType.REFLECTION,
180167
invocation -> {
181168
Class<?> thisClass = invocation.getInstance();
182-
return reflection().onType(TypeReference.of(thisClass))
183-
.withAnyMemberCategory(MemberCategory.INTROSPECT_DECLARED_METHODS, MemberCategory.INVOKE_DECLARED_METHODS);
169+
return reflection().onType(TypeReference.of(thisClass));
184170
}
185171
),
186172

@@ -194,10 +180,7 @@ enum InstrumentedMethod {
194180
if (field == null) {
195181
return runtimeHints -> false;
196182
}
197-
TypeReference thisType = invocation.getInstanceTypeReference();
198-
return reflection().onType(thisType).withMemberCategory(MemberCategory.PUBLIC_FIELDS)
199-
.and(runtimeHints -> Modifier.isPublic(field.getModifiers()))
200-
.or(reflection().onType(thisType).withMemberCategory(MemberCategory.DECLARED_FIELDS))
183+
return reflection().onType(field.getDeclaringClass())
201184
.or(reflection().onField(invocation.getReturnValue()));
202185
}),
203186

@@ -207,8 +190,7 @@ enum InstrumentedMethod {
207190
CLASS_GETFIELDS(Class.class, "getFields", HintType.REFLECTION,
208191
invocation -> {
209192
Class<?> thisClass = invocation.getInstance();
210-
return reflection().onType(TypeReference.of(thisClass))
211-
.withAnyMemberCategory(MemberCategory.PUBLIC_FIELDS, MemberCategory.DECLARED_FIELDS);
193+
return reflection().onType(TypeReference.of(thisClass));
212194
}
213195
),
214196

@@ -221,12 +203,7 @@ enum InstrumentedMethod {
221203
if (method == null) {
222204
return runtimeHints -> false;
223205
}
224-
TypeReference thisType = invocation.getInstanceTypeReference();
225-
return reflection().onType(thisType).withAnyMemberCategory(MemberCategory.INTROSPECT_PUBLIC_METHODS, MemberCategory.INVOKE_PUBLIC_METHODS)
226-
.and(runtimeHints -> Modifier.isPublic(method.getModifiers()))
227-
.or(reflection().onType(thisType).withAnyMemberCategory(MemberCategory.INTROSPECT_DECLARED_METHODS, MemberCategory.INVOKE_DECLARED_METHODS))
228-
.or(reflection().onMethod(method).introspect())
229-
.or(reflection().onMethod(method).invoke());
206+
return reflection().onType(method.getDeclaringClass());
230207
}
231208
),
232209

@@ -236,9 +213,7 @@ enum InstrumentedMethod {
236213
CLASS_GETMETHODS(Class.class, "getMethods", HintType.REFLECTION,
237214
invocation -> {
238215
Class<?> thisClass = invocation.getInstance();
239-
return reflection().onType(TypeReference.of(thisClass)).withAnyMemberCategory(
240-
MemberCategory.INTROSPECT_PUBLIC_METHODS, MemberCategory.INTROSPECT_DECLARED_METHODS,
241-
MemberCategory.INVOKE_PUBLIC_METHODS, MemberCategory.INVOKE_DECLARED_METHODS);
216+
return reflection().onType(TypeReference.of(thisClass));
242217
}
243218
),
244219

spring-core-test/src/main/java/org/springframework/aot/agent/RuntimeHintsAgent.java

+3
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,10 @@
3939
* @author Brian Clozel
4040
* @since 6.0
4141
* @see InvocationsRecorderClassTransformer
42+
* @deprecated as of 7.0 in favor of the {@code -XX:MissingRegistrationReportingMode=Warn} and
43+
* {@code -XX:MissingRegistrationReportingMode=Exit} JVM flags with GraalVM.
4244
*/
45+
@Deprecated(forRemoval = true)
4346
public final class RuntimeHintsAgent {
4447

4548
private static boolean loaded = false;

spring-core-test/src/main/java/org/springframework/aot/test/agent/RuntimeHintsRecorder.java

+6-3
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,20 @@
2222
import org.springframework.aot.agent.RecordedInvocation;
2323
import org.springframework.aot.agent.RecordedInvocationsListener;
2424
import org.springframework.aot.agent.RecordedInvocationsPublisher;
25-
import org.springframework.aot.agent.RuntimeHintsAgent;
2625
import org.springframework.aot.hint.RuntimeHints;
2726
import org.springframework.util.Assert;
2827

2928
/**
3029
* Invocations relevant to {@link RuntimeHints} recorded during the execution of a block
31-
* of code instrumented by the {@link RuntimeHintsAgent}.
30+
* of code instrumented by the {@link org.springframework.aot.agent.RuntimeHintsAgent}.
3231
*
3332
* @author Brian Clozel
3433
* @since 6.0
34+
* @deprecated as of 7.0 in favor of the {@code -XX:MissingRegistrationReportingMode=Warn} and
35+
* {@code -XX:MissingRegistrationReportingMode=Exit} JVM flags with GraalVM.
3536
*/
37+
@Deprecated(forRemoval = true)
38+
@SuppressWarnings("removal")
3639
public final class RuntimeHintsRecorder {
3740

3841
private final RuntimeHintsInvocationsListener listener;
@@ -49,7 +52,7 @@ private RuntimeHintsRecorder() {
4952
*/
5053
public static synchronized RuntimeHintsInvocations record(Runnable action) {
5154
Assert.notNull(action, "Runnable action must not be null");
52-
Assert.state(RuntimeHintsAgent.isLoaded(), "RuntimeHintsAgent must be loaded in the current JVM");
55+
Assert.state(org.springframework.aot.agent.RuntimeHintsAgent.isLoaded(), "RuntimeHintsAgent must be loaded in the current JVM");
5356
RuntimeHintsRecorder recorder = new RuntimeHintsRecorder();
5457
RecordedInvocationsPublisher.addListener(recorder.listener);
5558
try {

0 commit comments

Comments
 (0)