Protect JavaSE Applications

javaapp handles ordinary Java applications that have a main class. It produces the protected archive, the VLX JRE for each target platform, and the startup scripts.

1. Using the GUI

  1. On the application type page, select Java Application.

    Select Java Application

  2. Select the input JAR, the bundled Java version, and the target platforms, then choose simple or advanced mode.

    Select the input, Java version, target platform, and mode

  3. In advanced mode, fill in Main class if needed, then configure the JVM options, JavaFX settings, and exclusion rules. Simple mode skips this page. For what each option does, see Protector4J Advanced Mode Settings.

    Configure advanced options for an ordinary Java application

  4. Select the output directory, review the summary, then click Run protection.

    Select the output directory and run protection

2. CLI examples

When the manifest already declares the correct Main-Class:

p4j javaapp app.jar dist

When the manifest has no Main-Class, or you want to start from a different class, name it with --main:

p4j javaapp app.jar dist --main com.example.Main

Setting the main class and JVM options together:

p4j javaapp app.jar dist \
  --main com.example.Main \
  --jvm-option -Xms512m \
  --jvm-option -Xmx2g

Protecting only part of the application:

p4j javaapp app.jar dist \
  --protect 'com.example.core.**' \
  --exclude 'com.example.core.dto.**'

Compatibility scanning, and applying the recommendations automatically:

p4j javaapp app.jar --compat-scan
p4j javaapp app.jar dist --compat-apply

The two options cannot be used together. They differ as follows:

OptionWhat it doesWhen to use it
--compat-scanScans the input JAR, prints the risks and configuration recommendations, and exits. It does not encode anything and does not produce dist, so no output directory is needed.Read the report first when you protect an application for the first time, after upgrading dependencies or changing the protection scope, and when investigating a compatibility problem.
--compat-applyScans, merges in the conservative recommendations, then continues encoding and writes the output, so an output directory is required.Use it to finish packaging once you have read the scan results and accepted the recommendations. It also suits repeat builds and CI pipelines where the rules are already verified.

For javaapp, --compat-apply can add exclusion patterns based on the scan results and adjust the ZIP overlay, JavaFX, and archive suffix options. For those last three, a value given explicitly on the command line wins. Recommended exclusions are merged into your explicit --exclude patterns by default; pass --no-compat-excludes as well if you do not want them added. The scanner only performs static heuristic analysis, so problems that require source changes are not fixed by --compat-apply, and the packaged application still needs regression testing on the target platform.

For the other CLI commands, the full option list, environment variables, and automation examples, see the CLI Reference.

3. Output structure

dist/
├── app.p4jx              # or app.jar, with --archive-suffix jar
├── vlxjre/               # runtime matching the archive and target platform
├── lib/                  # manifest Class-Path dependencies, optional
├── run.sh
├── run.command
├── run.bat
└── README.md

Non-class resources are kept in the public resource view of the P4JX archive. Protected classes expose only a metadata stub to scanners; the real method bodies can be loaded only by the VLX runtime.

4. Starting the application

./run.sh [application arguments...]

On Windows:

run.bat [application arguments...]

Do not replace the vlxjre directory in the output with a system JRE. If you have to start the application by hand, use the generated script as a template and keep its class path, VM options, and JavaFX module options.

For Windows targets you can also generate a native launcher that runs on a double-click. It coexists with the startup scripts — see Create a Windows EXE Launcher.

JVM startup options

At packaging time, enter one option per line under JVM startup options in the GUI, or repeat the flag on the command line:

--jvm-option -Xms512m --jvm-option -Xmx2g

To change them permanently in a deployed directory:

  • macOS and Linux: edit run.sh and add JVM_OPTS+=("-Xms512m" "-Xmx2g") before the APP_JAVA_OPTS check. run.command calls the same run.sh.
  • Windows: edit run.bat and add set "JVM_OPTS=%JVM_OPTS% -Xms512m -Xmx2g" before the APP_JAVA_OPTS check.

One-off options can be injected through APP_JAVA_OPTS. For complete examples and caveats, see JVM Startup Options. Manual edits to the scripts are overwritten when you package again.

5. Choosing the protection scope

By default the application's own classes are protected. For production projects, it is better to name your own business packages explicitly:

--protect 'com.mycompany.product.**'

Classes you should normally exclude:

  • DTOs and records that Jackson serializes or deserializes directly;
  • Classes whose fields or methods are accessed through JNI;
  • Classes that an ORM, dependency injection container, or proxy framework needs to rewrite;
  • Third-party libraries and open source frameworks;
  • Classes that a custom ClassLoader has to redefine from a byte array.

6. The .p4jx and .jar suffixes

p4j javaapp app.jar dist --archive-suffix jar

This option changes the file name only; the archive content is still P4JX. Use it only when a third-party component hardcodes .jar in a URL or file name. It does not turn the archive into an ordinary ZIP or JAR.