无法从jar加载类定义

6 java applet securitymanager appletviewer

尝试将应用程序移植到其上时,我遇到了一个问题,JApplet因此它可以在浏览器上运行.

课程内容:

  1. Jar文件.包含我的CustomClassLoader实现.存储在网站上.
  2. 内容目录.填写编译的类.存储在用户计算机上.

问题:

NoClassDefFoundError试图用我的内容目录加载.class文件CustomClassLoader.

这个错误虽然无法实现,但却与jar中的一个类有关.这门课是抽象的.内容目录中的所有.class文件都扩展此类并填充所有必需的方法.加载这些类后,将引发错误.该程序在正常运行时运行java -jar file.jar良好.

这让我相信它与classpath有关.

安全设置:

我正在通过appletviewer命令运行applet,如下所示:

 appletviewer -J-Djava.security.policy=policy file.html
Run Code Online (Sandbox Code Playgroud)

在同一目录中是我的策略文件:

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";
};
Run Code Online (Sandbox Code Playgroud)

据我所知,没有其他安全例外被抛出.小程序已签名.

用于加载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>
Run Code Online (Sandbox Code Playgroud)

非常感谢任何帮助解决这个问题.

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

示例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[] {};
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

tbo*_*odt 4

类加载器有几个问题。第一个是该loadClass方法使用 a 参数String而不是 a 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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

您必须以某种方式找到内容目录并使用它来初始化contentDir

当作为 jar 运行时它起作用的原因是它能够加载类而无需自定义类加载器。