• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Bangs in URLs

 
Bartender
Posts: 1464
32
Netbeans IDE C++ Java Windows
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I have a bit of code that looks like this:


This works fine until I put it into a jar file. That's because the directory containing the application has a bang ("!") in its name, like "Wow!" has. At run-time, the url's toString method returns something like this:

jar:file:/R:/Program%20Files/Wow!/lib/MyLibrary.jar!/com/dumblux/experiment/Resources/pic.jpg



The second bang in that string apparently delimits the path to the jar to its left, and the path within the jar to its right. However, that first bang appears to be interpreted as though it were intended to do the same thing (and how could ImageIO.read be expected to do anything else?).

Now, if I change the first bang to its URL-encoded equivalent ("%21") and create a new URL with this code:


everything works fine. The only ASCII bang is where it should be, between the fully qualified path to the jar, and the path to the resource within the jar.

So, my question is: What better way is there to cope with this than searching the URL string for bangs and replacing all but the last one with their URL-encoded equivalents?

(I expect someone will want to ask me why I would pick a directory name with a bang in it in the first place. Please let it suffice to say that these decisions are made above my pay-grade.)
 
Bartender
Posts: 4179
22
IntelliJ IDE Python Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
So my question is why you need the URL? Why not get the stream directly?


[edit]used wrong getResource method[/edit]
 
Stevens Miller
Bartender
Posts: 1464
32
Netbeans IDE C++ Java Windows
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Steve Luke wrote:So my question is why you need the URL? Why not get the stream directly?


I hadn't tried that, but after trying it, the answer seems to be that getResourceAsStream returns null. I would expect that to result from getResourceAsStream getting the resource the same way as getResource does, then using the URL getResource returns to create the InputStream.
 
Marshal
Posts: 28193
95
Eclipse IDE Firefox Browser MySQL Database
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
What version of Java is that? I ask because handling of file URLs has been rife with errors in earlier versions. There were even versions which didn't URL-escape spaces in file names by %20, but it looks like that at least has been fixed.
 
Stevens Miller
Bartender
Posts: 1464
32
Netbeans IDE C++ Java Windows
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Paul Clapham wrote:What version of Java is that? I ask because handling of file URLs has been rife with errors in earlier versions. There were even versions which didn't URL-escape spaces in file names by %20, but it looks like that at least has been fixed.


Excellent question, Paul. I am using version 8, and I have tried the getResource method where the top-level directory had spaces in its name. Just as you say it should, it replaces those spaces with "%20" URL-encodings. Seems to me that this is another bug in the getResource method, which should replace bangs with "%21" in just the same way.
 
Sheriff
Posts: 10445
227
IntelliJ IDE Ubuntu
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Stevens Miller wrote:

Steve Luke wrote:So my question is why you need the URL? Why not get the stream directly?


I hadn't tried that, but after trying it, the answer seems to be that getResourceAsStream returns null.



Comparing that with your earlier post:

url = new URL("jar:file:/R:/Program%20Files/Wow%21/lib/MyLibrary.jar!/com/dumblux/experiment/Resources/pic.jpg");



You are passing the wrong path to getResourceAsStream() method. It should be:

 
Bartender
Posts: 689
17
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
And the jar must be on the classpath.
 
Steve Luke
Bartender
Posts: 4179
22
IntelliJ IDE Python Java
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Jaikaran brings up a good point, if you need absolute URLs (starting with '/') or relative URLs (without the starting '/'). I assumed MyClass was in the com.dumblux.experiment package. If it is, then MyClass.class.getResourceAsStream("Resources/pic.jpg") would produce a stream to the URL you defined. Then you need to identify if that is actually the path of the resource in the JAR file. If you open the JAR file and inspect it, where is the Resources folder? Is it at the top level (MyLibrary.jar!/Resources/) or is it in the package with MyClass (MyLibrary.jar!/com/dumblux/experiment/Resources/) or someplace else? From the null return I expect it is at the top level and you should use the absolute path MyClass.class.getResourceAsStream("/Resources/pic.jpg").
 
Stevens Miller
Bartender
Posts: 1464
32
Netbeans IDE C++ Java Windows
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Steve Luke wrote:If you open the JAR file and inspect it, where is the Resources folder? Is it at the top level (MyLibrary.jar!/Resources/) or is it in the package with MyClass (MyLibrary.jar!/com/dumblux/experiment/Resources/) or someplace else? From the null return I expect it is at the top level and you should use the absolute path MyClass.class.getResourceAsStream("/Resources/pic.jpg").



The class file and pic.img are in DLLibrary.jar. Here are the relevant lines from jar -tf lib\DLLibrary.jar:

 
Steve Luke
Bartender
Posts: 4179
22
IntelliJ IDE Python Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Stevens Miller wrote:


The file is pic.img, not pic.jpg. So you need to use MyClass.class.getResourceAsStream("Resources/pic.img")
 
Stevens Miller
Bartender
Posts: 1464
32
Netbeans IDE C++ Java Windows
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Steve Luke wrote:

Stevens Miller wrote:


The file is pic.img, not pic.jpg. So you need to use MyClass.class.getResourceAsStream("Resources/pic.img")



Sorry, that's a typo. I edited out a boatload of other lines from the jar -t output and mistyped it in the process. The jar -t output actually does say this:


My apologies for the confusion.

 
Stevens Miller
Bartender
Posts: 1464
32
Netbeans IDE C++ Java Windows
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Well, it turns out this is a known bug. Amazingly, it was reported on bugs.java.com as far back as 2001, and remains "unresolved" to this day, despite being reported again, and again, and again, and again, and again.

Some discussion about it at stackoverflow suggests there is no unambiguous solution, but I do think that, since the getResource method correctly encodes spaces as "%20" URL-encodings, it ought to be able to encode "!" characters in the path to the jar file with "%21" URL-encodings in just the same way. Is there any reason why another "!" would follow the "!" that delimits the jar path from the resource path?

Anyway, nice to get confirmation that it's a bug. I can use that to argue for a directory name with no bang in it.
 
Steve Luke
Bartender
Posts: 4179
22
IntelliJ IDE Python Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Looks like the getResourceAsStream() approach isn't going to work. It looks like when the JAR is in a path that contains a bang in it, the stream can't be created. Here is proof (same JAR in a path without the bang works, moved to Wow! subfolder and it doesn't work):


Here is the Tester code:
reply
    Bookmark Topic Watch Topic
  • New Topic