From 33058f2b292b3a581333bdfb21b8f671898c5060 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Tue, 8 Dec 2020 14:40:17 -0500 Subject: initial commit --- files/ja/rhino/community/index.html | 16 ++ files/ja/rhino/download_rhino/index.html | 104 +++++++ files/ja/rhino/index.html | 20 ++ files/ja/rhino/scopes_and_contexts/index.html | 126 +++++++++ files/ja/rhino/scripting_java/index.html | 377 ++++++++++++++++++++++++++ 5 files changed, 643 insertions(+) create mode 100644 files/ja/rhino/community/index.html create mode 100644 files/ja/rhino/download_rhino/index.html create mode 100644 files/ja/rhino/index.html create mode 100644 files/ja/rhino/scopes_and_contexts/index.html create mode 100644 files/ja/rhino/scripting_java/index.html (limited to 'files/ja/rhino') diff --git a/files/ja/rhino/community/index.html b/files/ja/rhino/community/index.html new file mode 100644 index 0000000000..d0cae094d5 --- /dev/null +++ b/files/ja/rhino/community/index.html @@ -0,0 +1,16 @@ +--- +title: Rhino コミュニティ +slug: Rhino/Community +tags: + - Rhino + - 要更新 +translation_of: Mozilla/Projects/Rhino/Community +--- +

Rhino に関する文書』の中では答えを見つけることができない質問がありますか? ここでは、いくつかの追加のヘルプ情報を提供します。

+

ニュースグループとメールゲートウェイ

+

The mozilla.dev.tech.js-engine.rhino newsgroup answers questions about Rhino. Click here to subscribe/unsubscribe.

+

The mozilla.dev.tech.js-engine newsgroup answers questions about the C implementation of JavaScript, and was also used for answering questions about Rhino until September 27, 2007. If you think you might be interested in it regardless, click here to subscribe/unsubscribe.

+

To view archived messages, try Google group for Rhino or other newsgroup services.

+

To view archived messages earlier than September 27, 2007, try Google group for the earlier newsgroup.

+

バグシステム

+

Rhino についてのバグは Bugzilla を使ってください。注記: Rhino は、独立したカテゴリを持っています。

diff --git a/files/ja/rhino/download_rhino/index.html b/files/ja/rhino/download_rhino/index.html new file mode 100644 index 0000000000..fafffa5929 --- /dev/null +++ b/files/ja/rhino/download_rhino/index.html @@ -0,0 +1,104 @@ +--- +title: ダウンロード Rhino +slug: Rhino/Download_Rhino +translation_of: Mozilla/Projects/Rhino/Download_Rhino +--- +

Rhino は、ソースとコンパイル済み形式、両方をダウンロード可能です。

+ +

バイナリ

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
リリースリリース日リリースノートダウンロード
Rhino 1.7R42012-06-18New in Rhino 1.7R4rhino1_7R4.zip
Rhino 1.7R52015-01-29リリース ノートrhino1_7R5.zip
Rhino 1.7.62015-04-15リリース ノートrhino1.7.6.zip
Rhino 1.7.72015-06-17リリース ノートrhino1.7.7.zip
Rhino 1.7.7.12016-02-01リリース ノートrhino1.7.7.1.zip
Rhino 1.7.7.22017-08-24リリース ノートrhino1.7.7.2.zip
Rhino 1.7.82018-01-22リリース ノートrhino1.7.8.zip
Rhino 1.7.92018-03-15リリース ノートrhino1.7.9.zip
Rhino 1.7.102018-04-09リリース ノートrhino1.7.10.zip
Rhino 1.7.112019-05-30リリース ノートrhino1.7.11.zip
Rhino 1.7.122020-01-13リリース ノートrhino1.7.12.zip
+ +

より古いバージョンの Rhino をダウンロードするには、Rhino ダウンロード・アーカイブ を参照してください。

+ +

ライセンス

+ +

Rhino はオープンソースです。リリース 1.7R4 以降はRhinoは MPL 2.0 ライセンスに基づいて利用できます

+ +

それ以前のバージョンは MPL 1.1/GPL 2.0 ライセンスの基にリリースされています。

+ +

詳細な情報は Rhinoライセンス を参照してください。

+ +

ソース

+ +

上記 zip ファイルからソースを得ることに加え、 github https://github.com/mozilla/rhino からもRhino ソースコードを見つけることができます。 次のコマンドを実行すればソースを入手できます。

