diff --git a/java/java-runtime/src/com/intellij/rt/execution/CommandLineWrapper.java b/java/java-runtime/src/com/intellij/rt/execution/CommandLineWrapper.java index e7cf5ec79988..f358514d4387 100644 --- a/java/java-runtime/src/com/intellij/rt/execution/CommandLineWrapper.java +++ b/java/java-runtime/src/com/intellij/rt/execution/CommandLineWrapper.java @@ -49,6 +49,7 @@ public class CommandLineWrapper { } private static MainPair loadMainClassFromClasspathJar(File jarFile, String[] args) throws Exception { + String[] mainArgs; final JarInputStream inputStream = new JarInputStream(new FileInputStream(jarFile)); try { final Manifest manifest = inputStream.getManifest(); @@ -61,6 +62,14 @@ public class CommandLineWrapper { System.setProperty(optionName, (String)vmOptions.get(optionName)); } } + String programParameters = manifest.getMainAttributes().getValue("Program-Parameters"); + if (programParameters == null) { + mainArgs = new String[args.length - 2]; + System.arraycopy(args, 2, mainArgs, 0, mainArgs.length); + } + else { + mainArgs = splitBySpaces(programParameters); + } } finally { if (inputStream != null) { @@ -69,11 +78,60 @@ public class CommandLineWrapper { jarFile.deleteOnExit(); } - String[] mainArgs = new String[args.length - 2]; - System.arraycopy(args, 2, mainArgs, 0, mainArgs.length); return new MainPair(Class.forName(args[1]), mainArgs); } + /** + * The implementation is copied from copied from com.intellij.util.execution.ParametersListUtil.parse and adapted to old Java versions + */ + private static String[] splitBySpaces(String parameterString) { + parameterString = parameterString.trim(); + + final ArrayList params = new ArrayList(); + final StringBuffer token = new StringBuffer(128); + boolean inQuotes = false; + boolean escapedQuote = false; + boolean nonEmpty = false; + + for (int i = 0; i < parameterString.length(); i++) { + final char ch = parameterString.charAt(i); + + if (ch == '\"') { + if (!escapedQuote) { + inQuotes = !inQuotes; + nonEmpty = true; + continue; + } + escapedQuote = false; + } + else if (Character.isWhitespace(ch)) { + if (!inQuotes) { + if (token.length() > 0 || nonEmpty) { + params.add(token.toString()); + token.setLength(0); + nonEmpty = false; + } + continue; + } + } + else if (ch == '\\') { + if (i < parameterString.length() - 1 && parameterString.charAt(i + 1) == '"') { + escapedQuote = true; + continue; + } + } + + token.append(ch); + } + + if (token.length() > 0 || nonEmpty) { + params.add(token.toString()); + } + + //noinspection SSBasedInspection + return (String[])params.toArray(new String[params.size()]); + } + private static class MainPair { private Class mainClass; private String[] args; diff --git a/platform/lang-api/src/com/intellij/execution/configurations/SimpleJavaParameters.java b/platform/lang-api/src/com/intellij/execution/configurations/SimpleJavaParameters.java index 3316113fb520..10cad3df97c0 100644 --- a/platform/lang-api/src/com/intellij/execution/configurations/SimpleJavaParameters.java +++ b/platform/lang-api/src/com/intellij/execution/configurations/SimpleJavaParameters.java @@ -18,6 +18,7 @@ package com.intellij.execution.configurations; import com.intellij.execution.ExecutionException; import com.intellij.execution.process.OSProcessHandler; import com.intellij.execution.process.ProcessTerminatedListener; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.projectRoots.JavaSdkType; import com.intellij.openapi.projectRoots.JdkUtil; import com.intellij.openapi.projectRoots.Sdk; @@ -33,6 +34,7 @@ import java.nio.charset.Charset; * @author Gregory.Shrago */ public class SimpleJavaParameters extends SimpleProgramParameters { + private static final Logger LOG = Logger.getInstance(SimpleJavaParameters.class); private Sdk myJdk; private String myMainClass; private final PathsList myClassPath = new PathsList(); @@ -41,6 +43,7 @@ public class SimpleJavaParameters extends SimpleProgramParameters { private boolean myUseDynamicClasspath; private boolean myUseClasspathJar = false; private boolean myUseDynamicVMOptions; + private boolean myPassProgramParametersViaClasspathJar; private String myJarPath; public String getMainClass() { @@ -105,10 +108,27 @@ public class SimpleJavaParameters extends SimpleProgramParameters { return myUseClasspathJar; } + /** + * Call this method and pass {@code true} to pass classpath of the application via MANIFEST.MF file in a specially generated classpath.jar + * archive instead of passing it via -classpath command line option. This may be needed to avoid problems with too long command line on Windows. + */ public void setUseClasspathJar(boolean useClasspathJar) { myUseClasspathJar = useClasspathJar; } + public boolean isPassProgramParametersViaClasspathJar() { + return myPassProgramParametersViaClasspathJar; + } + + /** + * Call this method and pass {@code true} to pass program parameters via attribute in MANIFEST.MF of the classpath jar instead of passing + * them via command line. This may be needed to avoid problems with too long command line on Windows. + */ + public void setPassProgramParametersViaClasspathJar(boolean passProgramParametersViaClasspathJar) { + LOG.assertTrue(myUseClasspathJar); + myPassProgramParametersViaClasspathJar = passProgramParametersViaClasspathJar; + } + @NotNull public GeneralCommandLine toCommandLine() { Sdk jdk = getJdk(); diff --git a/platform/lang-api/src/com/intellij/openapi/projectRoots/JdkUtil.java b/platform/lang-api/src/com/intellij/openapi/projectRoots/JdkUtil.java index 5efe5c90ff57..4c3fa6922a88 100644 --- a/platform/lang-api/src/com/intellij/openapi/projectRoots/JdkUtil.java +++ b/platform/lang-api/src/com/intellij/openapi/projectRoots/JdkUtil.java @@ -170,10 +170,12 @@ public class JdkUtil { commandLine.withParentEnvironmentType(javaParameters.isPassParentEnvs() ? ParentEnvironmentType.CONSOLE : ParentEnvironmentType.NONE); final Class commandLineWrapper; + boolean passProgramParametersViaClassPathJar = false; if ((commandLineWrapper = getCommandLineWrapperClass()) != null) { if (forceDynamicClasspath && !vmParametersList.hasParameter("-classpath") && !vmParametersList.hasParameter("-cp")) { if (isClassPathJarEnabled(javaParameters, PathUtil.getJarPathForClass(ClassPath.class))) { - appendJarClasspathParams(javaParameters, commandLine, vmParametersList, commandLineWrapper); + passProgramParametersViaClassPathJar = javaParameters.isPassProgramParametersViaClasspathJar(); + appendJarClasspathParams(javaParameters, commandLine, vmParametersList, commandLineWrapper, passProgramParametersViaClassPathJar); } else { appendOldCommandLineWrapper(javaParameters, commandLine, vmParametersList, commandLineWrapper); @@ -197,7 +199,9 @@ public class JdkUtil { commandLine.addParameter(jarPath); } - commandLine.addParameters(javaParameters.getProgramParametersList().getList()); + if (!passProgramParametersViaClassPathJar) { + commandLine.addParameters(javaParameters.getProgramParametersList().getList()); + } commandLine.withWorkDirectory(javaParameters.getWorkingDirectory()); @@ -283,7 +287,9 @@ public class JdkUtil { private static void appendJarClasspathParams(SimpleJavaParameters javaParameters, GeneralCommandLine commandLine, - ParametersList vmParametersList, Class commandLineWrapper) { + ParametersList vmParametersList, + Class commandLineWrapper, + boolean storeProgramParametersInJar) { try { final Manifest manifest = new Manifest(); manifest.getMainAttributes().putValue("Created-By", @@ -305,6 +311,10 @@ public class JdkUtil { else { commandLine.addParameters(vmParametersList.getList()); } + if (storeProgramParametersInJar) { + manifest.getMainAttributes().putValue("Program-Parameters", ParametersListUtil.join(javaParameters.getProgramParametersList().getList())); + } + final boolean notEscape = vmParametersList.hasParameter(PROPERTY_DO_NOT_ESCAPE_CLASSPATH_URL); final List classPathList = javaParameters.getClassPath().getPathList(); @@ -313,7 +323,7 @@ public class JdkUtil { final String jarFile = classpathJarFile.getAbsolutePath(); commandLine.addParameter("-classpath"); - if (writeDynamicVMOptions) { + if (writeDynamicVMOptions || storeProgramParametersInJar) { commandLine.addParameter(PathUtil.getJarPathForClass(commandLineWrapper) + File.pathSeparator + jarFile); appendEncoding(javaParameters, commandLine, vmParametersList); commandLine.addParameter(commandLineWrapper.getName());