{"id":20183661,"url":"https://github.com/glavo/japp","last_synced_at":"2026-01-22T11:04:02.686Z","repository":{"id":195417072,"uuid":"689245140","full_name":"Glavo/japp","owner":"Glavo","description":"A new packaging format for Java programs.","archived":false,"fork":false,"pushed_at":"2025-10-30T17:08:55.000Z","size":1057,"stargazers_count":92,"open_issues_count":0,"forks_count":2,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-10-30T19:11:20.700Z","etag":null,"topics":["java","jdk"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Glavo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"custom":["https://donate.glavo.site/"]}},"created_at":"2023-09-09T07:51:40.000Z","updated_at":"2025-10-30T17:08:58.000Z","dependencies_parsed_at":"2024-12-25T06:10:18.545Z","dependency_job_id":"25a96b80-cac7-4eaf-8a48-8e76e3562e29","html_url":"https://github.com/Glavo/japp","commit_stats":null,"previous_names":["glavo/japp"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Glavo/japp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Glavo%2Fjapp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Glavo%2Fjapp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Glavo%2Fjapp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Glavo%2Fjapp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Glavo","download_url":"https://codeload.github.com/Glavo/japp/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Glavo%2Fjapp/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28661882,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-22T01:17:37.254Z","status":"online","status_checked_at":"2026-01-22T02:00:07.137Z","response_time":144,"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"],"created_at":"2024-11-14T02:46:50.581Z","updated_at":"2026-01-22T11:04:02.669Z","avatar_url":"https://github.com/Glavo.png","language":"Java","readme":"# JApp\n\n[![Gradle Check](https://github.com/Glavo/japp/actions/workflows/check.yml/badge.svg)](https://github.com/Glavo/japp/actions/workflows/check.yml)\n\nJApp is a modern Java program packaging format.\n\nIts design goal is to be a better alternative to shadow jar (fat jar) and launch4j,\nand to be the optimal solution for single-file packaging and distribution of Java programs.\n\nThe project is under development. We have implemented a prototype, but it still needs to be refined.\n\nEveryone is welcome to report bugs, make feature requests, or discuss designs through [issues](https://github.com/Glavo/japp/issues/new/choose).\n\n## Features and Progress\n\n* Pack multiple modular or non-modular JARs into one file;\n  * Unlike Shadow JAR (Fat JAR), JApp has good support for the Java module system;\n    Resources from different JARs will be isolated under different prefixes instead of being mixed.\n\n    For example, if we put Gson and Apache Commons Lang 3 as modules into a JApp file,\n    their `module-info.class` URIs are as follows:\n    \n    ```\n    japp:/modules/com.google.gson/module-info.class\n    japp:/modules/org.apache.commons.lang3/module-info.class\n    ```\n\n    JApp also supports using the class path and module path at the same time.\n    After adding the above two modules, you can also put Guava into the class path,\n    the URI of class `com.google.common.collect.Multimap` is as follows:\n    \n    ```\n    japp:/classpath/guava-32.1.3-jre.jar/com/google/common/collect/Multimap.class\n    ```\n* JApp files can declare dependencies on JARs from other sources (such as maven repositories).\n  The contents of these JARs are not included in the JApp file, but are resolved on demand before running, \n  and then added to the module path or classpath like the JARs within the JApp file.\n* Using the [Zstandard](https://github.com/facebook/zstd) compression method, the file size is smaller than JAR;\n  * JApp compresses files using the zstd, which decompresses faster and has smaller file sizes than the deflate compression method used by JAR.\n    In addition, JApp also compresses file metadata and shares strings in the constant pool of Java Class files,\n    so JApp files are usually smaller than JAR files.\n\n    As a test case, I packed the [aya language](https://github.com/aya-prover/aya-dev) as a japp file,\n    the original fat jar is 6.81MiB, while the resulting JApp file is only 5.08MiB (-25.40%).\n* Automatically select a suitable Java Runtime to start the program based on user-specified conditions;\n  * Users can specify some conditions (such as Java version \u003e= 17),\n    and then the JApp launcher will find a suitable Java Runtime installed by the user to start the program based on these conditions.\n* JApp files can contain JVM options (such as `--add-exports`, `--enable-native-access`, `-D`, etc.), which are passed to the JVM at runtime;\n* It supports shebang, so you can run it with just `./myapp.japp \u003cargs\u003e`;\n* Supports conditional addition of JVM options, classpath, and module paths.\n\nWork in progress:\n\n* More tests;\n* Reimplement launcher in native language;\n  * The japp launcher's job is to find suitable Java, synthesize JVM options, and class/module paths based on conditions.\n    In the current prototype it is implemented in Java, which brings some limitations, I will rewrite it in native language in the future.\n* Implement a manager that manages a set of Java;\n  * Now that the japp launcher will only scan Java from a fixed list of paths, \n    we need a way to manage the list of available Java runtimes instead.\n* Support for filtering unused classes;\n* Support for embedding configuration files in JAR;\n* Support for Java 8.\n\nTo be investigated:\n\n* Support bundling and loading native libraries;\n* Supports reading JMod files when creating;\n* Proguard support;\n* Build time optimization;\n* Embed japp file data in the launcher instead of appending it at the end.\n\n## Vision for the future\n\nMy vision for this project is to provide two distribution options for all Java projects.\n\n### Distribute JApp files only\n\nIn the preferred solution, developers simply package the program into a japp file and distribute it.\nThis will keep the japp file minimal and easily cross-platform.\n\nUsers are expected to install the japp launcher themselves, ideally this should be done via winget/apt/Homebrew etc.\nThe japp launcher will register as the default program for opening japp files, \nand users should be able to easily launch japp applications from within a file manager or terminal.\n\nIn addition, japp launcher can do many other things.\nUsers can use it to manage Java (similar to sdkman/jenv) and download Java applications (similar to cargo/pip).\n\n### Distributing JApp files with the launcher embedded\n\nThis is the second-best option developers can embed the JApp Launcher in a japp file and distribute it.\nThe final product can have a file extension such as exe/sh.\n\nThis will sacrifice the cross-platform capabilities of the program files, but is the most user-friendly, \nas users can launch japp applications without installing Java and the japp launcher themselves.\nThe embedded japp launcher helps users download Java and prepare the runtime environment.\n\nFor cross-platform, we should also try our best to make it not so bad.\n\nFor the embedded launcher on Windows platform, we can consider building it for x86 32-bit first, \nmaking it compatible with Windows x86/x86-64/ARM64 at the same time.\n\nFor other platforms, we might be able to develop an embedded launcher in bash that is compatible with macOS,\nLinux, BSD, AIX, and even Windows (wsl/msys2/cygwin required).\n\nFurthermore, even if a japp file has an embedded launcher, it should be able to be launched using other launchers.\nDevelopers may consider distributing only a japp file with a launcher embedded for Windows,\nand let users of other platforms launch it using a self-installed japp launcher.\n\n## Try it\n\nNOTE: This project is in its early stages.\nSome designs have been simplified for convenience, and they will be improved in the future.\nThe japp file created so far should be used for testing only;\nThe format of japp files is not yet stable and is subject to change.\n\nTo try this project, you first need to build it:\n\n```shell\n./gradlew\n```\n\nThen, package your program as a japp file:\n\n(For Linux/macOS)\n```shell\n./bin/japp.sh create -o myapp.japp --module-path \u003cyour-app-module-path\u003e --class-path \u003cyour-app-class-path\u003e \u003cmain-class\u003e\n```\n\n(For Windows)\n```powershell\n.\\bin\\japp.ps1 create -o myapp.japp --module-path \u003cyour-app-module-path\u003e --class-path \u003cyour-app-class-path\u003e \u003cmain-class\u003e\n```\n\nNow you can run it:\n\n(For Linux/macOS)\n```shell\n./myapp.japp \u003cargs\u003e\n```\n\n(For Windows)\n```powershell\n.\\bin\\japp.ps1 run myapp.japp \u003cargs\u003e\n```\n\n## Options\n\nThe `japp create` command accepts the following basic options:\n\n* `-o \u003coutput file\u003e`\n\n### Config Group and Conditions\n\nJApp packages class paths, module paths, JVM options, etc. into **config group**s.\nYou can add these things to the config group using the following command line options:\n\n* `--module-path \u003cmodule path\u003e`\n* `--class-path \u003cclass path\u003e`\n* `--add-opens \u003cmodule\u003e/\u003cpackage\u003e=\u003ctarget-module\u003e(,\u003ctarget-module\u003e)*`\n* `--add-exports \u003cmodule\u003e/\u003cpackage\u003e=\u003ctarget-module\u003e(,\u003ctarget-module\u003e)*`\n* `--enable-native-access \u003cmodule name\u003e[,\u003cmodule name\u003e...]`\n* `-D\u003cname\u003e=\u003cvalue\u003e`\n* `-m \u003cmain module\u003e`\n* `\u003cmain class\u003e`\n\nA config group can have a set of sub-config groups.\nBy default, these options are added to the root config group.\nUse the `--group` command line option to start a new sub-config group, and use the `--end-group` option to end it.\n\nEach config group can specify a **condition** using the `--condition \u003ccondition\u003e` option.\n\nConditions represent requirements for the Java runtime and environment.\nFor example, condition `java(version: 11, arch: x86-64|aarch64)` indicates \nthat the Java runtime version must be at least 11 and the architecture must be x86-64 or AArch64.\nYou can also combine multiple conditions using `\u0026\u0026` or `||`, such as `java(version: 11) || java(arch: x86-64)`.\n\nThe japp launcher will search for a suitable Java runtime based on the condition of the root config group;\nIf there is no Java runtime that meets the condition, an error will be reported.\n\nThe conditions of sub-config groups are used to determine whether the group should be applied.\n\nExample:\n\n```bash\n./bin/japp.sh create -o myapp.japp \\\n  --condition java(version: 11) --module-path ./myapp.jar \\\n  --group --condition java(version: 22) --enable-native-access=org.glavo.myapp --end-group \\\n  -m org.glavo.myapp\n```\n\nIn the above example, assuming that `myapp.jar` exists in the current directory (the java module name is `org.glavo.myapp`),\nthis command will generate a japp file named `myapp.japp`.\nThe main module (also the only module in the `myapp.japp`) is `org.glavo.myapp`.\n\nAll you need to run it is this:\n\n```bash\n./myapp.japp\n```\n\nThe japp launcher looks for a Java runtime version 11 or higher to run the program.\nIf the Java runtime found is of version 22 or higher, the JVM option `--enable-native-access=org.glavo.myapp` is added.\n\n### Classpath and Module Path\n\nThe `--module-path` and `--classpath` options above accept arguments similar to the `java`/`javac` command:\n\n(For Windows, please replace the path separator with `;`)\n```\n--module-path \u003cpath 1\u003e:...:\u003cpath n\u003e\n```\n\nFor the `java`/`javac` command, each path must be a file.\nBut for japp, each path can contain an optional prefix `[\u003ckey1\u003e=\u003cvalue1\u003e,...,\u003ckey n\u003e=\u003cvalue n\u003e]` to specify options.\nWe can use this syntax to specify to look for jars from the maven repository instead of locally:\n\n```\n[type=maven]\u003cgroup\u003e/\u003cartifact\u003e/\u003cversion\u003e\n```\n\nFor example, the following option will add gson to the module path:\n\n```\n--module-path [type=maven]com.google.code.gson/gson/2.10\n```\n\nBy default, this dependency is bundled into the japp file just like a normal module path item.\nHowever, you can use the `bundle=false` option to tell japp to only declare a dependency on it and not bundle its contents into the japp file:\n\n```\n--module-path [type=maven,bundle=false]com.google.code.gson/gson/2.10\n```\n\nWhen running this japp file, the japp launcher will first download the dependencies locally,\nthen add it to the module path and then start the program.\n\n## Thanks\n\n\u003cimg alt=\"PLCT Logo\" src=\"./PLCT.svg\" width=\"200\" height=\"200\"\u003e\n\nThanks to [PLCT Lab](https://plctlab.github.io/) for supporting me.\n\n\u003cimg src=\"https://resources.jetbrains.com/storage/products/company/brand/logos/IntelliJ_IDEA.svg\" alt=\"IntelliJ IDEA logo.\"\u003e\n\nThis project is developed using JetBrains IDEA. Thanks to JetBrains for providing me with a free license.\n","funding_links":["https://donate.glavo.site/"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fglavo%2Fjapp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fglavo%2Fjapp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fglavo%2Fjapp/lists"}