I have a Java project and have to load resources such as sounds or images, which worked pretty well until I exported it into a jar file, where the app crashed because I it couldn't access the resources. I found after some research that I should use getClass().getClassLoader().getResource() or Class.getResource(). But after trying all the possibilities with the first or second function, with or without the leading /, but each time, I get null as a result, and used res/images/bg.jpg as argument. My project hierarchy looks like this:
|src
|Main.java
|res
|images
|bg.jpg
None of the solutions I've found on Stack Overflow or on Google worked for me. What am I doing wrong and what should I use?
EDIT
When exporting as jar, I am just right clicking on my project on Eclipse (without using any plug-ins), export and select runnable jar and explicitly declare my class Main as Classpath. When checking the content of the jar file, I can see the resources in the correct places.
The res folder should be a child of your src folder
|src
|Main.java
|res
|images
|bg.jpg
although standard practice would be to have the layout closer to
|src
| main
|java
|package
|Main.java
|resources
|images
|bp.jpg
The last time something like this happened to me, it was because my build did not copy the files into the jar. Might be worth doing a sanity check by listing the files in your jar:
jar tf /path/to/your.jar
Related
There are already heaps of answers to this problem. I have also tried a lot of them. I have not found a solution yet.
I load some images within my project (Swing - ImageIcons). In the run dialog all of them are also displayed in my GUI. But after compiling the program can't be started at all. The error messages are different depending on the procedure.
Lastly, I tried simply loading a File to print the absolute path. This then looked like this:
File f = new File(Loadscreen.class.getResource("../../../../resources/materials/icon.png").getFile());
System.out.println(f.getAbsolutePath());
The console returns a NullPointerException for this:
Console compiled:
Exception in thread "main" java.lang.NullPointerException
at de.franken.ration.gui.Loadscreen.<init>(Loadscreen.java:43)
at de.franken.ration.Rationboard.onEnable(Rationboard.java:84)
at de.franken.ration.Rationboard.main(Rationboard.java:75)
Console Eclipse:
H:\Users\Hinrich\Documents\Java\Rationboard\bin\resources\materials\icon.png
In line 43 I define f.
My tree looks like this:
Rationsboard
L_ src
L_ de
L_ franken
L_ ration
L_ gui
L_ Loadscreen.class
L_ resources
L_ materials
L_ icon.png
However, the icon is included in the JAR.
Thanks to all who respond.
//EDIT:
I played around a bit more. As long as the resource to be loaded is in the same package, it can be loaded. But if I change the package with ../, the NullPointerException comes up.
Use:
this.getClass().getResource("/resources/materials/icon.png");
Note the two differences to the approach seen in the question:
this.getClass() will find the context class loader appropriate for application resources.
"/resources/materials/icon.png" the leading / will tell the getResource method to search from the root of the class-path or Jar.
BTW: Don't get files involved at any point. getResource returns an URL and resources in a Jar are not accessible as File objects.
You can verify, as a first step, that the icon is included within the jar, by running jar -tf file.jar.
Have you tried
File f = new File(Loadscreen.class.getResource("/materials/icon.png").getFile()); System.out.println(f.getAbsolutePath());
assuming that the icon.png is in resources/materials folder?
Both class.getResource(FILE_NAME) and class.getClass().getClassLoader().getResource(FILE_NAME) run perfectly inside my eclipse but the same code getting failed to locate the file which is inside the jar file, when run as an executable jar in windows machine.
I have gone through all related links available for this problem (well, not exactly the same issue but 90% in sync), asked for solution but no reply came from any of those posts, so I'm posting my issue as a separate question hoping for help on this.
In total, 4 cases I have ran to resolve but none worked so far and I'm out of ideas now.
class.getClass().getClassLoader().getResource("/resources/readme.txt");
class.getResource("/resources/readme.txt");
class.getClass().getClassLoader().getResource("resources/readme.txt");
class.getResource("resources/readme.txt");
Ouf of all the above 4 cases, only 2 cases ran successfully in eclipse which are as mentioned below.
class.getResource("/resources/readme.txt");
class.getClass().getClassLoader().getResource("resources/readme.txt");
The other 2 cases just throwing me Exception in thread "main" java.lang.NullPointerException
Coming to the executable jar, all 4 cases are throwing me the Exception in thread "main" java.lang.NullPointerException.
So I have created a folder named resources where my jar is residing and placed my files inside this folder and ran the jar. Now the jar is running without any issues referring to the files inside the resources folder I created. So wherever I run this jar (windows, linux etc.,) I need to create a resources folder and place my files under the folder. Now the question is, can it be possible to make my jar refer the resources folder which is inside the jar itself?
Any help on this is much appreciated!
To get your txt file:
File yourFileIsHere = new File("resources/readme.txt");
Where put your file?
In the same location of your jar, example:
myapp/yourjar.jar
myapp/resources/readme.txt
If you want read file inside of your "src" folder:
InputStream yourInputStream = new YourClass().getClass().getClassLoader().getResourceAsStream("readme.txt");
If you are using Spring:
org.springframework.util.ResourceUtils.getFile("classpath:readme.txt")
Otherwise:
import com.google.common.io.Resources
byte[] byteSource = Resources.asByteSource(Resources.getResource("readme.txt")).read()
method class.getClass().getClassLoader().getResource() may take 3 prefixes: url:, classpath: and file: each prefix tells what is your base of search. If you want to search inside your jar use classpath: prefix. That tells your classloader to search everywhere within your classpath. Here is one example how to deal with it with Spring tools. Look also at ResourceLoader class in Spring
I have a code where i create Java Actions and try to associate Icons with them. One snapshot of code is
FileOpenCommand fileOpen = new FileOpenCommand(this);
fileOpen.putValue("ImageOnly", false);
fileOpen.putValue(Action.NAME, "Open");
fileOpen.putValue(Action.SMALL_ICON, new ImageIcon(getClass().getResource("../resources/File-Open-icon24x24.png")));
fileOpen.putValue(Action.SHORT_DESCRIPTION, "Opens the existing file.");
fileOpen.putValue("Group", "File");
fileOpen.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.CTRL_MASK));
this.commands.put("FileOpen", fileOpen);
The accent is on the line where I try to set the Action.SMALL_ICON property to the action. This works when executed in NetBeans environment either in debug or release mode. But when I've tried to execute jar file from the command line, it fails with exception.
Any idea? Anything to do with classpath? Resources folder is put as the package inside the main package.
Thanks in Advance!
I'm not entirely sure what exception is being thrown in your case, although assuming it is a NullPointerException, IOException, or IllegalArgumentException deriving from
fileOpen.putValue(Action.SMALL_ICON, new ImageIcon(getClass().getResource("../resources/File-Open-icon24x24.png")));
Your issue should be resolved simply by adding getClassLoader() between the getClass() and getResource(), like so:
fileOpen.putValue(Action.SMALL_ICON, new ImageIcon(getClass().getClassLoader().getResource("../resources/File-Open-icon24x24.png")));
Additionally, you must be exact in your filenames, specifically the extension. In this case, you are accessing File-Open-icon24x24.png, which will work perfectly fine regardless of whether the actual file is extended by png or PNG within Netbeans, but once exported the extension case matters.
Lastly, if neither of those changes resolve your problem, I would check your filepath, as there is most likely a logical error somewhere down the line.
When using embedded resources in Netbeans, you should have a resources folder containing additional folder or whatever data you need, which you seem to have, but this folder should be located inside the Netbeans project's src folder. getClass().getResource() returns the directory at the top of the package line, meaning if your class package is com.example.code, then the compiler will look for files/folder on the same level as com. Opening the Netbeans src folder you should see the initial com folder. Your resource folder should be placed directly next to that folder, as then it will be properly embedded in the jar file export.
In your code your path is ../resources/File-Open-icon24x24.png, which confuses me as to why you begin with ... I cannot see your folder structure so I cannot give a precise answer on this note, but you may be accessing the wrong location, although I feel like you are not as you said your project runs correctly within Netbeans. However, your resource files may not be correctly encoding into the jar file due to placement as mentioned. To test what your jar file actually contains, make a copy of it (for safety reasons) and change the file extension from jar to zip. You can then look through its contents in Windows Explorer, and see its directory structure. Another debugging trick for folder structures is to create a text file at the URL you are trying to access to see where it is placed.
Yesterday, I had a problem because I couldn't manage to open a xml file (it owuld give me a FileNotFoundException) located in the ressources folder of my .jar file, which I managed to open on eclipse using the following lines of code. You can see my old problem here. This was my code with the problem :
File xmlFile = new File("ressources/emitter.xml");
ConfigurableEmitter emitter = ParticleIO.loadEmitter(xmlFile);
Someone told me it that one way was to use getClassLoader().getRessourceAsStream method to open a xml file in a .jar file that was exported
InputStream i= this.getClass().getClassLoader().getResourceAsStream("ressources/emitter.xml");
ConfigurableEmitter emitter = ParticleIO.loadEmitter(i);
Unfortunately, that solution only works when I export my project into a .jar file, so if I want to go back debugging my program, I have to take the old code that would only works on eclipse.
My question is: is there any better way to do this without having to change my code if I want to export it or if I want to debug it?
Thank you
edit :
Thank you all, it works perfectly fine now
my problem was that I put my ressources folder like that :
+project
+src
+ressources
+emitter.xml
InputStream i= this.getClass().getClassLoader().getResourceAsStream("/ressources/emitter.xml");
The above should work in both cases (Note is is /resources/.... This is assuming say your directory structure is below:
MyProject
+src
+ressources
emitter.xml
Place the file alongside your source files, then you can use the getResourceAsStream() method in both cases. Don't forget to update the path (which should be the package name of your class, but with slashes instead of dots).
My question is: is there any better way to do this without having to
change my code if I want to export it or if I want to debug it?
Yes, use Maven. Maven will handle that and it hooks into Eclipse beautifully (NetBeans too!) What you do is place the resource in src/main/resources and then you can have Eclipse run the test goal of the Maven project or you can just run mvn test from the command line. Another advantage of using Maven here is that you can also have src/test/resources/emitter.xml which overrides the one in src/main with environment-specific test instructions and it won't affect your deployment.
InputStream i= getClass().getClassLoader().getResourceAsStream("ressources/emitter.xml");
or
InputStream i= getClass().getResourceAsStream("/ressources/emitter.xml");
(note the absolute positioning)
both work when the class is in the same jar, on the same class path.
In the jar the names must be case sensitive, but as the jar already works. Ensure that the ressources directory is on the class path too, or copied to the target directory.
As "ressources" is probably configured yourself (not named "resources" as in English), you probably need to add it to the build somehow.
Using the ClassLoader#getResource(), I need to access a file that is present in a project other than the one where my current code resides. How can this be done?
I'm using eclipse.
Directory Structure:
Root
|-project1
| |-package
| |-myResourceFile
|-project2
|-package
|-myCodeFile
I'm trying to get myResourceFile from myCodeFile, using myCodeFile.class.getClassLoader().getResource("../../project1/package/myResourceFile") but its always returning null. I do not want to add project1 to the classpath of project2. Though adding that also did not work.
With regards,
It's a bad idea to attempt to read files from another project like that because it ties you to exactly that directory structure. You already did the first step in decoupling the projects by using getResource() instead of using the java.util.File API so you can go the full way as well.
In Eclipse you can add other projects to a projects' build path (Project Properties -> Java Build Path -> Projects). You should be able to read the other projects' files now.
If you are using maven, then you can specify project1/package as a resource folder in the pom.xml of project2. You can theen use Classloader getResource method to get the resouce
http://maven.apache.org/plugins/maven-resources-plugin/examples/resource-directory.html