Document GraalJS Java interop differences - #86
Merged
Conversation
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
Contributor
There was a problem hiding this comment.
🟢 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.adocwith concise rules and references. - Updated
docs/runtime/java-bridge.adocto 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.
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
anatol-sialitski
approved these changes
Sep 9, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.adocNew
=== Java interopsection under GraalJS (anchorgraaljs-interop), four rules:__.toScriptValue()in,__.toNativeObject()out, the way the platform libraries do it. A JavaMapreturned raw stays a Java object, soObject.keys(), spread andJSON.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.Listreturns behave as arrays on both engines.bean.setValue(x), neverbean.value = x, which fails withUnknown identifier.Object.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'sJavaobject 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.adocThe parameter example taught the Nashorn-only form (
bean.text = …), which fails on GraalJS. It now callsbean.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/xpjs.nashorn-compatis set anywhere in the platform, so there is no compatibility fallback for the bean-property form.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,
appimmutability 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