1

Before when users were required to have a jre installed to run aps:

ProcessBuilder builder = new ProcessBuilder("java -jar execute.jar");   

Now with jlink and jpackage being released .jars can be deployed with a bundled jre.

What is the correct method to start another .jar from a program that had been deployed with jlink/jpackage?

java -jar will not work as java is not installed on the end user anymore

see: How to call an embedded jre from command line in order to run java applications

This is a similar problem but does not address creating the .jar with jlink/jpackage

jpell
  • 198
  • 2
  • 10

2 Answers2

0

If you have a main class defined, you should be able to run "java -jar HelloWorld.jar".

Otherwise seems like you can create a launcher pointing to a starting module.

From Redhat Reference: https://access.redhat.com/documentation/en-us/openjdk/11/html/using_jlink_to_customize_java_runtime_environment/creating-custom-jre-modular

Create a custom JRE with the required modules and a custom application launcher for your application.

$ ./jdk-11/bin/jlink --launcher hello=sample/sample.HelloWorld --module-path sample-module --add-modules sample --output custom-runtime
$ ./custom-runtime/bin/hello
Omeri
  • 187
  • 2
  • 16
0

If you have to run the second JAR in its own JVM, then you have to have a JRE or JDK installed to do that.

Alternatively, you need to use jlink or jpackage or whatever to turn it into a self-contained application and distribute that instead of the second JAR. The user has to install that application in a place that your main application can find.

In either case, you run the second application as a separate process; i.e. as a separate JVM.


If it acceptable to run the second JAR in the current JVM, then it may be possible to do the following:

  1. Open the JAR file to read its MANIFEST.
  2. Fetch the Main-Class and Class-Path manifest attributes
  3. Create a new classloader with a classpath that includes the second JAR and all of its dependencies. (This assumes that they are available ... at the locations specified by the Class-Path attribute.)
  4. Use the classloader to load the main class.
  5. Use reflection to find and call the main classes entry point method; i.e. the static void main(String[]) method. Pass it a String[] to represent the command line arguments.

There are a couple of problems with this approach.

  • The application you are running from the 2nd JAR will share the environment with your main application. The same standard input/output/error. The same current directory and environment variables.

  • If the second application misbehaves ... it can bring down the main application in various ways. A security sandbox might help, but it won't protect against everything.

  • If the main application has been distributed with a custom JRE, then it may not include all of the Java SE classes that the second application needs. If that is the case you will get classloader exceptions or errors.

Finally, this approach may not work at all if the packaging technology you use uses an AOT compiler to compile the main application + all classes that it uses to native code.


UPDATE - Now that I understand what you are actually doing here (you have a main app and an updater app), I think there is another way to do this. The jlink utility allows you to create a bundle which has multiple entry points. When this is installed, I would expect it to appear as commands with different names that are links to the same executable. They would (naturally) use the same embedded JRE.

Read the following for more information:

Note that doing it this way would address possible issues with functionality missing from the bundled JRE. The jlink or jpackage command should make sure that all classes / modules that are needed will be included.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • hmm, yeah I dont think its going to work. The first .jar is the updater which checks and downloads the business application if needed. Then runs it which is where I am stuck. Both .jars are non-modular and are fat-type jars with all dependencies included. – jpell Aug 29 '21 at 11:04
  • Could I someone locate the jre that was bundled with the application that was installed with the native installer with jpackage – jpell Aug 29 '21 at 11:05
  • I don't think that would be a good idea, but install the app and see if *you* can find the bundled JRE. It's not a good idea because of the 3rd bullet point. Especially since your first app is designed to be small. Also ... if you only distribute the main application as a JAR which uses the JRE in the updater, how would you update the JRE in the updater app to fix possible JRE bugs / security issues? – Stephen C Aug 29 '21 at 11:09
  • 1
    For what you are talking about, I think you should put the functionality of the main app and the updater into one jlink'd application bundle with two entrypoints. See https://docs.oracle.com/javase/10/deploy/self-contained-application-packaging.htm#JSDPG1000 – Stephen C Aug 29 '21 at 11:15
  • I tried with --add-launcher in jpackage and make some progress but cannot delete the old .jar because it in being used in a process. It seems the jpackage is incomplete and hopefully they add more functionality to it, like an update feature.. – jpell Aug 29 '21 at 13:05