Hutool ScriptUtils での JavaScript モジュール読み込みエラーの要因と解決策

事象の概要

Hutool ライブラリが提供する ScriptUtils を利用して JavaScript コードを実行する際、スクリプト内に require 文が含まれていると実行失敗が発生するケースがあります。これは特に Node.js 環境で開発されたモジュールを Java 上で動かそうとした際に顕著に現れる問題です。

エラー発生メカニズム

Hutool の ScriptUtils は、デフォルト設定において JDK 標準搭載の Nashorn エンジンを利用しています。Nashorn は Java 8 で導入されたもので、ECMAScript 5.1 仕様に基づいて実装されています。一方、require によるモジュール読み込みは Node.js 固有の CommonJS 規格であり、ECMAScript 標準仕様には含まれていません。この規格の不一致がエラーの根本原因となります。

具体的なエラー内容

例えば、以下のようなスクリプトを実行しようとすると異常が発生します。

const _ = require('lodash');
function process(data) {
    return data;
}

この場合、ScriptRuntimeException がスローされ、以下のようなメッセージが出力されます。

Expected an operand but found const

これは Nashorn エンジンが ES6 の構文である const や、Node.js 固有の関数である require を解釈できないことを示しています。

対処法

1. ES5 互換構文への書き換え

スクリプト側を Nashorn が理解できる形式に変更する方法です。変数宣言を var に変更し、モジュール読み込み部分を環境に合わせて調整します。

var _ = Packages.require('lodash');
function process(data) {
    return data;
}

ただし、この方法でも環境によっては require が認識されない可能性があるため、単純なロジックに限定されます。

2. JavaScript エンジンの変更

より現代的なエンジンへの切り替えが根本的な解決策となります。

  • GraalVM JavaScript エンジン: 最新の ECMAScript 仕様に対応しており、Node.js との互換性も高いです。
  • Rhino エンジン: Mozilla 由来の Java 実装エンジンで、設定により柔軟な動作が可能です。
  • J2V8 などのブリッジ: 実際の Node.js 環境を Java から呼び出す手法です。

3. 事前処理による回避

Java 側でスクリプト文字列を事前に解析し、require 文を削除したり、実際に必要なコードに置き換える処理を挟む方法もあります。

現代の Java 環境における選定基準

Nashorn エンジンは Java 15 以降で廃止予定となっているため、長期的な視点での選定が重要です。

  • 簡易なスクリプト実行であれば、ES5 準拠の構文に制限して Nashorn を利用し続けることも可能です。
  • 複雑なモジュール依存関係がある場合は、GraalVM の導入を検討すべきです。
  • マイクロサービス架构などが採用されている場合、JavaScript 側のロジックを Node.js サービスとして独立させ、HTTP 経由で連携する_architecture_も有効な選択肢です。

これらの技術的特性を理解し、プロジェクトの要件に合わせて適切な実行環境を選定することで、互換性問題を未然に防ぐことができます。

タグ: Hutool scriptutils Nashorn graalvm java-scripting

7月6日 19:04 投稿