Runtime.exec Usage
My program calls Runtime.exec(String) to run another external java application, it runs well in windows, but in Linux platform, it always throws error:
The java class is not found: com/**/MainClass
From the error message, it is obvious that JVM can not find the main class; usually this is because class path is not correctly configured.
But when I paste that string to shell, external program can be successfully started.
After goggle search, I figured out the root cause,
It's recommended to use Runtime.exec(String[]), and add each argument in its own element of the string array. Never add 2 arguments in one element.
Normally, in each element, we should not add ' or ", if we did that, it may cause exception or incorrect value that is not we want.
The following is a sample application to call another java application:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class AppInvoker
{
public static void main(String[] args)
{
try
{
String[] cmds = new String[] { "C:\\Program Files\\Java\\jdk1.6.0_23\\bin\\java",
// with "-ms64m -mx512m", it would fail: Invalid initial heap size: -Xms64m -mx512m
"-ms64m",
"-mx512m",
// if -Dfoo='D:\java projects', the foo value would be 'D:\java projects'
// if -Dfoo=\"D:\\java projects\", java.lang.ClassNotFoundException: projects, projects would be thought as main class.
// with "-Dfoo=D:\\java projects -Dbar=bar", value of foo would be - D:\java projects -Dbar=bar -.,
// bar is null, as it's not set.
"-Dfoo=D:\\java projects",
"-Dbar=bar",
"-classpath",
// don't add ' before classpath, otherwise it will throw ClassNotFoundException.
// "" is ok.
// safe way is to not add ' or " at all.
"D:\\java projects\\arguments.jar",
"CommandArguments",
"-nickname",
// with 'johnny depp', then value of nickname would be 'johnny depp'.
// with \"johnny depp\", then value of nickname is still johnny depp.
"johnny depp",
"-user",
"depp",
"-passwd",
"depp",
"-cfg",
"D:\\java projects\\my.cfg" };
final Process p = Runtime.getRuntime().exec(cmds);
// read input stream
new Thread()
{
public void run()
{
try
{
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while ((line = in.readLine()) != null)
{
System.out.println(line);
}
}
catch (Exception e)
{
e.printStackTrace();
}
};
}.start();
// read error stream
new Thread()
{
public void run()
{
try
{
BufferedReader errReader = new BufferedReader(new InputStreamReader(p.getErrorStream()));
String line;
while ((line = errReader.readLine()) != null)
{
System.err.println(line);
}
}
catch (Exception e)
{
e.printStackTrace();
}
};
}.start();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
public class CommandArguments
{
public static void main(String[] args)
{
// ready system property
System.out.println("foo:" + System.getProperty("foo"));
System.out.println("bar:" + System.getProperty("bar"));
System.out.println("infile:" + System.getProperty("infile"));
// read parameters
for (int i = 0; i < args.length; i++)
{
System.out.println("args[" + i + "] = " + args[i]);
}
}
}
From JDK5, it's recommended to use ProcessBuilder, which provides more functions and deal with spaces much better than Runtime.exec().