{"id":17981156,"url":"https://github.com/sormuras/jdk-tools","last_synced_at":"2025-08-02T06:04:38.937Z","repository":{"id":85458806,"uuid":"491773912","full_name":"sormuras/jdk-tools","owner":"sormuras","description":"🛠️ JDK Tools and Where to Find Them","archived":false,"fork":false,"pushed_at":"2023-05-30T09:24:06.000Z","size":46,"stargazers_count":5,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-04-06T09:04:37.543Z","etag":null,"topics":["java","jdk","tools"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sormuras.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-05-13T05:53:21.000Z","updated_at":"2023-04-11T14:43:04.000Z","dependencies_parsed_at":"2024-10-29T18:35:16.381Z","dependency_job_id":null,"html_url":"https://github.com/sormuras/jdk-tools","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/sormuras/jdk-tools","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sormuras%2Fjdk-tools","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sormuras%2Fjdk-tools/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sormuras%2Fjdk-tools/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sormuras%2Fjdk-tools/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sormuras","download_url":"https://codeload.github.com/sormuras/jdk-tools/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sormuras%2Fjdk-tools/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268339632,"owners_count":24234551,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-02T02:00:12.353Z","response_time":74,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["java","jdk","tools"],"created_at":"2024-10-29T18:08:15.348Z","updated_at":"2025-08-02T06:04:38.872Z","avatar_url":"https://github.com/sormuras.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# JDK Tools and Where to Find Them\n\nJava projects can be built using tools the Java Development Kit (JDK) provides.\nLet's write a Java Scripting program that uses tools as primitives.\n\nThe JDK does not include a \"build\" tool.\n\nUsers resort to 3rd-party tools in order to transform Java source code into shippable products.\n\nThe JDK does include a set of foundation tools: javac, jar, ..., jlink.\n\nThis session explores ways how to make\nthe implicit connection between JDK tools and Java modules explicit\nso that users are enabled to build Java projects more easily.\n\n## Outline\n\nThis session starts with an overview of 28+ tools shipping with JDK 20.\n\nAfter a short break (reading all linked man pages takes time),\na few tools are executed live on the command-line in order to\ncompile and link an example application.\n\nIn order to execute command-line tools programmatically,\nthe `ToolProvider` interface was introduced in Java 9.\nIt provides a way invoke tools without necessarily starting a new VM.\n\nLeveraging the \"Launch Single-File Source-Code Programs\" feature\nof JDK Enhancement Proposal (JEP) 330 a standalone tool-running\nprogram called `Tool.java` is developed in seven steps.\n\nThree abstractions are introduced along the way:\n\n- `ToolFinder` A finder of tools. Similar to what `ModuleFinder` is to `ModuleReference`.\n- `ToolRunner` A runner of tools. Uses `ToolFinder` and provides run time context.\n- `ToolOperator` An extension of `ToolProvider` to run tools within a tool run.\n\n## Tools, Options, Examples\n\n[JDK 20 Documentation](https://docs.oracle.com/en/java/javase/20/)\n\n[Java® Platform, Standard Edition \u0026 Java Development Kit Specifications Version 20](https://docs.oracle.com/en/java/javase/20/docs/specs)\n\n[Java® Development Kit Version 20 Tool Specifications](https://docs.oracle.com/en/java/javase/20/docs/specs/man)\n\n### Java Development Kit Version 20 Tool Specifications\n\n**All Platforms**\n\n* `jar` - create an archive for classes and resources, and manipulate or restore individual classes or resources from an archive\n* `jarsigner` - sign and verify Java Archive (JAR) files\n* `java` - launch a Java application\n* `javac` - read Java class and interface definitions and compile them into bytecode and class files\n* `javadoc` - generate HTML pages of API documentation from Java source files\n* `javap` - disassemble one or more class files\n* `jcmd` - send diagnostic command requests to a running Java Virtual Machine (JVM)\n* `jconsole` - start a graphical console to monitor and manage Java applications\n* `jdb` - find and fix bugs in Java platform programs\n* `jdeprscan` - static analysis tool that scans a jar file (or some other aggregation of class files) for uses of deprecated API elements\n* `jdeps` - launch the Java class dependency analyzer\n* `jfr` - parse and print Flight Recorder files\n* `jhsdb` - attach to a Java process or launch a postmortem debugger to analyze the content of a core dump from a crashed Java Virtual Machine (JVM)\n* `jinfo` - generate Java configuration information for a specified Java process\n* `jlink` - assemble and optimize a set of modules and their dependencies into a custom runtime image\n* `jmap` - print details of a specified process\n* `jmod` - create JMOD files and list the content of existing JMOD files\n* `jpackage` - package a self-contained Java application\n* `jps` - list the instrumented JVMs on the target system\n* `jrunscript` - run a command-line script shell that supports interactive and batch modes\n* `jshell` - interactively evaluate declarations, statements, and expressions of the Java programming language in a read-eval-print loop (REPL)\n* `jstack` - print Java stack traces of Java threads for a specified Java process\n* `jstat` - monitor JVM statistics\n* `jstatd` - monitor the creation and termination of instrumented Java HotSpot VMs\n* `jwebserver` - launch the Java Simple Web Server\n* `keytool` - manage a keystore (database) of cryptographic keys, X.509 certificate chains, and trusted certificates\n* `rmiregistry` - create and start a remote object registry on the specified port on the current host\n* `serialver` - return the `serialVersionUID` for one or more classes in a form suitable for copying into an evolving class\n\n**Windows Only**\n\n* `jabswitch` - enable or disable Java Access Bridge\n* `jaccessinspector` - examine accessible information about the objects in the Java Virtual Machine using the Java Accessibility Utilities API\n* `jaccesswalker` - navigate through the component trees in a particular Java Virtual Machine and present the hierarchy in a tree view\n* `javaw` - launch a Java application without a console window\n* `kinit` - obtain and cache Kerberos ticket-granting tickets\n* `klist` - display the entries in the local credentials cache and key table\n* `ktab` - manage the principal names and service keys stored in a local key table\n\n## An Example Project\n\n```text\n├───org.example\n│       module-info.java\n│\n├───org.example.app\n│   │   module-info.java\n│   │\n│   └───org\n│       └───example\n│           └───app\n│                   Main.java\n│\n└───org.example.lib\n    │   module-info.java\n    │\n    └───org\n        └───example\n            └───lib\n                │   ExampleStringSupport.java\n                │\n                └───internal\n                        EchoToolProvider.java\n```\n\n### javac\n\n\u003e Read Java class and interface definitions and compile them into bytecode and class files.\n\n```shell\njavac\n  --module org.example,org.example.app,org.example.lib\n  --module-source-path .\n  -d out/classes\n```\n\nHere, compile 3 modules, namely...\n\n- `org.example`,\n- `org.example.app`, and\n- `org.example.lib`.\n\nSearch source files in subdirectories of the current working directory `.`\nnamed like the modules, and store class files in `out/classes`,\ncreating a subdirectory for each module\n\n```text\n├───org.example\n│       module-info.class\n│       \n├───org.example.app\n│   │   module-info.class\n│   │   \n│   └───org\n│       └───example\n│           └───app\n│                   Main.class\n│\n└───org.example.lib\n    │   module-info.class\n    │   \n    └───org\n        └───example\n            └───lib\n                │   ExampleStringSupport.class\n                │\n                └───internal\n                        EchoToolProvider.class\n```\n\n### java (exploded modules)\n\n\u003e Launch Java application\n\n```shell\njava\n  --module-path out/classes\n  --module org.example.app/org.example.app.Main\n```\n\n### jar\n\n\u003e Create an archive for classes and resources.\n\nThree time's a charm, one call per module.\n\n```shell\njar\n  --create\n  --file out/modules/org.example.jar\n  -C out/classes/org.example .\n```\n\n```shell\njar\n  --create\n  --file out/modules/org.example.app.jar\n  -C out/classes/org.example.app .\n```\n\n```shell\njar\n  --create\n  --file out/modules/org.example.lib.jar\n  -C out/classes/org.example.lib .\n```\n\nHere, create a modular JAR file named `org.example[.[app|lib]].jar`.\n\n### java (archived modules)\n\n\u003e Launch Java application\n\n```shell\njava\n  --module-path out/modules\n  --module org.example.app/org.example.app.Main\n```\n\n### jlink\n\n\u003e Create custom runtime image\n\n```shell\njlink\n  --verbose\n  --output out/image\n  --module-path out/modules\n  --add-modules org.example\n  --launcher example=org.example.app/org.example.app.Main\n```\n\n### java (custom launcher)\n\n\u003e Launch Java application in a custom runtime image\n\n* Linux/Mac\n  ```shell\n  out/image/bin/example\n  ```\n\n* Windows\n  ```shell\n  out\\image\\bin\\example\n  ```\n\n## Seven Steps to Find, Load, and Run Tools\n\n### Step 0\n\nUse `ToolProvider` (from `java.base/java.util.spi`) to find, load, and run `javac` tool.\n\n```shell\njava src/Tool0.java\n```\n\n* Launch single-file source-code Java program (JEP 330)\n* Run: `java src/Tool0.java`\n* TODO Pass non-empty main args arrays as tool's arguments\n* Run: `java src/Tool0.java --version`\n\n```text\n// === DONE ===\n// [x] Used ToolProvider SPI\n// [x] Ignored result of the tool execution\n\n// === HINT ===\n// [ ] args.length != 0 ? args : new String[] {\"--version\"}\n// [ ] Run: java src/Tool0.java --help-extra\n// [ ] Run: java src/Tool0.java --help-lint\n\n// === NEXT ===\n//  ?  Run: java src/Tool0.java jar --version\n// --\u003e Transform into an application running an arbitrary tool\n```\n\n### Step 1\n\nAn application running an arbitrary tool.\n\n```shell\njava src/Tool1.java jar --version\n```\n\n* Show usage message on empty args array\n* Create `ToolRunner` interface with run method\n* Move find and run code into default implementation\n* TODO Print tool name and its args on run\n\n```text\n// DONE\n// [x] Let args[0] be the name of the tool to run and args[1..n] its arguments\n// [x] Added an abstraction for running a tool, throwing on non-zero exit code\n\n// HINT\n// [ ] System.out.println(\"// name = \" + name + \", args = \" + Arrays.deepToString(args));\n// [ ] Run with well-known system tools: javac, jar, jlink\n\n// NEXT\n//  ?  Run with: jfr\n// --\u003e Implement a `--list-tools` option showing all observable tools and exit\n// --\u003e By introducing a configurable `ToolFinder` abstraction\n```\n\n### Step 2\n\nIntroduce ToolFinder to list observable tools.\n\n* Create ToolFinder interface with abstract `List\u003cToolProvider\u003e findAll()` method\n* Add default `Optional\u003cToolProvider\u003e find(NAME)` method to ToolFinder\n* Add `ToolFinder.ofEmpty()` factory\n* In `ToolRunner`, replace `ToolProvider.findFirst(NAME)` usage with `ToolFinder.find(NAME)`\n* TODO Implement `ToolFinder.ofSystem()` by looking into `ToolProvider.findFirst(NAME)`\n\n```shell\njava src/Tool2.java --list-tools\n```\n\n```text\n// HINT:\n// [x] Run: java --limit-modules java.base src/Tool2.java\n\n// NEXT:\n//  ?  Run: java src/Tool2.java banner hello world\n// [ ] Implement a custom tool: `record Banner(String name) implements ToolProvider {...}`\n// [ ] Implement a tool finder that accepts instances of `ToolProvider`\n```\n\n### Step 3\n\nLocal tool Banner and finder of tool instances.\n\n```shell\njava src/Tool3.java banner hello world\n```\n\n```text\n// Next step:\n// [ ] Implement a tool finder that is composed of other finders\n// [ ] Compose application's tool finder\n```\n\n### Step 4\n\nComposing tool finders.\n\n```shell\njava src/Tool4.java --list-tools\n```\n\n```text\n// Next step:\n// [ ] How to implement a tool that runs other tools?\n// [ ] Add an abstraction for tool running tool: an operator\n```\n\n### Step 5\n\nA tool operator runs other tools.\n\n```shell\njava src/Tool5.java chain banner banner\n```\n\n```text\n// Next step:\n// [ ] Implement tool operators: Compile and Link\n```\n\n### Step 6\n\n```shell\njava src/Tool6.java chain compile link\n```\n\n```text\n// Next step:\n// [ ] GOTO Tool.java\n//     More ToolFinder...\n```\n\n## `Tool.java`\n\nPutting it all together to access all tools the JDK provides.\n\n```shell\njava src/Tool.java chain compile link run\n```\n\n* `ToolFinder.ofNativeTools(Path directory)`\n    * Leveraging `ProcessBuilder` and `Process` API.\n    * Example: `ofNativeTools(Path.of(System.getProperty(\"java.home\"), \"bin\"))`\n\nExplore more tool finders:\n\n* `ToolFinder.ofJavaPrograms(Path directory)`\n    * Single-File Source-Code Program `java Program.java ARGS...`\n    * Executable JAR file `java -jar program.jar ARGS...`\n\n* `ToolFinder.of(ModuleFinder)` and `ToolFinder.of(ModuleLayer)`\n    * Example: `of(ModuleFinder.of(Path.of(\"out\", \"modules\")))`\n\n## Talk-Related Links\n\n* JDK Tool Specifications\n  \u003chttps://docs.oracle.com/en/java/javase/20/docs/specs/man\u003e\n* Project Jigsaw: Module System Quick-Start Guide\n  \u003chttps://openjdk.java.net/projects/jigsaw/quick-start\u003e\n\n## More Tool-Related Links\n\n* List of Unix commands\n  \u003chttps://en.wikipedia.org/wiki/List_of_Unix_commands\u003e\n* Unix philosophy\n  \u003chttps://en.wikipedia.org/wiki/Unix_philosophy\u003e\n* JEP 293: Guidelines for JDK Command-Line Tool Options\n  \u003chttps://openjdk.java.net/jeps/293\u003e\n* JDK-8275072: Enhance java.util.spi.ToolProvider\n  \u003chttps://bugs.openjdk.java.net/browse/JDK-8275072\u003e\n* ARGument harVESTER - a simple command line parser written with Love and Java 15\n  \u003chttps://github.com/forax/argvester\u003e\n\n## More Tools, More Options, More Examples\n\n### jpackage\n\n### jtreg (7+)\n\n### jextract (?)\n\n### junit (external)\n\n### jreleaser (external)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsormuras%2Fjdk-tools","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsormuras%2Fjdk-tools","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsormuras%2Fjdk-tools/lists"}