You can use Runtime.exec()
or a ProcessBuilder to accomplish this.
Process proc = new ProcessBuilder("java", "-XMx512M", "-jar", "MainJar.jar").start();
int result = proc.waitFor();
But honestly I think it's an awful solution. I would favour an installation package like InstallAnywhere. Failing that I would use a shell script to launch the Jar. Encapsulating it in a Jar where it can't be edited is annoying to users and now you have parallel dependencies rather than a single file.
If you were going to take this route, it would be possible to use the same Jar for both purposes. Add your class file to launch with the correct parameters to the Jar, say AppLauncher.class
. We'll assume your program's real code starts at Main.class
.
public class AppLauncher {
public static void main(String... args) {
Process proc = new ProcessBuilder("java", "-XMx512M", "-cp", "MyJar.jar", "Main").start();
int result = proc.waitFor();
}
}
Then you would have your Manifest file of the jar point to this main class:
Main-Class: AppLauncher
You would then execute this jar via
java -jar MyJar.jar
Or through file associations (double click).
When it runs, it executes the command java -Xmx512M -cp MyJar.jar Main
which runs the main method of the Main class of your jar. The same jar is used in both invocations: the first time it automatically runs AppLauncher.main()
via the manifest file, the second time Main.main()
via an explicit process call.
This is still fragile of course. For one thing, it assumes that the working directory is set to the folder that contains your jar file. That's not always true.
Edit: Just in case you're not convinced to do otherwise, and actually take the ProcessBuilder route, there's more to it than just what I noted. There are pitfalls to avoid. For instance, I didn't read from the process's output stream (using Process.getInputStream()
) so if child Java process outputs anything to stdout, it will freeze when the OS buffer is filled.