0

I am writing an application that will load Java scripts. I currently have a GUI which utilizes a JFileChooser to allow the user to select a script from their machine. The script file can be anywhere. It is not on the classpath. Having only a File object to represent that script file, how can I obtain a Class representation of it?

I know that to load a class you need its binary name, so in.this.format. However, the problem with that is I don't know how the script writer may have packaged it. For example, he/she may have, while developing it, put the script file in the package foo.bar. After I download this script and place it in my documents (i.e., not in foo/bar), I can't load the script without knowing that it was packaged in foo.bar. If the class name is Test and I try to create a URLClassLoader pointing to the script file by doing new URLClassLoader(new URL[] { new URL(scriptFile.toURI().toURL()) }) and I do classLoader.loadClass("Test") I will get an exception saying that the class had the wrong name, and the correct name is foo.bar.Test. But how am I supposed to know that ahead of time?

This is what I have right now:

public class ScriptClassLoader extends URLClassLoader {

    private final File script;

    public ScriptClassLoader(File script) throws MalformedURLException {
        super(new URL[] { script.toURI().toURL() });
        this.script = script;
    }

    public Class<?> load() throws ClassNotFoundException {
        String fileName = script.getName();
        String className = fileName.substring(0, fileName.indexOf(".class"));
        return loadClass(className);
    }
}

How do people load scripts at runtime that are not part of the program's classpath, and the binary name of the class is not known?

3
  • 1
    This is by no means a solution, but you can catch the exception thrown, read the correct name, and then perform the read operation again. Yes, it's cheap, but it's the first thing that came into my mind in the first minute I read you issue. On the positive side, it shows that it is possible to do this in a correct way. Also, please post an MCVE. Commented Mar 28, 2014 at 20:15
  • I thought about this too, but that felt way too cheap. I may do this if more elegant solutions don't arise. Commented Mar 28, 2014 at 20:35
  • There are actually many solutions, see here and here for starters. Commented Mar 28, 2014 at 21:09

1 Answer 1

1

If you just need to load a class from a given .class file, no matter how this classes is named, you can load the data yourself and then call ClassLoader's defineClass() method:

RandomAccessFile raf = new RandomAccessFile(script, "r");
try {
    byte[] classData = new byte[(int) raf.length()];
    raf.readFully(classData);
    return super.defineClass(null, classData, 0, classData.length);
} finally {
    raf.close();
}
Sign up to request clarification or add additional context in comments.

3 Comments

In this case ScriptClassLoader need not even extend URLClassLoader - it may be inherited directly from ClassLoader.
How would this work if the main script file refers to other script files? If I have MainScript in foo.bar and it refers to SomeOtherScriptClass in foo.bar.other, would that method still work, if I just load MainScript? Or will I get a NoDefFoundError when the script's execution reaches code that utilizes methods in the SomeOtherScriptClass class?
@MartinTuskevicius To resolve unknown references to other classes JVM will call your ClassLoader's loadClass() method. You'll have to implement it so that it will look for SomeOtherScriptClass.class in foo/bar/other or in the current directory or wherever you like. That's the price you pay if you don't place .class files where they are expected to be.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.