GraalVM Hint Processor helps generate GraalVM hints for building native-image applications.
Fully AOT processing library, no dependencies, no runtime side-affects.
Features:
- Generate Reflection Hints (reflect-config.json)
- Generate Resource Hints (resource-config.json)
- Generate Options Hints (native-image.properties)
- Generate Initialization Hints (native-image.properties)
- Generate Dynamic Proxy Hints (dynamic-proxy-hint.json)
- Generate JNI Hints (jni-config.json)
- Generate Link Build Hints (native-image.properties)
annotationProcessor "io.goodforgod:graalvm-hint-processor:1.2.0"
compileOnly "io.goodforgod:graalvm-hint-annotations:1.2.0"
<dependencies>
<dependency>
<groupId>io.goodforgod</groupId>
<artifactId>graalvm-hint-annotations</artifactId>
<version>1.2.0</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.goodforgod</groupId>
<artifactId>graalvm-hint-processor</artifactId>
<version>1.2.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>io.goodforgod</groupId>
<artifactId>graalvm-hint-processor</artifactId>
<version>1.2.0</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
- @ReflectionHint
- @ResourceHint
- @NativeImageHint
- @InitializationHint
- @DynamicProxyHint
- @JniHint
- @LinkHint
- Group & Artifact name
You can read more about GraalVM reflection configuration in official documentation here.
There are available access hints:
- allPublicFields
- allPublicMethods
- allPublicConstructors
- allDeclaredFields
- allDeclaredMethods
- allDeclaredConstructors
Generating reflection access, most used cases is DTOs that are used for serialization/deserialization in any format (JSON for example).
Simple case for single Java class:
@ReflectionHint
public class RequestOnly {
private String name;
}
Generated reflection-config.json:
[{
"name": "io.goodforgod.graalvm.hint.processor.RequestOnly",
"allDeclaredConstructors": true,
"allDeclaredFields": true,
"allDeclaredMethods": true
}]
There may be more different cases, like generating hints for classes that are package private or just private, also there hint can be used for whole package.
Complex example generating reflection access:
@ReflectionHint(types = { Response.class, Request.class }, value = ReflectionHint.AccessType.ALL_DECLARED_FIELDS)
@ReflectionHint(typeNames = { "io.goodforgod.graalvm.hint.processor"})
public class ReflectionConfig {
private String name;
}
Generated reflection-config.json:
[{
"name": "io.goodforgod.graalvm.hint.processor",
"allDeclaredConstructors": true,
"allDeclaredFields": true,
"allDeclaredMethods": true
},
{
"name": "io.goodforgod.example.Response",
"allDeclaredFields": true
},
{
"name": "io.goodforgod.example.Request",
"allDeclaredFields": true
}]
You can read more about GraalVM resource configuration in official documentation here.
Hint allows generating config for resource files to be included/excluded when building native application. You can also include bundles into native image using this Hint.
Resource patterns specified with Java regexp to Include during native-image generation into the final application.
Include Hint:
@ResourceHint(include = { "simplelogger.properties", "application.yml", "*.xml" })
public class ResourceNames {
}
Generated resource-config.json:
{
"resources": {
"includes": [
{ "pattern" : "*.xml" },
{ "pattern": "application.yml" },
{ "pattern": "simplelogger.properties" }
]
}
}
Resource patterns specified with Java regexp to Exclude during native-image generation into the final application.
Exclude Hint:
@ResourceHint(exclude = { "*.xml" })
public class ResourceNames {
}
Generated resource-config.json:
{
"resources": {
"excludes": [
{ "pattern": "*.xml" }
]
}
}
Native Image needs ahead-of-time knowledge of the resource bundles your application needs so that it can load and store the appropriate bundles for usage in the generated binary.
Bundle Hint:
@ResourceHint(bundles = { "your.pkg.Bundle" })
public class ResourceNames {
}
Generated resource-config.json:
{
"bundles": [
{ "name": "your.pkg.Bundle" }
]
}
You can read more about GraalVM native-image options in official documentation here.
Hint allows generating config for native-image options and initial application entrypoint.
Simple hint configuration:
@NativeImageHint(entrypoint = EntrypointOnly.class)
public class EntrypointOnly {
public static void main(String[] args) {}
}
Generated native-image.properties:
Args = -H:Class=io.goodforgod.graalvm.hint.processor.EntrypointOnly
Complex hint configuration with options:
@NativeImageHint(entrypoint = Entrypoint.class, name = "myapp", options = { NativeImageOptions.PRINT_INITIALIZATION, NativeImageOptions.INLINE_BEFORE_ANALYSIS })
public class Entrypoint {
public static void main(String[] args) {}
}
Generated native-image.properties:
Args = -H:Class=io.goodforgod.graalvm.hint.processor.Entrypoint -H:Name=myapp \
-H:+PrintClassInitialization \
-H:+InlineBeforeAnalysis
You can read more about GraalVM initialization configuration in official documentation here.
Hint allows generating config for what classes to instantiate in runtime and what classes to instantiate in compile time.
Initialization hint configuration:
@InitializationHint(value = InitializationHint.InitPhase.BUILD, types = HintOptions.class)
@InitializationHint(value = InitializationHint.InitPhase.RUNTIME, typeNames = "io.goodforgod.graalvm.hint.processor")
public class EntrypointOnly {
}
Generated native-image.properties:
Args = --initialize-at-build-time=io.goodforgod.graalvm.hint.processor.HintOrigin.class \
--initialize-at-run-time=io.goodforgod.graalvm.hint.processor
Simple case for single Java class:
@InitializationHint
public class Self {
}
Generated native-image.properties:
Args = --initialize-at-build-time=io.goodforgod.graalvm.hint.processor.Self
You can read more about GraalVM DynamicProxyHint configuration in official documentation here.
Use can pass dynamic proxy resources (-H:DynamicProxyConfigurationResources) or files (-H:DynamicProxyConfigurationFiles) using corresponding options:
@DynamicProxyHint(resources = {"proxy-resource.json"}, files = {"proxy-file.json"})
public class Resource {
}
Generated native-image.properties:
Args = -H:DynamicProxyConfigurationFiles=proxy-file.json \
-H:DynamicProxyConfigurationResources=proxy-resource.json
You can fully configure proxy yourself using annotations only, without the need for manually creating JSON configurations.
@DynamicProxyHint(value = {
@DynamicProxyHint.Configuration(interfaces = {OptionParser.class, HintOrigin.class}),
@DynamicProxyHint.Configuration(interfaces = {HintOrigin.class})
})
public class Config {
}
Generated dynamic-proxy-hint-config.json:
[
{ "interfaces": [ "io.goodforgod.graalvm.hint.processor.OptionParser", "io.goodforgod.graalvm.hint.processor.HintOrigin" ] },
{ "interfaces": [ "io.goodforgod.graalvm.hint.processor.HintOrigin" ] }
]
Generated native-image.properties:
Args = -H:DynamicProxyConfigurationResources=META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/dynamic-proxy-config.json
In case you need to add only one interface for DynamicProxy Hint configuration, you can annotate that interface directly:
@DynamicProxyHint
public interface Self {
}
Generated dynamic-proxy-hint-config.json:
[
{ "interfaces": [ "io.goodforgod.graalvm.hint.processor.Self" ] }
]
Generated native-image.properties:
Args = -H:DynamicProxyConfigurationResources=META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/dynamic-proxy-config.json
You can read more about GraalVM JNI configuration in official documentation here.
There are available JNI access hints:
- allPublicFields
- allPublicMethods
- allPublicConstructors
- allDeclaredFields
- allDeclaredMethods
- allDeclaredConstructors
Simple case for single Java class:
@JniHint
public class RequestOnly {
private String name;
}
Generated jni-config.json:
[{
"name": "io.goodforgod.graalvm.hint.processor.RequestOnly",
"allDeclaredConstructors": true,
"allDeclaredFields": true,
"allDeclaredMethods": true
}]
There may be more different cases, like generating hints for classes that are package private or just private, also there hint can be used for whole package.
Complex example generating reflection access:
@JniHint(types = { Response.class, Request.class }, value = JniHint.AccessType.ALL_DECLARED_FIELDS)
@JniHint(typeNames = { "io.goodforgod.graalvm.hint.processor"})
public final class JniConfig {
}
Generated jni-config.json:
[{
"name": "io.goodforgod.graalvm.hint.processor",
"allDeclaredConstructors": true,
"allDeclaredFields": true,
"allDeclaredMethods": true
},
{
"name": "io.goodforgod.example.Response",
"allDeclaredFields": true
},
{
"name": "io.goodforgod.example.Request",
"allDeclaredFields": true
}]
You can read more about GraalVM Link Build configuration in official documentation here.
Hint is only available in GraalVM 22.1.0+, check this PR for more info.
Specify types to be fully defined at image build-time.
Simple case for single Java class:
@LinkHint
public class RequestOnly {
private String name;
}
Generated native-image.properties:
Args = --link-at-build-time=io.goodforgod.graalvm.hint.processor.RequestOnly
There may be more different cases, like generating hints for classes that are package private or just private, also there hint can be used for whole package.
Complex example generating link hints:
@LinkHint(types = { Response.class, Request.class })
@LinkHint(typeNames = { "io.goodforgod.graalvm.hint.processor"})
public final class JniConfig {
}
Generated native-image.properties:
Args = --link-at-build-time=io.goodforgod.graalvm.hint.processor,io.goodforgod.graalvm.hint.processor.Response,io.goodforgod.graalvm.hint.processor.Request
Is the same as using GraalVM flag without options.
If used without args, all classes in scope of the option are required to be fully defined.
Example how to force all classes to link in build time, no matter what how other class declare this hint, if any annotation with all = true found, then it will be used this way.
@LinkHint(all = true)
public class RequestOnly {
private String name;
}
Generated native-image.properties:
Args = --link-at-build-time
You can change the output group and artifact name, by default the group will be the package name where the annotated class was located and the artifact will be named hint.
For class:
package io.goodforgod.graalvm.hint.processor;
import io.goodforgod.graalvm.hint.annotation.ReflectionHint;
@ReflectionHint
public class Request {
private String name;
}
Hint will be generated into build/classes/java/main/META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/reflect-config.json
directory.
Where io.goodforgod.graalvm.hint.processor is group name and hint artifact name.
You can override default behavior and select our own group and artifact name via annotation processor options.
Annotation processor options:
- graalvm.hint.group - group name.
- graalvm.hint.artifact - artifact name.
Here are examples of configurations for Gradle and Maven.
Gradle
compileJava {
options.compilerArgs += [
"-Agraalvm.hint.group=my.group",
"-Agraalvm.hint.artifact=myartifact",
]
}
Maven
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
<configuration>
<parameters>true</parameters>
<compilerArgs>
<compilerArg>-Agraalvm.hint.group=my.group</compilerArg>
<compilerArg>-Agraalvm.hint.artifact=myartifact</compilerArg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
This project licensed under the Apache License 2.0 - see the LICENSE file for details