I ran afoul of the following problem. I have a work-around solution, but I would like to better understand what is going on. It seems that ".." does not work as I expect it to in the context of a jar. I will illustrate with an example.
I have a project in Eclipse with "audio" and "test" subfolders. Simplified map:
In Eclipse, using the following works (code line is within "MyTest"):
But it doesn't work when the project is exported to a jar. I get a NPE for the url.
I've managed the following work-around. Within "MyTest" I now use the following:
The closest I've come to an explanation is from the URL api. I quote what seems like the most relevant line (but which I do not understand):
Otherwise, the path is treated as a relative path and is appended to the context path, as described in RFC2396. Also, in this case, the path is canonicalized through the removal of directory changes made by occurences of ".." and ".".
Using System.out.println(url.getPath()); to investigate, the Eclipse run displays a straightforward set of file folders. In the context of the jar, the printout shows a "!" between the file location of the jar and the structure of the folders within the project. Using my workaround, everything looks as expected.
I can't seem to think up a test that will allow me to figure out how ".." is being interpreted, and I've been unable so far to find documentation on the "canonicalization" or on just how ".." is being interpreted in the context of the jar.
Any insights as to what is going on? Is there a symbol that can substitute for ".." for relative URLs pointing into jars?
The quote from the API which you posted fails to mention that "relative" in the phrase "relative path" doesn't have anything to do with the file system. As a result, it's easy for unwary readers of the document to go down the wrong road.
In fact the URL is relative to the class whose getResource() method is being called. In your case it's relative to the ClassBeingTested class, which as far as I can see isn't in any package, so "audio/bonk.wav" is the same as "/audio/bonk.wav". If your ClassBeingTested was in the "test.phil" package then "audio/bonk.wav" would be the same as "/test/phil/audio.bonk.wav".
So in your case the getResource method will be looking for something in the classpath which matches "/audio/bonk.wav". It will go through each of the entries in the classpath (which can be directories or jar files) looking for something like that. So if you've got an executable jar and nothing else is in its classpath, then you need an "audio" directory in the root of that jar which contains a "bonk.wav" file. Apparently you have that, so your program works okay.
Joined: Sep 01, 2010
Can I get a repeat of the answer if I provide more detail? There ARE packages involved. I'll use your suggestion "test.phil" as the package name, as long as we don't confuse package "test" with file folder "/test".
No external libraries or jars are being invoked, all the imports are correct, the code within the jar is complete and only uses standard Java libraries.
I have two alternative lines of code that were contained in "/ test / MyTest":
I wish to obtain the resource that is in a folder at the relative location ".. / audio". As far as I can tell, ".." should work to allow me to go up one level. It does seem to do this in Eclipse. But it doesn't in the jar file. My work-around solution was to use "ClassBeingTested" as the relative reference instead of "MyTest", so that I would not have to use "..". I think I understand why the latter (line 3) works. I don't understand why the former (line 1) does not work.
I'm also wondering, does there even exist a way to point to the relative location of "/ audio / bonk.wav" while using "/ test / MyTest" as the starting point for the relative address? In other words, does there exist a relative-address string that would accomplish this using the command like this: "MyTest.class.getResource(someString)"?
Or would doing so be bad form and be discouraged even if there was a way?
Phil Freihofner wrote:Can I get a repeat of the answer if I provide more detail?
The detail would have to include the directory structure of the jar; it's hard to talk about it when we don't know what it is.
Joined: Sep 01, 2010
Indeed using this form works perfectly well:
I think I now better understand this form of invocation (as opposed to the relative-address form). I always assumed that the search would only progress from a starting location that would match the folder of the class cited. In this example, MyTest is down in the /test folder, yet we are still able to search above this folder level. I did not know this!
@Paul, I apologize about not specifying the contents of the jar. This was a "made up" example, and I thought laying out the folder structure of the Eclipse project would suffice, as only the "export to jar" function is called. Here is the structure of what is inside the jar that is shown when converting the jar to a zip and looking inside:
test / phil / ClassBeingTested
test / phil / audio / bonk.wav
test / phil / test / MyTest
I'm still curious about the rules concerning the interpretation of ".." This symbol works in the "relative" form in Eclipse (no leading "/"), but not in a stand-alone jar.