@groovy.transform.CompileStatic @org.gradle.work.DisableCachingByDefault(because: Records what a run of the application did, which is not an output of its inputs) abstract class TraceNativeMetadataTask extends DefaultTask
Runs the application under GraalVM's tracing agent and writes down the reflection it did.
GenerateNativeMetadataTask records an application's own artefacts by reading the build
output, which needs no run and misses nothing of the application's. What it cannot know is the
framework's own reflection along a request path -- a controller method reached through Groovy's
dispatch, a conversion asked for while binding a form -- because none of that is in the
application's classes. An image built without it starts, serves its home page, and fails on the
request that first takes such a path.
The agent records exactly that, and records only what ran. So the paths are declared rather than discovered, and what is not listed is not covered:
grails {
nativeMetadata {
paths = ['/', '/login', '/book', '/book/create']
forms = ['/book/create']
}
}
A form is asked for, read, and submitted with the fields it declares, because posting fewer than it declares records less than the application does. A checkbox is a string on the wire and a boolean on the domain class, so a form submitted without one never asks the conversion service anything -- and an image built from that trace fails the first time someone ticks a box.
Forms are submitted before paths are asked for, and the session one establishes is carried through the rest of the trace. A page behind a login is reached by listing the login form, which makes the pages named after it reachable:
grails {
nativeMetadata {
forms = ['/login?username=admin&password=secret', '/book/create']
paths = ['/', '/book']
}
}
Where a page carries more than one form -- a layout's search or sign-out beside the page's own
-- the one declaring the most fields is submitted, and which it was is reported. A page whose
wanted form is not the fullest names it: '/book/create#bookForm'.
Written to the application's sources rather than to the build directory: what an image was built from should be reviewable, and a trace is only as good as the paths someone thought of.
| Constructor and description |
|---|
TraceNativeMetadataTask() |
| Type Params | Return Type | Name and description |
|---|---|---|
|
abstract RegularFileProperty |
getArchiveFile()The archive to run, which has to be the one the image will be built from. |
|
abstract ListProperty<java.lang.String> |
getForms()Pages whose form is to be filled in and submitted. |
|
abstract Property<java.lang.String> |
getJavaExecutable()A java from a GraalVM. |
|
abstract ListProperty<java.lang.String> |
getJvmArguments() |
|
abstract DirectoryProperty |
getOutputDirectory()Where the agent merges what it recorded. |
|
abstract ListProperty<java.lang.String> |
getPaths()Paths to ask for. |
|
abstract Property<java.lang.Integer> |
getPort() |
|
abstract Property<java.lang.Integer> |
getStartTimeoutSeconds() |
|
void |
trace() |
The archive to run, which has to be the one the image will be built from.
Pages whose form is to be filled in and submitted.
A java from a GraalVM. The agent ships with GraalVM rather than with a JDK, and an application built for an image is compiled for GraalVM's Java -- so the JDK that runs the build is usually neither, and running the trace on it fails at load or refuses the class file.
Where the agent merges what it recorded. Not declared as an output: it is in the application's sources, and a directory Gradle believes it owns is a directory Gradle will delete.
Paths to ask for.