+ +
git clone https://github.com/mozilla/rhino.git
+
+ +

Rhino のビルド・システムには  Ant を利用しています。 Rhino ディストリビューションのトップディレクトリで ant コマンドを走らせれば、利用可能なビルド対象のリストが表示されるはずです。

diff --git a/files/ja/rhino/index.html b/files/ja/rhino/index.html new file mode 100644 index 0000000000..58dd55c7a7 --- /dev/null +++ b/files/ja/rhino/index.html @@ -0,0 +1,20 @@ +--- +title: Rhino +slug: Rhino +translation_of: Mozilla/Projects/Rhino +--- +
Image:rhino.jpg
+ +

Rhino はすべてが Java で記述された JavaScript のオープンソースな実装です。それは一般的には、Java アプリケーション環境へ組み込まれて、エンドユーザーによるスクリプトの記述が可能になります。J2SE 6 ではデフォルトの Java スクリプティングエンジンとして組み込まれています。

+ +

ダウンロード

+ +

ソースとバイナリを取得する 方法。

+ +

ドキュメント

+ +

スクリプト記述者と組み込み開発者への Rhino の情報

+ +

ヘルプ

+ +

困ったときの いくつかのリソース

diff --git a/files/ja/rhino/scopes_and_contexts/index.html b/files/ja/rhino/scopes_and_contexts/index.html new file mode 100644 index 0000000000..5f9d70fa81 --- /dev/null +++ b/files/ja/rhino/scopes_and_contexts/index.html @@ -0,0 +1,126 @@ +--- +title: Rhino scopes and contexts +slug: Rhino/Scopes_and_Contexts +translation_of: Mozilla/Projects/Rhino/Scopes_and_Contexts +--- +

Rhinoをマルチスレッドの環境で使う前に、コンテキストとスコープの間の関係を理解することが大切です。両方ともスクリプトを実行するのに必要ですが、それぞれは異なる役割を担います。簡単なRhinoの埋め込みであればここに書いてある情報はあまり必要ではないでしょう。しかしより複雑な埋め込みやパフォーマンスと柔軟性を上げるためにはこれらのことが役に立つでしょう。

+ +

コンテキスト

+ +

コンテキストオブジェクトは実行環境に関するスレッド固有の情報を保持するために使われます。それぞれのスレッドに関連付けられたJavaScript実行環境のコンテキストは一つだけであるべきです。

+ +

現在のスレッドをコンテキストに関連付けるためには、 enter メソッドを呼びます:

+ +
Context cx = Context.enter();
+
+ +

実行が終わったら、コンテキストを抜けます:

+ +
Context.exit();
+
+ +

これらのコールはすでに現在のスレッドにコンテキストが関連付けられていたとしても、正しく動作します。これは内部的にカウンターをインクリメントします。カウンターが0になると、スレッドからの関連付けが解除されます。

+ +

exit() の呼び出しは実行中に例外が発生しても大丈夫なように、 finally ブロックで行うようにしてください。

+ +

スコープ

+ +

スコープはJavaScriptオブジェクトのセットです。スクリプトの実行には FunctionObject などのオブジェクトを保持しておくためのトップレベルスクリプト変数スコープを必要とします。

+ +

スコープはそれを作成したコンテキストとは独立しているということを理解することが大事です。あるコンテキストでスコープを作り、それを別のコンテキストでスクリプトを評価することが可能です。(一度コンテキストを抜けて再度入った場合や、別のスレッドで実行する場合など) 同じスコープに関して複数のスレッドで同時にスクリプトを実行することもできます。RhinoはJavaScriptオブジェクトのプロパティへのアクセスの原始性を保証します。しかしそれ以外の同時に実行されるスクリプトの保証はしません。もし二つのスクリプトが同じスコープを同時に使用する場合、スクリプトは共有変数へのアクセスを制御する必要があります。

+ +

トップレベルスコープは Context.initStandardObjects で作れます。

+ +
ScriptableObject scope = cx.initStandardObjects();
+
+ +

Rhinoを埋め込む最も簡単な方法は、必要に応じてこの方法で単に新しいスコープを作ることです。しかし initStandardObjects は高価なメソッドで、たくさんのメモリを確保します。複数のスコープやスレッドで作成したスコープを共有する方法は、後述します。

+ +

名前ルックアップ

+ +

