0x0b
js_about_08
最終更新:
0x0b
-
view
LiveConnect 概要
LiveConnect とは、既存の Java インフラを使い、JavaScript に Java のクラスのメソッドを呼び出す機能やその逆の機能を設ける API の名前です。
ラッパの使用
JavaScript において、ラッパとは元の言語のオブジェクトをくるんだ、ターゲットとする言語のデータ型のオブジェクトのことです。JavaScript でプログラミングするときは、ラッパオブジェクトを用いることで Java のオブジェクトのメソッドやフィールドにアクセスすることができます。つまり、ラッパのメソッドを呼び出したりプロパティにアクセスすることで Java のオブジェクトについて呼び出すことになるのです。Java 側では JavaScript のオブジェクトはクラス netscape.javascript.JSObject のインスタンスでラップされ、Java に渡されます。
JavaScript のオブジェクトが Java に送られる際、ランタイムエンジンは JSObject 型の Java ラッパを生成します。一方 JSObject が Java から JavaScript に送られるときは、ランタイムエンジンはそのラップを解き、その元々の JavaScript のオブジェクトの種類にします。JSObject クラスには JavaScript のメソッドを呼び出したり JavaScript のプロパティをテストするためのインタフェースが備わっています。
JavaScript から Java への通信
Java のパッケージやクラスを参照したり、Java のオブジェクトや配列を扱ったりするときには、特別な LiveConnect オブジェクトを使用します。JavaScript から Java へのアクセスはすべてこれらのオブジェクトを用いて行われます。それらのオブジェクトについて以下の表で簡単にまとめます。
オブジェクト | 説明 |
JavaArray | ラップされた Java の配列。JavaScript コード内からアクセスされる |
JavaClass | Java のクラスへの JavaScript からの参照 |
JavaObject | ラップされた Java のオブジェクト。JavaScript コード内からアクセスされる |
JavaPackage | Java のパッケージへの JavaScript からの参照 |
表:LiveConnect オブジェクト
注意:Java は強く型付けされた言語であり、JavaScript は弱く型付けされた言語であるため、LiveConnect を使用する際はもう一方の言語のために JavaScript ランタイムエンジンが引数の値を適当なデータ型に変換します。詳細は データ型の変換 をご覧ください。
ある意味で LiveConnect オブジェクトの存在は透過的です。かなり直観的に Java とやりとりできるからです。例えば、次のように Java の String オブジェクトを作成し、new 演算子を Java のコンストラクタとともに用いてそのオブジェクトを JavaScript の変数 myString に代入することができます。
var myString = new java.lang.String("Hello world")
この例では、変数 myString は JavaObject になります。Java の String オブジェクトのインスタンスを保持しているためです。JavaObject として、myString は java.lang.String およびそのスーパークラスである java.lang.Object のパブリックなインスタンスメソッドにアクセスできます。これらの Java のメソッドは JavaScript から JavaObject のメソッドとして使用できます。また、それは次のようにしてを呼び出すことができます。
myString.length() // 11 を返す
JavaClass オブジェクトの静的メンバは直接呼び出すことができます。
alert(java.lang.Integer.MAX_VALUE); // 2147483647 というアラート
Packages オブジェクト
Java のクラスが java、sun あるいは netscape パッケージのいずれの一部でもない場合は、Packages オブジェクトを用いてそれにアクセスします。例えば、Redwood 社が、実装したさまざまな Java のクラスを格納するための redwood という名前の Java パッケージを使用することを想定します。redwood の HelloWorld クラスのインスタンスを作成するには、次のようにそのクラスのコンストラクタにアクセスします。
Java のクラスが java、sun あるいは netscape パッケージのいずれの一部でもない場合は、Packages オブジェクトを用いてそれにアクセスします。例えば、Redwood 社が、実装したさまざまな Java のクラスを格納するための redwood という名前の Java パッケージを使用することを想定します。redwood の HelloWorld クラスのインスタンスを作成するには、次のようにそのクラスのコンストラクタにアクセスします。
var red = new Packages.redwood.HelloWorld()
デフォルトパッケージのクラス(すなわち明示的にはパッケージに名前を付けていないクラス)にアクセスすることもできます。例えば、HelloWorld クラスが直接 CLASSPATH に入っており、パッケージには入っていない場合、次のようにしてそれにアクセスできます。
var red = new Packages.HelloWorld()
LiveConnect の java、sun および netscape オブジェクトはよく使用される Java のパッケージであるために、短縮記法が備わっています。例えば次のように使用できます。
var myString = new java.lang.String("Hello world")
これは次のものを省略したものです。
var myString = new Packages.java.lang.String("Hello world")
Java の配列の使用
Java のメソッドで配列を作成し、JavaScript からその配列を参照するときは JavaArray を使用します。例えば、次のコードは int 型の 10 個の要素を持つ JavaArray x を作成します。
x = java.lang.reflect.Array.newInstance(java.lang.Integer, 10)
JavaScript の Array オブジェクトのように、JavaArray にはその配列の要素数を返す length プロパティがあります。Array.length とは異なり、JavaArray.length は読み取り専用のプロパティです。Java の配列は作成時に要素数が固定されるためです。
パッケージおよびクラスの参照
JavaScript から Java のパッケージやクラスへの簡単な参照では JavaPackage や JavaClass オブジェクトが作成されます。先の Redwood 社についての例では、例えば Packages.redwood という参照が JavaPackage オブジェクトです。同様に java.lang.String のような参照は JavaClass オブジェクトです。
JavaScript から Java のパッケージやクラスへの簡単な参照では JavaPackage や JavaClass オブジェクトが作成されます。先の Redwood 社についての例では、例えば Packages.redwood という参照が JavaPackage オブジェクトです。同様に java.lang.String のような参照は JavaClass オブジェクトです。
ほとんどの場合は JavaPackage および JavaClass オブジェクトについて気にする必要はありません。ただ Java のパッケージやクラスを使うだけのことであり、LiveConnect がこれらオブジェクトを透過的に生成するからです。
JavaScript 1.3 以前では JavaClass オブジェクトをパラメータとして Java のメソッドに渡す際に自動的には java.lang.Class のインスタンスに変換されません。そのため、java.lang.Class のインスタンスのラッパを作成しなければなりません。次の例では、forName メソッドがラッパオブジェクトである theClass を生成します。そしてそれを newInstance メソッドに渡し、配列を生成します。
// JavaScript 1.3 theClass = java.lang.Class.forName("java.lang.String") theArray = java.lang.reflect.Array.newInstance(theClass, 5)
JavaScript 1.4 以降では次の例のように JavaClass オブジェクトをメソッドに直接渡すことができます。
// JavaScript 1.4 theArray = java.lang.reflect.Array.newInstance(java.lang.String, 5)
char 型の引数
JavaScript 1.4 以降では char 型の引数を必要とする Java のメソッドに 1 文字の文字列を渡すことができます。例えば、次のようにして文字列 "H" を Character コンストラクタに渡すことができます。
c = new java.lang.Character("H")
JavaScript 1.3 以前では、このようなメソッドにはその文字の Unicode 値に対応する整数を渡さなければなりません。例えば、次のコードも "H" という値を変数 c に代入するものです。
c = new java.lang.Character(72)
JavaScript での Java の例外処理
Java のコードが実行時に失敗すると例外を投げます。JavaScript のコードが Java のデータメンバまたはメソッドにアクセスし、失敗すると、Java の例外が JavaScript に渡されます。それを処理できるようにするためです。JavaScript 1.4 からは try...catch 文でこの例外を受け取ることができます。
例えば、Java の forName メソッドを使用して Java のクラス名を theClass という変数に代入するとします。forName メソッドに渡す値が Java のクラス名に評価できなければそのメソッドは例外を投げます。次のようにして、例外を処理できるように forName 代入文を try ブロック内に置きます。
function getClass(javaClassName) { try { var theClass = java.lang.Class.forName(javaClassName); } catch (e) { return ("The Java exception is " + e); } return theClass }
この例では、javaClassName が "java.lang.String" のような正当なクラス名に評価されると代入が成功します。javaClassName が "String" のような不正なクラス名に評価されると getClass 関数が例外を受け取り、次のようなものを返します。
The Java exception is java.lang.ClassNotFoundException: String
例外の型に基づいて特別な処理をするには instanceof 演算子を使用します。
try { // ... } catch (e) { if (e instanceof java.io.FileNotFound) { // FileNotFound についての処理 } else { throw e; } }
JavaScript の例外についての詳細情報は 例外処理文 を参照してください。
Packages オブジェクト
Java to JavaScript Communication
Java で JavaScript のオブジェクトを使用したい場合は、その Java ファイルに netscape.javascript パッケージをインポートしなければなりません。このパッケージは次のクラスを定義しています。
netscape.javascript.JSObject:Java のコードから JavaScript のメソッドやプロパティにアクセスできるようにする。
netscape.javascript.JSException:Java のコードで JavaScript のエラーを処理できるようにする。
これらのクラスについての詳細は コア JavaScript リファレンス をご覧ください。
netscape.javascript.JSException:Java のコードで JavaScript のエラーを処理できるようにする。
これらのクラスについての詳細は コア JavaScript リファレンス をご覧ください。
LiveConnect クラスの場所の特定
古いバージョンの Netscape ブラウザではこれらのクラスがブラウザに同梱されていました。JavaScript 1.2 からはこれらのクラスは .jar ファイルに格納されています。それより古いバージョンの JavaScript では、これらのクラスは .zip ファイルに格納されています。例えば Windows NT 向けの Netscape Navigator 4 では、クラスは Navigator ディレクトリ直下の Program\Java\Classes ディレクトリ内の java40.jar ファイルに格納されています。
古いバージョンの Netscape ブラウザではこれらのクラスがブラウザに同梱されていました。JavaScript 1.2 からはこれらのクラスは .jar ファイルに格納されています。それより古いバージョンの JavaScript では、これらのクラスは .zip ファイルに格納されています。例えば Windows NT 向けの Netscape Navigator 4 では、クラスは Navigator ディレクトリ直下の Program\Java\Classes ディレクトリ内の java40.jar ファイルに格納されています。
より最近ではクラスは Sun の Java ランタイムに同梱されています。はじめはランタイムパッケージの "jre/lib" ディレクトリ内の "jaws.jar" ファイルに入っていましたが (JRE 1.3)、その後同じ場所の "plugin.jar" に移っています(JRE 1.4 以降)。
JDK での LiveConnect クラスの使用
LiveConnect クラスにアクセスするには、次のどちらかの方法で JDK コンパイラの CLASSPATH に .jar または .zip ファイルを配置します。
LiveConnect クラスにアクセスするには、次のどちらかの方法で JDK コンパイラの CLASSPATH に .jar または .zip ファイルを配置します。
CLASSPATH 環境変数を作成し、.jar または .zip ファイルのパスと名前を指定する。
コンパイル時に -classpath コマンドラインパラメータを用いて .jar または .zip ファイルの場所を指定する。
Windows NT では、コントロールパネルのシステムアイコンをダブルクリックし、CLASSPATH という名前のユーザ環境変数を作成し、それに次のような値を設定することで環境変数を指定できます。
コンパイル時に -classpath コマンドラインパラメータを用いて .jar または .zip ファイルの場所を指定する。
Windows NT では、コントロールパネルのシステムアイコンをダブルクリックし、CLASSPATH という名前のユーザ環境変数を作成し、それに次のような値を設定することで環境変数を指定できます。
C:\Program Files\Java\jre1.4.1\lib\plugin.jar
CLASSPATH についての詳細は Sun の JDK に関する資料をご覧ください。
注意:Java は強く型付けされた言語であり、JavaScript は弱く型付けされた言語であるため、LiveConnect を使用する際はもう一方の言語のために JavaScript ランタイムエンジンが引数の値を適当なデータ型に変換します。詳細は データ型の変換 をご覧ください。
Java の配列の使用
パッケージおよびクラスの参照
char 型の引数
JavaScript での Java の例外処理
Java から JavaScript への通信
LiveConnect クラスの使用
すべての JavaScript のオブジェクトは、Java コード内では netscape.javascript.JSObject のインスタンスとして現れます。Java コード内でメソッドを呼び出すときに、その引数として JavaScript のオブジェクトを渡すことができます。そうするためにはそのメソッドの対応する仮パラメータを JSObject 型に定義しなければなりません。
さらに、Java コード内で JavaScript のオブジェクトを使用するたびに、netscape.javascript.JSException 型の例外を処理する try...catch 文の内側でその JavaScript のオブジェクトを呼び出すようにしてください。こうすることで JSException 型の例外として Java に現れる、JavaScript コードの実行におけるエラーを Java コードで処理できるようになります。
JSObject を用いた JavaScript へのアクセス
例えば、JavaDog という Java のクラスを使用するとします。次のコードで示すように、JavaDog コンストラクタは JavaScript のオブジェクトである jsDog を引数としてとります。このオブジェクトは JSObject 型として定義されています。
例えば、JavaDog という Java のクラスを使用するとします。次のコードで示すように、JavaDog コンストラクタは JavaScript のオブジェクトである jsDog を引数としてとります。このオブジェクトは JSObject 型として定義されています。
import netscape.javascript.*; public class JavaDog { public String dogBreed; public String dogColor; public String dogSex; // クラスコンストラクタの定義 public JavaDog(JSObject jsDog) { // ここで try...catch を使用して JSExceptions を処理できるようにする this.dogBreed = (String)jsDog.getMember("breed"); this.dogColor = (String)jsDog.getMember("color"); this.dogSex = (String)jsDog.getMember("sex"); } }
JSObject の getMember メソッドは JavaScript のオブジェクトのプロパティにアクセスするために使用するものです。この例では JavaScript のプロパティである jsDog.breed の値を Java のデータメンバである JavaDog.dogBreed に代入するために getMember を使用しています。
注意:より現実的な例では try...catch 文の内側で getMember を呼び出し、JSException 型のエラーを処理できるようにします。詳細は Java での JavaScript の例外処理を参照してください。
getMember の動作をさらに知るために、JavaScript の Dog オブジェクトを作成し、その定義を見てみます。
function Dog(breed,color,sex) { this.breed = breed this.color = color this.sex = sex }
Dog の JavaScript のインスタンスである gabby は次のようにして作ることができます。
gabby = new Dog("lab","chocolate","female")
gabby.color を評価すると、それが "chocolate" という値を持っていることがわかります。ここで次のように gabby オブジェクトをコンストラクタに渡し、JavaScript コードで JavaDog のインスタンスを作成することにします。
javaDog = new Packages.JavaDog(gabby)
javaDog.dogColor を評価すると、それも "chocolate" という値を持っていることがわかります。これは Java のコンストラクタ内の getMember メソッドが gabby.color の値を dogColor に代入するからです。
Java での JavaScript の例外処理
実行時に Java からの JavaScript コードの呼び出しに失敗すると、例外が投げられます。Java から JavaScript コードを呼び出すときに try...catch 文でこの例外を受け取ることができます。JavaScript の例外は netscape.javascript.JSException のインスタンスとして Java コードから扱えます。
実行時に Java からの JavaScript コードの呼び出しに失敗すると、例外が投げられます。Java から JavaScript コードを呼び出すときに try...catch 文でこの例外を受け取ることができます。JavaScript の例外は netscape.javascript.JSException のインスタンスとして Java コードから扱えます。
JSException は JavaScript が投げるあらゆる種類の例外に対する Java のラッパです。JSObject のインスタンスが JavaScript のオブジェクトのラッパであるのと同じようなものです。Java で JavaScript コードを評価するときは JSException を使用してください。
Java で JavaScript コードを評価する際、次の状況でランタイムエラーが生じます。
JavaScript コードが評価されない。JavaScript のコンパイルエラーまたは実行時に生じる他のエラーによる。JavaScript インタプリタは JSException のインスタンスに変換されるエラーメッセージを生成する。
Java はうまく JavaScript コードを評価しても、JavaScript コードが処理方法が定かでない throw 文を実行する。JavaScript は JSException のインスタンスとしてラップされる例外を投げる。Java でこの例外のラップを解くには JSException の getWrappedException メソッドを使用する。
例えば、Java のオブジェクトである eTest に渡す文字列 jsCode をそのオブジェクトが評価するとします。次のようなエラー処理を実装することで、評価が原因のどちらの種類のランタイムエラーにも対応できます。
Java はうまく JavaScript コードを評価しても、JavaScript コードが処理方法が定かでない throw 文を実行する。JavaScript は JSException のインスタンスとしてラップされる例外を投げる。Java でこの例外のラップを解くには JSException の getWrappedException メソッドを使用する。
例えば、Java のオブジェクトである eTest に渡す文字列 jsCode をそのオブジェクトが評価するとします。次のようなエラー処理を実装することで、評価が原因のどちらの種類のランタイムエラーにも対応できます。
import netscape.javascript.JSObject; import netscape.javascript.JSException; public class eTest { public static Object doit(JSObject obj, String jsCode) { try { obj.eval(jsCode); } catch (JSException e) { if (e.getWrappedException()==null) return e; return e.getWrappedException(); } return null; } }
この例では、渡された文字列 jsCode を try ブロック内のコードが評価しようとします。文字列 "myFunction()" を jsCode の値として渡すとします。myFunction が JavaScript の関数として定義されていない場合、JavaScript インタプリタは jsCode を評価できません。インタプリタはエラーメッセージを生成し、Java のハンドラがそのメッセージを受け取り、doit メソッドは netscape.javascript.JSException のインスタンスを返します。
しかし、次のように myFunction が JavaScript で定義されているとします。
function myFunction() { try { if (theCondition == true) { return "Everything's ok"; } else { throw "JavaScript error occurred" ; } } catch (e) { if (canHandle == true) { handleIt(); } else { throw e; } } }
theCondition が false だと関数は例外を投げます。その例外は JavaScript コードで受け取られ、さらに canHandle が true の場合に JavaScript はそれを処理します。canHandle が false ならばその例外が再び投げられ、Java のハンドラがそれを受け取り、doit メソッドが次の Java の文字列を返します。
JavaScript error occurred
JavaScript の例外についての詳細情報は 例外処理文 を参照してください。
JavaScript の例外についての詳細情報は 例外処理文 を参照してください。
後方互換性
JavaScript 1.3 以前のバージョンでは、JSException クラスにはオプション的な文字列引数をとる 3 つのパブリックなコンストラクタがありました。この文字列引数は詳細なメッセージやその例外に対する他の情報を指定するものです。getWrappedException メソッドは使用できませんでした。
JavaScript 1.3 以前のバージョンでは、JSException クラスにはオプション的な文字列引数をとる 3 つのパブリックなコンストラクタがありました。この文字列引数は詳細なメッセージやその例外に対する他の情報を指定するものです。getWrappedException メソッドは使用できませんでした。
次のような try...catch 文を使用することで JavaScript 1.3 以前のバージョンで LiveConnect の例外を処理できます。
try { global.eval("foo.bar = 999;"); } catch (Exception e) { if (e instanceof JSException) { jsCodeFailed()"; } else { otherCodeFailed(); } }
この例では foo が定義されていないと eval 文が失敗します。try ブロックの eval 文が JSException を投げると catch ブロックが jsCodeFailed メソッドを実行します。try ブロックがそれ以外のエラーを投げると otherCodeFailed メソッドが実行されます。
データ型変換
Java は強く型付けされた言語であり、JavaScript は弱く型付けされた言語であるため、LiveConnect を使用する際はもう一方の言語のために JavaScript ランタイムエンジンが引数の値を適当なデータ型に変換します。この変換について以下のセクションで説明します。
JavaScript から Java への変換
Java から JavaScript への変換
Java から JavaScript への変換
JavaScript から Java への変換
JavaScript から Java のメソッドを呼び出し、それにパラメータを渡す際、渡すパラメータのデータ型は以下のセクションで説明するルールに従って変換されます。
数値
真偽値
文字列
undefined 値
null 値
JavaArray および JavaObject オブジェクト
JavaClass オブジェクト
その他の JavaScript のオブジェクト
netscape.javascript.JSObject のメソッドの戻り値は常に java.lang.Object のインスタンスに変換されます。このような戻り値の変換ルールもここで説明します。
真偽値
文字列
undefined 値
null 値
JavaArray および JavaObject オブジェクト
JavaClass オブジェクト
その他の JavaScript のオブジェクト
netscape.javascript.JSObject のメソッドの戻り値は常に java.lang.Object のインスタンスに変換されます。このような戻り値の変換ルールもここで説明します。
例えば JSObject.eval が JavaScript の数値を返すのであれば、この数値を java.lang.Object のインスタンスに変換するルールは 数値 に記載されています。
数値
Java のメソッドに JavaScript の数値型をパラメータとして渡すと、Java は次の表で示すルールに従ってその値を変換します。
Java のパラメータ型 | 変換ルール |
double | そのままの値が丸められたり絶対値や符号が損なわれたりすることなく Java に渡される。 NaN は NaN に変換される |
java.lang.Double java.lang.Object |
java.lang.Double の新しいインスタンスが作成され、そのままの値が丸められたり絶対値や符号が損なわれたりすることなく Java に渡される |
float | 値は浮動小数点数に丸められる。 大きすぎまたは小さすぎて表現できない値は正の無限大または負の無限大に丸められる。 NaN は NaN に変換される |
byte char int long short |
値は負の無限大方向に丸められる。 大きすぎまたは小さすぎて表現できない値はランタイムエラーとなる。NaN は変換されずにランタイムエラーとなる |
java.lang.String | 値は文字列に変換される。 237 は "237" になる |
boolean | 0 および NaN は false に変換される。 その他の値は true に変換される |
java.lang.String のインスタンスをパラメータに想定した Java のメソッドに JavaScript の数値をパラメータとして渡すと、その数値は文字列に変換されます。equals() メソッドを使用するとこの変換結果と他の文字列を比較することができます。
真偽値
Java のメソッドに JavaScript の真偽値型をパラメータとして渡すと、Java は次の表で示すルールに従ってその値を変換します。
Java のパラメータ型 | 変換ルール |
boolean | すべての値は Java の対応するものに直接変換される |
java.lang.Boolean java.lang.Object |
java.lang.Boolean の新しいインスタンスが作成される。各パラメータについて新しいインスタンスが作成される。同一のプリミティブ値を持つ 1 つのインスタンスではない |
java.lang.String | 値は文字列に変換される。 true は "true" になる。 false は "false" になる |
byte char double float int long short |
true は 1 になる。 false は 0 になる |
java.lang.String のインスタンスをパラメータに想定した Java のメソッドに JavaScript の真偽値をパラメータとして渡すと、その真偽値は文字列に変換されます。== 演算子を使用するとこの変換結果と他の文字列を比較することができます。
文字列
Java のメソッドに JavaScript の文字列型をパラメータとして渡すと、Java は次の表で示すルールに従ってその値を変換します。
Java のパラメータ型 | 変換ルール |
java.lang.String java.lang.Object |
JavaScript 1.4: JavaScript の文字列は Unicode 値を持つ java.lang.String のインスタンスに変換される。 JavaScript 1.3 以前: A JavaScript の文字列は ASCII 値を持つ java.lang.String のインスタンスに変換される |
byte double float int long short |
すべての値は ECMA-262 に記載された数値に変換される。 JavaScript の文字列は ECMA-262 に記載されたルールに従って数値に変換される |
char | JavaScript 1.4: 1 文字の文字列は Unicode 文字に変換される。 他のすべての値は数値に変換される。 JavaScript 1.3 以前: すべての値は数値に変換される |
boolean | 空文字列は false になる。 他のすべての値は true になる |
undefined 値
Java のメソッドに JavaScript の undefined 値をパラメータとして渡すと、Java は次の表で示すルールに従ってその値を変換します。
Java のパラメータ型 | 変換ルール |
lava.lang.String java.lang.Object |
値はその値が文字列 "undefined" である java.lang.String のインスタンスに変換される |
boolean | 値は false になる |
double | float 値は NaN になる |
byte char int long short |
値は 0 になる。 |
undefined 値の変換は JavaScript 1.3 以降でのみ可能です。それより古いバージョンでは undefined 値がサポートされていません。
java.lang.String のインスタンスをパラメータに想定した Java のメソッドに JavaScript の undefined 値をパラメータとして渡すと、その undefined 値は文字列に変換されます。== 演算子を使用するとこの変換結果と他の文字列を比較することができます。
null 値
Java のメソッドに JavaScript の null 値をパラメータとして渡すと、Java は次の表で示すルールに従ってその値を変換します。
Java のメソッドに JavaScript の null 値をパラメータとして渡すと、Java は次の表で示すルールに従ってその値を変換します。
Java のパラメータ型 | 変換ルール |
あらゆるクラス あらゆるインタフェースの種類 |
値は null になる |
byte char double float int long short |
値は 0 になる |
boolean | 値は false になる |
JavaArray および JavaObject オブジェクト
ほとんどの場合、Java のメソッドに JavaScript の JavaArray または JavaObject オブジェクトをパラメータとして渡すと、Java は単にそのオブジェクトのラップを解きます。そうでない場合にはJava は次の表で示すルールに従ってそのオブジェクトを別のデータ型に変換します。
ほとんどの場合、Java のメソッドに JavaScript の JavaArray または JavaObject オブジェクトをパラメータとして渡すと、Java は単にそのオブジェクトのラップを解きます。そうでない場合にはJava は次の表で示すルールに従ってそのオブジェクトを別のデータ型に変換します。
Java のパラメータ型 | 変換ルール |
ラップが解かれたオブジェクトと代入互換性のある、あらゆるインタフェースまたはクラス | オブジェクトのラップが解かれる |
java.lang.String | オブジェクトのラップが解かれ、ラップが解かれた Java のオブジェクトの toString メソッドが呼び出され、java.lang.String の新しいインスタンスが返される |
byte char double float int long short |
オブジェクトのラップが解かれ、次の状況のどちらかが起こる。&brラップが解かれた Java のオブジェクトに doubleValue メソッドがあれば、JavaArray または JavaObject がこのメソッドが返す値に変換される。 ラップが解かれた Java のオブジェクトに doubleValue メソッドがなければエラーが生じる |
boolean | JavaScript 1.3 以降ではオブジェクトのラップが解かれ、次の状況のどちらかが起こる。 オブジェクトが null ならば false に変換される。 オブジェクトがそれ以外の値ならば true に変換される JavaScript 1.2 以前ではオブジェクトのラップが解かれ、次の状況のどちらかが起こる ラップが解かれたオブジェクトに booleanValue メソッドがあれば、ソースオブジェクトが戻り値に変換される。 オブジェクトに booleanValue メソッドがなければ変換に失敗する |
ラップが解かれたオブジェクトが Java のパラメータ型のインスタンスであれば、インタフェースまたはクラスがラップが解かれたオブジェクトと代入互換性があるということです。つまり、次の文は必ず true を返します。
unwrappedObject instanceof parameterType
JavaClass オブジェクト
Java のメソッドに JavaScript の JavaClass オブジェクトをパラメータとして渡すと、Java は次の表で示すルールに従ってその値を変換します。
Java のメソッドに JavaScript の JavaClass オブジェクトをパラメータとして渡すと、Java は次の表で示すルールに従ってその値を変換します。
Java のパラメータ型 | 変換ルール |
java.lang.Class | オブジェクトのラップが解かれる。 |
netscape.javascript.JSObject java.lang.Object |
JavaClass オブジェクトが netscape.javascript.JSObject の新しいインスタンス内にラップされる |
java.lang.String | オブジェクトのラップが解かれ、ラップが解かれた Java のオブジェクトの toString メソッドが呼び出され、java.lang.String の新しいインスタンスが返される |
boolean | JavaScript 1.3 以降ではオブジェクトのラップが解かれ、次の状況のどちらかが起こる。 オブジェクトが null ならば false に変換される。 オブジェクトがそれ以外の値ならば true に変換される。 JavaScript 1.2 以前ではオブジェクトのラップが解かれ、次の状況のどちらかが起こる。 ラップが解かれたオブジェクトに booleanValue メソッドがあれば、ソースオブジェクトが戻り値に変換される。 オブジェクトに booleanValue メソッドがなければ変換に失敗する。 |
その他の JavaScript のオブジェクト
Java のメソッドに JavaScript のその他のオブジェクトをパラメータとして渡すと、Java は次の表で示すルールに従ってその値を変換します。
Java のパラメータ型 | 変換ルール |
netscape.javascript.JSObject java.lang.Object |
オブジェクトが netscape.javascript.JSObject の新しいインスタンス内にラップされる |
java.lang.String | オブジェクトのラップが解かれ、ラップが解かれたオブジェクトの toString メソッドが呼び出され、java.lang.String の新しいインスタンスが返される |
byte char double float int long short |
オブジェクトが ECMA-262 に記載された ToPrimitive 演算子の論理を使用した値に変換される。この演算子で使用される PreferredType ヒントは Number |
boolean | JavaScript 1.3 以降ではオブジェクトのラップが解かれ、次の状況のどちらかが起こる。 オブジェクトが null ならば false に変換される。 オブジェクトがそれ以外の値ならば true に変換される。 JavaScript 1.2 以前ではオブジェクトのラップが解かれ、次の状況のどちらかが起こる。 ラップが解かれたオブジェクトに booleanValue メソッドがあれば、ソースオブジェクトが戻り値に変換される。 オブジェクトに booleanValue メソッドがなければ変換に失敗する。 |
Java から JavaScript への変換
Java から JavaScript への変換
Java から JavaScript に渡された値は次のように変換されます。
- Java の byte、char、short、int、long、float および double は JavaScript の数値に変換される。
- Java の boolean は JavaScript の真偽値に変換される。
クラス netscape.javascript.JSObject のオブジェクトは元の JavaScript のオブジェクトに変換される。
- Java の配列は JavaScript の擬似的な Array オブジェクトに変換される。このオブジェクトは JavaScript の Array オブジェクトと全く同じような挙動をとる。つまり、arrayName[index](index は整数)という構文でそれにアクセスでき、その長さを arrayName.length で決定できる。
- Java のそれ以外のクラスのオブジェクトは JavaScript のラッパに変換される。このラッパを通じて Java のオブジェクトのメソッドやフィールドにアクセスすることができる。
- このラッパから文字列への変換では元のオブジェクト上で toString メソッドが呼び出される。
数値への変換では、可能であれば doubleValue メソッドが呼び出され、そうでなければ失敗する。
- JavaScript 1.3 以降の真偽値への変換では、そのオブジェクトが null であれば false を、そうでなければ true を返す。
- JavaScript 1.2 以前の真偽値への変換では、可能であれば booleanValue メソッドが呼び出され、そうでなければ失敗する。
- java.lang.Double および java.lang.Integer のインスタンスは JavaScript の数値ではなく JavaScript のオブジェクトに変換されることに注意してください。同様に、java.lang.String のインスタンスも JavaScript の文字列ではなく JavaScript のオブジェクトに変換されます。
Java の String オブジェクトは JavaScript のラッパにも対応しています。JavaScript の文字列を必要とする JavaScript のメソッドを呼び出し、それにこのラッパを渡すとエラーになります。そうではなく、次のようにラッパに空文字列を付加することでそのラッパを JavaScript の文字列に変換してください。
var JavaString = JavaObj.methodThatReturnsAString(); var JavaScriptString = JavaString + "";
E4X(ECMAScript for XML) を用いた XML 処理
JavaScript 1.6 で導入
JavaScript 1.6 で初めて導入された E4X により、JavaScript 言語にネイティブ XML オブジェクトが導入され、さらに XML 文書リテラルを JavaScript コードに埋め込むための構文も追加されています。
JavaScript 1.6 で初めて導入された E4X により、JavaScript 言語にネイティブ XML オブジェクトが導入され、さらに XML 文書リテラルを JavaScript コードに埋め込むための構文も追加されています。
E4X の完全な定義は Ecma-357 仕様 でなされています。この章では実用的な概要を示します。完全なリファレンスではありません。
互換性の問題
<script> 要素のサポートがブラウザの間で広く普及する前は、JavaScript をページに埋め込むときに HTML コメントタグで囲むことで、<script> を知らないブラウザが JavaScript コードをそのまま表示してしまうのを防ぐということが一般的でした。この慣習はもう不要ですが、古いコードでは残っていることがあります。後方互換性のため、E4X はコメントや CDATA セクションを無視するのがデフォルトの動作です。e4x=1 引数を <script> タグに加えることでこの制限を無効にできます。
<script type="text/javascript;e4x=1"> ... </script>
XML オブジェクトの作成
E4X には XML オブジェクトを作成する方法が 2 つあります。1 つ目は XML コンストラクタに文字列を渡す方法です。
var languages = new XML('<languages type="dynamic"><lang>JavaScript</lang><lang>Python</lang></languages>');
2 つ目はスクリプトに XML を XML リテラルとして直接埋め込むことです。
var languages = <languages type="dynamic"> <lang>JavaScript</lang> <lang>Python</lang> </languages>;
どちらの場合も結果として得られるオブジェクトは E4X XML オブジェクトです。これには内部データにアクセスしたりそれを変更したりするための便利な構文が備わっています。
XML オブジェクトは通常の JavaScript オブジェクトのように見え、そのような挙動をとりますが、その 2 つは同じものではありません。E4X では E4X XML オブジェクトにおいてのみ動作する新たな構文が導入されています。その構文は JavaScript プログラマにとって取っつきやすいように設計されていますが、E4X では XML からネイティブ JavaScript オブジェクトへの直接のマッピングが用意されていません。そう見えるだけです。
属性の操作
上記の例を実行すると変数 languages は XML 文書の <languages> に対応する XML オブジェクトへの参照となります。このノードには type という 1 つの属性があり、それにアクセスしたり、それを変更したりする方法はいくつもあります。
alert(languages.@type); // "dynamic" というアラート languages.@type = "agile"; alert(languages.@type); // "agile" というアラート alert(languages.toString()); /* アラート: <languages type="agile"><lang>JavaScript</lang><lang>Python</lang></languages> */
XML オブジェクトの操作
XML オブジェクトにはその中身を検査したり変更するためのメソッドがたくさん用意されています。それらは JavaScript の通常のドットや [] という記法をサポートしていますが、オブジェクトのプロパティにアクセスするのではなく、E4X ではその要素の子にアクセスするための演算子として定義されています。
var person = <person> <name>Bob Smith</name> <likes> <os>Linux</os> <browser>Firefox</browser> <language>JavaScript</language> <language>Python</language> </likes> </person>; alert(person.name); // Bob Smith alert(person['name']); // Bob Smith alert(person.likes.browser); // Firefox alert(person['likes'].browser); // Firefox
複数の要素がマッチするようなものにアクセスすると XMLList が返されます。
alert(person.likes.language.length()); // 2
DOM と同様に * を使うことですべての子ノードにアクセスすることができます。
alert(person.likes.*.length()); // 4
. 演算子は与えられたノードの直接の子にアクセスしますが、.. 演算子はネストの深さにかかわらずすべての子にアクセスします。
alert(person..*.length()); // 11
この場合、length() メソッドは 11 を返します。結果として得られる XMLList には要素とテキストノードがともに含まれるためです。
XML 要素を表すオブジェクトには便利なメソッドがたくさん用意されています。そのうちのいくつかを以下に示します。
alert(person.name.text()) // Bob Smith
var xml = person.toXMLString(); // XML からなる文字列
var personCopy = person.copy(); // XML オブジェクトのディープコピー
var child = person.child(1); // 2 番目の子ノード:この場合は <likes> 要素
XMLLists の操作
XML オブジェクトに加えて、E4X では XMLList オブジェクトが導入されています。XMLList は XML オブジェクトの順序付きの集まりを表します。例えば、要素のリストです。上記の例に続き、次のようにすると <lang> 要素の XMLList にアクセスすることができます。
var langs = languages.lang;
XMLList には格納している要素数を知るための length() メソッドがあります。
alert(languages.lang.length());
JavaScript の配列とは違い、length はプロパティではなくメソッドであり、必ず length() として呼び出さなければならないことに注意してください。
次のようにしてマッチする要素について繰り返すことができます。
for (var i = 0; i < languages.lang.length(); i++) { alert(languages.lang[i].toString()); }
ここでは配列のアイテムに順にアクセスするときと全く同じ構文を使っています。このように通常の配列に似ているにもかかわらず、XMLList は forEach のような Array のメソッドをサポートしていません。また、Array.forEach() のような Array のジェネリックスも XMLList オブジェクトとは互換性がありません。
JavaScript 1.6 で JavaScript の E4X サポートの一部として導入された for each...in 文 を使うこともできます。
for each (var lang in languages.lang) { alert(lang); }
for each...in は通常の JavaScript のオブジェクトについて使うと、そのオブジェクトに含まれる値(キーではなく)に対して繰り返すこともできます。for...in と同様、配列について使用するのは 全く推奨できません。
整形式の XML を文書を作らずとも、次のような XML リテラル構文を用いて XMLList を作ることができます。
var xmllist = <> <lang>JavaScript</lang> <lang>Python</lang> </>;
- = 演算子を使うと文書内の XMLList に要素を新たに追加することができます。
languages.lang += <lang>Ruby</lang>;
通常の DOM メソッドで返されるノードリストとは異なり、XMLList は静的であり、DOM 内の変更が自動的には反映されません。既存の XML オブジェクトのサブセットとして XMLList を作成し、その後オリジナルの XML を変更した場合、XMLList にはその変更が反映されません。最新の状態にするには作り直す必要があります。
var languages = <languages> <lang>JavaScript</lang> <lang>Python</lang> </languages>; var lang = languages.lang; alert(lang.length()); // 2 というアラート languages.lang += <lang>Ruby</lang>; alert(lang.length()); // やはり 2 というアラート lang = languages.lang; // XMLList を作り直す alert(lang.length()); // 3 というアラート
検索とフィルタ
E4X には特定の基準にマッチする文書内のノードを選択するための特別な演算子が用意されています。このようなフィルタ演算は丸括弧で囲んだ式で指定します。
var html = <html> <p id="p1">First paragraph</p> <p id="p2">Second paragraph</p> </html>;
alert(html.p.(@id == "p1")); // "First paragraph" というアラート
式の手前のパスにマッチするノード(この場合は p 要素)は式が評価される前にスコープチェーンに追加されます。with 文 を使ってノードが指定されているかのような動作です。
式の手前のパスにマッチするノード(この場合は p 要素)は式が評価される前にスコープチェーンに追加されます。with 文 を使ってノードが指定されているかのような動作です。
したがって、フィルタは現在の要素内の単一ノードの値に対しても実行することができます。
var people = <people> <person> <name>Bob</name> <age>32</age> </person> <person> <name>Joe</name> <age>46</age> </person> </people>; alert(people.person.(name == "Joe").age); // 46 というアラート
フィルタ式に JavaScript 関数を使うこともできます。
function over40(i) { return i > 40; } alert(people.person.(over40(parseInt(age))).name); // Joe というアラート
名前空間の処理
E4X は名前空間を考慮しています。ノードや属性を表すあらゆる XML オブジェクトには QName オブジェクトを返す name() メソッドがあり、名前空間要素を簡単に検査することができます。
var xhtml = <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Embedded SVG demo</title> </head> <body> <h1>Embedded SVG demo</h1> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"> <circle cx="50" cy="50" r="20" stroke="orange" stroke-width="2px" fill="yellow" /> </svg> </body> </html>; alert(xhtml.name().localName); // "html" というアラート alert(xhtml.name().uri); // "http://www.w3.org/1999/xhtml" というアラート
名前空間内にある要素にアクセスするには、まずその名前空間についての URI を格納した Namespace オブジェクトを作ります。
var svgns = new Namespace('http://www.w3.org/2000/svg');
すると、通常の要素指定子の代わりに namespace::localName の形式で E4X クエリに使用することができます。
var svg = xhtml..svgns::svg; alert(svg); // 文書の <svg> 部分が表示される