Monday, April 22, 2013

IllegalArgumentException - Executable name has embedded quote, split the arguments

The way your Java program deals with external command invocations can be Runtime.exec, java.lang.ProcessBuilder or calling a web server wrapper that avoids huge memory leaking (JVM-Fork() problem) as I have posted before.

If you are using Runtime.exec without arrays for parameters then most likely you will face an "IllegalArgumentException" starting with version 1.7.0_21 in Windows platforms. The message states "Executable name has embedded quote, split the arguments". The solution as explained by Oracle is to use an array if you stick to Runtime.exec or migrate to java.lang.ProcessBuilder. Please refer to http://www.oracle.com/technetwork/java/javase/7u21-relnotes-1932873.html#jruntime for details.

I ignore if java7 has already corrected for good the momentary overcommit of swap space as a result of using fork() but we have found using the wrapper mentioned above has done the trick so far for us but for sure using a wrapper is not always an option.

3 comments:

Matthew Weiler said...

Thank you, you're a life saver.

It sucks that I had to re-write some of my code due to a Java update, but at least the solution was clear.

Thanks again,
Matt

shivling todkar said...

HAVING ERROR
"Exception in thread "Thread-4" java.lang.IllegalArgumentException: Executable name has embedded quote, split the arguments"
Code as below



public static void restartApplication(Runnable runBeforeRestart) throws IOException {
try {
// java binary
String java = System.getProperty("java.home") + "/bin/java";
// vm arguments

System.out.println("11111111");

List vmArguments = ManagementFactory.getRuntimeMXBean().getInputArguments();
System.out.println("333333");
StringBuffer vmArgsOneLine = new StringBuffer();
for (String arg : vmArguments) {
// if it's the agent argument : we ignore it otherwise the
// address of the old application and the new one will be in conflict
if (!arg.contains("-agentlib")) {
vmArgsOneLine.append(arg);
vmArgsOneLine.append(" ");
}
}
System.out.println("22222222");
// init the command to execute, add the vm args
final StringBuffer cmd = new StringBuffer("\"" + java + "\" " + vmArgsOneLine);

// program main and program arguments
System.out.println("55555");
String[] mainCommand = System.getProperty("sun.java.command").split(" ");
//String[] mainCommand = System.getProperty(SUN_JAVA_COMMAND).split(" ");
// program main is a jar
System.out.println("666666666");
if (mainCommand[0].endsWith(".jar")) {
// if it's a jar, add -jar mainJar
cmd.append("-jar " + new File(mainCommand[0]).getPath());
} else {
// else it's a .class, add the classpath and mainClass
cmd.append("-cp \"" + System.getProperty("java.class.path") + "\" " + mainCommand[0]);
}
// finally add program arguments
System.out.println("7777777777777");
for (int i = 1; i < mainCommand.length; i++) {
cmd.append(" ");
cmd.append(mainCommand[i]);
}
//cmd.append("\"");
System.out.println("14444444444444");
//ProcessBuilder svnProcessBuilder = new ProcessBuilder(cmd.toString());
//Runtime.getRuntime().exec(svnProcessBuilder.toString());
// execute the command in a shutdown hook, to be sure that all the
// resources have been disposed before restarting the application
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
try {


System.out.println("********** "+cmd.toString());

// byte bytes[] = cmd.toString().getBytes();


Runtime.getRuntime().exec(cmd.toString());



} catch (IOException e) {
e.printStackTrace();
}
}
});
// execute some custom code before restarting
if (runBeforeRestart!= null) {
runBeforeRestart.run();
}
// exit
System.exit(0);
} catch (Exception e) {
// something went wrong
//throw new IOException("Error while trying to restart the application", e);
System.out.println("ERROR "+e);

}
}

pls tell solutions
thanx in advance

Nestor Urquiza said...

@shivling as explained in http://www.oracle.com/technetwork/java/javase/7u21-relnotes-1932873.html#jruntime use a variant of Runtime.exec that allows the command and arguments to be specified in an array. What you are doing is concatenating in a string the whole command line.

The preferred method though is to use java.lang.ProcessBuilder in case you are in jdk5 and above.

Followers