Execute a Java program from our Java program

I used

Runtime.getRuntime().exec("_____")

but it throws a IOException as below:

java.io.IOException: CreateProcess: c:/ error=5
  at java.lang.Win32Process.create(Native Method)
  at java.lang.Win32Process.<init>(Win32Process.java:63)
  at java.lang.Runtime.execInternal(Native Method

I don't know whether I have the problem with specifying the path or something else. Can anyone please help me with the code.


Solution 1:

You're trying to execute "C:/". You'll want to execute something like:

"javaw.exe d:\\somejavaprogram\\program.jar"

Notice the path separators.

I'm assuming this is for an ad-hoc project, rather than something large. However, for best practice running external programs from code:

  • Don't hardcode the executable location, unless you're certain it will never change
  • Look up directories like %windir% using System.getenv
  • Don't assume programs like javaw.exe are in the search path: check them first, or allow the user to specify a location
  • Make sure you're taking spaces into account: "cmd /c start " + myProg will not work if myProg is "my program.jar".

Solution 2:

You can either launch another JVM (as described in detail in other answers). But that is not a solution i would prefer.

Reasons are:

  • calling a native program from java is "dirty" (and sometimes crashes your own VM)
  • you need to know the path to the external JVM (modern JVMs don't set JAVA_HOME anymore)
  • you have no control on the other program

Main reason to do it anyway is, that the other application has no control over your part of the program either. And more importantly there's no trouble with unresponsive system threads like the AWT-Thread if the other application doesn't know its threading 101.

But! You can achieve more control and similar behaviour by using an elementary plugin technique. I.e. just call "a known interface method" the other application has to implement. (in this case the "main" method).

Only it's not quite as easy as it sounds to pull this off.

  • you have to dynamically include required jars at runtime (or include them in the classpath for your application)
  • you have to put the plugin in a sandbox that prevents compromising critical classes to the other application

And this calls for a customized classloader. But be warned - there are some well hidden pitfalls in implementing that. On the other hand it's a great exercise.

So, take your pick: either quick and dirty or hard but rewarding.

Solution 3:

java.io.IOException: CreateProcess: c:/ error=5
        at java.lang.Win32Process.create(Native Method)
        at java.lang.Win32Process.&lt;init&gt;(Win32Process.java:63)
        at java.lang.Runtime.execInternal(Native Method)

If I recall correctly, error code 5 means access denied. This could be because your path is incorrect (trying to execute "c:/") or you are bumping against your OS security (in which case, look at the permissions).

If you are having trouble locating the Java executable, you can usually find it using system properties:

public class LaunchJre {

    private static boolean isWindows() {
        String os = System.getProperty("os.name");
        if (os == null) {
            throw new IllegalStateException("os.name");
        }
        os = os.toLowerCase();
        return os.startsWith("windows");
    }

    public static File getJreExecutable() throws FileNotFoundException {
        String jreDirectory = System.getProperty("java.home");
        if (jreDirectory == null) {
            throw new IllegalStateException("java.home");
        }
        File exe;
        if (isWindows()) {
            exe = new File(jreDirectory, "bin/java.exe");
        } else {
            exe = new File(jreDirectory, "bin/java");
        }
        if (!exe.isFile()) {
            throw new FileNotFoundException(exe.toString());
        }
        return exe;
    }

    public static int launch(List<String> cmdarray) throws IOException,
            InterruptedException {
        byte[] buffer = new byte[1024];

        ProcessBuilder processBuilder = new ProcessBuilder(cmdarray);
        processBuilder.redirectErrorStream(true);
        Process process = processBuilder.start();
        InputStream in = process.getInputStream();
        while (true) {
            int r = in.read(buffer);
            if (r <= 0) {
                break;
            }
            System.out.write(buffer, 0, r);
        }
        return process.waitFor();
    }

    public static void main(String[] args) {
        try {
            Runtime.getRuntime().exec("c:/");

            List<String> cmdarray = new ArrayList<String>();
            cmdarray.add(getJreExecutable().toString());
            cmdarray.add("-version");
            int retValue = launch(cmdarray);
            if (retValue != 0) {
                System.err.println("Error code " + retValue);
            }
            System.out.println("OK");
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

(Tested Windows XP, Sun JRE 1.6; Ubuntu 8.04, OpenJDK JRE 1.6)

This is the equivalent of running:

java -version

You may also want to look at the "java.library.path" system property (and "path.separator") when trying to locate the executable.

Solution 4:

How about just calling the main from your java program?

Test.main(null);

This worked fine for me