Class NativeImageMetadataGenerator
META-INF/native-image/org.apache.groovy/groovy/reachability-metadata.json
(GROOVY-12365), so that a dynamic Groovy application builds with plain
native-image and no agent step for anything the runtime does
on its own behalf.
Every entry is derived from what the runtime is known to do, rather than recorded by observing an application, and is conditional on the class that performs the access being reached (the metaclass registry, or the invokedynamic bootstrap), so a statically compiled program that links no dynamic call site carries none of it:
- The metaclass registry bootstrap (conditional on
MetaClassRegistryImpl). Creating the registry scans the static methods of the DGM method holders, instantiates the additional meta-method classes, loads every type named in the DGM records by name, and caches the receiver types; a parameter or return type is cached when a call is first selected. Caching an abstract type reads its methods, and those of its abstract superclasses and superinterfaces, to decide whether it is a single-abstract-method type. None of these classes is initialised yet when that happens, hence the registry condition. This is where JDK types appear: they are reflected over on every application's behalf. - The invokedynamic machinery (conditional on
IndyInterface). Its classes obtain method handles to their own methods and to a few JDK and MOP methods through aLookupheld in a run-time-initialised class, which the image builder cannot fold, so the targets are registered. - Default-import class discovery (conditional on
Java17).getDefaultImportClassesloadsGroovySystemandgroovy.beans.ListenerListby name to locate the groovy jar; those names are not constantClass.forNamearguments the image builder can fold. - Groovy-owned types that get a metaclass (conditional on the
registry too, since a metaclass can be created for a class before the class
initialises).
CachedClassreads their declared constructors, methods and fields, up the superclass chain, and the JDK's Introspector their public methods; every interface in the hierarchy is cached and SAM-checked. The types are the Groovy-owned DGM receivers and the runtime classes an ordinary dynamic program instantiates, such as its closure and range implementations. - Negative lookups by naming convention, for every type above that
gets a metaclass:
<Type>BeanInfoand<Type>Customizer(the Introspector) andgroovy.runtime.metaclass.<Type>MetaClass(the registry's custom metaclass lookup). Registering the absent names makes the lookups fail with theClassNotFoundExceptionthe callers expect rather than a missing-registration error.
--exact-reachability-metadata.
The tests-native subproject checks all of this against a probe
program: its checkNativeMetadata task fails on any Groovy-owned need
the native-image agent records that is not shipped, and its nativeRun
tasks build and run the probe as an image with nothing but this metadata for
Groovy's part.
Not emitted, deliberately: Class.forName calls with a constant name
(the image builder folds them, absent classes included); reflection over
the application's classes and the JDK types it uses dynamically; dynamic
proxies for closures coerced to interfaces; serialization. Those depend on
what the application does and remain the application's, or the
native-image agent's, responsibility.
- Since:
- 6.0.0
-
Field Summary
Fields -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionstatic voidThe build's entry point for a module:<artifactId> <targetDirectory> <extensionClasses> <staticExtensionClasses>, the class lists comma-separated and possibly empty.static Stringwrite(List<GeneratedMetaMethod.DgmMethodRecord> records, String targetDirectory) Writes the metadata file undertargetDirectory.static StringwriteForModule(String artifactId, List<Class<?>> instanceExtensions, List<Class<?>> staticExtensions, String targetDirectory) Writes the metadata of an extension module (a jar with aMETA-INF/groovy/org.codehaus.groovy.runtime.ExtensionModuledescriptor) undertargetDirectory, asMETA-INF/native-image/org.apache.groovy/<artifactId>/reachability-metadata.json.
-
Field Details
-
METADATA_DIRECTORY
The metadata directory inside the jar, per the GraalVM conventionMETA-INF/native-image/<groupId>/<artifactId>/.- See Also:
-
METADATA_FILE
- See Also:
-
-
Constructor Details
-
NativeImageMetadataGenerator
public NativeImageMetadataGenerator()
-
-
Method Details
-
write
public static String write(List<GeneratedMetaMethod.DgmMethodRecord> records, String targetDirectory) throws IOException Writes the metadata file undertargetDirectory.- Parameters:
records- the DGM recordsDgmConverterproducedtargetDirectory- the classes directory the jar is assembled from- Returns:
- the path of the file written
- Throws:
IOException
-
writeForModule
public static String writeForModule(String artifactId, List<Class<?>> instanceExtensions, List<Class<?>> staticExtensions, String targetDirectory) throws IOException Writes the metadata of an extension module (a jar with aMETA-INF/groovy/org.codehaus.groovy.runtime.ExtensionModuledescriptor) undertargetDirectory, asMETA-INF/native-image/org.apache.groovy/<artifactId>/reachability-metadata.json. The registry loads the descriptor's extension classes by name, scans their static methods and caches every type in those signatures, all while it bootstraps; the entries are conditional on the registry.- Parameters:
artifactId- the module's artifact id, e.g.groovy-nioinstanceExtensions- the descriptor'sextensionClassesstaticExtensions- the descriptor'sstaticExtensionClassestargetDirectory- the directory the jar is assembled from- Returns:
- the path of the file written
- Throws:
IOException
-
main
The build's entry point for a module:<artifactId> <targetDirectory> <extensionClasses> <staticExtensionClasses>, the class lists comma-separated and possibly empty. The classes are loaded without initialisation, so no Groovy runtime starts here.- Throws:
IOExceptionClassNotFoundException
-