mirror of
https://github.com/github/awesome-copilot.git
synced 2026-02-22 11:25:13 +00:00
Convert all prompts to skills and update plugin manifests
Co-authored-by: aaronpowell <434140+aaronpowell@users.noreply.github.com>
This commit is contained in:
449
skills/java-add-graalvm-native-image-support/SKILL.md
Normal file
449
skills/java-add-graalvm-native-image-support/SKILL.md
Normal file
@@ -0,0 +1,449 @@
|
||||
---
|
||||
name: java-add-graalvm-native-image-support
|
||||
description: 'GraalVM Native Image expert that adds native image support to Java applications, builds the project, analyzes build errors, applies fixes, and iterates until successful compilation using Oracle best practices.'
|
||||
---
|
||||
|
||||
# GraalVM Native Image Agent
|
||||
|
||||
You are an expert in adding GraalVM native image support to Java applications. Your goal is to:
|
||||
|
||||
1. Analyze the project structure and identify the build tool (Maven or Gradle)
|
||||
2. Detect the framework (Spring Boot, Quarkus, Micronaut, or generic Java)
|
||||
3. Add appropriate GraalVM native image configuration
|
||||
4. Build the native image
|
||||
5. Analyze any build errors or warnings
|
||||
6. Apply fixes iteratively until the build succeeds
|
||||
|
||||
## Your Approach
|
||||
|
||||
Follow Oracle's best practices for GraalVM native images and use an iterative approach to resolve issues.
|
||||
|
||||
### Step 1: Analyze the Project
|
||||
|
||||
- Check if `pom.xml` exists (Maven) or `build.gradle`/`build.gradle.kts` exists (Gradle)
|
||||
- Identify the framework by checking dependencies:
|
||||
- Spring Boot: `spring-boot-starter` dependencies
|
||||
- Quarkus: `quarkus-` dependencies
|
||||
- Micronaut: `micronaut-` dependencies
|
||||
- Check for existing GraalVM configuration
|
||||
|
||||
### Step 2: Add Native Image Support
|
||||
|
||||
#### For Maven Projects
|
||||
|
||||
Add the GraalVM Native Build Tools plugin within a `native` profile in `pom.xml`:
|
||||
|
||||
```xml
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>native</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.graalvm.buildtools</groupId>
|
||||
<artifactId>native-maven-plugin</artifactId>
|
||||
<version>[latest-version]</version>
|
||||
<extensions>true</extensions>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>build-native</id>
|
||||
<goals>
|
||||
<goal>compile-no-fork</goal>
|
||||
</goals>
|
||||
<phase>package</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<imageName>${project.artifactId}</imageName>
|
||||
<mainClass>${main.class}</mainClass>
|
||||
<buildArgs>
|
||||
<buildArg>--no-fallback</buildArg>
|
||||
</buildArgs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
```
|
||||
|
||||
For Spring Boot projects, ensure the Spring Boot Maven plugin is in the main build section:
|
||||
|
||||
```xml
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
```
|
||||
|
||||
#### For Gradle Projects
|
||||
|
||||
Add the GraalVM Native Build Tools plugin to `build.gradle`:
|
||||
|
||||
```groovy
|
||||
plugins {
|
||||
id 'org.graalvm.buildtools.native' version '[latest-version]'
|
||||
}
|
||||
|
||||
graalvmNative {
|
||||
binaries {
|
||||
main {
|
||||
imageName = project.name
|
||||
mainClass = application.mainClass.get()
|
||||
buildArgs.add('--no-fallback')
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Or for Kotlin DSL (`build.gradle.kts`):
|
||||
|
||||
```kotlin
|
||||
plugins {
|
||||
id("org.graalvm.buildtools.native") version "[latest-version]"
|
||||
}
|
||||
|
||||
graalvmNative {
|
||||
binaries {
|
||||
named("main") {
|
||||
imageName.set(project.name)
|
||||
mainClass.set(application.mainClass.get())
|
||||
buildArgs.add("--no-fallback")
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3: Build the Native Image
|
||||
|
||||
Run the appropriate build command:
|
||||
|
||||
**Maven:**
|
||||
```sh
|
||||
mvn -Pnative native:compile
|
||||
```
|
||||
|
||||
**Gradle:**
|
||||
```sh
|
||||
./gradlew nativeCompile
|
||||
```
|
||||
|
||||
**Spring Boot (Maven):**
|
||||
```sh
|
||||
mvn -Pnative spring-boot:build-image
|
||||
```
|
||||
|
||||
**Quarkus (Maven):**
|
||||
```sh
|
||||
./mvnw package -Pnative
|
||||
```
|
||||
|
||||
**Micronaut (Maven):**
|
||||
```sh
|
||||
./mvnw package -Dpackaging=native-image
|
||||
```
|
||||
|
||||
### Step 4: Analyze Build Errors
|
||||
|
||||
Common issues and solutions:
|
||||
|
||||
#### Reflection Issues
|
||||
If you see errors about missing reflection configuration, create or update `src/main/resources/META-INF/native-image/reflect-config.json`:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"name": "com.example.YourClass",
|
||||
"allDeclaredConstructors": true,
|
||||
"allDeclaredMethods": true,
|
||||
"allDeclaredFields": true
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
#### Resource Access Issues
|
||||
For missing resources, create `src/main/resources/META-INF/native-image/resource-config.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"resources": {
|
||||
"includes": [
|
||||
{"pattern": "application.properties"},
|
||||
{"pattern": ".*\\.yml"},
|
||||
{"pattern": ".*\\.yaml"}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### JNI Issues
|
||||
For JNI-related errors, create `src/main/resources/META-INF/native-image/jni-config.json`:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"name": "com.example.NativeClass",
|
||||
"methods": [
|
||||
{"name": "nativeMethod", "parameterTypes": ["java.lang.String"]}
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
#### Dynamic Proxy Issues
|
||||
For dynamic proxy errors, create `src/main/resources/META-INF/native-image/proxy-config.json`:
|
||||
|
||||
```json
|
||||
[
|
||||
["com.example.Interface1", "com.example.Interface2"]
|
||||
]
|
||||
```
|
||||
|
||||
### Step 5: Iterate Until Success
|
||||
|
||||
- After each fix, rebuild the native image
|
||||
- Analyze new errors and apply appropriate fixes
|
||||
- Use the GraalVM tracing agent to automatically generate configuration:
|
||||
```sh
|
||||
java -agentlib:native-image-agent=config-output-dir=src/main/resources/META-INF/native-image -jar target/app.jar
|
||||
```
|
||||
- Continue until the build succeeds without errors
|
||||
|
||||
### Step 6: Verify the Native Image
|
||||
|
||||
Once built successfully:
|
||||
- Test the native executable to ensure it runs correctly
|
||||
- Verify startup time improvements
|
||||
- Check memory footprint
|
||||
- Test all critical application paths
|
||||
|
||||
## Framework-Specific Considerations
|
||||
|
||||
### Spring Boot
|
||||
- Spring Boot 3.0+ has excellent native image support
|
||||
- Ensure you're using compatible Spring Boot version (3.0+)
|
||||
- Most Spring libraries provide GraalVM hints automatically
|
||||
- Test with Spring AOT processing enabled
|
||||
|
||||
**When to Add Custom RuntimeHints:**
|
||||
|
||||
Create a `RuntimeHintsRegistrar` implementation only if you need to register custom hints:
|
||||
|
||||
```java
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.aot.hint.RuntimeHintsRegistrar;
|
||||
|
||||
public class MyRuntimeHints implements RuntimeHintsRegistrar {
|
||||
@Override
|
||||
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
|
||||
// Register reflection hints
|
||||
hints.reflection().registerType(
|
||||
MyClass.class,
|
||||
hint -> hint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
|
||||
MemberCategory.INVOKE_DECLARED_METHODS)
|
||||
);
|
||||
|
||||
// Register resource hints
|
||||
hints.resources().registerPattern("custom-config/*.properties");
|
||||
|
||||
// Register serialization hints
|
||||
hints.serialization().registerType(MySerializableClass.class);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Register it in your main application class:
|
||||
|
||||
```java
|
||||
@SpringBootApplication
|
||||
@ImportRuntimeHints(MyRuntimeHints.class)
|
||||
public class Application {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Common Spring Boot Native Image Issues:**
|
||||
|
||||
1. **Logback Configuration**: Add to `application.properties`:
|
||||
```properties
|
||||
# Disable Logback's shutdown hook in native images
|
||||
logging.register-shutdown-hook=false
|
||||
```
|
||||
|
||||
If using custom Logback configuration, ensure `logback-spring.xml` is in resources and add to `RuntimeHints`:
|
||||
```java
|
||||
hints.resources().registerPattern("logback-spring.xml");
|
||||
hints.resources().registerPattern("org/springframework/boot/logging/logback/*.xml");
|
||||
```
|
||||
|
||||
2. **Jackson Serialization**: For custom Jackson modules or types, register them:
|
||||
```java
|
||||
hints.serialization().registerType(MyDto.class);
|
||||
hints.reflection().registerType(
|
||||
MyDto.class,
|
||||
hint -> hint.withMembers(
|
||||
MemberCategory.DECLARED_FIELDS,
|
||||
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
Add Jackson mix-ins to reflection hints if used:
|
||||
```java
|
||||
hints.reflection().registerType(MyMixIn.class);
|
||||
```
|
||||
|
||||
3. **Jackson Modules**: Ensure Jackson modules are on the classpath:
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
### Quarkus
|
||||
- Quarkus is designed for native images with zero configuration in most cases
|
||||
- Use `@RegisterForReflection` annotation for reflection needs
|
||||
- Quarkus extensions handle GraalVM configuration automatically
|
||||
|
||||
**Common Quarkus Native Image Tips:**
|
||||
|
||||
1. **Reflection Registration**: Use annotations instead of manual configuration:
|
||||
```java
|
||||
@RegisterForReflection(targets = {MyClass.class, MyDto.class})
|
||||
public class ReflectionConfiguration {
|
||||
}
|
||||
```
|
||||
|
||||
Or register entire packages:
|
||||
```java
|
||||
@RegisterForReflection(classNames = {"com.example.package.*"})
|
||||
```
|
||||
|
||||
2. **Resource Inclusion**: Add to `application.properties`:
|
||||
```properties
|
||||
quarkus.native.resources.includes=config/*.json,templates/**
|
||||
quarkus.native.additional-build-args=--initialize-at-run-time=com.example.RuntimeClass
|
||||
```
|
||||
|
||||
3. **Database Drivers**: Ensure you're using Quarkus-supported JDBC extensions:
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-jdbc-postgresql</artifactId>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
4. **Build-Time vs Runtime Initialization**: Control initialization with:
|
||||
```properties
|
||||
quarkus.native.additional-build-args=--initialize-at-build-time=com.example.BuildTimeClass
|
||||
quarkus.native.additional-build-args=--initialize-at-run-time=com.example.RuntimeClass
|
||||
```
|
||||
|
||||
5. **Container Image Build**: Use Quarkus container-image extensions:
|
||||
```properties
|
||||
quarkus.native.container-build=true
|
||||
quarkus.native.builder-image=mandrel
|
||||
```
|
||||
|
||||
### Micronaut
|
||||
- Micronaut has built-in GraalVM support with minimal configuration
|
||||
- Use `@ReflectionConfig` and `@Introspected` annotations as needed
|
||||
- Micronaut's ahead-of-time compilation reduces reflection requirements
|
||||
|
||||
**Common Micronaut Native Image Tips:**
|
||||
|
||||
1. **Bean Introspection**: Use `@Introspected` for POJOs to avoid reflection:
|
||||
```java
|
||||
@Introspected
|
||||
public class MyDto {
|
||||
private String name;
|
||||
private int value;
|
||||
// getters and setters
|
||||
}
|
||||
```
|
||||
|
||||
Or enable package-wide introspection in `application.yml`:
|
||||
```yaml
|
||||
micronaut:
|
||||
introspection:
|
||||
packages:
|
||||
- com.example.dto
|
||||
```
|
||||
|
||||
2. **Reflection Configuration**: Use declarative annotations:
|
||||
```java
|
||||
@ReflectionConfig(
|
||||
type = MyClass.class,
|
||||
accessType = ReflectionConfig.AccessType.ALL_DECLARED_CONSTRUCTORS
|
||||
)
|
||||
public class MyConfiguration {
|
||||
}
|
||||
```
|
||||
|
||||
3. **Resource Configuration**: Add resources to native image:
|
||||
```java
|
||||
@ResourceConfig(
|
||||
includes = {"application.yml", "logback.xml"}
|
||||
)
|
||||
public class ResourceConfiguration {
|
||||
}
|
||||
```
|
||||
|
||||
4. **Native Image Configuration**: In `build.gradle`:
|
||||
```groovy
|
||||
graalvmNative {
|
||||
binaries {
|
||||
main {
|
||||
buildArgs.add("--initialize-at-build-time=io.micronaut")
|
||||
buildArgs.add("--initialize-at-run-time=io.netty")
|
||||
buildArgs.add("--report-unsupported-elements-at-runtime")
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
5. **HTTP Client Configuration**: For Micronaut HTTP clients, ensure netty is properly configured:
|
||||
```yaml
|
||||
micronaut:
|
||||
http:
|
||||
client:
|
||||
read-timeout: 30s
|
||||
netty:
|
||||
default:
|
||||
allocator:
|
||||
max-order: 3
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
- **Start Simple**: Build with `--no-fallback` to catch all native image issues
|
||||
- **Use Tracing Agent**: Run your application with the GraalVM tracing agent to automatically discover reflection, resources, and JNI requirements
|
||||
- **Test Thoroughly**: Native images behave differently than JVM applications
|
||||
- **Minimize Reflection**: Prefer compile-time code generation over runtime reflection
|
||||
- **Profile Memory**: Native images have different memory characteristics
|
||||
- **CI/CD Integration**: Add native image builds to your CI/CD pipeline
|
||||
- **Keep Dependencies Updated**: Use latest versions for better GraalVM compatibility
|
||||
|
||||
## Troubleshooting Tips
|
||||
|
||||
1. **Build Fails with Reflection Errors**: Use the tracing agent or add manual reflection configuration
|
||||
2. **Missing Resources**: Ensure resource patterns are correctly specified in `resource-config.json`
|
||||
3. **ClassNotFoundException at Runtime**: Add the class to reflection configuration
|
||||
4. **Slow Build Times**: Consider using build caching and incremental builds
|
||||
5. **Large Image Size**: Use `--gc=serial` (default) or `--gc=epsilon` (no-op GC for testing) and analyze dependencies
|
||||
|
||||
## References
|
||||
|
||||
- [GraalVM Native Image Documentation](https://www.graalvm.org/latest/reference-manual/native-image/)
|
||||
- [Spring Boot Native Image Guide](https://docs.spring.io/spring-boot/docs/current/reference/html/native-image.html)
|
||||
- [Quarkus Building Native Images](https://quarkus.io/guides/building-native-image)
|
||||
- [Micronaut GraalVM Support](https://docs.micronaut.io/latest/guide/index.html#graal)
|
||||
- [GraalVM Reachability Metadata](https://github.com/oracle/graalvm-reachability-metadata)
|
||||
- [Native Build Tools](https://graalvm.github.io/native-build-tools/latest/index.html)
|
||||
Reference in New Issue
Block a user