【问题标题】:Why is my javap output different than yours for the same jar file?为什么对于同一个 jar 文件,我的 javap 输出与您的不同?
【发布时间】:2011-01-11 09:03:54
【问题描述】:

我在编译依赖于 jline-0.9.94 的 maven 代码时遇到问题。具体来说,我正在使用其默认 Ant 目标编译 Groovy 1.7.6 并收到以下错误:

[...]
-banner:
     [echo] Java Runtime Environment version: 1.6.0_22
     [echo] Java Runtime Environment vendor: Apple Inc.
     [echo] Ant version: Apache Ant version 1.7.1 compiled on June 27 2008
     [echo] Operating system name: Mac OS X
     [echo] Operating system architecture: x86_64
     [echo] Operating system version: 10.6.6
     [echo] Base directory: /Users/ldhanson2/tmp/groovy-1.7.6
     [echo] Java Home: /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home
[...]
-stagedcompile-groovy:
  [groovyc] Compiling 166 source files to /Users/ldhanson2/tmp/groovy-1.7.6/target/classes
  [groovyc] org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
  [groovyc] Compile error during compilation with javac.
  [groovyc] /Users/ldhanson2/tmp/groovy-1.7.6/src/main/groovy/ui/InteractiveShell.java:222: cannot find symbol
  [groovyc] symbol  : method setDefaultPrompt(java.lang.String)
  [groovyc] location: class jline.ConsoleReader
  [groovyc]         reader.setDefaultPrompt("groovy> ");
  [groovyc]               ^

jline 依赖已正确解析,但奇怪的是 jar 中似乎没有 setDefaultPrompt 方法:

$ javap -classpath target/lib/compile/jline-0.9.94.jar jline.ConsoleReader | grep setDefaultPrompt
$ 

(javap 输出中似乎也缺少其他方法,但 setDefaultPrompt 是破坏我构建的方法。)

我尝试从本地 maven 存储库中清除 jline 并再次尝试,但无济于事。我还检查了来自Maven Central 的 jline jarfile 以及具有相同结果的镜像。

奇怪的是,我可以将 jar 文件复制到另一台机器(Sun)并执行完全相同的步骤,并且我在 jar 文件中看到了预期的 setDefaultPrompt 方法。其他人也在 Mac 上成功执行了相同的步骤。

我的机器上可能发生什么会阻止 Java 工具链查看 jar 文件中包含的方法?

【问题讨论】:

  • 雪豹下的 jline jar 也有同样的问题。你找到答案了吗?

标签: java macos groovy javap jline


【解决方案1】:

我在我的机器上遇到了同样的问题(编译 JRuby,而不是 Groovy)。

我的问题的解决方案是我在 /Library/Java/Extensions/jline-0_9_5.jar 中发现了一个古老的 jline jar,因此我对其进行了核对并用更现代的版本替换了它。

【讨论】:

  • 啊哈!显然,该目录总是添加到类路径中,甚至在您为 javap 指定的目录之前。所以我实际上并没有看到我认为我正在检查的 jar 文件的 javap 输出。偷偷摸摸。我通过添加 /dev/null 的 -extdirs 选项来阻止 javap 添加 /Library/Jar/Extensions 来验证这一点,此时我可以看到我正在查看的 jline 版本的实际内容。
  • 是的,这是有道理的;我也在使用javap进行验证。我同意这完全是偷偷摸摸的。如果没有覆盖 shell 并给出误导性的结果,那么拥有 classpath 选项似乎有点毫无意义。这个问题把我逼疯了!我通过运行 2 行程序输出类位置来诊断它: URL location = ConsoleReader.class.getProtectionDomain().getCodeSource().getLocation();
【解决方案2】:

您必须拥有不同版本的 JAR 文件。

【讨论】:

  • 我可以将确切的文件复制到另一台机器上,然后就可以看到缺少的方法。我已经编辑了我的问题以说明这一点。
【解决方案3】:

在我的带有 java 1.5.0_13 的 Mac 10.5.8 上无法重现

如果你提取jline-0.9.94.jar并阅读它的META-INF/MANIFEST.MF那么你可能会发现这个jar是由java 1.4.2_16编译的:

 清单版本:1.0
 存档器版本:Plexus 存档器
 创建者:Apache Maven
 建造者:杰森
 构建-Jdk:1.4.2_16

JRE 向后兼容很好,但是你的 1.6.0_22 和 1.4.2_16 之间的距离很大。

所以,我假设你从 source code 重新编译 jline。

【讨论】:

  • 我从源代码(使用 JDK 1.6.0_22)重新编译了 jline,结果相同 - javap 没有看到 JAR 中存在的所有方法。
猜你喜欢
  • 2020-10-01
  • 2016-10-10
  • 1970-01-01
  • 1970-01-01
  • 2019-10-01
  • 2021-06-14
  • 2017-01-03
  • 1970-01-01
相关资源
最近更新 更多