Every time I run the exported .jar
file, that contains a JFrame
with an image as its icon, the file doesn't run, unless I extract the file. In the compiler it is running. I dont want to make a launcher that saves both, the resources package and the jar file, in a directory.

- 12,108
- 5
- 47
- 66

- 532
- 7
- 20
-
1Does the code load the resources using a `File` or `String`? When they have become embedded resources they must be accessed by `URL`. – Andrew Thompson Sep 26 '14 at 09:36
-
1Examine how to use [resources](http://docs.oracle.com/javase/tutorial/deployment/webstart/retrievingResources.html), here is a lot of same questions, for [example](http://stackoverflow.com/questions/4801386/how-do-i-add-an-image-to-a-jbutton). – alex2410 Sep 26 '14 at 09:41
-
http://stackoverflow.com/questions/941754/how-to-get-a-path-to-a-resource-in-a-java-jar-file – Stefan Sep 26 '14 at 10:09
1 Answers
"Why my Jar doesn't run unless I extract files?"
This seems to be the behavior of using File
to your resources. Take for example
File file = new File("resources/image.png");
Image image = ImagIO.read(file);
And you project structure (Note the resources
should actually be in the src
, so that it builds into the jar automatically - unless you configure it differently. But for the sake of this argument, let's say you do confgigure it where resources
is built to the jar)
C:\
Project
resources\image.png
Some examination:
Run from IDE - WORKS! Why? Using
File
looks for files on the file system. Using a relative path, the search will begin from the "working directory", which in the case of the IDE in generally the project root. So"resources/image.png"
is a valid path, relative toProjectRoot
Build jar, say it ends up in a
dist
dir in the project. This is what it looks likeProjectRoot dist ProjectRoot.jar
Now for the sake of this argument (and is actually the correct way), let's try and print the URL of the resource in out program, so that when you run the jar, it prints out the URL of the file
URL url = Test.class.getResource("/resources/image.png"); System.out.println(url.toString());
When we run the jar
C:\ProjectRoot\dist> java -jar ProjectRoot.jar
We will see the print outC:\ProjectRoot\dist\ProjectRoot.jar!\resources\image.png
. You can obviously see even though the current working directory is the location of the jar, the paths no longer match, with the added jarProjectRoot.jar!
location.So why does it work when we extract it. Well when you extract it, then the path is correct
C:\ProjectRoot dist resources/image.png // from extracted jar ProjectRoot.jar
When you run from the
C:\ProjectRoot\dist >
, theresource
dir is where is should be.
Ok enough with the explanation.
For this reason, when you want to read embedded resources, they should be read from an URL as Andrew Thompson mentioned. This url should be relative to the class calling it, or the class loader. Here are a couple different ways:
As shown already
URL url = getClass().getResource("/resources/image.png");
Notice the
/
. This will bring us to the root of the classpath, where theresources
dir will be.URL
can be passed to many constructors, likeImageIcon(URL)
or `ImageI.read(URL)You can use:
InputStream is = getClass().getResourceAsStream("/resources/image.png");
Which will use an URL under the hood. You can use
InputStream
with many constructors also.There's also ways to use the class loader, which will start at the root, so you don't need the
/
URL url = getClass().getClassLoader().getResource("resources/image.png");
So there are a few ways you can go about it. But in general, reading File
with hard coded string paths is never a good idea, when using embedded resources. It's possible to obtain the path dynamically so you can use File
, but you will still need to use one of the aforementioned techniques, which unless you really need a File
would be pointless, as you can do what you need with the InputStream
or URL
To make a long story short
This would work
ProjectRoot
src\resources\image.png
URL url = getClass().getResource("/resources/image.png");
Image image = ImageIO.read(url);

- 205,037
- 37
- 486
- 720
-
Thank you for your proper and clear explanation I already did use the URL and `getClass().getResource(PATH)` it appears that I wrote .PNG instead of .png but java case-sensitivity didn't noticed it maybe because it understood the ending in the compiler (Just a guess but maybe because in the compiler it also created instance .PNG of the image) and I verified it by trying to add another images. so for short, thank you very much and cheers. – Elian Kamal Sep 28 '14 at 15:13