ではどのようにスコープは名前を見つけるのに使われるのでしょう?簡単に言えば、変数は現在の変数から始まって (これはプログラム中でどんなコードが実行されるかによります)、プロトタイプチェインを辿ります。そして親子チェインを辿ります。下の図では、6個のオブジェクトが辿られる様子が描かれています。

+ +
+
Order of lookups in a two-deep scope chain with prototypes.
+
+ +

より具体的な例として、次のスクリプトを考えてみましょう:

+ +
var g = 7;
+
+function f(a) {
+  var v = 8,
+      x = v + a;
+}
+
+f(6);
+
+ +

トップレベル変数 g があり、 f の呼び出しは新たなトップレベル変数 x を作成します。全てのトップレベル変数はスコープオブジェクトのプロパティです。 f の実行を開始するとき、スコープチェインは関数のアクティベーションオブジェクトから開始し、トップレベルスコープで終わります (下図参照)。アクティベーションオブジェクトは二つのプロパティを持っています。'a' は引数、'v' は変数です。トップレベルスコープは変数 g と関数 f を持っています。

+ +
+
シンプルなスクリプトのスコープチェインの例
+
+ +

x = v + a; というステートメントが実行されるとき、スコープチェインが辿られ 'x' プロパティを探します。何も見つからなければ新たな'x' プロパティがトップレベルスコープに作られます。

+ +

スコープの共有

+ +

JavaScriptはクラスベースの継承よりも委譲を使う言語です。これはそれ自体が大きなトピックですが、これにより複数のスコープで読み取り専用の変数を共有する簡単な方法が与えられます。

+ +

これを行うためには、オブジェクトのプロトタイプを設定します。JavaScriptでオブジェクトのプロパティにアクセスするとき、与えられた名前をまずオブジェクトのプロパティから探します。もし見つからなければ、オブジェクトのプロトタイプを探しにいきます。これはプロトタイプチェインの最後に到達するまで続きます。

+ +

なので、複数のスコープで情報を共有する場合、まず共有したいオブジェクトを作成します。通常このオブジェクトは initStandardObjects で作られます。組み込み用にいくつかの追加のオブジェクトを持つかもしれません。そしてさらに新しいオブジェクトを作成して、そのオブジェクトの setPrototypemethod を呼び、共有オブジェクトをプロトタイプに設定します。そして新しいスコープの親はnullにします:

+ +
Scriptable newScope = cx.newObject(sharedScope);
+newScope.setPrototype(sharedScope);
+newScope.setParentScope(null);
+
+ +

The call to newObject simply creates a new JavaScript object with no properties. It uses thesharedScope passed in to initialize the prototype with the standard Object.prototype value.

+ +

これで newScope をスクリプトを評価するスコープとして使うことができます。このスコープをインスタンススコープと呼びましょう。スクリプトで定義される全てのトップレベル関数や変数はインスタンススコープのプロパティになります。Uses of standard objects like Function, String, or RegExp will find the definitions in the shared scope. Multiple instance scopes can be defined and have their own variables for scripts yet share the definitions in the shared scope. These multiple instance scopes can be used concurrently.

+ +

Sealed shared scopes

+ +

The ECMAScript standard defines that scripts can add properties to all standard library objects and in many cases it is also possible to change or delete their properties as well. Such behavior may not be suitable with shared scopes since if a script by mistake adds a property to a library object from the shared scope, that object would not be garbage collected until there are no active references to the shared scope potentially leading to memory leaks. In addition if a script alters some of the standard objects, the library may not work properly for other scripts. Such bugs are hard to debug and to remove a possibility for them to occur one can seal the shared scope and all its objects.

+ +

A notion of a sealed object is a JavaScript extension supported by Rhino and it means that properties can not be added/deleted to the object and the existing object properties can not be changed. Any attempt to modify sealed object throws an exception. To seal all objects in the standard library passtrue for the sealed argument when calling Context.initStandardObjects(ScriptableObject, boolean):

+ +
ScriptableObject sealedSharedScope = cx.initStandardObjects(null, true);
+
+ +

This seals only all standard library objects, it does not seal the shared scope itself thus after callinginitStandardObjects, sealedSharedScope can be farther populated with application-specific objects and functions. Then after a custom initialization is done, one can seal the shared scope by callingScriptableObject.sealObject():

+ +
sealedSharedScope.sealObject();
+
+ +

Note that currently one needs to explicitly seal any additional properties he adds to the sealed shared scope since although after calling sealedSharedScope.sealObject(); it would no be possible to set the additional properties to different values, one still would be able to alter the objects themselves.

+ +

