Failing to load class definition from jar
Asked Answered
J

1

6

I ran across an issue when attempting to port an application over to JApplet so it can run on a browser.

Program Contents:

  1. Jar file. Contains my CustomClassLoader implementation. Stored on website.
  2. Content directory. Filled with compiled classes. Stored on the users computer.

Issue:

I am getting a NoClassDefFoundError when attempting to load .class files in the content directory with my CustomClassLoader.

The error, although unattainable, relates back to a class inside the jar. The class is abstract. All the .class files in the content directory extend this class and fill all the required methods. Upon loading these classes, the error is thrown. The program, when ran normally java -jar file.jar, works perfectly fine.

This makes me believe it has to do with the classpath.

Security Setup:

I am running the applet through the appletviewer command like so:

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

In the same directory is my policy file:

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

As far as I know, no other security exceptions are being thrown. The applet is signed.

HTML File Used To Load Applet:

<!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>

Any help towards fixing this problem is greatly appreciated.

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

Example 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[] {};
        }
    }
}
Jameejamel answered 30/7, 2013 at 10:27 Comment(9)
You might give a look at this: https://mcmap.net/q/1914305/-export-java-applet-to-jar/…Attalie
I have 2 boot classes. One for jar access, manifest links to this one. The other for applet access, HTML links to this one.Jameejamel
Does any of you .java files have a main Method?Attalie
@NiteshVerma Yes. I do not see the connection between the two, when it loads perfectly fine. It just can't function properly.Jameejamel
Could you care to share some more codeAttalie
@NiteshVerma what would you want to see?Jameejamel
The contenst of the jar file: CustomClassLoader and the content directory comppiled classesAttalie
@NiteshVerma I have shown what I am willing to show. I doubt the answer lies in any other place, considering it works when not ran as an applet. Only then, does it fail.Jameejamel
clould the problem be inside the init() method (probale, not sure).Attalie
T
4

There are several things wrong with the class loader. The first is that the loadClass method uses an argument of a String rather than a File, the string being the name of the class to load. This is because the class to load might not be in a file, it might be on a network connection, and anyway the JVM doesn't know how to find the file. The second is that it is bad practice to override loadClass, because if you do, it interferes with the default behavior, which first tries to load classes the normal way, and only resorts to calling the findClass method if that doesn't work. So, you should override findClass instead of defineClass. Here's the updated code:

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

You must find the content directory somehow and use that to initialize contentDir.

The reason this works when run as a jar is cause it is then capable of loading the classes without needing a custom class loader.

Tillandsia answered 2/8, 2013 at 0:41 Comment(2)
It works perfectly fine as an executable jar, but not when ran as an applet. The file argument already has the contentDir appended and the .class appended (explains the substring). The classes I am also trying to load are not added in the classpath, which is why I just resort to defining them, instead of trying to load them. I am almost sure the problem lies within the security manager.Jameejamel
If you read that last comment I just deleted, you can ignore it. I actually found a work-around and may be coming to a solution soon. You just reminded me of something.Jameejamel

© 2022 - 2024 — McMap. All rights reserved.