【问题标题】:Getting all imported classes for a jar获取 jar 的所有导入类
【发布时间】:2016-03-09 22:17:47
【问题描述】:

对于给定的 jar,我想找出这个 jar 使用的所有类(尽可能)。由于我有很多罐子,我想自动化这个过程。到目前为止,我最好的想法是

  1. 反编译jar(我没有这方面的经验,但应该有命令行工具)。
  2. 查找导入并解析它们。

但我希望其他人以前做过类似的事情并就此给我建议。

【问题讨论】:

  • 对于这个罐子的“使用”,你的意思是这个罐子“包含”?
  • 我认为他只是在源代码的某个地方实际使用的那些(因此他解析导入的想法)
  • @DavideLorenzoMARINO 不。我知道很容易找出 jar 中包含哪些类。我想知道使用了哪些类,即通过限定名称导入或调用。

标签: java jar decompiling


【解决方案1】:

使用专门的工具可能是可靠地做到这一点的方法。

但是,一种非常笨拙的方法是获取 JAR 中所有 .class 文件的列表,将 JAR 放在类路径中并使用 javap 获取对其他类的引用:

#!/usr/bin/env bash
javap -cp $1 -v \
   `zipinfo -1 $1 '*.class' | sed 's:/:.:g' | sed 's:\.class$::'` | \
   grep ' = Class' | sed 's:.*// ::' | sort | uniq

guava-19.0.jar 上运行此程序会得到this

"[[B"
"[B"
"[[C"
"[C"
com/google/common/annotations/Beta
com/google/common/annotations/GwtCompatible
com/google/common/annotations/GwtIncompatible
com/google/common/annotations/VisibleForTesting
com/google/common/base/Absent
com/google/common/base/AbstractIterator
...............................................................
"[Lcom/google/common/util/concurrent/MoreExecutors$DirectExecutor;"
"[Lcom/google/common/util/concurrent/Service$State;"
"[Lcom/google/thirdparty/publicsuffix/PublicSuffixType;"
"[Ljava/io/File;"
"[[Ljava/lang/annotation/Annotation;"
"[Ljava/lang/annotation/Annotation;"
"[Ljava/lang/Class;"
"[Ljava/lang/Comparable;"
"[Ljava/lang/Enum;"
"[[Ljava/lang/Object;"
"[Ljava/lang/Object;"
"[Ljava/lang/reflect/Field;"
"[Ljava/lang/reflect/Method;"
"[Ljava/lang/reflect/Type;"
"[Ljava/lang/reflect/TypeVariable;"
"[Ljava/lang/StackTraceElement;"
"[Ljava/lang/String;"
"[Ljava/net/URL;"
"[Ljava/util/Iterator;"
"[Ljava/util/Map$Entry;"
"[[S"
"[S"
sun/misc/Unsafe
"[[Z"
"[Z"

您需要更多的输出格式,并且正如其他人指出的那样,它不会使用反射。

这是如何工作的:

zipinfo -1 $1 '*.class' 将打印出$1 中所有.class 文件的名称,这是所显示脚本的参数。 seds 将 /s 更改为 .s 并删除 .class 扩展名,这样您就可以得到一个 Java 样式的类名列表。您可以更优雅地执行此操作,但它应该可以工作。

javap 调用将 jar 放在带有-cp 的类路径中,并传递所有类。 -v 使其输出大量信息,包括一些表示对类名称的引用的条目。 grep 确保我们只查看那些,sed 删除一些我们不感兴趣的额外信息。sort | uniq 确保我们不会多次打印任何类的名称。它确实需要更多sedding 来标准化输出格式。

【讨论】:

  • 你能简单解释一下你的“命令行魔法”是做什么的吗?
【解决方案2】:

一种简单的方法是尝试在不添加该 jar 的情况下编译您的代码。

尝试编译并查看编译器错误是最快的方法。

但请记住,也可以使用反射(例如通过 spring 配置文件)在运行时加载一个类,并且在没有 jar 的情况下编译代码不会在运行时通知您潜在的错误。

【讨论】:

  • 这不是我想要的。我想编写一个程序,给出一长串 jars(比如 100 个),并为每个 jars 返回“使用”的 jars 列表(导入等,反射可能会被忽略)。
  • 一个jar使用另一个jar的信息并没有在jar本身中列出。如果您使用像 maven 这样的跟踪依赖项的系统,您可以这样做。否则不行。
  • 不是罐子,而是类。如果我例如在 jd-gui(反编译器)中打开一个 jar,我看到了不同源文件的反编译导入。
  • 是的,但是一个类只使用另一个类....不是罐子。该类可能存在于许多罐子中。因为在 jar 中没有对构建所需的 jar 的引用,所以不可能有任何确定的信息。
  • 为了明确这一点。我想找出 JAR 中引用了哪些类。我对这些课程的来源不感兴趣。我想要一些我输入“foo.jar”的东西,它会输出一个像 org.apache.SomeClass、org.apache.AnotherClass、这样的列表......这个信息必须在 jar 中的某个地方(分别是包含的类文件),因为它由类加载器使用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-07-06
  • 1970-01-01
  • 1970-01-01
  • 2023-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多