Note that currently in order to use Java classes (LiveConnect) from a sealed shared scope you need to pre-load a number of objects needed for LiveConnect into the scope before it gets sealed. These objects would normally be lazy loaded but the lazy loading fails if the scope is sealed.

+ +
ScriptableObject sealedSharedScope  = cx.initStandardObjects(null, true);
+
+// Force the LiveConnect stuff to be loaded.
+String loadMe = "RegExp; getClass; java; Packages; JavaAdapter;";
+cx.evaluateString(sealedSharedScope , loadMe, "lazyLoad", 0, null);
+sealedSharedScope .sealObject();
+ +

Dynamic Scopes

+ +

There's one problem with the setup outlined above. Calls to functions in JavaScript use static scope, which means that variables are first looked up in the function and then, if not found there, in the lexically enclosing scope. This causes problems if functions you define in your shared scope need access to variables you define in your instance scope.

+ +

With Rhino 1.6, it is possible to use dynamic scope. With dynamic scope, functions look at the top-level scope of the currently executed script rather than their lexical scope. So we can store information that varies across scopes in the instance scope yet still share functions that manipulate that information reside in the shared scope.

+ +

The DynamicScopes example illustrates all the points discussed above.

+ +

More on Scopes

+ +

The key things to determine in setting up scopes for your application are

+ +
    +
  1. What scope should global variables be created in when your script executes an assignment to an undefined variable, and
  2. +
  3. What variables should your script have access to when it references a variable?
  4. +
+ +

The answer to 1 determines which scope should be the ultimate parent scope: Rhino follows the parent chain up to the top and places the variable there. After you've constructed your parent scope chain, the answer to question 2 may indicate that there are additional scopes that need to be searched that are not in your parent scope chain. You can add these as prototypes of scopes in your parent scope chain. When Rhino looks up a variable, it starts in the current scope, walks the prototype chain, then goes to the parent scope and its prototype chain, until there are no more parent scopes left.

diff --git a/files/ja/rhino/scripting_java/index.html b/files/ja/rhino/scripting_java/index.html new file mode 100644 index 0000000000..f9d5c0c6f6 --- /dev/null +++ b/files/ja/rhino/scripting_java/index.html @@ -0,0 +1,377 @@ +--- +title: Java のスクリプティング +slug: Rhino/Scripting_Java +tags: + - Rhino +translation_of: Mozilla/Projects/Rhino/Scripting_Java +--- +

この記事では Rhino を使用して JavaScript を超えて Java に到達する方法を説明します。Java によるスクリプティングには多くの用途があります。これは、利用可能な多くの Java ライブラリを利用して、強力なスクリプトを素早く作成することを可能にします。スクリプトを書くことで Java クラスをテストできます。 私たちは、探索的プログラミングのためのスクリプトを使用して、Java 開発を支援することもできます。探索的プログラミングとは、ライブラリや API がそれを使用するクイックプログラムを書くことによって何ができるのかを学習するプロセスです。ここからわかるように、スクリプトによってこのプロセスが簡単になります。

+ +

ECMA 標準では Java (またはそのような外部オブジェクトシステムとの通信) は扱いません。したがって、この章で扱うすべての機能を拡張機能と見なす必要があります。

+ +

Java パッケージとクラスへのアクセス

+ +

すべての Java コードはクラスの一部です。すべての Java クラスはパッケージの一部です。ただし、JavaScript では、スクリプトはパッケージ階層の外に存在します。どうしたら Java パッケージのクラスにアクセスできるでしょうか?

+ +

Rhino は Packages という名前の最上位変数を定義します。Packages 変数のプロパティはすべて javacom などのトップレベルの Java パッケージです。たとえば、java パッケージの値にアクセスできます。

+ +
js> Packages.java
+[JavaPackage java]
+ +

便利なショートカットとして、Rhino は Packages.java と同等のトップレベルの変数 java を定義しています。したがって、前の例はさらに短くなる可能性があります。

+ +
js> java
+[JavaPackage java]
+
+ +

パッケージの階層を下げるだけで Java クラスにアクセスできます。

+ +
js> java.io.File
+[JavaClass java.io.File]
+
+ +

スクリプトが多数の異なる Java クラスにアクセスすると、毎回そのクラスの完全なパッケージ名を使用するのが面倒になることがあります。Rhino は Java の import 宣言と同じ目的を果たすトップレベル関数 importPackage を提供します。たとえば、java.io パッケージ内のすべてのクラスをインポートし、File という名前だけを使用して java.io.File クラスにアクセスできます。

