アプレットの互換性 — Microsoft と Java 2 の仮想マシン



このドキュメントでは、Microsoft 仮想マシン (VM) と Sun Java 2 VM のアプレットの互換性に関する既知の問題について説明します。


ClassFormatError

このエラーは、古い JDK 1.0.2 または 1.1 コンパイラによって生成されたバイトコードが原因で発生します。これまで、該当するコンパイラによって多くのバイトコードが生成されていますが、いずれも Java VM 仕様に準拠していません。最近の J2SE リリースのべリファイアは不正なクラスフォーマットに関して非常に厳しくなっているため、こうした不正なクラスファイルがロードされると、VM によって ClassFormatError がスローされます。

古いクラスファイルに関する典型的な問題点は以下のとおりです (ただしすべてを網羅したものではない)。

この種類の問題は、現在の JDK にある Javac バイトコードコンパイラを使用してクラスを再コンパイルすれば回避することができます。サードパーティのオブファスケータを使用する場合は、それが正しいクラスファイル形式に準拠したクラスファイルを作成するかどうかを確認してください。

不正なクラスファイルをもついくつかのアプレットを Java 2 で実行できるようにするために、Java Plug-in には、不正なクラスファイルを正しいものに変換するバイトコード変換プログラムが含まれています。現時点では、以下の ClassFormatError による不正なクラスファイルだけが変換されます。

しかし、次の ClassFormatError の問題は、バイトコード変換プログラムでは解決しません。

そのため、上記の問題を含むクラスファイルは、Java 2 では実行できません。

sun.audio によるセキュリティ例外

JDK 1.1 のアプレットでは sun.audio パッケージにアクセスできました。しかし、Java 2 ではアプレットサンドボックスが閉じられたため、sun.audio パッケージのクラスライブラリにアクセスしようとしたアプレットは SecurityException になります。

アプレットの互換性を最大限にするため、Java Plug-in ではアプレットサンドボックスが開けられ、アプレットが再び sun.audio パッケージにアクセスできるようになりました。

AppletContext.getAudioClip() および AppletContext.getImage() のリソースが検索できない

Microsoft による実装と Sun による実装では、AppletContext.getImage() および AppletContext.getAudioClip() のリソースルックアップシーケンスが異なっています。 

Microsoft VM では、リソースは以下の順序で検索されます。

  1. HTML の archive または cabbase パラメータで指定されたアーカイブ
  2. codebase の URL

Sun による実装では、リソースは単に codebase の URL で検索されます。

この結果、Microsoft VM のリソースルックアップシーケンスに依存したアプレットの中には、Java 2 ではリソースを正しくロードできないものがあります。 

アプレットの互換性を最大限にするため、Java Plug-in ではリソースルックアップシーケンスが以下のように変更されました。

  1. HTML の archive パラメータで指定されたアーカイブ
  2. codebase の URL

ClassLoader 共有ポリシー

ClassLoader 共有ポリシーは、Microsoft による実装と Sun による実装で異なっています。 

Microsoft による実装では、以下の場合だけ ClassLoader オブジェクトがアプレット間で共有されます。

Sun による実装では、codebase の値が同じである場合だけ ClassLoader オブジェクトがアプレット間で共有されます。

Microsoft による実装の ClassLoader 共有ポリシーに依存するアプレットの中には、潜在的なクラス定義の競合のために Java 2 では正しく実行されないものもあります。 

アプレットの互換性を最大限にするため、Java Plug-in では ClassLoader 共有ポリシーが変更されました。以下の場合だけ ClassLoader オブジェクトがアプレット間で共有されるようになりました。

セキュリティモデル — Java 2 と Microsoft

Java 2 の備えている新しいセキュリティモデルは、JDK 1.1 よりもはるかにすぐれた機能と柔軟性を提供していますが、Microsoft VM セキュリティモデルは、JDK 1.1 と独自の技術に基づいています。 

この問題は解決不能です。そのため、Microsoft のセキュリティモデルに依存したアプレットは Java 2 では正しく実行されません。

アプレットのパッケージ化

