Skip to content

Commit

Permalink
Deprecate RuntimeHintsAgent Java agent
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bclozel committed Nov 29, 2024
1 parent 71362c9 commit 0759129
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 287 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2024 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.
Expand All @@ -20,13 +20,11 @@
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.util.ResourceBundle;
import java.util.function.Function;
import java.util.function.Predicate;

import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.TypeReference;
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
Expand Down Expand Up @@ -67,8 +65,7 @@ enum InstrumentedMethod {
CLASS_GETCLASSES(Class.class, "getClasses", HintType.REFLECTION,
invocation -> {
Class<?> thisClass = invocation.getInstance();
return reflection().onType(TypeReference.of(thisClass))
.withAnyMemberCategory(MemberCategory.DECLARED_CLASSES, MemberCategory.PUBLIC_CLASSES);
return reflection().onType(TypeReference.of(thisClass));
}
),

Expand All @@ -81,7 +78,7 @@ enum InstrumentedMethod {
if (constructor == null) {
return runtimeHints -> false;
}
return reflection().onConstructor(constructor).introspect();
return reflection().onType(constructor.getDeclaringClass());
}
),

Expand All @@ -91,9 +88,7 @@ enum InstrumentedMethod {
CLASS_GETCONSTRUCTORS(Class.class, "getConstructors", HintType.REFLECTION,
invocation -> {
Class<?> thisClass = invocation.getInstance();
return reflection().onType(TypeReference.of(thisClass)).withAnyMemberCategory(
MemberCategory.INTROSPECT_PUBLIC_CONSTRUCTORS, MemberCategory.INTROSPECT_DECLARED_CONSTRUCTORS,
MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);
return reflection().onType(TypeReference.of(thisClass));
}
),

Expand All @@ -103,7 +98,7 @@ enum InstrumentedMethod {
CLASS_GETDECLAREDCLASSES(Class.class, "getDeclaredClasses", HintType.REFLECTION,
invocation -> {
Class<?> thisClass = invocation.getInstance();
return reflection().onType(TypeReference.of(thisClass)).withMemberCategory(MemberCategory.DECLARED_CLASSES);
return reflection().onType(TypeReference.of(thisClass));
}
),

Expand All @@ -116,9 +111,7 @@ enum InstrumentedMethod {
if (constructor == null) {
return runtimeHints -> false;
}
TypeReference thisType = invocation.getInstanceTypeReference();
return reflection().onType(thisType).withMemberCategory(MemberCategory.INTROSPECT_DECLARED_CONSTRUCTORS)
.or(reflection().onConstructor(constructor).introspect());
return reflection().onType(constructor.getDeclaringClass());
}
),

Expand All @@ -128,8 +121,7 @@ enum InstrumentedMethod {
CLASS_GETDECLAREDCONSTRUCTORS(Class.class, "getDeclaredConstructors", HintType.REFLECTION,
invocation -> {
Class<?> thisClass = invocation.getInstance();
return reflection().onType(TypeReference.of(thisClass))
.withAnyMemberCategory(MemberCategory.INTROSPECT_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);
return reflection().onType(TypeReference.of(thisClass));
}),

/**
Expand All @@ -141,9 +133,7 @@ enum InstrumentedMethod {
if (field == null) {
return runtimeHints -> false;
}
TypeReference thisType = invocation.getInstanceTypeReference();
return reflection().onType(thisType).withMemberCategory(MemberCategory.DECLARED_FIELDS)
.or(reflection().onField(field));
return reflection().onType(field.getDeclaringClass());
}
),

Expand All @@ -153,7 +143,7 @@ enum InstrumentedMethod {
CLASS_GETDECLAREDFIELDS(Class.class, "getDeclaredFields", HintType.REFLECTION,
invocation -> {
Class<?> thisClass = invocation.getInstance();
return reflection().onType(TypeReference.of(thisClass)).withMemberCategory(MemberCategory.DECLARED_FIELDS);
return reflection().onType(TypeReference.of(thisClass));
}
),

Expand All @@ -166,10 +156,7 @@ enum InstrumentedMethod {
if (method == null) {
return runtimeHints -> false;
}
TypeReference thisType = invocation.getInstanceTypeReference();
return reflection().onType(thisType)
.withAnyMemberCategory(MemberCategory.INTROSPECT_DECLARED_METHODS, MemberCategory.INVOKE_DECLARED_METHODS)
.or(reflection().onMethod(method).introspect());
return reflection().onType(method.getDeclaringClass());
}
),

Expand All @@ -179,8 +166,7 @@ enum InstrumentedMethod {
CLASS_GETDECLAREDMETHODS(Class.class, "getDeclaredMethods", HintType.REFLECTION,
invocation -> {
Class<?> thisClass = invocation.getInstance();
return reflection().onType(TypeReference.of(thisClass))
.withAnyMemberCategory(MemberCategory.INTROSPECT_DECLARED_METHODS, MemberCategory.INVOKE_DECLARED_METHODS);
return reflection().onType(TypeReference.of(thisClass));
}
),

Expand All @@ -194,10 +180,7 @@ enum InstrumentedMethod {
if (field == null) {
return runtimeHints -> false;
}
TypeReference thisType = invocation.getInstanceTypeReference();
return reflection().onType(thisType).withMemberCategory(MemberCategory.PUBLIC_FIELDS)
.and(runtimeHints -> Modifier.isPublic(field.getModifiers()))
.or(reflection().onType(thisType).withMemberCategory(MemberCategory.DECLARED_FIELDS))
return reflection().onType(field.getDeclaringClass())
.or(reflection().onField(invocation.getReturnValue()));
}),

Expand All @@ -207,8 +190,7 @@ enum InstrumentedMethod {
CLASS_GETFIELDS(Class.class, "getFields", HintType.REFLECTION,
invocation -> {
Class<?> thisClass = invocation.getInstance();
return reflection().onType(TypeReference.of(thisClass))
.withAnyMemberCategory(MemberCategory.PUBLIC_FIELDS, MemberCategory.DECLARED_FIELDS);
return reflection().onType(TypeReference.of(thisClass));
}
),

Expand All @@ -221,12 +203,7 @@ enum InstrumentedMethod {
if (method == null) {
return runtimeHints -> false;
}
TypeReference thisType = invocation.getInstanceTypeReference();
return reflection().onType(thisType).withAnyMemberCategory(MemberCategory.INTROSPECT_PUBLIC_METHODS, MemberCategory.INVOKE_PUBLIC_METHODS)
.and(runtimeHints -> Modifier.isPublic(method.getModifiers()))
.or(reflection().onType(thisType).withAnyMemberCategory(MemberCategory.INTROSPECT_DECLARED_METHODS, MemberCategory.INVOKE_DECLARED_METHODS))
.or(reflection().onMethod(method).introspect())
.or(reflection().onMethod(method).invoke());
return reflection().onType(method.getDeclaringClass());
}
),

Expand All @@ -236,9 +213,7 @@ enum InstrumentedMethod {
CLASS_GETMETHODS(Class.class, "getMethods", HintType.REFLECTION,
invocation -> {
Class<?> thisClass = invocation.getInstance();
return reflection().onType(TypeReference.of(thisClass)).withAnyMemberCategory(
MemberCategory.INTROSPECT_PUBLIC_METHODS, MemberCategory.INTROSPECT_DECLARED_METHODS,
MemberCategory.INVOKE_PUBLIC_METHODS, MemberCategory.INVOKE_DECLARED_METHODS);
return reflection().onType(TypeReference.of(thisClass));
}
),

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@
* @author Brian Clozel
* @since 6.0
* @see InvocationsRecorderClassTransformer
* @deprecated as of 7.0 in favor of the {@code -XX:MissingRegistrationReportingMode=Warn} and
* {@code -XX:MissingRegistrationReportingMode=Exit} JVM flags with GraalVM.
*/
@Deprecated(forRemoval = true)
public final class RuntimeHintsAgent {

private static boolean loaded = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,20 @@
import org.springframework.aot.agent.RecordedInvocation;
import org.springframework.aot.agent.RecordedInvocationsListener;
import org.springframework.aot.agent.RecordedInvocationsPublisher;
import org.springframework.aot.agent.RuntimeHintsAgent;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.util.Assert;

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

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

0 comments on commit 0759129

Please sign in to comment.