+ +
js> importPackage(java.io)
+js> File
+[JavaClass java.io.File]
+
+ +

ここで importPackage(java.io) は、java.io パッケージ内のすべてのクラス (File など) を最上位レベルで使用可能にします。これは import java.io.*; Java 宣言と実質的に同じです。

+ +

Java では java.lang.* が暗黙的にインポートされるのに対し、Rhino はそうでないことに注意することが重要です。その理由は、JavaScript には java.lang パッケージで定義された名前とは異なる独自のトップレベルオブジェクト BooleanMathNumberObject、および String があるからです。この競合のため、java.lang パッケージで importPackage を使用しないことをお勧めします。

+ +

注意すべき点の1つは、Rhino が Java パッケージまたはクラス名を指定する際にエラーを処理することです。java.MyClass にアクセスすると、Rhino は java.MyClass という名前のクラスのロードを試みます。そのロードに失敗すると、java.MyClass はパッケージ名であるとみなされ、エラーは報告されません。

+ +
js> java.MyClass
+[JavaPackage java.MyClass]
+
+ +

このオブジェクトをクラスとして使用しようとした場合にのみ、エラーが報告されます。

+ +

外部パッケージとクラス

+ +

Rhino で外部パッケージやクラスを使用することもできます。.jar または .class ファイルがクラスパス上にあることを確認してから、JavaScript アプリケーションにインポートすることができます。これらのパッケージは java パッケージにはない可能性が高いので、パッケージ名の前に "Packages." を付ける必要があります。たとえば、org.mozilla.javascript パッケージをインポートするには、次のように importPackage() を使用できます。

+ +
$ java org.mozilla.javascript.tools.shell.Main
+js> importPackage(Packages.org.mozilla.javascript);
+js> Context.currentContext;
+org.mozilla.javascript.Context@bb6ab6
+
+ +

場合によっては、importClass() メソッドを使用してインポートするのではなく、例にあるようにパッケージの完全修飾名を使用します。これも可能ですが、入力が増えます。完全修飾名を使用すると、上記の例は次のようになります。

+ +
$ java org.mozilla.javascript.tools.shell.Main
+js> jsPackage = Packages.org.mozilla.javascript;
+[JavaPackage org.mozilla.javascript]
+js> jsPackage.Context.currentContext;
+org.mozilla.javascript.Context@bb6ab6
+
+ +

また、パッケージから1つのクラスだけをインポートする場合は、importClass() メソッドを使用してクラスをインポートできます。上記の例は、次のように表すことができます。

+ +
$ java org.mozilla.javascript.tools.shell.Main
+js> importClass(Packages.org.mozilla.javascript.Context);
+js>  Context.currentContext;
+org.mozilla.javascript.Context@bb6ab6
+ +

Java をあわせて使用する

+ +

Java クラスにアクセスできるようになったので、次の論理的なステップはオブジェクトを作成することです。これは、Java の場合と同様に new 演算子を使用して動作します。

+ +
js> new java.util.Date()
+Thu Jan 24 16:18:17 EST 2002
+
+ +

新しいオブジェクトを JavaScript 変数に格納すると、そのオブジェクトに対してメソッドを呼び出すことができます。

+ +
js> f = new java.io.File("test.txt")
+test.txt
+js> f.exists()
+true
+js> f.getName()
+test.txt
+
+ +

静的メソッドおよびフィールドは、クラスオブジェクト自体からアクセスできます。

+ +
js> java.lang.Math.PI
+3.141592653589793
+js> java.lang.Math.cos(0)
+1
+
+ +

JavaScript では、Java と異なり、メソッド自体はオブジェクトであり、呼び出されるだけでなく評価されます。メソッドオブジェクトを単独で表示すると、メソッドのさまざまなオーバーロードされた形式を見ることができます。

+ +
js> f.listFiles
+function listFiles() {/*
+java.io.File[] listFiles()
+java.io.File[] listFiles(java.io.FilenameFilter)
+java.io.File[] listFiles(java.io.FileFilter)
+*/}
+
+ +

この出力は、File クラスが3つのオーバーロードされたメソッド listFiles を定義していることを示しています。1つは引数を取らず、他は FilenameFilter 引数を持つもの、FileFilter 引数を持つものです。すべてのメソッドは File オブジェクトの配列を返します。Java メソッドのパラメータと戻り値の型を見ることができるのは、メソッドを調べている可能性があり、パラメータや戻り値の型が不明な探索プログラミングで特に役立ちます。

