When the repository doesn’t have reachability metadata for a library you are using, the easiest way to generate it is to execute the test suite of the library with the Native Image Agent enabled. The agent is installed together with native-image and can be used to identify elements used during application execution that cannot be discovered by static analysis.
Libraries using Gradle (and in the future Maven) can leverage the Native Build Tools to automatically enable the agent, to collect the metadata from the appropriate tasks/targets.
Gradle users can configure the agent by adding the following block:
graalvmNative {
agent {
defaultMode = "conditional"
modes {
conditional {
userCodeFilterPath = "user-code-filter.json"
}
}
metadataCopy {
mergeWithExisting = true
inputTaskNames.add("test")
outputDirectories.add("src/main/resources/META-INF/native-image/acme")
}
}
}
To run the test task with the agent, run ./gradlew -Pagent
test. This will generate metadata in the build output directory of the project (under build/native/agent/test
).
The metadataCopy
task copies, and optionally merges, metadata into the project specified by the output directories. This task can also be configured on the command line: ./gradlew metadataCopy --task test --dir src/main/resources/META-INF/native-image/acme
.
The conditional mode requires the users to pass an agent filter file that tells the agent which classes belong to the target library. This filter file has the same format as other agent filter files. Conditions will only be generated on classes whose names are matched by this filter.
A sample filter file (user-code-filter.json) for a library whose classes are all contained in com.acme
:
{
"rules": [
{"excludeClasses": "**"},
{"includeClasses": "com.acme.**"}
]
}
The collected metadata can further be filtered by setting extraFilterPath
in the agent block:
graalvmNative {
agent {
modes {
conditional {
userCodeFilterPath = "user-code-filter.json"
extraFilterPath = "extra-code-filter.json"
}
}
}
The filter excludes conditions and metadata that it matches. This allows easy filtering of irrelevant classes, e.g., classes used only during testing like Mockito mocks.
Conditional metadata can be generated by inserting the Native Image Agent options into the command line of the JVM that runs the tests.
To enable the agent, add the following to the java
command line:
java -agentlib:native-image-agent=config-output-dir=metadata/{pid},experimental-conditional-config-part ...
When the JVM exits, the agent will output metadata with additional information into the metadata/{jvm-pid}
directory.
The output directory in the above command line depends on the PID of the running JVM.
This is especially useful when the build tool runs multiple JVMs concurrently.
To produce conditional metadata, use the native-image-configure
tool and pass the agent output directories:
native-image-configure generate-conditional --user-code-filter=user-code-filter.json --class-name-filter=extra-code-filter.json --input-dir=<agent-output-dir> --input-dir=<agent-output-dir-2>... --output-dir=final-metadata/
The used filters have the same meaning as filters specified in the Gradle agent DSL block above.
The best thing for the community is to include the generated metadata and build file changes into the library itself. Before creating a PR to the library:
- Copy the metadata to the project sources under META-INF/native-image/artifact.id with
metadataCopy
. - Introduce a CI task that tests the library with the newly added metadata.
If the library maintainers do not accept the change, the next best thing is to open a ticket on the library’s issue tracker so the community can upvote this feature. In the meantime, you can open a PR to this repository. See how to contribute.