Is it possible to add a folder which contains java source code as a classpath element. I have tried a few things and it seems that the classloadr is not picking up java soruce files? One of my attempts is shown below....
File uncompressedSrc = new File("uncompressed" + File.separator + "src" + File.separator);
URL uncompressedSrcURL = null;
try {
uncompressedSrcURL = new URL("file://"
+ uncompressedSrc.getAbsolutePath());
} catch (MalformedURLException e) {
e.printStackTrace();
}
URL elements[] = { uncompressedSrcURL };
new URLClassLoader(elements, ClassLoader.getSystemClassLoader());
I have found a solution to my problem... I used the following dirty "hack" to add a folder to class path...
public static void addUrl(URL u) {
URLClassLoader sysloader = (URLClassLoader) ClassLoader
.getSystemClassLoader();
Class<URLClassLoader> sysclass = URLClassLoader.class;
try {
Method method = sysclass.getDeclaredMethod("addURL", parameters);
method.setAccessible(true);
method.invoke(sysloader, new Object[] { u });
} catch (Throwable t) {
t.printStackTrace();
try {
throw new IOException(
"Error, could not add URL to system classloader");
} catch (IOException e) {
logger.log(Level.SEVERE, e.getMessage());
}
}
}
Java source code is nothing the JVM can handle by itself. Only compiled class files may be loaded by the classloader. So you may only add the content of JAR files or CLASS files to the classpath.
Sorry. I skimmed through your question way to fast.
As #Daniel says, the JVM can not read .java files, only .class files.
The java-files can be compiled into class-files and loaded in the JVM programatically as described here: Programmatically Compile and Execute with Java
The key ingredient is the following
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager filemanager = compiler.getStandardFileManager( null, null, null );
try {
Iterable compilationUnits = filemanager.getJavaFileObjects( file );
compiler.getTask( null, filemanager, null, null, null, compilationUnits ).call();
filemanager.close();
} catch ( IOException e ) {
e.printStackTrace();
}
Hope that helps!
Related
This is my "test-addon"
And I'm trying to load my "main class" using:
Class<?> jarClass;
try {
ClassLoader cls = ClassLoader.getSystemClassLoader();
jarClass = cls.loadClass("main.Addon");
} catch (ClassNotFoundException e) {
throw new InvalidPluginException("\"Addon class\" was not found", e);
}
As you can see in the image, the class exists, but it still returns:
Line 21: jarClass = cls.loadClass("main.Addon");
QUESTION: why does this happen
The jar or directory that contains main.Addon isn't on the classpath.
Try Addon (no package specifier). In Maven-style projects, src/main is the root (default) package.
The problem was that I used the SystemClassLoader, not my own.
A simple fix for this was: jarClass = Class.forName("main.Addon", true, this);
I currently have the following problem:
I have created a updater jar from which a client jar is downloaded and placed in some directory (just somewhere on the disk, not associated with the directory of the updater jar). I use the following code the run the client jar from the updater:
private void startApplication() {
String url = getFilePath()+"client.jar";
URL parsedURL = null;
try {
parsedURL = new File(url).toURI().toURL();
} catch (MalformedURLException e) {
e.printStackTrace();
}
ClassLoader loader = URLClassLoader.newInstance(new URL[]{parsedURL}, getClass().getClassLoader());
Class<?> cl = null;
try {
cl = Class.forName("org.myApp.client.mainPackage.Main", true, loader);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
finally {
loader = null;
}
Class<? extends Application> runClass = cl.asSubclass(Application.class);
// Avoid Class.newInstance, for it is evil.
Constructor<? extends Application> ctor = null;
try {
ctor = runClass.getConstructor();
} catch (NoSuchMethodException | SecurityException e) {
e.printStackTrace();
}
Application doRun = null;
try {
doRun = ctor.newInstance();
} catch (InstantiationException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException e) {
e.printStackTrace();
}
try {
doRun.start(primaryStage);
} catch (Exception e) {
e.printStackTrace();
}
}
This code seems to work, because the Main of the client.jar gets runned. However, after its Main is started, I get an exception from the client jar. The Main from the client jar tries to load a FXML file in the upper pane. This is the exception:
ClassNotFoundException: org.myApp.client.lockscreen.LockscreenController when loading a FXML file
I do not know what triggers this error. The client jar just runs as should be, when I run it standalone.
Do I need to load all classes from the client jar from the updater jar?
Any help is greatly appreciated!
Everybody thanks for your help. I was able to fix it like this (thanks Jool, you will get all the credits):
I downloaded and runned the client jar, assuming it would have its own references. However, as Jool said, I had to add the director to the class path. What I did wrong, was that I added the directory, and not the Jar file. You have to add the JAR file too ! I did that with this code:
public void addPath(String s) throws Exception {
File f = new File(s);
URI u = f.toURI();
URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
Class<URLClassLoader> urlClass = URLClassLoader.class;
Method method = urlClass.getDeclaredMethod("addURL", new Class[]{URL.class});
method.setAccessible(true);
method.invoke(urlClassLoader, new Object[]{u.toURL()});
}
And then I just called addPath(url) before running the client jar.
It is saying that the class cannot be found because it is not on your classpath.
This depends on how you build your application (Ant, Maven etc), since this determines how the location of the .jar file is known, and where the .jar file is.
If you are using an IDE, there would usually be some sort of Libraries placeholder in which you define .jars that you are dependent upon.
I am developing a class loader that will load plugins into my software. I have a jar file with two things in it, the package containing my code, and a text file containing the name of the class that I want to load from the jar. Is there a way for my app to read the text in the file and get the class name, then load the class with that name from the jar file?
This is the code that works:
content = new Scanner(new File("plugins/" + listOfFiles[i].getName().replaceAll(".jar", "") + "/" + "plugin.cfg")).useDelimiter("\\Z").next();
URL[] urls = null;
try {
File dir = new File("plugins/" + listOfFiles[i].getName());
URL url = dir.toURL();
urls = new URL[]{url};
} catch (MalformedURLException e) {
}
try {
ClassLoader cl = new URLClassLoader(urls);
Class cls = cl.loadClass(content.replaceAll("Main-Class:", ""));
Method enable = cls.getMethod("enable", (Class<?>[]) null);
enable.invoke(enable, null);
}catch (Exception e) {
System.out.println("One of the installed plugins might have an invalid plugin.cfg.");
}
The code reads a file with the name of the main class in it, and then loads that class from the jar file it extracted earlier.
I have written an application which manages several plugins which are provided as jars. I load the plugin classes using an URLClassLoader which works as supposed.
But now I am writing a plugin which loads some resources which are stored inside the jar. If I start this plugin as a standalone application everything works, but if I start it from inside my application I get a NullPointerException when I try to open the resources InputStream.
I open the stream like this:
this.getClass().getResourceAsStream("/templates/template.html");
My Eclipse project structure looks like:
src
|
+ My source files
resources
|
+ templates
|
+ template.html
The following loads my plugins:
private List<Class<?>> loadClasses(final File[] jars) {
List<Class<?>> classes = new ArrayList<Class<?>>();
URL[] urls = getJarURLs(jars);
URLClassLoader loader = new URLClassLoader(urls);
for (File jar : jars) {
JarFile jarFile = null;
try {
jarFile = new JarFile(jar);
} catch (IOException e) {
// Skip this jar if it can not be opened
continue;
}
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
if (isClassFile(entry.getName())) {
String className = entry.getName().replace("/", ".").replace(".class", "");
Class<?> cls = null;
try {
cls = loader.loadClass(className);
} catch (ClassNotFoundException e) {
// Skip this jar if a class inside it can not be loaded
continue;
}
classes.add(cls);
}
}
try {
jarFile.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
loader.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return classes;
}
/**
* Checks if a path points to a class file or not.
*
* #param path the filename to check
* #return {#code true} if the path points to a class file or {#code false}
* if not
*/
private boolean isClassFile(final String path) {
return path.toLowerCase().endsWith(".class") && !path.toLowerCase().contains("package-info");
}
Then I make instances from this classes using newInstance().
I think that the root path of the plugins jar is not the same as the root path of the application or that not all contents of the jar files are loaded or both...
Can someone help me?
First note, that using getClass().getResource(...) also delegates to a ClassLoader, which is also responsible for loading resources. Which class loader is used? It is the same class loader, with which the class was loaded. Point.
In your code, you build up an URLClassLoader for loading some classes. So the same URLClassLoader will then be used for loading the resources, if the above mentioned call comes from a class inside your plugin.
This all seems to be ok ... but you did a little mistake. At the end of loading you also closed the loader. This will prevent subsequent calls to loadClass or getResource from returning anything meaningful. In fact, it could null, as now the loader cannot load the resource anymore.
Conclusion: Do not close the URLClassLoader, if you still need it ofr loading purposes. Instead keep the reference to this class loader and close it at the end of your program runtime.
I've been unsuccessfully trying to get a class from a .jar file. The .jar is located at C:\CTF.jar and contains a .class file CaptureTheFlagRules in a folder named CTF. The following code does not work:
try {
File jarFile = new File("C:\\CTF.jar");
URLClassLoader urlClassLoader = URLClassLoader.newInstance(new URL[]
{ jarFile.toURI().toURL() }, getClass.getClassLoader());
Class<?> unknownClass = Class.forName("CaptureTheFlagRules",
true, urlClassLoader);
....
} catch (MalformedURLException e) {
} catch (ClassNotFoundException e) {
}
The code throughs a ClassNotFoundException at the forName() call. What do I need to do to get my class?
Try:
Class<?> unknownClass = Class.forName("CTF.CaptureTheFlagRules",
true, urlClassLoader);
If it's in the CTF folder, it's probably in the CTF package.