簡體   English   中英

無法從jar加載類定義

[英]Failing to load class definition from jar

嘗試將應用程序移植到JApplet時,我遇到了一個問題,因此它可以在瀏覽器上運行。

課程內容:

  1. Jar文件。 包含我的CustomClassLoader實現。 存儲在網站上。
  2. 內容目錄。 填寫編譯的類。 存儲在用戶計算機上。

問題:

嘗試使用CustomClassLoader在內容目錄中加載.class文件時,我得到NoClassDefFoundError

這個錯誤雖然無法實現,但卻與jar中的一個類有關。 這門課是抽象的。 內容目錄中的所有.class文件都擴展此類並填充所有必需的方法。 加載這些類后,將引發錯誤。 程序,當正常運行java -jar file.jar ,工作得很好。

這讓我相信它與classpath有關。

安全設置:

我通過appletviewer命令運行applet,如下所示:

 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";
};

據我所知,沒有其他安全例外被拋出。 小程序已簽名。

用於加載Applet的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;
    }
}

示例Runner: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[] {};
        }
    }
}

類加載器有幾個問題。 第一個是loadClass方法使用String的參數而不是File ,該字符串是要加載的類的名稱。 這是因為要加載的類可能不在文件中,它可能在網絡連接上,並且無論如何JVM都不知道如何查找文件。 第二個是覆蓋loadClass是不好的做法,因為如果這樣做,它會干擾默認行為,它首先嘗試以正常方式加載類,並且只有在不起作用的情況下才會調用findClass方法。 因此,您應該覆蓋findClass而不是defineClass 這是更新的代碼:

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運行時的原因是因為它能夠加載類而無需自定義類加載器。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM