I'm working on a project where users can store plugins in raw Java code. My application will then take those plugins, compile them, and import them. The classes are based off of an interface that's stored within my jar. However, when I try to run it using a JavaCompiler.CompilationTask it refuses to allow me to add the current jar to the classpath of the compiler. This being the case, when it tries to compile it it acts as though the interface isn't available to be implemented.
Here is the structure of my files:
The main .jar file:
CommandProcessor.java
----------------------------------------------
package plugins;
public interface CommandProcessor {
public String onCommand(String command);
}
I then have a function for loading the plugins.
http://hastebin.com/jabacopeye.coffee (HasteBin to keep from over-cluttering the question)
Here is an example of one of the user plugins:
public class MyCommand implements plugins.CommandProcessor {
@Override
public String onCommand(String command){
return "this is a test";
}
}
Whenever the application tries to compile this externally stored .java file, it says that the class "plugins.CommandProcessor" does not exist.
As you stated that,
Whenever the application tries to compile this externally stored .java file, it says that the class "plugins.CommandProcessor" does not exist.
task.call()
is called then URLClassLoader can not load file from "./plugins/WebC/plugins/"
location. So your code can not proceed on following
if (task.call()) {
URLClassLoader classLoader = new URLClassLoader(new URL[]{new File("./plugins/WebC/plugins/").toURI().toURL()});
Class<?> loadedClass = classLoader.loadClass(className);
Object obj = loadedClass.newInstance();
if (obj instanceof CommandProcessor) {
CommandProcessor cmd = (CommandProcessor)obj;
classLoader.close();
return cmd;
}else{
classLoader.close();
}
}
So you need to specify jars on the classpath.
The java compiler and run-time can search for classes not only in separate files, but also in JAR' archives. A JAR file can maintain its own directory structure, and Java follows exactly the same rules as for searching in ordinary directories. Specifically,
directory name = package name'. Because a JAR is itself a directory, to include a JAR file in the class search path, the path must reference the JAR itself, not merely the directory that contains the JAR. This is a very common error. Suppose I have a JAR myclasses.jar in directory /myclasses. To have the Java compiler look for classes in this jar, we need to specify:
javac -classpath /myclasses/myclasses.jar ...
and not merely the directory myclasses.
In the examples above, we have told javac to search in only one directory at a time. In practice, your class search path will contain numerous directories and JAR archives. The -classpath option to javac and java allows multiple entries to be specified, but notice that the syntax is slightly different for Unix and Windows systems. On Unix, we would do this:
javac -classpath dir1:dir2:dir3 ...
whereas on Windows we have:
javac -classpath dir1;dir2;dir3 ...
The reason for the difference is that Windows uses the colon (:) character as part of a filename, so it can't be used as a filename separator. Naturally the directory separator character is different as well: forward slash (/) for Unix and backslash () for Windows.
You should be creating all of your classes using a custom ClassLoader
that can handle the resolution you are expecting. You can code in the loading of any external jar file contents as well your required interfaces. The JVM would keep track of any of the classes you define.
The main program would create your, soon to be written, ScriptingClassLoader
that would contain resolution scripting source code:
public class ScriptingClassLoader extends ClassLoader {
public Class findClass(String name) {
// you can fixup the desired api interface here
// as you already know where they are
byte[] b = loadClassData(name);
return defineClass(name, b, 0, b.length);
}
private byte[] loadClassData(String name) {
// go find your script source and compile
// can be local disk, etc. You are only returning
// the byte code here
}
}
http://docs.oracle.com/javase/8/docs/api/java/lang/ClassLoader.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With