From 7f8f09c899ac179c42acfdc5ea02bbfc5d1b145d Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Mon, 18 May 2026 21:35:06 +0100 Subject: [PATCH] Native-access via bootJar manifest, not CLI flags everywhere MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit JDK 22+ honors an 'Enable-Native-Access' attribute on the executable jar's manifest (JEP 472). Setting it once on the Spring Boot bootJar removes the need to remember --enable-native-access=ALL-UNNAMED in: - Docker init script's JAVA_BASE_OPTS injection - Tauri Rust launcher's java_options vector - Anywhere else somebody runs the bootJar …and also future-proofs against JDK 26's hard-fail behavior without each launch point having to track the flag. app/core/build.gradle: add 'Enable-Native-Access': 'ALL-UNNAMED' to the bootJar manifest attributes block. build.gradle (bootRun jvmArgs): keep --enable-native-access=ALL-UNNAMED because bootRun launches from classfiles, not the bootJar — the manifest mechanism doesn't apply to that codepath, only to 'java -jar'. scripts/init-without-ocr.sh: drop the FFM injection. frontend/src-tauri/src/commands/backend.rs: drop the CLI arg. --- app/core/build.gradle | 10 +++++++++- build.gradle | 6 ++++-- frontend/src-tauri/src/commands/backend.rs | 9 ++++----- scripts/init-without-ocr.sh | 10 ---------- 4 files changed, 17 insertions(+), 18 deletions(-) diff --git a/app/core/build.gradle b/app/core/build.gradle index 7a30f47663..5daead24dc 100644 --- a/app/core/build.gradle +++ b/app/core/build.gradle @@ -160,7 +160,15 @@ bootJar { manifest { attributes( 'Implementation-Title': 'Stirling-PDF', - 'Implementation-Version': project.version + 'Implementation-Version': project.version, + // JDK 22+ honors this manifest attribute on the executable jar: + // grant native-access (FFM restricted methods) without needing + // --enable-native-access on the CLI / JAVA_TOOL_OPTIONS at launch. + // ALL-UNNAMED matches the unnamed module that Spring Boot's fat + // jar runs as (everything on the classpath), which includes + // JPDFium and its FFM-using internals. + // Ref: https://openjdk.org/jeps/472 ('Enable-Native-Access' attr) + 'Enable-Native-Access': 'ALL-UNNAMED' ) } } diff --git a/build.gradle b/build.gradle index f7989d76c0..6253b1442f 100644 --- a/build.gradle +++ b/build.gradle @@ -452,8 +452,10 @@ subprojects { "-XX:+ExplicitGCInvokesConcurrent", "-XX:+UseStringDeduplication", "-XX:+UseCompactObjectHeaders", - // JPDFium uses FFM; JDK 26 will reject native access without - // this flag. Required at JDK 25 to silence the warning chain. + // bootRun launches from classfiles (not the bootJar), so the + // 'Enable-Native-Access' manifest attribute baked into the + // jar (see app/core/build.gradle) doesn't apply here. + // Keep the CLI form for the dev loop. "--enable-native-access=ALL-UNNAMED" ] } diff --git a/frontend/src-tauri/src/commands/backend.rs b/frontend/src-tauri/src/commands/backend.rs index 81f634d3bd..f72bef8ee5 100644 --- a/frontend/src-tauri/src/commands/backend.rs +++ b/frontend/src-tauri/src/commands/backend.rs @@ -205,11 +205,10 @@ fn run_stirling_pdf_jar(app: &tauri::AppHandle, java_path: &PathBuf, jar_path: & let java_options = vec![ "-Xmx2g", - // JPDFium uses Foreign Function & Memory (FFM). JDK 25 warns without - // this flag; JDK 26+ will refuse native access entirely. ALL-UNNAMED - // because the Spring Boot fat jar runs from the classpath, not the - // module path. - "--enable-native-access=ALL-UNNAMED", + // FFM native access (for JPDFium) is granted by the + // 'Enable-Native-Access: ALL-UNNAMED' manifest attribute baked into + // the Spring Boot bootJar (see app/core/build.gradle). No CLI flag + // needed here. "-DBROWSER_OPEN=false", "-DSTIRLING_PDF_TAURI_MODE=true", &log_path_option, diff --git a/scripts/init-without-ocr.sh b/scripts/init-without-ocr.sh index b23c28eb5b..a22ee61d88 100755 --- a/scripts/init-without-ocr.sh +++ b/scripts/init-without-ocr.sh @@ -816,16 +816,6 @@ if [ "$AOT_ENABLED" = "true" ]; then fi fi -# ---------- FFM Native Access ---------- -# JPDFium uses the Foreign Function & Memory API to call into PDFium. -# JDK 25 warns when libraries call restricted methods without explicit -# permission; JDK 26+ will refuse outright. ALL-UNNAMED because Stirling-PDF -# runs as a Spring Boot fat jar on the classpath (not the module path). -case "${JAVA_BASE_OPTS}" in - *enable-native-access*) ;; - *) JAVA_BASE_OPTS="${JAVA_BASE_OPTS} --enable-native-access=ALL-UNNAMED" ;; -esac - # Collapse duplicate whitespace JAVA_BASE_OPTS=$(echo "$JAVA_BASE_OPTS" | tr -s ' ')