Add graalvm-native-images: Boot 4.1 + GraalVM CE for JDK 25, AOT processing,

the tracing agent, and a real reflection-collision trap

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EQNA6DJ9VgCtW6zhCE8Xud
This commit is contained in:
Claude
2026-09-20 11:03:09 +00:00
parent e4b5636f7c
commit 8cdfcd4d8d
23 changed files with 627 additions and 0 deletions
@@ -0,0 +1,17 @@
package com.ankurm.graalvmdemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* Companion app for the ankurm.com GraalVM native images post. Built three ways from the same
* source: a plain {@code java -jar}, a Spring Boot AOT-processed JVM run, and a GraalVM native
* image. See docs/02-building-the-image.md for the exact commands behind each measurement.
*/
@SpringBootApplication
public class GraalvmDemoApplication {
public static void main(String[] args) {
SpringApplication.run(GraalvmDemoApplication.class, args);
}
}
@@ -0,0 +1,18 @@
package com.ankurm.graalvmdemo;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* The baseline endpoint used for every startup-time and memory measurement in this chapter --
* deliberately trivial, so the numbers reflect the framework and the runtime, not application
* work. See docs/01-building-the-image.md.
*/
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "Hello from a GraalVM native image!";
}
}
@@ -0,0 +1,8 @@
package com.ankurm.graalvmdemo.report;
public class JsonReport implements ReportFormat {
@Override
public String render(String message) {
return "{\"report\":\"" + message + "\"}";
}
}
@@ -0,0 +1,8 @@
package com.ankurm.graalvmdemo.report;
public class PlainTextReport implements ReportFormat {
@Override
public String render(String message) {
return "REPORT: " + message;
}
}
@@ -0,0 +1,29 @@
package com.ankurm.graalvmdemo.report;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* Loads a {@link ReportFormat} implementation by a class name built at request time from the
* {@code format} query parameter -- a stand-in for the real-world "pluggable strategy resolved by
* a string from configuration" pattern (a plugin name, a feature flag, a database column).
* Nothing here gives GraalVM's build-time static analysis a way to know which classes this
* reflective call can reach; see docs/02-the-reflection-trap.md for the real failure and its fix.
*/
@RestController
public class ReportController {
@GetMapping("/report")
public String report(@RequestParam(defaultValue = "plain") String format, @RequestParam(defaultValue = "quarterly numbers") String message) {
String simpleName = "plain".equals(format) ? "PlainTextReport" : "JsonReport";
String className = "com.ankurm.graalvmdemo.report." + simpleName;
try {
Class<?> clazz = Class.forName(className);
ReportFormat instance = (ReportFormat) clazz.getDeclaredConstructor().newInstance();
return "OK via reflection on " + className + ": " + instance.render(message);
} catch (ReflectiveOperationException e) {
return "REFLECTION-FAILED class=" + className + " exception=" + e.getClass().getName() + " message=" + e.getMessage();
}
}
}
@@ -0,0 +1,10 @@
package com.ankurm.graalvmdemo.report;
/**
* Deliberately loaded by class name at runtime, never referenced by a Spring bean definition or a
* static {@code new PlainTextReport()} anywhere in this codebase -- see docs/02-the-reflection-trap.md
* for why that specific shape is what breaks under GraalVM's closed-world analysis.
*/
public interface ReportFormat {
String render(String message);
}
@@ -0,0 +1,16 @@
{
"reflection": [
{
"type": "com.ankurm.graalvmdemo.report.PlainTextReport",
"methods": [
{ "name": "<init>", "parameterTypes": [] }
]
},
{
"type": "com.ankurm.graalvmdemo.report.JsonReport",
"methods": [
{ "name": "<init>", "parameterTypes": [] }
]
}
]
}
@@ -0,0 +1,13 @@
spring:
application:
name: graalvm-native-images
management:
endpoints:
web:
exposure:
include: health
logging:
pattern:
console: "%msg%n"