4

I kow there are dozens (if not hundreds) questions about Java's getResource/getResourceAsStream but i did not find any answers to my problem.

I load jars dynamically with: (String path is given)

File jar = new File(path);
URL url = new URL("file", "localhost", jar.getAbsolutePath());
URLClassLoader loader = new URLClassLoader(new URL[] { url });
c = loader.loadClass(name);

Then within the jar i try to load a resource in the jar. This resource clearly exists in the jar and the whole procedure works if I just run the whole thing with a class loader in Eclipse. In a jar it does not work.$

getClass().getResourceAsStream("resource.dat"); 

I tried every possible combination of /packageName/resource.dat, packageName/resource.dat, /resource.dat and resource.dat. They all throw a stream closed Exception.

The I tried debugging and ended up printing the URL of these files loaded via getClass().getResource(path)

This led to following URL and it does not look normal to me. Is it supposed to say "localhostC:..."?

jar:file://localhostC:\Users\******\export.jar!/packageName/resource.dat

Converting this URL also throws an Exception (URISyntaxException).

Is this URL really broken or am I just doing something wrong?

moschn
  • 68
  • 5

2 Answers2

2

Try changing the line:

URL url = new URL("file", "localhost", jar.getAbsolutePath());

to

URL url = new URL("file", null, jar.getAbsolutePath());

The host parameter in the URL constructor is not applicable in this case.

Federico Sierra
  • 5,118
  • 2
  • 23
  • 36
  • Thank you! This works. Still weird why it would add "localhost" in the getResource tag. – moschn Oct 28 '14 at 18:45
  • When I had `url = new URL[]{new URL("file:///" + jar.getAbsolutePath())};` - classLoader.getResourceAsStream return null for all entries in jar besides /META-INF/MANIFEST.MF – Dariusz Skrudlik Jan 13 '17 at 16:54
2

First, the File class has a toURI() method, so the preferred way to get a URL pointing to a file is:

URL url = new File(path).toURI().toURL();

So using this, the class loader:

File jar = new File(path);
URLClassLoader loader = new URLClassLoader(new URL[] { jar.toURI().toURL() });

Next, when you want to load a resource for the jar, use a Class that is originating from the jar, so if you already loaded the Class c:

Class<?> c = loader.loadClass(classPathAndName);
URL resource = c.getResource("data.txt");

This will result in something like:

jar:file:/C:/test/testjar.jar!/testpkg/data.txt

Alternatively you can use the ClassLoader to get the resource like:

loader.getResoure(packageAndResourceName);

But note that this quoting from the javadoc:

This method will first search the parent class loader for the resource; if the parent is null the path of the class loader built-in to the virtual machine is searched. That failing, this method will invoke findResource(String) to find the resource.

icza
  • 389,944
  • 63
  • 907
  • 827