+ +

探索的プログラミングのもう1つの有用な機能は、オブジェクトに対して定義されたすべてのメソッドとフィールドを表示する機能です。JavaScript の for..in 構文を使用して、これらの値をすべて出力することができます:

+ +
js> for (i in f) { print(i) }
+exists
+parentFile
+mkdir
+toString
+wait
+[44 others]
+
+ +

File クラスのメソッドだけでなく、(wait のような) 基本クラス java.lang.Object から継承されたメソッドもリストされていることに注意してください。これにより、深くネストされた継承階層のオブジェクトを扱うことが容易になります。これは、そのオブジェクトで使用可能なすべてのメソッドを見ることができるからです。

+ +

Rhino は、JavaBeans のプロパティにプロパティ名で直接アクセスできるようにすることで、別の便利さを提供します。JavaBean のプロパティ foo は、getFoosetFoo のメソッドで定義されています。さらに、同じ名前のブール値プロパティは、isFoo メソッドで定義することができます。たとえば、次のコードは実際に File オブジェクトの getName メソッドと isDirectory メソッドを呼び出します。

+ +
js> f.name
+test.txt
+js> f.directory
+false
+
+ +

オーバーロードされたメソッドの呼び出し

+ +

引数の型に基づいて呼び出すメソッドを選択するプロセスはオーバーロード解決と呼ばれます。Java では、オーバーロードの解決はコンパイル時に実行され、Rhino では実行時に行われます。第2章で議論したように、JavaScript の動的型指定を使用すると、この違いは避けられません。変数の型は実行時まで認識されないため、過負荷解決が発生するだけです。

+ +

例として、いくつかのオーバーロードされたメソッドを定義し、それらを呼び出す以下の Java クラスを考えてみましょう。

+ +
public class Overload {
+
+    public String f(Object o) { return "f(Object)"; }
+    public String f(String s) { return "f(String)"; }
+    public String f(int i)    { return "f(int)"; }
+
+    public String g(String s, int i) { return "g(String,int)"; }
+    public String g(int i, String s) { return "g(int,String)"; }
+
+    public static void main(String[] args) {
+        Overload o = new Overload();
+        Object[] a = new Object[] { new Integer(3), "hi", Overload.class };
+        for (int i = 0; i != a.length; ++i)
+            System.out.println(o.f(a[i]));
+    }
+}
+
+ +

プログラムをコンパイルして実行すると、出力が生成されます

+ +
f(Object)
+f(Object)
+f(Object)
+
+ +

しかし、同様のスクリプトを書くと

+ +
var o = new Packages.Overload();
+var a = [ 3, "hi", Packages.Overload ];
+for (var i = 0; i != a.length; ++i)
+    print(o.f(a[i]));
+
+ +

それを実行すると、出力が得られます

+ +
f(int)
+f(String)
+f(Object)
+
+ +

Rhino は実行時にオーバーロードされたメソッドを選択するため、引数に一致するより具体的な型を呼び出します。その間、Java はコンパイル時に引数の型だけでオーバーロードされたメソッドを選択します。

+ +

これは、各呼び出しでより良い一致が可能なメソッドを選択する利点がありますが、より多くの作業が行われるためパフォーマンスに影響します。実際には、この性能コストは実際のアプリケーションでは顕著ではありません。

+ +

過負荷の解決は実行時に発生するため、実行時に失敗する可能性があります。たとえば、Overload のメソッド g を2つの整数で呼び出すと、どちらのメソッドの形式も他よりも引数の型が近くないため、エラーが発生します。

+ +
js> o.g(3,4)
+js:"<stdin>", line 2: The choice of Java method Overload.g
+matching JavaScript argument types (number,number) is ambiguous;
+candidate methods are:
+class java.lang.String g(java.lang.String,int)
+class java.lang.String g(int,java.lang.String)
+
+ +

オーバーロードセマンティクスのより正確な定義については、Java メソッドのオーバーロードと LiveConnect 3 を参照してください。

+ +

Java インターフェイスの実装

+ +

Java クラスにアクセスし、Java オブジェクトを作成し、それらのオブジェクトのフィールド、メソッド、プロパティにアクセスできるようになったので、私たちはすぐに大きな力を持っています。しかし、それだけでは不十分な例がいくつかあります。Java の多くの API は、クライアントが実装しなければならないインターフェースを提供することで機能します。その1つの例は Thread クラスです。そのコンストラクタは、新しいスレッドが開始されたときに呼び出される単一メソッドの run を含む Runnable を取ります。

