Demonstrates Quarkus + Oracle GraalVM 25 Advanced Obfuscation (AO) on a production-grade stack.
This is not a hello-world that only adds -H:AdvancedObfuscation. It demonstrates Quarkus running on a native image with AO and embedded:
- Quarkus ArC CDI
- SmallRye Fault Tolerance
- Redis cache
- Postgres/Hibernate
- SmallRye Health + Micrometer/Prometheus
- backbone-kit metrics, logging, throttle components
JDK 25, Docker, Task, jq.
task compose:up
task test
task dev # optional — :8080curl -s 'http://localhost:8080/ping?caller=demo' | jq
curl -s http://localhost:8080/q/health/ready | jqtask ao:build # regenerates reflect-config, then container-build (~15m)
task ao:image
task ao:run
task ao:smokeao:build produces a Linux/glibc runner (required on macOS for the UBI image).
AO renames reachable types by default. Quarkus FT, Narayana/Arjuna, and Vert.x still need original names for reflection, CDI, and FT frames.
Oracle docs point at -H:Preserve=package=…. On a Quarkus classpath that is a reachability hammer: it pulls optional /
unreachable types (Log4j bridges, Kotlin, MP Metrics, deployment classes) into the image, and the build dies with
NoClassDefFoundError. Narrower Preserve packages still did.
{
"name": "io.smallrye.faulttolerance.…",
"condition": {
"typeReachable": "io.smallrye.faulttolerance.…"
}
}AO keeps the name when the type is reachable, without force-including the rest of Quarkus. Generators under
scripts/native/ (also run by task ao:reflect / ao:build):
generate-ft-ao-reflect-config.sh— SmallRye / Quarkus / MicroProfile Fault Tolerancegenerate-arjuna-ao-reflect-config.sh— narrow Narayana/Arjuna suffixes (blanketcom.arjuna.**OOM / times out)generate-redis-vertx-ao-reflect-config.sh— Redis cache/client + Mutiny Vert.x
| Symptom | Generator |
|---|---|
| SmallRye FT NPE / mangled FT frames | FT |
NoSuchMethodException on Arjuna *EnvironmentBean |
Arjuna |
No bean found for obfuscated Vert.x (e.g. amo.amn) |
Redis/Vert.x |
- Micrometer Vert.x binder NPE under AO →
quarkus.micrometer.binder.vertx.enabled=false org.fusesource.jansi→--initialize-at-run-time(merged with AO flags inTaskfile.ymlao:build; CLIadditional-build-argsreplacesapplication.propertiesfor that key)
- Rename-only carve-outs are awkward today:
-H:Preserveis reachability, not "keep these names." - Large framework-wide reflect Preserve lists can OOM AO compile (seen with Arjuna).
- AO is Oracle GraalVM only; Quarkus native guides are Mandrel-first, so Quarkus + AO is under-documented.