From 2733e06033717b2f5d1b918537c06eefdea13ceb Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Fri, 24 Jul 2015 18:08:35 +0200 Subject: [PATCH] fix compatibility of IDEA 15 with sources from previous versions --- .../rt/execution/CommandLineWrapper.java | 147 ++++++++++++++---- 1 file changed, 117 insertions(+), 30 deletions(-) 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 c6c229df1977..8026ef8e1400 100644 --- a/java/java-runtime/src/com/intellij/rt/execution/CommandLineWrapper.java +++ b/java/java-runtime/src/com/intellij/rt/execution/CommandLineWrapper.java @@ -15,13 +15,12 @@ */ package com.intellij.rt.execution; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; +import java.io.*; import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.*; import java.util.jar.JarInputStream; import java.util.jar.Manifest; @@ -35,9 +34,21 @@ public class CommandLineWrapper { public static void main(String[] args) throws Exception { final File jarFile = new File(args[0]); - JarInputStream inputStream = null; + final MainPair mainPair = args[0].endsWith(".jar") ? loadMainClassFromClasspathJar(jarFile, args) + : loadMainClassWithOldCustomLoader(jarFile, args); + String[] mainArgs = mainPair.getArgs(); + Class mainClass = mainPair.getMainClass(); + System.arraycopy(args, 2, mainArgs, 0, mainArgs.length); + //noinspection SSBasedInspection + Class mainArgType = (new String[0]).getClass(); + Method main = mainClass.getMethod("main", new Class[]{mainArgType}); + ensureAccess(main); + main.invoke(null, new Object[]{mainArgs}); + } + + private static MainPair loadMainClassFromClasspathJar(File jarFile, String[] args) throws Exception { + final JarInputStream inputStream = new JarInputStream(new FileInputStream(jarFile)); try { - inputStream = new JarInputStream(new FileInputStream(jarFile)); final Manifest manifest = inputStream.getManifest(); final String vmParams = manifest.getMainAttributes().getValue("VM-Options"); if (vmParams != null) { @@ -49,25 +60,34 @@ public class CommandLineWrapper { } } } - catch (IOException ignore) {} finally { if (inputStream != null) { inputStream.close(); } jarFile.deleteOnExit(); } - - String mainClassName = args[1]; - String[] mainArgs = new String[args.length - 2]; - System.arraycopy(args, 2, mainArgs, 0, mainArgs.length); - Class mainClass = Class.forName(mainClassName); - //noinspection SSBasedInspection - Class mainArgType = (new String[0]).getClass(); - Method main = mainClass.getMethod("main", new Class[]{mainArgType}); - ensureAccess(main); - main.invoke(null, new Object[]{mainArgs}); + + return new MainPair(Class.forName(args[1]), new String[args.length - 2]); } + private static class MainPair { + private Class mainClass; + private String[] args; + + public MainPair(Class mainClass, String[] args) { + this.mainClass = mainClass; + this.args = args; + } + + public Class getMainClass() { + return mainClass; + } + + public String[] getArgs() { + return args; + } + } + public static void parseVmOptions(String vmParams, Map vmOptions) { int idx = vmParams.indexOf(PREFIX); while (idx >= 0) { @@ -89,15 +109,82 @@ public class CommandLineWrapper { } private static void ensureAccess(Object reflectionObject) { - // need to call setAccessible here in order to be able to launch package-local classes - // calling setAccessible() via reflection because the method is missing from java version 1.1.x - final Class aClass = reflectionObject.getClass(); - try { - final Method setAccessibleMethod = aClass.getMethod("setAccessible", new Class[] {boolean.class}); - setAccessibleMethod.invoke(reflectionObject, new Object[] {Boolean.TRUE}); - } - catch (Exception e) { - // the method not found - } - } + // need to call setAccessible here in order to be able to launch package-local classes + // calling setAccessible() via reflection because the method is missing from java version 1.1.x + final Class aClass = reflectionObject.getClass(); + try { + final Method setAccessibleMethod = aClass.getMethod("setAccessible", new Class[]{boolean.class}); + setAccessibleMethod.invoke(reflectionObject, new Object[]{Boolean.TRUE}); + } + catch (Exception e) { + // the method not found + } + } + + //todo delete; but new idea won't run correctly tests which start process with CommandLineWrapper + private static MainPair loadMainClassWithOldCustomLoader(File file, String[] args) throws Exception { + final List urls = new ArrayList(); + final StringBuffer buf = new StringBuffer(); + final BufferedReader reader = new BufferedReader(new FileReader(file)); + try { + while (reader.ready()) { + final String fileName = reader.readLine(); + if (buf.length() > 0) { + buf.append(File.pathSeparator); + } + buf.append(fileName); + File classpathElement = new File(fileName); + try { + //noinspection Since15, deprecation + urls.add(classpathElement.toURI().toURL()); + } + catch (NoSuchMethodError e) { + //noinspection deprecation + urls.add(classpathElement.toURL()); + } + } + } + finally { + reader.close(); + } + if (!file.delete()) file.deleteOnExit(); + System.setProperty("java.class.path", buf.toString()); + + int startArgsIdx = 2; + + String mainClassName = args[startArgsIdx - 1]; + String[] mainArgs = new String[args.length - startArgsIdx]; + System.arraycopy(args, startArgsIdx, mainArgs, 0, mainArgs.length); + + for (int i = 0; i < urls.size(); i++) { + URL url = (URL)urls.get(i); + urls.set(i, internFileProtocol(url)); + } + + ClassLoader loader = new URLClassLoader((URL[])urls.toArray(new URL[urls.size()]), null); + final String classLoader = System.getProperty("java.system.class.loader"); + if (classLoader != null) { + try { + loader = (ClassLoader)Class.forName(classLoader).getConstructor(new Class[]{ClassLoader.class}).newInstance(new Object[]{loader}); + } + catch (Exception e) { + //leave URL class loader + } + } + Class mainClass = loader.loadClass(mainClassName); + Thread.currentThread().setContextClassLoader(loader); + + return new MainPair(mainClass, mainArgs); + } + + private static URL internFileProtocol(URL url) { + try { + if ("file".equals(url.getProtocol())) { + return new URL("file", url.getHost(), url.getPort(), url.getFile()); + } + } + catch (MalformedURLException ignored) { + } + return url; + } }