Path to JAR - any problems with this approach?

I know this is a commonly asked question, but after doing some research on it I still have some doubts.

Say I have a directory structure like this:

parent_folder
--MyApp.jar

In order to make some documents distributed with the game more easily accessible to the user, I’d like to get the absolute path of parent_folder. It seems like the most reliable method for this is to use getResource(), as in the following code (error checking omitted for brevity):

String path = Main.class.getResource("Main.class").getPath();
path = path.substring(0, path.indexOf("/MyApp.jar!"));
path = new URL(path).toURI().getPath();

Am I on the right track here? Can anyone spot any problems with this approach, or any cases where it might fail?

Instead of:

path = path.substring(0, path.indexOf("/MyApp.jar!"));

I would use the more flexible:

path = path.substring(0, path.lastIndexOf(File.separator));

Still, instead of playing with Strings, you could also just get it’s parents absolute path:

File file = new File(Main.class.getResource("Main.class").getFile());
file.getParentFile().getAbsolutePath();

But… hardcoding “Main.class” is unnecessary as well, you could try making a temp file instead, which results in:

File temp = File.createTempFile("temp", ".tmp" );
temp.deleteOnExit();
temp.getParentFile().getAbsolutePath();

I’d simply delegate you to do a 2 sec. Google Search which will show you this: http://stackoverflow.com/questions/320542/how-to-get-the-path-of-a-running-jar-file

This does not work because it will cut away at the last package component of a class, leaving you with nothing but the simple class name + ‘.class’.

This also does not work because it will give you the package inside the jar file as a file path.

Or simpler:


System.getProperty("java.io.tmpdir");

Although that has nothing to do with the actual question of figuring out the JAR path of the running application. :wink:

If you do not want to hardcode the class name as a string literal, then just use Main.class.getSimpleName() + ".class". This also allows for refactorings and code obfuscation tools to function.

KaiHH, I searched extensively before posting here, and have read the exact thread you linked to in its entirety several times.

Your next question might by why that thread wasn’t sufficient, so I’ll go into a little more detail here.

The answers in that thread fall into a few basic categories:

  • Use getProtectionDomain(). My concerns about this are that there are some caveats mentioned in the thread, and that it can throw a SecurityException. That may or may not be a problem in practice (I’m not sure), but one of my goals is to minimize the number of possible failure points, and in that sense getResource() seems a little more promising.

  • Use getResource(). There were some caveats mentioned with this approach as well, although I’m pretty confident they don’t apply in my particular case. The issue remains of decoding the URL and converting it to the needed form. Some of the answers skipped this part; one highly-rated answer seemed to address it, but I wasn’t able to get that method to work (which may have been user error, or I may have simply misunderstood what was being suggested).

  • Use ‘user.dir’. This of course will not give the desired results in all cases.

I’ll also mention that some of the answers seemed to have errors or be problematic in various ways. Some of the answers came with the caveat of only having been tested on certain platforms, and some seem to make more assumptions regarding the format of the returned URL than others. In short, it’s not just a matter of popping into that thread and finding the answer. There are probably 10 to 20 different specific solutions offered there, and much discussion about potential problems and pitfalls. Extracting a robust, reliable solution from that thread might seem trivial to you, but for me it’s taken some work (and I’m still somewhat uncertain about it).

The code I posted here is the solution I came up with after reading that thread and many others. I wanted to get some other eyes on it because I’m not confident I’ve covered every angle or necessarily understood everything I’ve read correctly. If it’s a trivial problem with a trivial solution, it should be easy to look over the three lines of code I posted and point out any problems with it.

Anyway, if anyone can pick the code apart, please do! I’d very much like to know if there’s anything wrong with it.

[s]Yes, that would be the conclusion of that post.

But maybe your problem is no problem.
Why are you needing to identify the JAR file of your application in the first place?
Do you want to load a resource from it, in which case you can do that via the ClassLoader?
Do you need to identify the JAR file in order to distribute it to some other place?
Maybe we can find a solution to by pass the problem of identifying the JAR file altogether?[/s]

Ahhh… sorry, did not read your initial post thoroughly, which was about having documents being easily distributed to the user. So, they do not reside in the JAR files.

Well, maybe we’re just running into some communication problems :slight_smile: I said in my original post that I still had some doubts ‘after doing some research’, and what kind of research doesn’t include a 2-second Google search? :wink: So I’m not sure where that came from.

Anyway, I also gave the reason for wanting to do this in my original post, but I’m happy to repeat it (and elaborate a bit).

I have some documents (licenses and other legal stuff) that I’ll be distributing in a folder with my game. My concern is that this folder may be difficult for the user to access if the game ends up being installed in a non-obvious location (such as a hidden folder).

Getting the absolute path to this folder would make some options available. At the very least I could display the path so the user knows where the game is installed. Also, although this can’t really be relied on, I could use the Desktop class to open the folder for the user automatically.