[GR-76332] Preserve reflection linkage errors.#13738
Open
graalvmbot wants to merge 3 commits into
Open
Conversation
9bc9577 to
b01854e
Compare
b01854e to
e61e114
Compare
e61e114 to
e51a954
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary:
Native Image now preserves JVM reflection lookup failures when registered reflection metadata refers to missing classes. The image build records the query-level LinkageError that core reflection would produce, then rethrows it from the generated image instead of returning incomplete metadata or failing while encoding metadata.
What was failing before:
A user can compile an application while a signature type is present, then run or build it in an environment where that signature type is missing. Core reflection resolves some signature types lazily, so the class itself can still load, but a metadata query fails when it tries to expose the missing type.
For example, each of these JVM reflection queries can fail independently:
Before this change, Native Image could diverge from the JVM. Some generated images returned successful metadata where the JVM would throw LinkageError. The record-component variant also exposed a hosted encoding problem: the build tried to call Class#getRecordComponents() while encoding metadata, so it failed with NoClassDefFoundError before it could preserve the lookup error for run time.
Reproducer:
Create this source file:
Compile it, then remove only the referenced signature type:
The JVM behavior is that the individual reflection queries throw LinkageError:
Register the same metadata for Native Image:
[ { "name": "BrokenMethods", "allDeclaredMethods": true }, { "name": "BrokenFields", "allDeclaredFields": true }, { "name": "BrokenConstructors", "allDeclaredConstructors": true }, { "name": "BrokenRecord", "allRecordComponents": true } ]Build and run the image:
Expected behavior:
The generated image should match the JVM: each affected query rethrows LinkageError. It should not silently return partial metadata, and it should not fail during image generation while trying to materialize record components whose component type is missing.
Key architectural changes:
ReflectionDataBuilder now treats reflection lookup failures as part of the metadata contract. When it probes core reflection behavior during analysis, it stores query-specific failures on TypeData:
RuntimeMetadataEncoderImpl then consumes these through ReflectionHostedSupport alongside the materialized metadata:
For record components, ReflectionHostedSupport#getRecordComponents now has an explicit split in meaning:
getRecordComponents returns only metadata that can be safely materialized during image building. If Class#getRecordComponents() is supposed to fail for a type, the encoder must read getRecordComponentLookupErrors() instead. This prevents hosted metadata materialization from bypassing the preserved-error path.
Why multiple fields are needed:
The JVM APIs fail independently. A class can have a broken field signature while its methods and constructors are still queryable:
A single LinkageError field on TypeData would be wrong in one of two ways:
The separate fields preserve the behavior of each Class API entry point exactly. They also keep partial metadata usable when only one lookup family is broken, which matches the JVM and avoids making unrelated reflection queries fail in the generated image.