+ +

このニーズに対応するため、Rhino はインターフェイスを実装する新しい Java オブジェクトを作成する機能を提供します。まず、Java インターフェイスで必要とされるメソッドと名前が一致する関数プロパティーを持つ JavaScript オブジェクトを定義する必要があります。Runnable を実装するには、パラメータを指定せずに実行するメソッドを1つだけ定義する必要があります。第3章から覚えていれば、{propertyName:value} 表記で JavaScript オブジェクトを定義することは可能です。この構文を関数式と組み合わせて使用すると、run メソッドで JavaScript オブジェクトを定義できます。

+ +
js> obj = { run: function () { print("\nrunning"); } }
+[object Object]
+js> obj.run()
+
+running
+
+ +

Runnable を構築することによって、Runnable インターフェイスを実装するオブジェクトを作成できます。

+ +
js> r = new java.lang.Runnable(obj);
+[object JavaObject]
+
+ +

Java ではインプリメンテーションが利用できないため、インターフェイス上で new 演算子を使用することはできません。ここで Rhino は JavaScript オブジェクト obj から実装を取得します。Runnable を実装するオブジェクトができたので、Thread を作成して実行することができます。run に対して定義した関数は、新しいスレッドで呼び出されます。

+ +
js> t = new java.lang.Thread(r)
+Thread[Thread-2,5,main]
+js> t.start()
+js>
+
+running
+
+ +

最後の js プロンプトと新しいスレッドからの出力は、スレッドのスケジューリングに応じてどちらの順序でも表示されます。

+ +

Rhino は Runnable を実装する新しい Java クラスのバイトコードを生成し、run メソッドへのすべての呼び出しを関連する JavaScript オブジェクトに転送します。このクラスを実装するオブジェクトは Java アダプタと呼ばれます。JavaScript への転送は実行時に行われるため、呼び出されるまでインターフェイスを実装するメソッドの定義を遅らせることができます。必要なメソッドを省略することは大規模なプログラミングにおいては悪い習慣ですが、小さなスクリプトや探索的プログラミングには便利です。

+ +

JavaAdapter コンストラクタ

+ +

前のセクションでは、Java インターフェイスで new 演算子を使用して Java アダプタを作成しました。このアプローチには限界があります。複数のインターフェイスを実装することは不可能であり、非抽象クラスを拡張することもできません。これらの理由から、JavaAdapter コンストラクタがあります。

+ +

JavaAdapter コンストラクタの構文は次のとおりです。

+ +
new JavaAdapter(javaIntfOrClass, [javaIntf, ..., javaIntf,] javascriptObject)
+
+ +

ここで javaIntfOrClass は実装するインターフェイスまたは拡張するクラスであり、javaIntf は実装するための追加のインターフェイスです。javascriptObject は、Java アダプタから呼び出されるメソッドを含む JavaScript オブジェクトです。

+ +

実際には、JavaAdapter コンストラクタを直接呼び出す必要はほとんどありません。ほとんどの場合、new 演算子を使用する前の構文で十分です。

+ +

Java インターフェイスとしての JavaScript 関数

+ +

多くの場合、前述の Runnable の例のように、またはさまざまなイベントリスナの実装を提供する場合のように、1つのメソッドだけを持つインターフェイスを実装する必要があります。 これを容易にするために、Rhino はそのようなインターフェイスが期待されるときに JavaScript 関数を渡すことができます。この関数はインターフェイスメソッドの実装として呼び出されます。

+ +

以下は単純化された Runnable の例です:

+ +
js> t = java.lang.Thread(function () { print("\nrunning"); });
+Thread[Thread-0,5,main]
+js> t.start()
+js>
+running
+
+ +

Rhino では、すべてのメソッドが同じシグネチャを持つ場合、複数のメソッドを持つ Java インターフェイスの実装として JavaScript 関数を使用することもできます。関数を呼び出すと、Rhino はメソッドの名前を追加の引数として渡します。関数は、呼び出されたメソッドに代わって関数を使用して区別できます。

+ +
js> var frame = new Packages.javax.swing.JFrame();
+js> frame.addWindowListener(function(event, methodName) {
+	if (methodName == "windowClosing") {
+            print("Calling System.exit()..."); java.lang.System.exit(0);
+	}
+    });
+js> frame.setSize(100, 100);
+js> frame.visible = true;
+true
+js> Calling System.exit()...
+
+ +

