Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/glavo/japp


https://github.com/glavo/japp

Last synced: 3 days ago
JSON representation

Awesome Lists containing this project

README

        

# JApp

A new packaging format for Java programs.

Features:

* Pack multiple modular or non-modular JARs into one file;
* Unlike Shadow JAR (Fat JAR), JApp has good support for the Java module system;
Resources from different JARs will be isolated under different prefixes instead of being mixed.

For example, if we put Gson and Apache Commons Lang 3 as modules into a JApp file,
their `module-info.class` URIs are as follows:

```
japp:/modules/com.google.gson/module-info.class
japp:/modules/org.apache.commons.lang3/module-info.class
```

JApp also supports using the class path and module path at the same time.
After adding the above two modules, you can also put Guava into the class path,
the URI of class `com.google.common.collect.Multimap` is as follows:

```
japp:/classpath/guava-32.1.3-jre.jar/com/google/common/collect/Multimap.class
```
* JApp files can declare dependencies on JARs from other sources (such as maven repositories).
The contents of these JARs are not included in the JApp file, but are resolved on demand before running,
and then added to the module path or classpath like the JARs within the JApp file.
* Using the [Zstandard](https://github.com/facebook/zstd) compression method, the file size is smaller than JAR;
* JApp compresses files using the zstd, which decompresses faster and has smaller file sizes than the deflate compression method used by JAR.
In addition, JApp also compresses file metadata and shares strings in the constant pool of Java Class files,
so JApp files are usually smaller than JAR files.

As a test case, I packed the [aya language](https://github.com/aya-prover/aya-dev) as a japp file,
the original fat jar is 6.81MiB, while the resulting JApp file is only 5.08MiB (-25.40%).
* Automatically select a suitable Java Runtime to start the program based on user-specified conditions;
* Users can specify some conditions (such as Java version >= 17),
and then the JApp launcher will find a suitable Java Runtime installed by the user to start the program based on these conditions.
* JApp files can contain JVM options (such as `--add-exports`, `--enable-native-access`, `-D`, etc.), which are passed to the JVM at runtime;
* It supports shebang, so you can run it with just `./myapp.japp `;
* Supports conditional addition of JVM options, classpath, and module paths.

Work in progress:

* More tests;
* Reimplement launcher in native language;
* The japp launcher's job is to find suitable Java, synthesize JVM options, and class/module paths based on conditions.
In the current prototype it is implemented in Java, which brings some limitations, I will rewrite it in native language in the future.
* Implement a manager that manages a set of Java;
* Now that the japp launcher will only scan Java from a fixed list of paths,
we need a way to manage the list of available Java runtimes instead.
* Support for filtering unused classes;
* Support embedding configuration files in JAR;
* Support for Java 8.

To be investigated:

* Support bundling and loading native libraries;
* Supports reading JMod files when creating;
* Proguard support;
* Build time optimization.

Welcome to discuss in [Discussions](https://github.com/Glavo/japp/discussions).

## Try it

NOTE: This project is in its early stages.
Some designs have been simplified for convenience, and they will be improved in the future.
The japp file created so far should be used for testing only;
The format of japp files is not yet stable and is subject to change.

To try this project, you first need to build it:

```shell
./gradlew
```

Then, package your program as a japp file:

(For Linux/macOS)
```shell
./bin/japp.sh create -o myapp.japp --module-path --class-path
```

(For Windows)
```powershell
.\bin\japp.ps1 create -o myapp.japp --module-path --class-path
```

Now you can run it:

(For Linux/macOS)
```shell
./myapp.japp
```

(For Windows)
```powershell
.\bin\japp.ps1 run myapp.japp
```

## Options

The `japp create` command accepts the following basic options:

* `-o `

### Config Group and Conditions

JApp packages class paths, module paths, JVM options, etc. into **config group**s.
You can add these things to the config group using the following command line options:

* `--module-path `
* `--class-path `
* `--add-opens /=(,)*`
* `--add-exports /=(,)*`
* `--enable-native-access [,...]`
* `-D=`
* `-m `
* ``

A config group can have a set of sub-config groups.
By default, these options are added to the root config group.
Use the `--group` command line option to start a new sub-config group, and use the `--end-group` option to end it.

Each config group can specify a **condition** using the `--condition ` option.

Conditions represent requirements for the Java runtime and environment.
For example, condition `java(version: 11, arch: x86-64|aarch64)` indicates
that the Java runtime version must be at least 11 and the architecture must be x86-64 or AArch64.
You can also combine multiple conditions using `&&` or `||`, such as `java(version: 11) || java(arch: x86-64)`.

The japp launcher will search for a suitable Java runtime based on the condition of the root config group;
If there is no Java runtime that meets the condition, an error will be reported.

The conditions of sub-config groups are used to determine whether the group should be applied.

Example:

```bash
./bin/japp.sh create -o myapp.japp \
--condition java(version: 11) --module-path ./myapp.jar \
--group --condition java(version: 22) --enable-native-access=org.glavo.myapp --end-group \
-m org.glavo.myapp
```

In the above example, assuming that `myapp.jar` exists in the current directory (the java module name is `org.glavo.myapp`),
this command will generate a japp file named `myapp.japp`.
The main module (also the only module in the `myapp.japp`) is `org.glavo.myapp`.

All you need to run it is this:

```bash
./myapp.japp
```

The japp launcher looks for a Java runtime version 11 or higher to run the program.
If the Java runtime found is of version 22 or higher, the JVM option `--enable-native-access=org.glavo.myapp` is added.

### Classpath and Module Path

The `--module-path` and `--classpath` options above accept arguments similar to the `java`/`javac` command:

(For Windows, please replace the path separator with `;`)
```
--module-path :...:
```

For the `java`/`javac` command, each path must be a file.
But for japp, each path can contain an optional prefix `[=,...,=]` to specify options.
We can use this syntax to specify to look for jars from the maven repository instead of locally:

```
[type=maven]//
```

For example, the following option will add gson to the module path:

```
--module-path [type=maven]com.google.code.gson/gson/2.10
```

By default, this dependency is bundled into the japp file just like a normal module path item.
However, 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:

```
--module-path [type=maven,bundle=false]com.google.code.gson/gson/2.10
```

When running this japp file, the japp launcher will first download the dependencies locally,
then add it to the module path and then start the program.

## Thanks

Thanks to [PLCT Lab](https://plctlab.github.io/) for supporting me.

IntelliJ IDEA logo.

This project is developed using JetBrains IDEA. Thanks to JetBrains for providing me with a free license.