6

アプリケーションを に移植JAppletしてブラウザで実行できるようにしようとすると、問題が発生しました。

プログラム内容:

  1. ジャーファイル。CustomClassLoader私の実装が含まれています。ウェブサイトに保存されます。
  2. コンテンツ ディレクトリ。コンパイルされたクラスでいっぱいです。ユーザーのコンピューターに保存されます。

問題:

コンテンツ ディレクトリにNoClassDefFoundError.class ファイルを読み込もうとすると、.class ファイルが表示されますCustomClassLoader

エラーは達成できませんが、jar 内のクラスに関連しています。クラスは抽象です。コンテンツ ディレクトリ内のすべての .class ファイルは、このクラスを拡張し、必要なすべてのメソッドを埋めます。これらのクラスをロードすると、エラーがスローされます。プログラムは、正常に実行された場合java -jar file.jar、完全に正常に動作します。

これは、クラスパスと関係があると私に信じさせます。

セキュリティ設定:

appletviewer次のようなコマンドでアプレットを実行しています。

 appletviewer -J-Djava.security.policy=policy file.html

同じディレクトリに私のポリシー ファイルがあります。

grant {
  permission java.lang.RuntimePermission "getenv.APPDATA";
  permission java.io.FilePermission "<<ALL FILES>>", "read, write, delete, execute";
  permission java.lang.RuntimePermission "exitVM";
  permission java.util.PropertyPermission "user.name", "read";
  permission java.lang.RuntimePermission "createClassLoader";
};

私の知る限り、他のセキュリティ例外はスローされていません。アプレットは署名されています。

アプレットのロードに使用される HTML ファイル:

<!DOCTYPE html>
<html>
    <body>
        <object width="1000" height="600" classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"
            codebase="http://java.sun.com/products/plugin/autodl/jinstall-1_4-windows-i586.cab#Version=1,4,0,0">
            <param name="archive" value="file.jar"/>
            <param name="code" value="package.to.Boot"/>
        </object>
    </body>
</html>

この問題を解決するための助けをいただければ幸いです。

CustomClassLoader.java:

package org.obicere.cc.methods;

import java.io.File;

public class CustomClassLoader extends ClassLoader {
    //...
    private Class<?> loadClass(final File file) {
        try {
            final byte[] data = IOUtils.readData(file);
            return super.defineClass(file.getName().substring(0, file.getName().length() - 6), data, 0, data.length);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

ランナーの例: CanReachRunner.java

import java.lang.reflect.Method;
import java.util.Random;

import org.obicere.cc.executor.Result;
import org.obicere.cc.tasks.projects.Runner;

public class CanReachRunner extends Runner {

    @Override
    public Result[] getResults(Class<?> clazz) {
        try {
            final Method method = clazz.getMethod("canReach", int.class, int.class, int.class);
            final Random ran = new Random();
            final Result[] results = new Result[10];
            for (int i = 0; i < 10; i++) {
                final int small = ran.nextInt(5) + 5;
                final int large = ran.nextInt(5);
                final int goal = (small + large * 5) + 5 + ran.nextInt(6);
                results[i] = new Result(method.invoke(clazz.newInstance(), small, large, goal), (goal <= small + large * 5) && goal % 5 <= small, small, large, goal);
            }
            return results;
        } catch (Exception e) {
            return new Result[] {};
        }
    }
}
4

1 に答える 1

4

クラスローダーにはいくつかの問題があります。1 つ目は、メソッドが aではなくloadClassa の引数を使用することです。文字列はロードするクラスの名前です。これは、ロードするクラスがファイル内にない可能性があり、ネットワーク接続上にある可能性があり、とにかく JVM がファイルを見つける方法を知らないためです。2 つ目は、オーバーライドすると、最初に通常の方法でクラスをロードしようとし、それが機能しない場合にのみメソッドを呼び出すというデフォルトの動作に干渉するため、オーバーライドするのは悪い習慣です。したがって、代わりにオーバーライドする必要があります。更新されたコードは次のとおりです。StringFileloadClassfindClassfindClassdefineClass

public class CustomClassLoader extends ClassLoader {
    private Class<?> findClass(String class) {
        try {
            File contentDir = ...; // You have to fill this in with the location of the content dir
            final byte[] data = IOUtils.readData(new File(contentDir, class + ".class");
            return defineClass(class, data, 0, data.length);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

何らかの方法でコンテンツ ディレクトリを見つけ、それを使用して初期化する必要がありますcontentDir

これがjarとして実行されたときに機能する理由は、カスタムクラスローダーを必要とせずにクラスをロードできるためです。

于 2013-08-02T00:41:50.160 に答える