GroovyでJavaScriptソースをコールしてみる2

2019-03-21Groovy,JavaScript

はじめに

GroovyでJavaScriptソースをコールしてみる の続きです。

obj.get("age", obj) のように、1回のメソッド呼び出しのために2回もオブジェクトインスタンスを記述するのが面倒です。
これをなんとかしたいと思います。

metaClass を使って、プロパティにもっと簡単にアクセスできるようにしてみます。

metaClass を使って、プロパティにもっと簡単にアクセスできるようにしてみる

metaClass.getAt() メソッドを実装してやることで、Groovy内のオブジェクトに対して以下のようにプロパティアクセス可能となります。

X.metaClass.getAt = { String key -> /* any logic */ }

X x = new X()

x["some-field"]

obj.get("age", obj) という記述を metaClass.getAt() でくるんでやることで、 obj["age"] のようにアクセスできるようにしてやろうと思います。

その前に寄り道。取得できたJavaScriptのオブジェクトってどんなJavaクラスなの?

これを知らなくても metaClass.getAt に設定するクロージャ処理は実装可能ですが、
寄り道して、JavaScript実行結果から取得されたオブジェクトのクラスを調べてどのようにプロパティ情報が格納されているのかを調べてみることにしました。

import javax.script.*;

def engine = new ScriptEngineManager().getEngineByName("JavaScript");

engine.with {
    eval("var genzou = {age:29, sex:'man'};");

    def obj = eval("genzou")
    println obj.properties
}

プロパティをすべて舐めて出力してみました。
結果、以下のように。

["allIds":["age", "sex"], "parentScope":com.sun.script.javascript.RhinoTopLevel@1feaf06, "ids":["age", "sex"], "sealed":false, "class":class sun.org.mozilla.javascript.internal.NativeObject, "className":"Object", "maxInstanceId":0, "prototype":[object Object]]

なんか難しそうだw。

  • allIds って何だ??
  • ids との違いは分からないが、多分一緒かな。
  • classsun.org.mozilla.javascript.internal.NativeObject であることだけははっきりしました。
  • sunmozilla ってどっちなんだろう(笑)

本題に戻って、 metaClass.getAt に設定するクロージャ処理を実装

本題に戻ります。 NativeObject クラスの metaClass プロパティに getAt メソッドを追加してみる。

import javax.script.*;

def engine = new ScriptEngineManager().getEngineByName("JavaScript");

engine.with {
    eval("var genzou = {age:29, sex:'man'};");

    // 拡張してみる
    sun.org.mozilla.javascript.internal.NativeObject.metaClass.getAt = { String key -> delegate.get(key, delegate) }

    def obj = eval("genzou")
    println obj["age"]
}

出力結果は 「29.0」 。おおーーできたよ!やった。

いくつか分かったことが。callしたJavaScriptの結果が数値の場合には、 Double型で返ってくる みたい。それから、今回は Rhino を使用していないですが、Rhinoを使用した場合には sun.org.mozilla.javascript.internal.NativeObject の部分が org.mozilla.javascript.NativeObject となるみたいです。 sun のJavaScript実装と、 Rhino のJavaScript実装の2つがあるんですね。知らずに組むと混乱しそう。

ひとこと

できれば、 getAt メソッドを使用せず、 println obj.age みたいにプロパティ参照形式で記述したい・・・

更に続きます。

2019-03-21Groovy,JavaScript