编码URI的路径在内置到JAR中时的行为有所不同

时间:2015-07-02 01:33:35

标签: java jar hashmap containskey

我调用了HashMap的containsKey方法,我期望返回true。如果我将程序编译为.class文件并运行它,它返回true,但如果我构建一个JAR,那么同样的调用返回false,原因是我无法理解。

我已经调试了.class和JAR版本(使用http://www.eclipsezone.com/eclipse/forums/t53459.html中描述的远程连接的JAR),在这两种情况下,HashMap似乎包含了我尝试的密钥检查。

HashMap使用URI对象作为键。以下是每个调试会话中显示的变量的内容:

以.class文件格式运行

HashMap Key:java.net.URI = file:/E:/SSD%20App%20Libraries/Google%20Drive/Programming/Bet%20Matching/Java%20Sim/target/classes/simfiles/paytables/

URIToCheck:java.net.URI = file:///E:/SSD%20App%20Libraries/Google%20Drive/Programming/Bet%20Matching/Java%20Sim/target/classes/simfiles/paytables/

结果:GameTreeItemsMap.containsKey(URIToCheck)true

以JAR格式运行

HashMap Key:java.net.URI = jar:file:/E:/SSD%20App%20Libraries/Google%20Drive/Programming/Bet%20Matching/Java%20Sim/out/artifacts/JavaSim_jar/Java%20Sim.jar!/simfiles/paytables/

URIToCheck:java.net.URI = jar:file:///E:/SSD%2520App%2520Libraries/Google%2520Drive/Programming/Bet%2520Matching/Java%2520Sim/out/artifacts/JavaSim_jar/Java%2520Sim.jar!/simfiles/paytables/

结果:GameTreeItemsMap.containsKey(URIToCheck)false

我希望该方法在两种情况下都返回true。在JAR中,URI在某种程度上表现不同吗?发生了什么事?

提前感谢您的帮助!

修改1 正如我所指出的那样,JAR案例中的URIToCheck正在进行双重编码(%2520而不是%20)。这是生成URIToCheck的代码。我使用walkFileTree方法。

        Files.walkFileTree(paytableHomePath, new SimpleFileVisitor<Path>(){
            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {

                Path parentPath = dir.getParent();

                URI parentURIToCheck = parentPath.toUri();

                boolean testContain = GameTreeItemsMap.containsKey(parentURIToCheck);

                return FileVisitResult.CONTINUE;
            }

在JAR情况下,URI parentURIToCheck是双重编码的(对于应该有%20的空格,%5250),而在.class情况下,这不会发生。知道为什么吗?

1 个答案:

答案 0 :(得分:1)

这与HashMap无关。您似乎在Java Zip File System Provider中发现了一个错误,即它将Path转换为双重编码的URI。

我找不到它的现有错误,所以我提交了一个。 (有this related bug,我怀疑其修复的原因是这个。)更新:这是Java bug 8131067

这是我用Java 1.8.0_45-b14编写的用来演示问题的程序。传递一个.jar文件,其路径中有一个或多个空格作为第一个命令行参数。

import java.util.Map;
import java.util.Collections;
import java.net.URI;
import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.Paths;

public class JarPathTest {
    public static void main(String[] args)
    throws IOException {

        Path zip = Paths.get(args[0]);

        URI zipURI = URI.create("jar:" + zip.toUri());
        System.out.println(zipURI);

        Map<String, String> env = Collections.emptyMap();

        try (FileSystem fs = FileSystems.newFileSystem(zipURI, env)) {
            Path root = fs.getPath("/");
            System.out.println(root.toUri());
        }
    }
}

您可以通过将已解码的URI视为仍为百分比编码来解决此问题:

parentURIToCheck = URI.create(
    parentURIToCheck.getScheme() + ":" +
    parentURIToCheck.getSchemeSpecificPart());