クラスの動的読み込み
概要
java.lang.Class
の forName()
メソッドは、実行時にクラスを動的に読み込むための方法です。PreEmptive Protection - DashO では、いかなる場合でも、どのクラスが動的に読み込まれるかを判断することは不可能です。次のコードを考えてみましょう。
public Object getNewClass() {
String newClassName = getUserInputString();
try {
Object newClass = Class.forName(newClassName).newInstance();
return newClass;
} catch(Exception e) {
// handle
}
}
このコードは名前で指定されたクラスを読み込み、そのクラスのインスタンスを動的に作成します。さらに、その名前はユーザーが入力する文字列によって指定されます。ユーザーがどのクラスの名前を入力するかは、DashO では予測できません。その解決策として、読み込める可能性のあるすべてのクラスの名前を対象から除外します。そうしても、メソッドおよびフィールドの名前を変更することは可能です。これは、手作業による構成が必要になります。
メモ:
動的に読み込むクラスの指定を誤ると、難読化したアプリケーションでエラーが発生する可能性があります。
予測可能な動的読み込み
最も単純なケースは、あなたが、動的読み込みを介して読み込まれる可能性のあるクラスを正確に把握しているほど、あなたのアプリケーションを理解している場合です。動的に読み込まれるクラスは、基本クラスまたは共通インターフェイスを共有します。
String s = getShapeName();
Shape myShape = (Shape)Class.forName(s).newInstance();
myShape.draw();
この例では、DashO は自動的にこのパターンを検出し、すべての Shape
クラスを対象として選択することができます。別の種類の作成パターンが使用された場合は、DashO 構成ファイルの entrypoints セクションにクラスを個別に追加する必要があります。
<entrypoints>
<classes name="Triangle"/>
<classes name="Rectangle"/>
</entrypoints>
この場合は、DashO は Shape
階層から使用されていないメソッドを除去することができます。
予測不能な動的読み込み
動的に読み込まれるクラスが、アプリケーションが難読化される時点でわからないというケース、たとえば、ユーザー インターフェイスのアプリケーションの構築で、アプリケーションのユーザーが独自のコンポーネントやサード パーティ製コンポーネントを含める可能性がある場合などは、既存のクラスを無条件のエントリ ポイントとして追加する必要があります。
<entrypoints>
<unconditional name="Triangle"/>
<unconditional name="Rectangle"/>
</entrypoints>
これにはいくつかの影響があります。
除去オプションにかかわらず、無条件に選択されるクラスのメソッドおよびフィールドは除去されません。
名前の変更オプションにかかわらず、クラスとそのメンバーのどちらの名前も変更されません。
クラス内のすべてのメソッドは、エントリ ポイント メソッドとして扱われます。
これらの法則は、未知のクラスへのインターフェイスは元の状態のままになるという考えを強要します。
リフレクション レポート
DashO には、動的に読み込む方法や対象を指定できる機能がいくつか用意されています。DashO の fornamedetection オプションは、動的に読み込まれるクラス インスタンスのほとんど、あるいはすべてを処理します。
<global>
<option>fornamedetection</option>
</global>
DashO は、forName()
の使用を見つけたすべての場所を報告します。これは、レポート ファイルの一部として、依存関係分析後の出力として提供されます。fornamedetection オプションは、間違った答えを返すことはありませんが、まったく答えを返さないこともあるので注意してください。DashO が動的に読み込まれたクラスを判断できない("unable to determine")と報告するインスタンスには、手作業による構成が必要です。
NOTE: Reflection use public void com.yoyodyne.Application.getInterface() – java.lang.Class.newInstance() - [BaseInterface Possible: InterfaceImplementor] Reflection use public boolean com.yoyodyne.Test.connect() - Class.forName() Reflection use public float com.yoyodyne.Test.calculate() - Class.forName() - [com.yoyodyne.Linker]
DashO は、メソッド connect()
で動的に読み込まれたクラスを判断できないため、手動による構成が必要になります。このメソッドで動的に読み込まれたクラスは、<entrypoints> セクション下で <classes>
タグを使用して、対象選択される必要があります。
DashO がリフレクションの使用を見つけた場合に、force グローバル オプションが指定されていないと、DashO は出力クラスも出力 jar も作成しません。