【问题标题】:Need help with strange Class#getResource() issue需要帮助解决奇怪的 Class#getResource() 问题
【发布时间】:2010-01-14 16:53:16
【问题描述】:

我有一些从现有 jar 中读取配置文件的遗留代码,例如:

URL url = SomeClass.class.getResource("/configuration.properties");
// some more code here using url variable
InputStream in = url.openStream();

显然它以前工作过,但是当我执行此代码时,URL 是有效的,但我在第三行得到一个 IOException,说它找不到文件。该 url 类似于“file:jar:c:/path/to/jar/somejar.jar!configuration.properties”,因此它看起来不像是类路径问题 - java 非常清楚在哪里可以找到文件..

上面的代码是 ant 任务的一部分,在执行任务时失败了。

太奇怪了——我将代码和 jar 文件复制到一个单独的类中,它按预期工作,属性文件是可读的。

在某个时候,我将 ant 任务的代码更改为

URL url = SomeClass.class.getResource("/configuration.properties");
// some more code here using url variable
InputStream in = SomeClass.class.getResourceAsStream("/configuration.properties");

现在它可以工作了——直到它在另一个实现了类似访问模式的类中崩溃..

为什么它以前可以工作,为什么现在失败了?我目前看到的唯一区别是,旧版本是使用 java 1.4 完成的,而我现在正在尝试使用 Java 6。

解决方法

今天我在构建服务器上安装了 Java 1.4.2_19 并让 ant 使用它。令我完全失望的是:问题消失了。在我看来,java 1.4.2 可以处理这种类型的 URL,而 Java 1.6 不能(至少在我的上下文/环境中)。

我仍然希望得到解释,尽管我正面临重写部分代码以使用表现更稳定的 Class#getRessourceAsStream 的工作......

【问题讨论】:

  • 如果你可以调试它,看看 Java 做了什么会很有趣。随着 Eclipse 执行服务器,一些断点和对 Java 类代码的嗅探也许你可以得到一些东西(或者如果 URL 代码足够复杂的话,只是头疼:)。无论如何,Class#getResourceAsStream 似乎更直接且与环境无关。
  • 是的,我必须调试。包括头痛,因为问题只出现在构建服务器上的 hudson 触发的 ant 构建中......但是应该可以将远程调试会话从 Eclipse 连接到该 ant 构建 - 我会随时通知您进度; )
  • 如果你想调试它,你可能应该从打印SomeClass.class.getClassLoader()开始,谁知道呢,它们可能不一样。

标签: java ant


【解决方案1】:

ClassLoader.getResourceAsStream 的典型实现是:

public InputStream getResourceAsStream(String name) {
    URL url = getResource(name);
    try {
        return url != null ? url.openStream() : null;
    } catch (IOException e) {
        return null;
    }
}

Class.getResourcegetResourceAsStream 的行为相同。

所以看起来要么您使用了一个奇怪且损坏的 ClassLoader 子类,要么您的测试中有一些错误。

【讨论】:

  • 很好的提示 - 现在我已经安装了两个 jdk,我将看看这两个版本的实现。也许这会导致答案。
【解决方案2】:

它适用于 getresourceasstream,因为它位于类路径中,但它不适用于 URL,可能是因为 URL 不正确。

我不知道 getResource 创建的 URL 是否不正确,或者协议没有正确的处理程序(不是 file:jar:c:/myjar.jar!configuration.properties 或类似的东西(带有两个冒号吗?)

【讨论】:

  • 当我请求 Class.getResource("/java/util/ArrayList.class") 时,我的 Java6 运行时打印 jar:file:/C:/Archivos%20de%20programa/Java/jdk1.6.0_14/jre/lib/rt.jar!/java/util/ArrayList.class。我认为这是正确的格式。
  • 感谢正确的 URL 格式 - 我在写这个问题时无法正确查找它;)但这不是问题。它必须以前工作过,并且 sn-p 在“独立上下文”中与同一个库一起工作(iaw 一些带有 main 方法的虚拟类)
  • 我在考虑权限问题。这真是一个奇怪的问题:)
【解决方案3】:

使用 urlConnection.setUseCaches(false),因为它是一个 ant 任务,它很可能不会在单独的进程中被分叉。 URL 缓存文件(或 JarFile 在这种情况下)...如果文件由于构建而发生更改,您会得到非常相似的行为。

你可能想在useCaches(true), JarURLConnection.getJarFile().close()的同时关闭修改后的jar文件

有时我希望 Jar/Zip 的处理能好一点

干杯

【讨论】:

  • 可能是问题 - 一年前我遇到了这个问题,不再维护项目 - 可能是 jar 文件是在同一个构建“会话”期间创建/更改的。不幸的是,我无法测试和验证,但对此答案的强烈+1! (顺便说一句,它会解释为什么它适用于旧的 java 版本吗?)
  • @Andreas_D: >>BTW,能解释一下为什么它适用于旧的java版本吗?
【解决方案4】:

在使用包含空格的文件 URL 时,多个 Java 版本存在错误。 “/path/to/jar”可能不是你的真实路径,所以我至少假设这是你遇到的。你的代码至少在理论上是可以的。

【讨论】:

  • 谢谢,但这不是问题 - 路径不包含空格。
  • 你为什么不发布确切的 URL 和抛出的确切异常(不仅仅是“类似”)。那么,也许有人可以帮助你?
  • 代码已公开,因此我不会将任何内容粘贴到互联网上。虽然这会更容易,因为现在我必须发明例子来解释我的问题。空格是一个猜测,不错的猜测,但请相信我,如果路径有空格,我会在该区域进行调查或在问题中提及该事实。
猜你喜欢
  • 1970-01-01
  • 2011-06-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多