Aplikasi berbasis JVM yang berjalan normal sering kali mengalami HTTP 401 Unauthorized atau HTTP 500 Internal Server Error begitu dikompilasi menjadi binary native menggunakan GraalVM. Masalah utama biasanya berakar pada auth token deserialization failure saat library parsing JWT/OAuth2 (seperti Jackson, Nimbus JOSE, atau JJWT) gagal merekonstruksi payload JSON ke POJO/Record karena ketiadaan metadata refleksi.
Penyebab Auth Token Deserialization Failure di Native Image
GraalVM menerapkan teknik ahead-of-time (AOT) compilation dengan analisis closed-world assumption. SubstrateVM menganalisis dependensi bytecode yang reachable dari main() entry point. Komponen yang dipanggil dinamis via Java Reflection dianggap tidak digunakan (dead code), sehingga dipotong (pruned) dari binary untuk meminimalkan ukuran file.
Ketika client mengirim Bearer token ke API gateway atau auth filter:
- Filter membaca header
Authorization: Bearer <token>dan mengekstrak claims payload. - Library JSON parser mencoba memanggil default constructor atau getter/setter via reflection untuk mengisi field seperti
sub,roles,exp, atau custom claims. - Karena class mapping token payload tidak didaftarkan secara eksplisit ke reachability metadata, GraalVM membuang metadata refleksi tersebut.
- Runtime melempar
ClassNotFoundException,NoSuchMethodException, atauInvalidDefinitionException, menggagalkan pipeline otentikasi.
Identifikasi Error Integrasi Auth Gateway
Saat dynamic pruning terjadi, log native image menghasilkan stack trace khas berikut:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.example.auth.dto.UserTokenPayload` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (String)"{"sub":"usr_1029","roles":["ADMIN"],"exp":1741520000}"; line: 1, column: 2]
at com.example.auth.filter.JwtAuthFilter.doFilter(JwtAuthFilter.java:48)
at org.graalvm.nativeimage.builder/...API gateway menerima token valid, namun microservice backend menolaknya karena instansiasi payload gagal.
Solusi: Konfigurasi Reachability Metadata (reflect-config.json)
Untuk mempertahankan metadata yang dibutuhkan runtime JSON mapper, daftarkan DTO token ke dalam META-INF/native-image/reflect-config.json.
1. Model Data Auth Payload
Gunakan Java Record atau POJO standar:
package com.example.auth.dto;
import java.util.List;
public record UserTokenPayload(
String sub,
List<String> roles,
long exp
) {}2. Entry pada reflect-config.json
Daftarkan class beserta accessors dan konstruktor secara eksplisit:
[
{
"name": "com.example.auth.dto.UserTokenPayload",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true
}
]Letakkan file ini di path: src/main/resources/META-INF/native-image/<group-id>/<artifact-id>/reflect-config.json.
Otomasi Metadata via GraalVM Tracing Agent
Menulis konfigurasi manual rawan kesalahan bila payload token memuat class bersarang (nested DTOs). Gunakan GraalVM Tracing Agent pada fase JVM test suite untuk mengumpulkan metadata secara otomatis.
Jalankan unit/integration test dengan JVM flag:
java -agentlib:native-image-agent=config-output-dir=src/main/resources/META-INF/native-image \
-jar target/auth-service-runner.jarPastikan test case mencakup simulasi full request authentication dengan parsing token riil agar jalur eksekusi refleksi terekam oleh agent.
Pertimbangan Size Optimization
Menambahkan metadata refleksi memperbesar binary akhir. Terapkan strategi berikut untuk menjaga binary tetap optimal:
- Hindari wildcard registration: Jangan mendaftarkan seluruh package DTO jika hanya subset class yang dipakai untuk auth payload.
- Gunakan flag native-image terarah: Pasang parameter optimasi seperti
-O3atau optimasi ukuran-Ostanpa menonaktifkan--no-fallback. - Gunakan static token decoder alternatif: Bila memungkinkan, gunakan library parser berbasis bytecode generator tanpa reflection saat compile-time (misal: parsing berbasis Jackson Afterburner/Blackbird atau zero-reflection parser manual).
Pemeriksaan Akhir
Sebelum deployment ke production cluster, validasi native executable dengan smoke test spesifik auth:
./target/auth-service &
APP_PID=$!
# Kirim request dengan valid signed JWT
curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer <VALID_TEST_JWT>" \
http://localhost:8080/api/v1/protected-resource
kill $APP_PIDJika output menghasilkan HTTP 200 (bukan 401 atau 500), metadata refleksi deserialization payload berhasil dipreservasi.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!