How to run javap programmatically
In this article, we are goring to learn how to run javap
programmatically.
javap
‘s main class is com.sun.tools.javap.Main
and its main feature is offered by com.sun.tools.javap.JavapTask.
These classes are located in jdk.jdeps
module. This module is not exported to java.se
module so that we cannot create its instance by new
operator.
How can we call javap
from java.se
module? By java.util.spi.ToolProvider
is the only way. com.sun.tools.javap.Main$JavapToolProvider
, which is javap
‘s implementation of ToolProvider
, can be obtained by passing "javap"
to static method ToolProvider#findFirst(String)
.
ToolProvider javap = ToolProvider.findFirst("javap").orElseThrow()
ToolProvider
has only one method(except for default method) run(PrintWriter, PrintWriter, String...)
. As you know javac
is flexible, we can customize JavaFileObject
and JavaFileManager
to return byte[]
from memory instead of files. But as you can guess from the interface of ToolProvider
, there is no room for us to customize javap
feature. We can only pass arguments as we always pass to javap
command in terminal. For example calling run
method with -v
(verbose), -p
(all classes and members) of Foo.class
…
StringWriter out = new StringWriter();
PrintWriter stdout = new PrintWriter(out);StringWriter err = new StringWriter();
PrintWriter stderr = new PrintWriter(err);int exitCode = javap.run(
stdout,
stderr,
"-v", "-p", "/path/to/Foo.class");
An outputs of javap
is written to the first PrintWriter
, and error messages are written to the first PrintWriter
(I don’t know why they are not written to stderr…)
—
BTW I wrote an application while investigating programmatical javap
calling. Here is the URL of the repository. If you are interested in the repository, please visit it.