Java 2 および JDK 1.1 におけるアプレットのパッケージ化は、.jar ファイルを通じて実行されますが、Microsoft VM では、.jar ファイルと独自の .cab (キャビネット) ファイルを通じて実行されます。 

この問題は解決不能です。したがって、Microsoft の .cab ファイル形式にパッケージ化されたアプレットは Java 2 にロードされません。

Java 言語仕様の厳密さ (null と長さゼロの文字列)

JDK 1.1 では、クラスライブラリにおける null と長さがゼロの文字列の取り扱いに関する Java 言語仕様が緩やかでした。API によっては null を、長さゼロの文字列として扱うものもあれば、null そのものとして扱うものもありました。Java 2 では Java 言語仕様が厳密になり、正確な動作を指定するようになりました。

この問題は解決不能です。null を長さゼロの文字列として処理する API に依存しているアプレットは、Java 2 では例外となります。

アプレットの署名 — RSA と Authenticode

Java 2 では、アプレット署名を RSA および .jar ファイルを通じてサポートしていますが、Microsoft ではアプレット署名を、独自の Authenticode および .cab ファイルテクノロジを通じてサポートしています。

この問題は解決不能です。Microsoft の Authenticode および .cab ファイルテクノロジに依存する署名アプレットは、Java 2 では正しくロードされません。

AWT クラスライブラリにおける実装の変更

過去には、AWT はスレッドに対して安全であると考えるプログラマがいました。そのため、AWT ライブラリを使用して記述された一部のアプレットは複数のスレッドで GUI とやり取していますが、クラスライブラリが同期化の問題を処理するものとみなしていました。しかし、実際は AWT または Swing のいずれもスレッドに対して安全ではありません。そのため、GUI またはプロセスのイベントを更新するすべてのコードは、イベントディスパッチスレッドで発生しなければなりません。これに失敗すると、デッドロックまたは競合状態になる可能性があります。詳細については、『The Swing Tutorial』「How to Use Threads」を参照してください。このチュートリアルの例では特に Swing を扱っていますが、同じ規則がすべての Component に当てはまります。

Java と JavaScript の間の通信

Microsoft による実装では、HTML ページの JavaScript で公開されるアプレットのメソッドとプロパティは、アプレットオブジェクトのメソッドやプロパティとまったく同じものです。Java Plug-in では、アプレットのメソッドとプロパティは、JavaBeans のイントロスペクションを通じて HTML の JavaScript で公開されます。JavaBeans のイントロスペクションは、アプレットオブジェクトの命名規則によってメソッドとプロパティの分析を行います。これによる影響として、アプレットのフィールドがそれぞれ異なる方法で処理されます。

この問題は Java Plug-in の今後のリリースで解決される予定です。現在のところ、Java 2 ではアプレットオブジェクトのフィールドにアクセスする JavaScript は正しく動作しません。   

Microsoft 独自の Java クラス、メソッド、および変数

Microsoft による VM の実装では、J/Direct、AFC、WFC など多くの独自のクラスライブラリが提供されています。その他のクラス、メソッド、および変数については、「How to avoid potential pitfalls of Microsoft's non-standard SDK for Java」を参照してください。

この問題は解決不能です。Microsoft の独自の Java クラスライブラリに依存したアプレットは Java 2 では正しく動作しません。

Applet.getParameter() から返される文字列内の空白文字

Microsoft による実装では、文字列が Applet.getParameter() 内でアプレットに返される前に、空白文字が取り除かれます。しかし、Sun による実装では、文字列は HTML パラメータで指定されたとおりに返されます。この結果、JDK 1.1 アプレットの中には Java 2 で実行できないものがあります。JDK 1.1 アプレットのロジックでは、空白を想定していないためです。

アプレットの互換性を最大限にするため、Java Plug-in では Applet.getParameter() の実装が変更され、戻り値から空白文字が取り除かれています。

java.util.Hashtable.hashCode() における設計変更    

JDK 1.1 では Hashtable.hashCode() はオブジェクト ID に基づいて実装されているので、hashCode() が呼び出された場合、Hashtable オブジェクトはそれぞれ一意の値を返します。Java 2 では Hashtable.hashCode() の実装が、Java Collection Framework の一部として値に基づくものに変更されました。Hashtable オブジェクトは、格納しているオブジェクトに基づいてハッシュコードの値を返します。  

