Skip to content

Document GraalJS Java interop differences - #86

Merged
rymsha merged 5 commits into
masterfrom
claude/nashorn-graaljs-migration-xscuuv
Sep 9, 2026
Merged

Document GraalJS Java interop differences#86
rymsha merged 5 commits into
masterfrom
claude/nashorn-graaljs-migration-xscuuv

Conversation

@rymsha

@rymsha rymsha commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

GraalJS does not convert values at the Java boundary the way Nashorn did, and developers keep rediscovering the same handful of failures — often by writing long private notes for their AI assistant instead of finding it in the docs.

docs/runtime/engines.adoc

New === Java interop section under GraalJS (anchor graaljs-interop), four rules:

  • Convert every value that crosses the boundary__.toScriptValue() in, __.toNativeObject() out, the way the platform libraries do it. A Java Map returned raw stays a Java object, so Object.keys(), spread and JSON.stringify() see its class methods rather than its entries, and raise nothing — while a single property read still answers, which is what makes it easy to miss. List returns behave as arrays on both engines.
  • Call setters, don't assign propertiesbean.setValue(x), never bean.value = x, which fails with Unknown identifier.
  • Pass the type the method declares — arguments are not coerced; parse request parameters before they reach Java.
  • Don't branch on a Java value's type from JavaScriptObject.prototype.toString.call(value) no longer names the Java class.

Plus a note that the bridge is __ on both engines and that an engine's own interop global (Nashorn's Java object among them) is not part of XP's API, and a link to the GraalJS reference documentation with the caveat that it describes the standalone engine — read it alongside the page's Not supported list.

docs/runtime/java-bridge.adoc

The parameter example taught the Nashorn-only form (bean.text = …), which fails on GraalJS. It now calls bean.setText(…) / bean.setSize(…), matching how the platform libraries are written, with a warning explaining why. Two short additions elsewhere on the page: arguments are not coerced on the way in (wrap objects and arrays in __.toScriptValue()), and complex return values need __.toNativeObject().

Verified against enonic/xp

  • No js.nashorn-compat is set anywhere in the platform, so there is no compatibility fallback for the bean-property form.
  • Every lib-* module already uses explicit setters plus __.toScriptValue / __.toNativeObject (e.g. bean.setKey(key) in lib-content), which is what makes those the portable pattern to document.

Deliberately left out

Module-level state is already covered in Script contexts on the same page. The test-runtime setup, app immutability and the request-context-at-module-load issue are not Java interop, so they are not part of this change.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Dx8tfKuJaZd2rDvkF8Aoba


Generated by Claude Code

GraalJS does not convert values at the Java boundary the way Nashorn
did, and developers hit the same handful of failures each time. Add a
short "Java interop" section to the engines page covering the four
rules: convert with __.toScriptValue/__.toNativeObject, call setters
instead of assigning properties, pass the declared parameter type, and
do not type-check Java values from JavaScript. Note that XP's bridge is
__ rather than an engine's own Java global, and link the GraalJS
reference with the caveat that XP does not expose everything it
documents.

Fix the Java bridge page accordingly: its parameter example used the
Nashorn-only property assignment, which fails on GraalJS - it now calls
setters, the way the platform libraries do.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dx8tfKuJaZd2rDvkF8Aoba
Copilot AI lite review requested due to automatic review settings September 8, 2026 20:02

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The changes are low-risk documentation improvements with only minor wording/grammar tweaks suggested in review comments.

Pull request overview

Updates the Enonic XP runtime reference documentation to capture key Nashorn vs GraalJS Java interop differences so developers avoid common boundary-conversion and bean-access pitfalls.

Changes:

  • Added a new GraalJS-focused “Java interop” section in docs/runtime/engines.adoc with concise rules and references.
  • Updated docs/runtime/java-bridge.adoc to use explicit bean setters (instead of Nashorn-only property assignment) and added clarifying notes on argument/return conversions.
File summaries
File Description
docs/runtime/java-bridge.adoc Updates bean parameter-setting example to use setters and documents GraalJS boundary conversion expectations.
docs/runtime/engines.adoc Adds a dedicated GraalJS “Java interop” section describing key behavioral differences from Nashorn.
Review details

Suppressed comments (1)

docs/runtime/java-bridge.adoc:126

  • Grammar: “type conversions applies” should be “type conversions apply”.
When returning simple values from Java to a JavaScript caller, the same type conversions applies.
  • Files reviewed: 2/2 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread docs/runtime/engines.adoc Outdated
Comment thread docs/runtime/java-bridge.adoc Outdated
Arguments are never coerced; HTTP request parameters arriving as
strings are one instance of that, not the rule itself.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dx8tfKuJaZd2rDvkF8Aoba
Formalise the wording and move the identifiers out of the sentences:
each of the four rules is now a subsection with a TypeScript example
showing the supported form beside the one that fails, rather than a
labelled list carrying the code inline.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dx8tfKuJaZd2rDvkF8Aoba
Review feedback on the wording. The assignment is to a property on the
bean object, not to a Java field, so say that GraalJS exposes the bean's
methods and public fields and no property named after the setter. Also
state plainly that inspecting an unconverted Java map throws nothing,
rather than that it "raises nothing".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dx8tfKuJaZd2rDvkF8Aoba
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dx8tfKuJaZd2rDvkF8Aoba
@rymsha
rymsha merged commit 33837dc into master Sep 9, 2026
2 checks passed
@rymsha
rymsha deleted the claude/nashorn-graaljs-migration-xscuuv branch September 9, 2026 08:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants