2

I know there are already a lot similar questions here, but I couldn't get any smarter form them. I want to load a class inside a jar file, at this point this is no problem, but when I want to pass the path to my own ClassLoader it throws an exception it cannot find the class. Is it possible to load a class inside a jar using an absolute path? For instance,
Class cls = loader.loadClass(/path/MyPlugin.jar/MyPlugin.class);

But when I do this:

File test = new File("path/plugins/MyPlugin.jar/MyPlugin.class");
System.out.println(test.exists());

It prints out false. I tried using MyPlugin.jar!/MyPlugin.class or MyPlugin.jar.jar!MyPlugin.class which i've seen sometimes on the web, even though i don't really know what it means...

When I do this it finds the class:

URLClassLoader loader = new URLClassLoader(new URL[] { "path/plugins/MyPlugin.jar" });
Class cl = loader.loadClass("MyPlugin");

But now, how can I receive the path? Something like URL url = cl.getResource("MyPlugin"); (which gives back a null)

domizai
  • 343
  • 1
  • 5
  • 13

2 Answers2

4

You can obtain URLs to classpath resources using ClassLoader.getResources. To find a jar with specific class, you may use the following

URL url = classLoader.getResource("com/example/SomeClass.class");
JarURLConnection connection = (JarURLConnection) url.openConnection();
JarFile file = connection.getJarFile();
String jarPath = file.getName();

where classLoader is any classloader capable of finding the class you want to load. If the jar is a part of your application's classpath, you may use system classloader:

ClassLoader classLoader = ClassLoader.getSystemClassloader();

Otherwise, you need to know the jar file location beforehand, and create an instance of URLClassLoader, passing the jar in the constructor:

ClassLoader classLoader = new URLClassLoader(new URL[]{new URL("path/to/the/jar/file.jar")});

and then use it to load your class.

Marcin Łoś
  • 3,226
  • 1
  • 19
  • 21
  • I tried it, even though i don't know if i got it right. How would this look like in practice? – domizai Sep 03 '13 at 14:42
  • On second thought, manual string manipulation is not necessary. See my edit. – Marcin Łoś Sep 03 '13 at 14:53
  • Sorry I'm totally new here. What does classloader refer to? So example is actually a jar called example.jar? – domizai Sep 03 '13 at 14:57
  • 1
    Well... if you know the class name and the jar location, you can use the approach from the second part of my answer. If you have the class already loaded, you can use the suggestion from the first part. Otherwise, I see no way to do it; you cannot load the class if it's not on the classpath and you don't know what jar(s) contain its definition. – Marcin Łoś Sep 03 '13 at 15:08
  • Ahh, I see... Well, I'm not aware of any way to use `File`-based API to address jar content, sorry. Using `File` as the only classpath element type seems unnecessarily limiting, though. Is the classloader under your controll? Or, if you're fine with hackish solution, perhaps it has the constructor that allows specifying parent classloader? You could inject the `URLClassLoader` and let you have you `PluginClassLoader` delegate loading to it. – Marcin Łoś Sep 03 '13 at 15:57
  • How come it says this path doesn't exist? `URL url = cl.getResource("MyPlugin.class"); // output: "jar:file:/.../plugins/MyPlugin.jar!/MyPlugin.class"` `System.out.println(new File(url.toString()).exists()); // output: false` – domizai Sep 03 '13 at 17:39
  • Because when i do this: `ClassLoader cl = new PluginClassLoader(new File("jar:file:/.../MyPlugin.jar!/"));` `Class c = cl.loadClass("MyPlugin.class");` I get a `FileNotFoundException: jar:file:/.../MyPlugin.jar!/MyPlugin.class (No such file or directory)` ...? – domizai Sep 03 '13 at 18:12
  • 1
    Well, that's because while the path exists, `File` API is not jar-aware. It cannot look inside the jar and see that there is indeed `MyPlugin.class` file. I'm afraid you cannot do it without changing `PluginClassLoader`. – Marcin Łoś Sep 03 '13 at 21:35
0

If you want to access a file in your jar file you have to put it in the same directory as the class files are.

For example if Main.class is in bin/my/pkg/Main.class you can store your MyPlugin.class in the same directory (bin/my/pkg/MyPlugin.class) and then, if you want to access that file use

URL url = Main.getResource("MyPlugin.class");

Which uses the location of Main.class in your project as root.

Hope it helps!

schaeferpp
  • 109
  • 10
  • That's not quite right. Jar file needs to be on the classpath. Placing *the jar* on the classpath does not make it part of the classpath. – Marcin Łoś Sep 03 '13 at 14:44
  • Getting an error when trying this `URL url = PluginTest.getResource("MyPlugin.class");`. And receiving a null when trying this: `URL url = this.getClass().getClassLoader().getResource("MyPlugin.class");` – domizai Sep 03 '13 at 14:49
  • Are you aware that you need to use fully qualified name, with `/` in place of dots? – Marcin Łoś Sep 03 '13 at 15:12
  • So i need to do this "MyPlugin/class"? – domizai Sep 03 '13 at 15:14
  • 1
    Assuming you plugin is `com.example.MyPlugin`, you need `com/example/MyPlugin.class`. If it's in the default package, `MyPlugin.class` indeed should do. – Marcin Łoś Sep 03 '13 at 15:19