diff --git a/docs/reference-manual/native-image/ReachabilityMetadata.md b/docs/reference-manual/native-image/ReachabilityMetadata.md index 1f7d435432d4a..c9597005a9703 100644 --- a/docs/reference-manual/native-image/ReachabilityMetadata.md +++ b/docs/reference-manual/native-image/ReachabilityMetadata.md @@ -468,14 +468,14 @@ The Native Image agent does not support custom implementations of `ResourceBundl This mode will be made the default behavior of Native Image in a future release. We encourage you to start transitioning your code as soon as possible. The [Native Image agent](AutomaticMetadataCollection.md) outputs JSON files that conform to both the default and strict modes of operation. -The following options are useful for debugging issues during the transition to the strict mode: - -* `-H:ThrowMissingRegistrationErrors=`: limits `MissingReflectionRegistrationError` to be thrown from a defined list of packages. - This is useful when using some library code that has not been ported to the new mode yet; -* `-H:MissingRegistrationReportingMode`: sets how `MissingReflectionRegistrationError` is reported: - * `Throw` is the default. The error is simply thrown as a Java exception; - * `Warn` outputs a small stack trace for every error encountered, which results in a report of all the places the tested code is going to throw when the strict mode is enabled; - * `Exit` exits the program when encountering the error. This is useful to detect blanket `catch (Throwable t) {` blocks that would otherwise silence the error. +Native Image also provides some useful options for debugging issues during the transition to the strict mode: + +* To make sure that the reflection for your image is configured correctly you can add `-H:ThrowMissingRegistrationErrors=` to the native-image build arguments. + If the resulting image fails in libraries that are not under your control, you can add a package prefix to the option to limit the errors to operations called from classes within the specified packages: `-H:ThrowMissingRegistrationErrors=`. +* The default behavior under `-H:ThrowMissingRegistrationErrors=` is to throw an error, which will potentially end the program execution. + To get an overview of all places in your code where missing registrations occur, including a small stack trace, without committing to the strict behavior you can add `-XX:MissingRegistrationReportingMode=Warn` to the program invocation. + To detect places where the application accidentally swallows a missing registration error (such as with blanket `catch (Throwable t)` blocks), you can add `-XX:MissingRegistrationReportingMode=Exit` to the program invocation. + The application will then unconditionally print the error message and stack trace and exit immediately without throwing. ### Further Reading diff --git a/substratevm/CHANGELOG.md b/substratevm/CHANGELOG.md index 7c4bc8d6b6259..b40ae73eeb2e4 100644 --- a/substratevm/CHANGELOG.md +++ b/substratevm/CHANGELOG.md @@ -12,6 +12,7 @@ This changelog summarizes major changes to GraalVM Native Image. * (GR-52030) Add a stable name for `Proxy` types in Native Image. The name `$Proxy[id]` is replaced by `$Proxy.s[hashCode]` where `hashCode` is computed using the names of the `Proxy` interfaces, the name of the class loader and the name of the module if it is not a dynamic module. * (GR-47712) Using the `--static` option without the `--libc=musl` option causes the build process to fail (and reports the appropriate error). Static linking is currently only supported with musl. * (GR-50434) Introduce a `"type"` field in reflection and JNI configuration files to support more than simple named types. +* (GR-52314) `-XX:MissingRegistrationReportingMode` can now be used on program invocation instead of as a build option, to avoid a rebuild when debugging missing registration errors. ## GraalVM for JDK 22 (Internal Version 24.0.0) * (GR-48304) Red Hat added support for the JFR event ThreadAllocationStatistics. diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/MissingRegistrationUtils.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/MissingRegistrationUtils.java index ec60a51a9e776..a6a4977952c28 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/MissingRegistrationUtils.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/MissingRegistrationUtils.java @@ -24,11 +24,10 @@ */ package com.oracle.svm.core; -import static com.oracle.svm.core.SubstrateOptions.ReportingMode.Warn; - import java.io.Serial; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicReference; import com.oracle.svm.core.util.ExitStatus; @@ -46,7 +45,7 @@ public static SubstrateOptions.ReportingMode missingRegistrationReportingMode() private static final int CONTEXT_LINES = 4; - private static final Set seenOutputs = SubstrateOptions.MissingRegistrationReportingMode.getValue() == Warn ? ConcurrentHashMap.newKeySet() : null; + private static final AtomicReference> seenOutputs = new AtomicReference<>(null); public static void report(Error exception, StackTraceElement responsibleClass) { if (responsibleClass != null && !MissingRegistrationSupport.singleton().reportMissingRegistrationErrors(responsibleClass)) { @@ -93,13 +92,13 @@ public static void report(Error exception, StackTraceElement responsibleClass) { break; } } - if (seenOutputs.isEmpty()) { + if (seenOutputs.get() == null && seenOutputs.compareAndSet(null, ConcurrentHashMap.newKeySet())) { /* First output, we print an explanation message */ System.out.println("Note: this run will print partial stack traces of the locations where a " + exception.getClass().toString() + " would be thrown " + "when the -H:+ThrowMissingRegistrationErrors option is set. The trace stops at the first entry of JDK code and provides " + CONTEXT_LINES + " lines of context."); } String output = sb.toString(); - if (seenOutputs.add(output)) { + if (seenOutputs.get().add(output)) { System.out.print(output); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java index 584df260cb63b..f0cf38ed4803d 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java @@ -1036,7 +1036,7 @@ public enum ReportingMode { "\"Throw\" (default): Throw a MissingReflectionRegistrationError;", "\"Exit\": Call System.exit() to avoid accidentally catching the error;", "\"Warn\": Print a message to stdout, including a stack trace to see what caused the issue."})// - public static final HostedOptionKey MissingRegistrationReportingMode = new HostedOptionKey<>( + public static final RuntimeOptionKey MissingRegistrationReportingMode = new RuntimeOptionKey<>( ReportingMode.Throw); @Option(help = "Instead of warning, throw IOExceptions for link-at-build-time resources at build time")//