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 では、リソースは以下の順序で検索されます。
archive
または cabbase
パラメータで指定されたアーカイブcodebase
の URLSun による実装では、リソースは単に codebase の URL で検索されます。
この結果、Microsoft VM のリソースルックアップシーケンスに依存したアプレットの中には、Java 2 ではリソースを正しくロードできないものがあります。
アプレットの互換性を最大限にするため、Java Plug-in ではリソースルックアップシーケンスが以下のように変更されました。
archive
パラメータで指定されたアーカイブcodebase
の URLClassLoader
共有ポリシー ClassLoader
共有ポリシーは、Microsoft による実装と Sun による実装で異なっています。
Microsoft による実装では、以下の場合だけ ClassLoader
オブジェクトがアプレット間で共有されます。
codebase
の値が同じであり、archive
の値が同じであり、かつcabbase
の値が同じであるSun による実装では、codebase
の値が同じである場合だけ ClassLoader
オブジェクトがアプレット間で共有されます。
Microsoft による実装の ClassLoader
共有ポリシーに依存するアプレットの中には、潜在的なクラス定義の競合のために Java 2 では正しく実行されないものもあります。
アプレットの互換性を最大限にするため、Java Plug-in では ClassLoader
共有ポリシーが変更されました。以下の場合だけ ClassLoader
オブジェクトがアプレット間で共有されるようになりました。
codebase
の値が同じであり、cache_archive
の値が同じであり、java_archive
の値が同じであり、かつ archive
の値が同じである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 にロードされません。
null
と長さゼロの文字列)JDK 1.1 では、クラスライブラリにおける null
と長さがゼロの文字列の取り扱いに関する Java 言語仕様が緩やかでした。API によっては null
を、長さゼロの文字列として扱うものもあれば、null
そのものとして扱うものもありました。Java 2 では Java 言語仕様が厳密になり、正確な動作を指定するようになりました。
この問題は解決不能です。null
を長さゼロの文字列として処理する API に依存しているアプレットは、Java 2 では例外となります。
Java 2 では、アプレット署名を RSA および .jar
ファイルを通じてサポートしていますが、Microsoft ではアプレット署名を、独自の Authenticode および .cab
ファイルテクノロジを通じてサポートしています。
この問題は解決不能です。Microsoft の Authenticode および .cab
ファイルテクノロジに依存する署名アプレットは、Java 2 では正しくロードされません。
過去には、AWT はスレッドに対して安全であると考えるプログラマがいました。そのため、AWT ライブラリを使用して記述された一部のアプレットは複数のスレッドで GUI とやり取していますが、クラスライブラリが同期化の問題を処理するものとみなしていました。しかし、実際は AWT または Swing のいずれもスレッドに対して安全ではありません。そのため、GUI またはプロセスのイベントを更新するすべてのコードは、イベントディスパッチスレッドで発生しなければなりません。これに失敗すると、デッドロックまたは競合状態になる可能性があります。詳細については、『The Swing Tutorial』の「How to Use Threads」を参照してください。このチュートリアルの例では特に Swing を扱っていますが、同じ規則がすべての Component
に当てはまります。
Microsoft による実装では、HTML ページの JavaScript で公開されるアプレットのメソッドとプロパティは、アプレットオブジェクトのメソッドやプロパティとまったく同じものです。Java Plug-in では、アプレットのメソッドとプロパティは、JavaBeans のイントロスペクションを通じて HTML の JavaScript で公開されます。JavaBeans のイントロスペクションは、アプレットオブジェクトの命名規則によってメソッドとプロパティの分析を行います。これによる影響として、アプレットのフィールドがそれぞれ異なる方法で処理されます。
この問題は Java Plug-in の今後のリリースで解決される予定です。現在のところ、Java 2 ではアプレットオブジェクトのフィールドにアクセスする JavaScript は正しく動作しません。
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
のチェックが削除されました。
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 2 の Java クラスライブラリでは多くの変更が行われました。API の中には実装において明確になったもの、切り下げられたもの、置き換えられたものがあります。以下は、Microsoft の VM で実行されるアプレットが Java 2 では失敗する原因となっているものです。
java.awt.Graphics.drawString()
drawString()
は null
を空の文字列として扱います。Java 2 では、drawString()
は null
をそのものとして扱うため、NullPointerException
がスローされます。java.awt.Graphics.drawImage()
drawImage()
は null
イメージを無視します。Java 2 では、drawImage()
は null
をそのものとして扱うため、NullPointerException
がスローされます。java.awt.Color
コンストラクタColor
コンストラクタに境界値を上回ったり下回ったりする値が渡された場合、コンソールで警告メッセージが出力されますが、値は最大値または最小値に自動的にリセットされます。Java 2 では Color
コンストラクタが不正な値をチェックし、IllegalArgumentException
をスローします。Thread.stop(), Thread.suspend(), Thread.resume()
AccessControlException
が発生します。 これらの問題の影響下にあるアプレットは例外となり、Java 2 では正しく実行されません。
これは、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
要素に使用しないでください。