how to get artifacts built with Intellij IDEA to find included res directory?

Hi,

I asked this question on stackoverflow a while back and got no answer whatsoever. I have a directory called res included in my game which holds my sound and graphics data. I have a completed demo that I’m trying to build into a standalone jar artifact from IntelliJ IDEA. I included the directory in the artifact build, but when I run the standalone jar, it looks for the resources by prepending the entire root directory of my computer to the resource directory. Does anyone know how to fix this??

Here is some example output. Notice how it looks for the resource starting at root on my machine:

jeep@VICTORY ~/Dropbox/WGU/Capstone/C436/Demos $ java -jar Varg.jar
Error getting resource stream!
/home/jeep/Dropbox/WGU/Capstone/C436/Demos/res/audio/sfx/axe_throw.wav (No such file or directory)
Error getting resource stream!
/home/jeep/Dropbox/WGU/Capstone/C436/Demos/res/audio/sfx/boss_explode.wav (No such file or directory)
Error getting resource stream!
/home/jeep/Dropbox/WGU/Capstone/C436/Demos/res/audio/sfx/drink_potion.wav (No such file or directory)
Error getting resource stream!
/home/jeep/Dropbox/WGU/Capstone/C436/Demos/res/audio/sfx/enemy_explode.wav (No such file or directory)
Error getting resource stream!
/home/jeep/Dropbox/WGU/Capstone/C436/Demos/res/audio/sfx/enemy_hit.wav (No such file or directory)
Error getting resource stream!
/home/jeep/Dropbox/WGU/Capstone/C436/Demos/res/audio/sfx/flame.wav (No such file or directory)
Error getting resource stream!
/home/jeep/Dropbox/WGU/Capstone/C436/Demos/res/audio/sfx/grab_item.wav (No such file or directory)
Error getting resource stream!
/home/jeep/Dropbox/WGU/Capstone/C436/Demos/res/audio/sfx/hero_dead.wav (No such file or directory)
Error getting resource stream!
/home/jeep/Dropbox/WGU/Capstone/C436/Demos/res/audio/sfx/hero_hurt.wav (No such file or directory)
Error getting resource stream!
/home/jeep/Dropbox/WGU/Capstone/C436/Demos/res/audio/sfx/squish.wav (No such file or directory)
Error getting resource stream!
/home/jeep/Dropbox/WGU/Capstone/C436/Demos/res/audio/sfx/switch.wav (No such file or directory)
Error getting resource stream!
/home/jeep/Dropbox/WGU/Capstone/C436/Demos/res/audio/sfx/textbox.wav (No such file or directory)
Error getting resource stream!
/home/jeep/Dropbox/WGU/Capstone/C436/Demos/res/audio/sfx/void_sound.wav (No such file or directory)
Error getting resource stream!
/home/jeep/Dropbox/WGU/Capstone/C436/Demos/res/audio/sfx/water_drain.wav (No such file or directory)
Error getting resource stream!
/home/jeep/Dropbox/WGU/Capstone/C436/Demos/res/audio/sfx/zap.wav (No such file or directory)
Exception in thread "main" java.lang.NullPointerException
        at audio.Sfx.play(Sfx.java:36)
        at Main.main(Main.java:15)
Shutting down TinySound...
TinySound shutdown complete!

How are you passing the path into the lib that should load the resources? How do these paths look like? I suggest you need something like described here https://stackoverflow.com/questions/3823746/open-file-try-filesystem-first-then-jars nur i may made wrong assumptions.

[quote]How are you passing the path into the lib that should load the resources?
[/quote]
I pass them like this:

public static final Sfx VOID_SOUND = new Sfx(TinySound.loadSound(new File("res/audio/sfx/void_sound.wav")));

I didn’t do a very good job of explaining some things. I just posted a new question on SO with more detail, so I’ll link it rather than re type it all here:

I think I articulated it better in that post.

I’m going to go out on a limb here and say that I think the answer is that it isn’t possible. I think the only way resources can be readable from inside the jar file is if they are somewhere in the classpath. In my case I have resources (maps) that write to disk and are read later, that way the state of the map is persistent when you transition from zone to zone. The problem is that you can’t write files to the classpath; they must be in an external directory. However, I probably should move the sound effects to the classpath, since those aren’t being written.

You are passing a relative path to File so it’s resolving that against the directory you’re running the JAR from to get the absolute paths you posted. This is what you’re telling it to do! What path are you expecting?

Using relative paths with a JAR is error prone unless you have a launching script (or use the getprotectiondomain().getcodesource().getlocation() workaround) - the path will be wherever you launch the JAR from, not the location of the JAR itself.

If you want to put the resources in the JAR you’ll need to switch to getClass().getResource()

Yes, I assumed that this is the problem, because it always is, when people try to include ressources into their artifact :slight_smile: In the link I posted is an example how you can make a distinction between “run from the ide” and “run from production-single-artifact-build”. Basically it’s a configuration based switch that switches between file system loading and the getClass().getResource() idea nsigma mentioned already.

Yes, thank you both; I understand. If you want to access resources that are inside the JAR, they must exist inside the classpath and are accessible using a class loader. You can perform a conditional test to determine whether to use the class loader or access using a relative path. If you try to access internal files using a relative path, the path will resolve to the path where the JAR exists, to inside the JAR, so it’s only good for external resources. It’s clear now. :slight_smile:

Yes, but this bit is incorrect. It will resolve to where you launch the JAR from (ie. if from terminal the pwd, not necessarily where the JAR is). Add in the possibility of users setting up symlinks, etc. and relying on the relative path can be a bad idea. See this old message with a bash launcher script that works around this issue (from the Linux / OSX NetBeans launcher) http://www.java-gaming.org/topics/cannot-run-a-program-by-clicking-on-its-icon-whereas-it-works-in-command-line/36811/msg/350522/view.html#msg350522

Or, as mentioned above, in your Java code you can use


URL jarLocation = MyClass.class.getProtectionDomain().getCodeSource().getLocation();

see https://stackoverflow.com/questions/320542/how-to-get-the-path-of-a-running-jar-file

Thanks, that clears it up nicely.