この変更によって、JDK 1.1 のアプレットのいくつかは、Hashtable オブジェクトをそれ自身に追加した場合に中断してしまいます。なぜなら、この変更は Collection Framework の基本設計を乱し、StackOverflowError が発生するからです。同じ Hashtable オブジェクトから一定の値を返すために、Hashtable.hashCode() に依存しているいくつかのアプレットコードで、ロジックが破壊されてしまいます。

アプレットの互換性を最大限にするため、Hashtable.hashCode() の実装が変更され、こうした特別なケースをチェックしてスタックのオーバーフローを回避するようになりました。

アプレットからフレームへのアクセス

マウスイベントの追跡やその他の理由により、アプレットがそのフレームにアクセスしようとすることがあります。Microsoft による実装と Sun による実装では、フレームとアプレットの間でコンテナ数が異なります。

Microsoft VM における特定の包含レベルにあるフレームに依存する (AWT 階層コンポーネントツリー全体をナビゲートしない) アプレットは、Java 2 では失敗する可能性があります。もっともよく見られる症状は、AWT ディスパッチイベントスレッドからの ClassCastException です。

この問題は解決不能です。そのため、Java 2 ではこの問題を抱えたアプレットは正しく動作しません。

MAYSCRIPT

Netscape Navigator と Java Plug-in では、JavaScript にアクセスするアプレットはアプレット要素で MAYSCRIPT 属性を指定する必要があります。しかし Microsoft による実装ではこの特別なパラメータが重視されないため、アプレットはあらゆる条件下で JavaScript にアクセスすることができます。インターネット上のアプレットのほとんどは、Netscape ではなく Microsoft VM をターゲットにしているため、MAYSCRIPT が指定されていません。

アプレットの互換性を最大限にするため、Java Plug-in から MAYSCRIPT のチェックが削除されました。

HTTP の User-Agent

Microsoft と Sun による実装では、HTTP 接続が要求されたときに、異なる HTTP の User-Agent の文字列がサーバに渡されます。多くの Web サイトが Sun ではなく Microsoft VM をターゲットにしているため、こうした Web サイトでは Sun の HTTP の User-Agent を認識せず、失敗が起こります。

このため、Java Plug-in で使用されている HTTP の User-Agent 文字列は、Microsoft の User-Agent に似たものにしてきました。こうすることで、ほとんどの Web サーバでは、Java Plug-in を実行するアプレットからの要求を認識します。

アプレットの起動および停止時のイベント

Microsoft と Sun による実装では、アプレットの起動時と停止時に発生するイベントは完全に同じではありません。たとえば、アプレットのロジックが Applet.start() または Applet.stop() の呼び出し時に表示されるアプレットに依存することは、Microsoft による実装には当てはまりますが、Sun による実装には当てはまりません。

Microsoft VM においてアプレットが起動および停止するときの特定のイベントに依存しているアプレットは、Java 2 では正しく機能しません。もっともよく見られる症状は、AWT ディスパッチイベントスレッドからの NullPointerException です。

この問題は解決不能です。

Java クラスライブラリの互換性 

Java 2 の Java クラスライブラリでは多くの変更が行われました。API の中には実装において明確になったもの、切り下げられたもの、置き換えられたものがあります。以下は、Microsoft の VM で実行されるアプレットが Java 2 では失敗する原因となっているものです。

これらの問題の影響下にあるアプレットは例外となり、Java 2 では正しく実行されません。

Java Moniker

これは、Java 2 ではサポートされていない、Microsoft 独自のテクノロジです。

object 属性と PARAM 要素

従来のアプレット形式では、PARAM 要素と object 属性を同時に使用すると、Sun VM の場合は例外「Either "code" or "object" should be specified, but not both.」がスローされます。Microsoft VM では、例外はスローされません。これは互換性の問題です。Sun VM でこの例外を回避するには、アプレットで object という名前の属性を PARAM 要素に使用しないでください。