Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to open resources in directories which end with an exclamation mark (!)

The getResourceAsStream-method returns null whenever running the executable jar in a directory which ends with a exclamation mark.

For the following example, I have a Eclipse project the following directory structure:

src\ (Source Folder)
    main\ (Package)
        Main.java
    res\ (Source Folder)
        images\
            Logo.png

I'm reading the Logo.png as follows:

public static void main(String[] args) throws IOException {
    try (InputStream is = Main.class.getClassLoader().getResourceAsStream("images/Logo.png")) {
        Image image = ImageIO.read(is);
        System.out.println(image);
    }   
}

See the attachment for 2 test cases. First, the executable jar is started from the directory "D:\test123!@#" without any problems. Secondly, the executable jar is started from the directory "D:\test123!@#!!!", with problems.

Are directories ending with an exclamation mark not supported? Is the code wrong?

Thanks in advance.

Error when running the executable jar in a directory ending with !

like image 320
Velth Avatar asked Jul 04 '13 09:07

Velth


People also ask

What does it mean when a tool has a red circle with an exclamation mark inside?

It means there is a problem with the build path in your project. If it is an android project then it mostly means the target value specified in project.

What is the exclamation mark?

The exclamation mark (!), known informally as a bang or a shriek, is used at the end of a sentence or a short phrase which expresses very strong feeling. Here are some examples: What a lovely view you have here! That's fantastic!


2 Answers

A simple work around for Windows is to use "\" instead of "/" in the path. That would mean the "!/" character sequence is found after the full path. For instance:

new URL("jar:file:\\d:\\test1231@#!!!\\test.jar!/images/Logo.png");

My Code:

File jar = new File(jarPath + "/" + jarName);
URL url = new URL("jar:" + jar.toURI() + "!" + dataFilePath);
InputStream stream = null;
try {
    stream = url.openStream();
} catch (FileNotFoundException e) {
    // Windows fix
    URL urlFix = new URL("jar:" + jar.toURI().toString().replace('/', '\\')
        + "!" + dataFilePath);
    stream = urlFix.openStream();
}

I use toURI() because it handles things like spaces.

Fixes:

The fix itself would be for Java to check if the file exists and if not continue to the next separator (the "!/" part of the url) until the separators are exhausted, then throw the exception. So it would see that "d:\test1231@#!!" throws a java.io.FileNotFoundException and would then try "d:\test1231@#!!!\test.jar" which does exist. This way it does not matter if there are "!" in the file path or in the jar's files.

Alternatively the "!/" can be switched to something else that is an illegal file name or to something specific (like "jarpath:").

Alternatively make the jar's file path use another parameter.

Note:

It may be possible to override something, swap a handler, or change the code to open the file first then look inside the jar file later but I have not looked.

like image 24
Arckaroph Avatar answered Oct 06 '22 07:10

Arckaroph


Probably because of this bug or any of the many similar bugs in the Java bug database:

http://bugs.sun.com/view_bug.do?bug_id=4523159

The reason is that "!/" in a jar URL is interpreted as the separator between the JAR file name and the path within the JAR itself. If a directory name ends with !, the "!/" character sequence at the end of the directory is incorrectly interpreted. In your case, you are actually trying to access a resource with the following URL:

jar:file:///d:/test1231@#!!!/test.jar!/images/Logo.png

The bug has been open for almost 12 years and is not likely to be fixed. Actually I don't know how it can be fixed without breaking other things. The problem is the design decision to use ! as a character with a special meaning (separator) in the URL scheme for JAR files:

jar:<URL for JAR file>!/<path within the JAR file>

Since the exclamation mark is an allowed character in URLs, it may occur both in the URL to the JAR file itself, as well as in the path within the JAR file, making it impossible in some cases to find the actual "!/" separator.

like image 131
jarnbjo Avatar answered Oct 06 '22 08:10

jarnbjo