从命令行创建Java项目的可视化调用图

26

我想要在命令行中创建Java项目的调用图。我探索了几个项目,每次都没有达到我的目标(无论是我的理解还是功能上)。能够提供一些简单的指导将会很棒,我的额外目标是获得这个图的文本表示。

以下是我尝试过的内容:

调用图:https://github.com/gousiosg/java-callgraph

这给了我想要的文本输出,但我找不到一种方法(在查看了文档一段时间后),将其转换为可视化(图像文件)输出。

Soot: http://sable.github.io/soot/

在花费大量时间浏览 SOOT 文档之后(似乎很难跟随),我设法让 SOOT 创建字节码。然而,我找不到任何关于如何从中创建调用图的指南。我只在主页上看到它可以做到这一点,并且通过我的谷歌搜索获得了几封电子邮件交流,其中所有问题都没有答案。我正在使用以下命令进行夜间构建:

java -cp soot-trunk.jar soot.Main -cp . -pp HelloWorld

在这里,HelloWorld是我的java文件的名称,我得到了一个输出,它是一个.class文件,但我不知道如何获取实际的调用图。这是在按照此处的指南后:https://github.com/Sable/soot/wiki/Running-Soot。当我查看有关可视化的链接时,它们似乎都是损坏的链接,然后将重定向回主页。我可以看到关于在命令行页面上使用-cg标志的一些信息,但无法使其工作 - 我只会得到选项解析错误,建议使用无效参数:https://ssebuild.cased.de/nightly/soot/doc/soot_options.htm#phase_5

搜索stackoverflow-现有答案 我已经查看了几个类似的问题,例如:Static analysis of Java call graph。然而,答案只是说“使用soot”或“使用调用图”,我已经尝试过这些方法,但没有任何运气 - 尽管我最接近文本输出的调用图。

我看到一些基于GUI的软件和eclipse插件声称可以创建调用图,但我正在尝试从命令行中使其工作。

非常感谢任何帮助,一个指南或一组使用调用图、Soot或另一个程序的命令将非常有帮助。也许值得将任何短教程提交回给他们以供文档使用,因为在搜索时似乎有更多的问题而不是答案。

供参考,我当前正在尝试使用下面的非常简单的类:

public class HelloWorld {

    public static void main(String[] args) {
        foo();
    }
    public static void foo(){
        System.out.println("Hello World");
    }
}
3个回答

14
看起来 Call Graph 生成了相当不错的输出。让我们快速进行一次 PoC。
我将使用 Call Graph 开发人员提供的样本输出。
org.apache.batik.dom.AbstractParentNode:appendChild org.apache.batik.dom.AbstractParentNode:fireDOMNodeInsertedEvent 6270
org.apache.batik.dom.AbstractParentNode:fireDOMNodeInsertedEvent org.apache.batik.dom.AbstractDocument:getEventsEnabled 6280
org.apache.batik.dom.AbstractParentNode:checkAndRemove org.apache.batik.dom.AbstractNode:getOwnerDocument 6280
org.apache.batik.dom.util.DoublyIndexedTable:put org.apache.batik.dom.util.DoublyIndexedTable$Entry:DoublyIndexedTable$Entry 6682
org.apache.batik.dom.util.DoublyIndexedTable:put org.apache.batik.dom.util.DoublyIndexedTable:hashCode 6693
org.apache.batik.dom.AbstractElement:invalidateElementsByTagName org.apache.batik.dom.AbstractElement:getNodeType 7198
org.apache.batik.dom.AbstractElement:invalidateElementsByTagName org.apache.batik.dom.AbstractDocument:getElementsByTagName 14396
org.apache.batik.dom.AbstractElement:invalidateElementsByTagName org.apache.batik.dom.AbstractDocument:getElementsByTagNameNS 28792
有几个图形渲染引擎可用。最简单的是 DOT(请查看链接,列出了几个其他好的工具)。
为了使用 DOT,我需要稍微转换一下数据。假设我想保留 ClassName:methodName 并跳过 package。
这很容易,你可以使用任何工具来完成,但我会使用 sed
OUT=callgraph.dot
echo "graph test {" > $OUT
sed -E 's/[a-z]+\.//g; s/[0-9]+\/;/; s/ / -- /; s/[\$|\:]/_/g'  callgraph.txt >> $OUT
echo "}" >> $OUT
dot -Tpng callgraph.dot -o callgraph.png
这里是生成的结果:
这是一个名为“graph test”的图形,其中包含了多个节点和它们之间的关系。以下是节点及其关系的描述:
- AbstractParentNode_appendChild 和 AbstractParentNode_fireDOMNodeInsertedEvent 之间有一条边; - AbstractParentNode_fireDOMNodeInsertedEvent 和 AbstractDocument_getEventsEnabled 之间有一条边; - AbstractParentNode_checkAndRemove 和 AbstractNode_getOwnerDocument 之间有一条边; - DoublyIndexedTable_put 和 DoublyIndexedTable_Entry_DoublyIndexedTable_Entry 之间有一条边; - DoublyIndexedTable_put 和 DoublyIndexedTable_hashCode 之间有一条边; - AbstractElement_invalidateElementsByTagName 和 AbstractElement_getNodeType 之间有一条边; - AbstractElement_invalidateElementsByTagName 和 AbstractDocument_getElementsByTagName 之间有一条边; - AbstractElement_invalidateElementsByTagName 和 AbstractDocument_getElementsByTagNameNS 之间有一条边。
以上节点和边的描述并不完整,只是对它们的简要概括。

enter image description here

所有图表均从初始数据中提取:

enter image description here

请注意,您可以按照自己的需求调整渲染。 DOTgraphviz 的一部分,这是一个非常灵活的工具集。

我的回答背后有一个通用的想法:

  • 使用任何适合的工具生成跟踪
  • 找到一个好的渲染解决方案
  • 花些时间以便获得简单的自动转换

顺便说一下,看看 canviz

Canviz 是一个 JavaScript 库,用于将 Graphviz 图形绘制到 Web 浏览器画布中。更确切地说,Canviz 是一个 JavaScript xdot 渲染器。它在大多数现代浏览器中都可以使用。

祝编码愉快 :)


谢谢!虽然我还没有时间尝试这个,但它看起来正是我想要的。毫无疑问,这个答案也会帮助未来查看这个问题的人,因为解释得很清楚。非常感谢。 - ThePerson

2
这是一个老问题,但我仍然没有找到一个好的工具。所以,按照这个线程上的建议,我创建了java-call-graph-plotter。它使用java-call-graph和VisJs来实现这一点。 您可以按照以下步骤进行操作:
克隆repo并进入项目文件夹:
git clone https://github.com/marcello-dev/java-call-graph-plotter.git
cd java-call-graph-plotter 创建调用图:
java -jar javacg/javacg-0.1-SNAPSHOT-static.jar target-jar/demo-customer-0.0.1-SNAPSHOT.jar > call-graph.txt
为Python 3创建虚拟环境: python3 -m venv venv
激活它:
source venv/bin/activate 安装依赖项: pip install -r requirements.txt
绘制图表: python callgraphplotter.py call-graph.txt ApiDBSelector 将生成一个名为call-graph.html的文件在输出文件夹中。您可以在浏览器中打开它。希望您会发现它有用!更多信息在这里

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接