0

I've created a jar-File with maven. When i open this jar i can find the following content:

my.jar
|_text1.txt
|_folder
|_ ... some other stuff

When i'm running this code snippet in Eclipse, content of "text1.txt" and all filenames from folder content where printed out

String tmp = IOUtils.toString(App.class.getClassLoader().getResourceAsStream("text1.txt"), StandardCharsets.UTF_8);
System.err.println(tmp);
            
tmp = IOUtils.toString(App.class.getClassLoader().getResourceAsStream("folder"), StandardCharsets.UTF_8);
System.err.println(tmp);

When i'm running this code as a standalone program, content from "text1.txt" will be printed as well, but the second part for folders returns null.

What am i doing wrong?

streetmaster86
  • 67
  • 1
  • 1
  • 7

1 Answers1

2

App.class.getClassLoader().getResourceAsStream

Don't do this. The right way is App.class.getResourceAsStream. There are times when getCLassLoader() returns null; in such cases, your strategy is broken, the above will work fine. Also, your way is more calls and more code for no gain.

IOUtils.toString(App.class.getClassLoader().getResourceAsStream("folder")

You can't get a 'folder'. What do you think this would even do? The abstraction designed into the resource loader system (which is what you're using here) doesn't let you get folders in any way, and does not allow you to list the contents of a folder either. (You're possibly looking for SPI: Service Provider Interface).

IOUtils

You do not need this; java.nio.file.Files is built-in, and has a toString method just the same. It even defaults to UTF-8 so you don't have to specify it.

App.class.getResourceAsStream("text1.txt")

This will look for t1.txt in the exact same place as App.class. Even the same package structure. If you want to go from the 'root' of where App.class is found (so, the thing on your -classpath, generally), put a slash in front: Ask for "/text1.txt" for example).

Given that you have text1.txt in the root, and not in com/foo/pkg next to com/foo/pkg/MyApp.class, you'd need to specify "/text1.txt" to find it.

If you're unsure about where this stuff is looking, sysout the result of this call:

App.class.getResource("App.class");

this prints a URL and from it your eyeballs will be able to tell where it's looking.

and all filenames from folder content where printed out

That's nice. This does not work - that eclipse gives you this at runtime is weirdness baked in, but the spec fundamentally has no abstraction for this. ClassLoader implementations can do whatever they want (it's a pluggable system) and the only method they need implement is 'find the resource at this location'. There is no obligation to return a string of filenames if you ask for a 'folder', and most classloaders (including the one reading jar files) simply don't.

The solution is SPI: At compile time make a file that lists paths or classnames, and then at runtime use the resource system to load the file, and then load every class / every resource listed inside it. An annotation processor can automate the process of generating this file as part of compilation, making the whole ordeal seamless. Search the web for SPI java for more.

rzwitserloot
  • 85,357
  • 5
  • 51
  • 72
  • Consider expanding the warning against `getClassLoader()` into an answer for the [Different ways of loading a file as an InputStream](https://stackoverflow.com/questions/676250/). – jaco0646 Jan 03 '21 at 15:59