6

I am in the process of building a wrapper jar for a jar that I built. It will handle updating the main application and making sure users are valid users. I am having a major issue though, because I can't get the external jar launching function working. This is what I have so far:

ProcessBuilder builder = new ProcessBuilder("java -jar ~/Documents.Java/myJar.jar");
try {
    Process process = builder.start();
} catch (Exception e) {
    e.printStackTrace();
}

However, I am just getting a file not found exception.

java.io.IOException: Cannot run program "java -jar ~/Documents/Java/myJar.jar": error=2, No such file or directory
at java.lang.ProcessBuilder.start(ProcessBuilder.java:1048)
at com.mycompany.DHSLauncher.Launcher.lambda$4(Launcher.java:109)
at java.util.Optional.ifPresent(Optional.java:159)
at com.mycompany.DHSLauncher.Launcher.showLogin(Launcher.java:102)
at com.mycompany.DHSLauncher.Launcher.start(Launcher.java:35)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$162(LauncherImpl.java:863)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$175(PlatformImpl.java:326)
at com.sun.javafx.application.PlatformImpl.lambda$null$173(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(PlatformImpl.java:294)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)

Caused by: java.io.IOException: error=2, No such file or directory
at java.lang.UNIXProcess.forkAndExec(Native Method)
at java.lang.UNIXProcess.<init>(UNIXProcess.java:248)
at java.lang.ProcessImpl.start(ProcessImpl.java:134)
at java.lang.ProcessBuilder.start(ProcessBuilder.java:1029)
... 10 more

If I copy java -jar ~/Documents.Java/myJar.jar and paste it right into terminal, it works and the jar launches. I have no idea what is going on here. Is the path supposed to be relative to the location of the running jar?

Aaron
  • 306
  • 1
  • 4
  • 11

3 Answers3

8

Tilde expansion (the leading ~) is a feature of the shell. You are not invoking java through a shell, so that is not happening. Use the System.getProperty("user.home") method to find the user's home directory and build the command using that instead of the tilde.

Jim Garrison
  • 85,615
  • 20
  • 155
  • 190
  • Ok, I am still getting the file not found exception. I changed to what you suggested, and then I got a permission denied. I figured out how to set the file to executable, but I am back to the file not found again. – Aaron Sep 17 '16 at 05:15
  • Did you confirm that `user.dir` has the correct value? Did you confirm that you are building the path correctly? Show the complete final assembled command line that you are passing to `ProcessBuilder` – Jim Garrison Sep 17 '16 at 05:16
  • Show the complete final assembled command line that you are passing to `ProcessBuilder`. You will also need to provide the complete path to the `java` command, as it may not be on the path. – Jim Garrison Sep 17 '16 at 05:17
  • `ProcessBuilder builder = new ProcessBuilder("java -jar " + System.getProperty("user.home") + "/Documents/Java/myJar.jar");` I also echoed builder.directory(), and it returns null. – Aaron Sep 17 '16 at 05:19
  • No. Put the concatenated command into a `String` before invoking `ProcessBuilder` and print out that string. – Jim Garrison Sep 17 '16 at 05:20
  • This returns `java -jar /Users/Aaron/Documents/Java/myJar.jar` – Aaron Sep 17 '16 at 05:21
  • Add the complete path to the `java` command as well; also note that in your code above you have `.../Documents.Java/...` which does not match what is in your last comment. – Jim Garrison Sep 17 '16 at 05:23
  • `ProcessBuilder builder = new ProcessBuilder("/Library/Java/JavaVirtualMachines/jdk1.8.0_91.jdk/Contents/Home/jre/bin/java -jar /Users/Aaron/Documents/Java/myJar.jar");` You mean the java path like this? – Aaron Sep 17 '16 at 05:33
  • @JimGarrison I also tried `Runtime.getRuntime().exec("java -jar ~/Documents.Java/myJar.jar")` but I get "Error: Unable to access jarfile ~/Documents.Java/myJar.jar". I thought generating the Process in this way, the command would run in the shell (and the tilde would be expanded), but failed. Took care of permissions and paths, but still fail. Posted this comment if anyone may try this in a successful way. – gthanop Sep 17 '16 at 08:23
6

Near dupe Java execute process on linux and Difference between ProcessBuilder and Runtime.exec()

In addition to the correct points about tilde-(non-)expansion, you are passing an entire commandline as one argument to new ProcesssBuilder. Unlike Runtime.exec() which treats a single String as a special case and splits into whitespace-delimited tokens mostly (but not exactly) like typical Unix shells, the ProcessBuilder ctor does not do this. This can be seen in the exception message at the beginning of the traceback you posted. You need separate arguments like:

ProcessBuilder builder = new ProcessBuilder("java", "-jar", 
    System.getProperty("user.home")+"/Documents.Java/myJar.jar");
// three String's passed to vararg, compiler makes array for you

or possibly (but I don't recommend)

String line = "java -jar " + System.getProperty("user.home")+"/Documents.Java/myJar.jar";
ProcessBuilder builder = new ProcessBuilder( line.split(" ") );
// array of three String's passed directly to vararg

And replace java by a full pathname if the desired java program (or a link to it) isn't found first when searching the PATH in effect for your JVM process.

Community
  • 1
  • 1
dave_thompson_085
  • 34,712
  • 6
  • 50
  • 70
1

I have a somewhat different idea - of course Jim is correct as in "~" will not work within the process builder; and using the System prefs is normally the way to go.

On top of that I suggested: simply verify in advance that any filename you are using on the command line points to an existing file.

Why not create a File object pointing to your JAR? So you don't need to wait for IOExceptions to happen, you do a simple exists() call to understand if path that you pulled together for your JAR makes sense. And you could do the same for your java executable!

GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • In the end I ended up doing this for debugging purposes, but I will keep it to validate like you suggested. – Aaron Sep 17 '16 at 16:08