Java 配列の作成

+ +

Rhino には Java 配列を作成するための特別な構文はありません。このためには java.lang.reflect.Array クラスを使用する必要があります。5つの Java 文字列の配列を作成するには次の呼び出しを行います。

+ +
js> a = java.lang.reflect.Array.newInstance(java.lang.String, 5);
+[Ljava.lang.String;@7ffe01
+
+ +

プリミティブ型の配列を作成するには、java.lang パッケージの関連オブジェクトクラスで定義されている特殊な TYPE フィールドを使用する必要があります。たとえば、バイトの配列を作成するには特別なフィールド java.lang.Byte.TYPE を使用する必要があります。

+ +
js> a = java.lang.reflect.Array.newInstance(java.lang.Character.TYPE, 2);
+[C@7a84e4
+
+ +

結果の値は、その型の Java 配列が許可されている任意の場所で使用できます。

+ +
js> a[0] = 104
+104
+js> a[1] = 105
+105
+js> new java.lang.String(a)
+hi
+
+ +

Java 文字列と JavaScript 文字列

+ +

Java 文字列と JavaScript 文字列は同じではないことに注意してください。Java 文字列は java.lang.String 型のインスタンスであり、そのクラスによって定義されたすべてのメソッドを持ちます。JavaScript 文字列には String.prototype で定義されたメソッドがあります。最も一般的な障害は length です。これは Java 文字列のメソッドであり、JavaScript 文字列の動的プロパティです。

+ +
js> javaString = new java.lang.String("Java")
+Java
+js> jsString = "JavaScript"
+JavaScript
+js> javaString.length()
+4
+js> jsString.length
+10
+
+ +

Rhino は2つの型の違いを減らすための助けとなります。まず Java 文字列を Java メソッドに渡し、Rhino が変換を実行します。 前の例の java.lang.String コンストラクタの呼び出しで実際にこの機能が動作していました。

+ +

Rhino は、java.lang.String クラスがまだそれらを定義していない場合、JavaScript メソッドを Java 文字列で使用できるようにします。例えば:

+ +
js> javaString.match(/a.*/)
+ava
+
+ +

JavaImporter コンストラクタ

+ +

JavaImporter は、Java のスクリプト作成時に明示的なパッケージ名を省略できる新しいグローバルコンストラクタです。

+ +
var SwingGui = JavaImporter(Packages.javax.swing,
+                            Packages.javax.swing.event,
+                            Packages.javax.swing.border,
+                            java.awt.event,
+                            java.awt.Point,
+                            java.awt.Rectangle,
+                            java.awt.Dimension);
+...
+
+with (SwingGui) {
+    var mybutton = new JButton(test);
+    var mypoint = new Point(10, 10);
+    var myframe = new JFrame();
+...
+}
+
+ +

これまでこのような機能は org.mozilla.javascript.ImporterTopLevel クラスをトップレベルのスコープとして使用した埋め込みにのみ使用できました。このクラスでは、スクリプト用の importPackage() および importClass() グローバル関数が追加されていますが、広範囲に使用すると Java クラスの名前でグローバル名前空間が汚染され、ロードされたクラスがガベージコレクションから保護されます。

+ +

詳細については Bugzilla 245882 を参照してください。

+ +

Java 例外

+ +

Java メソッドによってスローされた例外は、try ... catch 文を使用して JavaScript コードで捕捉できます。Rhino は Java 例外を次のプロパティを持つエラーオブジェクトにラップします。

+ + + +

instanceof 演算子を使用すると、例外の型を問い合せることができます。

+ +
try {
+    java.lang.Class.forName("NonExistingClass");
+} catch (e) {
+    if (e.javaException instanceof java.lang.ClassNotFoundException) {
+       print("Class not found");
+    }
+}
+
+ +

Rhino は、例外の条件付きキャッチを定義する try ... catch ステートメントの拡張もサポートしています。

+ +
function classForName(name) {
+    try {
+        return java.lang.Class.forName(name);
+    } catch (e if e.javaException instanceof java.lang.ClassNotFoundException) {
+        print("Class " + name + " not found");
+    } catch (e if e.javaException instanceof java.lang.NullPointerException) {
+        print("Class name is null");
+    }
+}
+
+classForName("NonExistingClass");
+classForName(null);
+
-- cgit v1.2.3-54-g00ecf