Skip to content

Conversation

@jormundur00
Copy link
Member

@jormundur00 jormundur00 commented Nov 10, 2025

In this PR we add the Maven mojo and Gradle task for generating and providing to the native image build classpath a dynamic-access-metadata.json file, when emitting a Build Report (when the --emit build-report build argument is present) and the used release of the graalvm-reachability-metadata repository contains the library-and-framework-list.json file.

The generated JSON file maps all of the artifacts present on the classpath that exist in the library-and-framework-list.json to the list of their transitive dependencies (as they are marked as "metadata provided-for" by the parent artifact). It is later used by the dynamic access tab of the native image Build Report to mark these "provided-for" dependencies as being covered by native image and not "needing investigation". The JSON file follows the schema at: https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/assets/dynamic-access-metadata-schema-v1.0.0.json.

Both the Maven mojo and the Gradle task can be ran standalone, but will automatically run when emitting a Build Report and running the native image build mojo/task.

Fixes: #801.

@oracle-contributor-agreement
Copy link

Thank you for your pull request and welcome to our community! To contribute, please sign the Oracle Contributor Agreement (OCA).
The following contributors of this PR have not signed the OCA:

  • PR author: jormundur00

To sign the OCA, please create an Oracle account and sign the OCA in Oracle's Contributor Agreement Application.

When signing the OCA, please provide your GitHub username. After signing the OCA and getting an OCA approval from Oracle, this PR will be automatically updated.

If you are an Oracle employee, please make sure that you are a member of the main Oracle GitHub organization, and your membership in this organization is public.

@oracle-contributor-agreement oracle-contributor-agreement bot added the OCA Required At least one contributor does not have an approved Oracle Contributor Agreement. label Nov 10, 2025
});
}

public Path getRepositoryDirectory() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ Should probably return Optional<Path> instead, so that we don't have to figure out if null is expected or not.

private static final String PROVIDES_FOR = "providesFor";

@Internal
public abstract Property<Configuration> getRuntimeClasspath();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ This is not compatible with Gradle's configuration cache. We shouldn't use Configuration as input (probably a Property<ResolvedComponentResult>).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've since moved to the usage of Property<ResolvedComponentResult> and SetProperty<ResolvedArtifactResult> (trying to follow the pattern you used when setting properties for the CollectReachabilityMetadata task to be safe).

Set<File> classpathEntries = runtimeClasspathConfig.getFiles();

Map<String, Set<String>> exportMap = buildExportMap(
runtimeClasspathConfig.getResolvedConfiguration().getFirstLevelModuleDependencies(),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ You should use a dependency graph as input instead. This isn't compatible with the configuration cache.

* entry in the {@value #LIBRARY_AND_FRAMEWORK_LIST} file.
*/
private Set<String> readArtifacts(File inputFile) throws IOException {
Set<String> artifacts = new HashSet<>();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should probably use a LinkedHashSet so that the result is consistent across invocations.

tasks,
deriveTaskName(binaryName, "generate", "DynamicAccessMetadata"));
imageBuilder.configure(buildImageTask -> {
if (buildImageTask.getOptions().get().getBuildArgs().get().stream()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ This is likely to fail, because you are reading the build arguments during configuration of a task, which is non deterministic (depends on when the build args are changed in a script). Either the reasoning has to be deferred to execution time, based on the actual arguments, or it should use a non eager transformation (not use .get() but .map).

}

dependencies {
implementation libs.openjson
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ The Gradle plugin shouldn't have a direct dependency on openjson. The common utils should have one, but there's no reason the Gradle plugin should directly depend on it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've created a separate DynamicAccessMetadataUtils class where I do this serialization and JSON parsing (which I left in the commons.utils package), so now I don't add this direct dependency on openjson here anymore.

FYI: Not sure if the same applies for the native-maven-plugin, but in the build.gradle.kts for it, we already depend on both libs.utils and libs.openjson.

@jormundur00 jormundur00 changed the title Generate dynamic access metadata and provide it to the classpath when emitting a Build Report Generate dynamic access metadata and provide it to the classpath when emitting a Build Report (passing "--emit build-report" as a build argument)) Nov 10, 2025
@oracle-contributor-agreement oracle-contributor-agreement bot added OCA Verified All contributors have signed the Oracle Contributor Agreement. and removed OCA Required At least one contributor does not have an approved Oracle Contributor Agreement. labels Nov 10, 2025
@jormundur00 jormundur00 changed the title Generate dynamic access metadata and provide it to the classpath when emitting a Build Report (passing "--emit build-report" as a build argument)) Generate dynamic access metadata and provide it to the classpath when passing "--emit build-report" as a build argument Nov 10, 2025
@jormundur00 jormundur00 requested a review from melix November 13, 2025 11:36
@jormundur00 jormundur00 requested a review from vjovanov November 20, 2025 13:24
@jormundur00
Copy link
Member Author

Hey @melix, I've refactored the code to align with your requested changes, so please take another look when you have the time.

}

@Internal
public abstract Property<ResolvedComponentResult> getRuntimeClasspathGraph();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think these are really internal, right? Internal means used internally but without influencing the inputs. If the graph changes, I assume that this has to be taken into account?

@jormundur00 jormundur00 force-pushed the jvukicev/dynamic-access-metadata branch from d4b8af7 to 7d13364 Compare November 27, 2025 14:12
@jormundur00 jormundur00 merged commit 54db68c into graalvm:master Nov 28, 2025
190 checks passed
@melix
Copy link
Collaborator

melix commented Nov 28, 2025

I was thinking that maybe instead of complicated logic to figure out if --emit-build-report is used, this should be the other way around: add a DSL argument Property<Boolean> emitBuildReport and simply use that. That would be the idiomatic Gradle way I think: a DSL flag determines what behavior to expect and the build tool generates the proper arguments. If the feature is not directly related to emitting a build report, maybe we should have a generateDynamicAccessMetadata which, if enabled, makes sure that --emit-build-report is added. In general in Gradle we want to avoid explicit arguments: buildArgs should be restricted to "unusual" args or things we can't figure out.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

OCA Verified All contributors have signed the Oracle Contributor Agreement.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Generate dynamic access metadata when emitting a build report

3 participants