diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/PluginManager.java b/platform/platform-impl/src/com/intellij/ide/plugins/PluginManager.java index 7103dcacfe29..e110b2935472 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/PluginManager.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/PluginManager.java @@ -45,10 +45,7 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.IdeFrame; import com.intellij.openapi.wm.ex.WindowManagerEx; -import com.intellij.util.ArrayUtil; -import com.intellij.util.ExceptionUtil; -import com.intellij.util.Function; -import com.intellij.util.PlatformUtils; +import com.intellij.util.*; import com.intellij.util.graph.CachingSemiGraph; import com.intellij.util.graph.DFSTBuilder; import com.intellij.util.graph.Graph; @@ -60,7 +57,6 @@ import org.jdom.Document; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import sun.reflect.Reflection; import javax.swing.*; import javax.swing.event.HyperlinkEvent; @@ -77,7 +73,6 @@ import java.util.zip.ZipInputStream; */ @SuppressWarnings({"UseOfSystemOutOrSystemErr", "CallToPrintStackTrace"}) // No logger is loaded at this time so we have to use these. public class PluginManager { - @NonNls private static final String PROPERTY_PLUGIN_PATH = "plugin.path"; @NonNls public static final String INSTALLED_TXT = "installed.txt"; @NonNls private static final String SPECIAL_IDEA_PLUGIN = "IDEA CORE"; @@ -119,6 +114,7 @@ public class PluginManager { } public static void initPlugins(@Nullable StartupProgress progress) { + PluginClassLoaderDetector.install(); long start = System.currentTimeMillis(); try { initializePlugins(progress); @@ -224,7 +220,7 @@ public class PluginManager { final IdeaPluginDescriptorImpl[] pluginDescriptors = loadDescriptors(progress); - final Class callerClass = Reflection.getCallerClass(1); + final Class callerClass = ReflectionUtil.getCallerClass(1); final ClassLoader parentLoader = callerClass.getClassLoader(); final List result = new ArrayList(); @@ -296,7 +292,7 @@ public class PluginManager { ourPlugins = pluginDescriptors; } - public static void initClassLoader(final ClassLoader parentLoader, final IdeaPluginDescriptorImpl descriptor) { + public static void initClassLoader(@NotNull ClassLoader parentLoader, @NotNull IdeaPluginDescriptorImpl descriptor) { final List classPath = descriptor.getClassPath(); final ClassLoader loader = createPluginClassLoader(classPath.toArray(new File[classPath.size()]), new ClassLoader[]{parentLoader}, descriptor); diff --git a/platform/platform-impl/src/com/intellij/util/PluginClassLoaderDetector.java b/platform/platform-impl/src/com/intellij/util/PluginClassLoaderDetector.java new file mode 100644 index 000000000000..a411e2fb64f7 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/util/PluginClassLoaderDetector.java @@ -0,0 +1,36 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.util; + +import com.intellij.ide.plugins.IdeaPluginDescriptor; +import com.intellij.ide.plugins.PluginManager; +import com.intellij.openapi.extensions.PluginId; + +public class PluginClassLoaderDetector implements Function { + private static final PluginClassLoaderDetector INSTANCE = new PluginClassLoaderDetector(); + + @Override + public ClassLoader fun(String className) { + PluginId pluginId = PluginManager.getPluginByClassName(className); + IdeaPluginDescriptor plugin = PluginManager.getPlugin(pluginId); + if (plugin == null) return null; + return plugin.getPluginClassLoader(); + } + + public static void install() { + ReflectionUtil.PLUGIN_CLASS_LOADER_DETECTOR = INSTANCE; + } +} diff --git a/platform/util/src/com/intellij/openapi/util/IconLoader.java b/platform/util/src/com/intellij/openapi/util/IconLoader.java index 2d08c30fcc8b..09c0bc25e895 100644 --- a/platform/util/src/com/intellij/openapi/util/IconLoader.java +++ b/platform/util/src/com/intellij/openapi/util/IconLoader.java @@ -20,6 +20,7 @@ import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.reference.SoftReference; import com.intellij.util.ImageLoader; +import com.intellij.util.ReflectionUtil; import com.intellij.util.RetinaImage; import com.intellij.util.containers.ConcurrentHashMap; import com.intellij.util.containers.WeakHashMap; @@ -27,7 +28,6 @@ import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import sun.reflect.Reflection; import javax.swing.*; import java.awt.*; @@ -113,18 +113,18 @@ public final class IconLoader { @NotNull public static Icon getIcon(@NonNls @NotNull final String path) { int stackFrameCount = 2; - Class callerClass = Reflection.getCallerClass(stackFrameCount); + Class callerClass = ReflectionUtil.getCallerClass(stackFrameCount); while (callerClass != null && callerClass.getClassLoader() == null) { // looks like a system class - callerClass = Reflection.getCallerClass(++stackFrameCount); + callerClass = ReflectionUtil.getCallerClass(++stackFrameCount); } if (callerClass == null) { - callerClass = Reflection.getCallerClass(1); + callerClass = ReflectionUtil.getCallerClass(1); } return getIcon(path, callerClass); } @Nullable - private static Icon getReflectiveIcon(String path, ClassLoader classLoader) { + private static Icon getReflectiveIcon(@NotNull String path, ClassLoader classLoader) { try { String pckg = path.startsWith("AllIcons.") ? "com.intellij.icons." : "icons."; Class cur = Class.forName(pckg + path.substring(0, path.lastIndexOf('.')).replace('.', '$'), true, classLoader); @@ -144,12 +144,12 @@ public final class IconLoader { */ public static Icon findIcon(@NonNls @NotNull String path) { int stackFrameCount = 2; - Class callerClass = Reflection.getCallerClass(stackFrameCount); + Class callerClass = ReflectionUtil.getCallerClass(stackFrameCount); while (callerClass != null && callerClass.getClassLoader() == null) { // looks like a system class - callerClass = Reflection.getCallerClass(++stackFrameCount); + callerClass = ReflectionUtil.getCallerClass(++stackFrameCount); } if (callerClass == null) { - callerClass = Reflection.getCallerClass(1); + callerClass = ReflectionUtil.getCallerClass(1); } return findIcon(path, callerClass); } @@ -196,10 +196,10 @@ public final class IconLoader { private static String undeprecate(String path) { String replacement = ourDeprecatedIconsReplacements.get(path); - return replacement != null ? replacement : path; + return replacement == null ? path : replacement; } - private static boolean isReflectivePath(String path) { + private static boolean isReflectivePath(@NotNull String path) { List paths = StringUtil.split(path, "."); return paths.size() > 1 && paths.get(0).endsWith("Icons"); } @@ -218,7 +218,7 @@ public final class IconLoader { } @Nullable - public static Icon findIcon(String path, final ClassLoader classLoader) { + public static Icon findIcon(@NotNull String path, final ClassLoader classLoader) { path = undeprecate(path); if (isReflectivePath(path)) return getReflectiveIcon(path, classLoader); if (!path.startsWith("/")) return null; @@ -295,14 +295,17 @@ public final class IconLoader { public static Icon getTransparentIcon(@NotNull final Icon icon, final float alpha) { return new Icon() { + @Override public int getIconHeight() { return icon.getIconHeight(); } + @Override public int getIconWidth() { return icon.getIconWidth(); } + @Override public void paintIcon(final Component c, final Graphics g, final int x, final int y) { final Graphics2D g2 = (Graphics2D)g; final Composite saveComposite = g2.getComposite(); @@ -346,14 +349,17 @@ public final class IconLoader { return icon != null ? icon : EMPTY_ICON; } + @Override public void paintIcon(Component c, Graphics g, int x, int y) { getRealIcon().paintIcon(c, g, x, y); } + @Override public int getIconWidth() { return getRealIcon().getIconWidth(); } + @Override public int getIconHeight() { return getRealIcon().getIconHeight(); } @@ -369,6 +375,7 @@ public final class IconLoader { super(image); } + @Override public final synchronized void paintIcon(final Component c, final Graphics g, final int x, final int y) { super.paintIcon(null, g, x, y); } @@ -399,7 +406,7 @@ public final class IconLoader { return icon != null ? icon.getIconHeight() : 0; } - protected synchronized final Icon getOrComputeIcon() { + protected final synchronized Icon getOrComputeIcon() { if (!myWasComputed || isDarkVariant != USE_DARK_ICONS) { isDarkVariant = USE_DARK_ICONS; myWasComputed = true; @@ -420,7 +427,7 @@ public final class IconLoader { private final Class myCallerClass; private final String myPath; - public ByClass(Class aClass, String path) { + public ByClass(@NotNull Class aClass, @NotNull String path) { myCallerClass = aClass; myPath = path; } diff --git a/platform/util/src/com/intellij/openapi/util/JDOMExternalizableStringList.java b/platform/util/src/com/intellij/openapi/util/JDOMExternalizableStringList.java index 6f7a051ae6b7..6fdf557832dd 100644 --- a/platform/util/src/com/intellij/openapi/util/JDOMExternalizableStringList.java +++ b/platform/util/src/com/intellij/openapi/util/JDOMExternalizableStringList.java @@ -16,9 +16,9 @@ package com.intellij.openapi.util; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.util.ReflectionUtil; import org.jdom.Element; import org.jetbrains.annotations.NotNull; -import sun.reflect.Reflection; import java.util.ArrayList; import java.util.Collection; @@ -51,7 +51,7 @@ public class JDOMExternalizableStringList extends ArrayList implements J for (final Object o : element.getChildren()) { Element listElement = (Element)o; if (ATTR_LIST.equals(listElement.getName())) { - final ClassLoader classLoader = Reflection.getCallerClass(2).getClassLoader(); + final ClassLoader classLoader = ReflectionUtil.getCallerClass(2).getClassLoader(); for (final Object o1 : listElement.getChildren()) { Element listItemElement = (Element)o1; if (!ATTR_ITEM.equals(listItemElement.getName())) { diff --git a/platform/util/src/com/intellij/util/ImageLoader.java b/platform/util/src/com/intellij/util/ImageLoader.java index d34faff6d8b0..508768a149dc 100644 --- a/platform/util/src/com/intellij/util/ImageLoader.java +++ b/platform/util/src/com/intellij/util/ImageLoader.java @@ -86,12 +86,12 @@ public class ImageLoader implements Serializable { @Nullable public static Image loadFromResource(@NonNls String s) { int stackFrameCount = 2; - Class callerClass = Reflection.getCallerClass(stackFrameCount); + Class callerClass = ReflectionUtil.getCallerClass(stackFrameCount); while (callerClass != null && callerClass.getClassLoader() == null) { // looks like a system class - callerClass = Reflection.getCallerClass(++stackFrameCount); + callerClass = ReflectionUtil.getCallerClass(++stackFrameCount); } if (callerClass == null) { - callerClass = Reflection.getCallerClass(1); + callerClass = ReflectionUtil.getCallerClass(1); } return loadFromResource(s, callerClass); } diff --git a/platform/util/src/com/intellij/util/ReflectionUtil.java b/platform/util/src/com/intellij/util/ReflectionUtil.java index 307e0998c182..98a985eef23a 100644 --- a/platform/util/src/com/intellij/util/ReflectionUtil.java +++ b/platform/util/src/com/intellij/util/ReflectionUtil.java @@ -39,7 +39,7 @@ public class ReflectionUtil { @Nullable public static Type resolveVariable(TypeVariable variable, final Class classType, boolean resolveInInterfacesOnly) { final Class aClass = getRawType(classType); - int index = ArrayUtil.find(ReflectionCache.getTypeParameters(aClass), variable); + int index = ArrayUtilRt.find(ReflectionCache.getTypeParameters(aClass), variable); if (index >= 0) { return variable; } @@ -63,7 +63,7 @@ public class ReflectionUtil { } if (resolved instanceof TypeVariable) { final TypeVariable typeVariable = (TypeVariable)resolved; - index = ArrayUtil.find(ReflectionCache.getTypeParameters(anInterface), typeVariable); + index = ArrayUtilRt.find(ReflectionCache.getTypeParameters(anInterface), typeVariable); if (index < 0) { LOG.error("Cannot resolve type variable:\n" + "typeVariable = " + typeVariable + "\n" + "genericDeclaration = " + declarationToString(typeVariable.getGenericDeclaration()) + "\n" + "searching in " + declarationToString(anInterface)); @@ -73,7 +73,7 @@ public class ReflectionUtil { return Object.class; } if (type instanceof ParameterizedType) { - return getActualTypeArguments(((ParameterizedType)type))[index]; + return getActualTypeArguments((ParameterizedType)type)[index]; } throw new AssertionError("Invalid type: " + type); } @@ -81,7 +81,7 @@ public class ReflectionUtil { return null; } - public static String declarationToString(final GenericDeclaration anInterface) { + public static String declarationToString(@NotNull GenericDeclaration anInterface) { return anInterface.toString() + Arrays.asList(anInterface.getTypeParameters()) + " loaded by " + ((Class)anInterface).getClassLoader(); @@ -118,9 +118,9 @@ public class ReflectionUtil { return (Class)((ParameterizedType)type).getRawType(); } if (type instanceof TypeVariable && classType instanceof ParameterizedType) { - final int index = ArrayUtil.find(ReflectionCache.getTypeParameters(aClass), type); + final int index = ArrayUtilRt.find(ReflectionCache.getTypeParameters(aClass), type); if (index >= 0) { - return getRawType(getActualTypeArguments(((ParameterizedType)classType))[index]); + return getRawType(getActualTypeArguments((ParameterizedType)classType)[index]); } } } else { @@ -307,21 +307,30 @@ public class ReflectionUtil { } } + /** + * @see com.intellij.ide.plugins.PluginManager#initPlugins(com.intellij.ide.StartupProgress) + */ + @SuppressWarnings("JavadocReference") + static volatile Function PLUGIN_CLASS_LOADER_DETECTOR = FunctionUtil.nullConstant(); + /** * Returns the class this method was called 'framesToSkip' frames up the caller hierarchy. + * JDK used to have {@link sun.reflect.Reflection#getCallerClass(int)} until jdk 1.8 build 87. + * So we have to resort to slow stack unwinding. * * NOTE: * Extremely expensive! * Please consider not using it. * These aren't the droids you're looking for! */ + @SuppressWarnings("JavadocReference") @Nullable public static Class getCallerClass(int framesToSkip) { - int adjustedFramesForThisCall = framesToSkip/*+1*/; // take into account this method frame + int frames = framesToSkip; StackTraceElement[] stackTrace = new Throwable().getStackTrace(); String className = null; - for (int i = 1; i<=adjustedFramesForThisCall; i++) { + for (int i = 1; i<=frames; i++) { if (i >= stackTrace.length) { break; } @@ -330,10 +339,10 @@ public class ReflectionUtil { if (className.equals("java.lang.reflect.Method") || className.equals("sun.reflect.NativeMethodAccessorImpl") || className.equals("sun.reflect.DelegatingMethodAccessorImpl")) { - adjustedFramesForThisCall++; + frames++; continue; } - if (i == adjustedFramesForThisCall) { + if (i == frames) { break; } } @@ -344,15 +353,21 @@ public class ReflectionUtil { className = ReflectionUtil.class.getName(); } - //Class realClass = Reflection.getCallerClass(adjustedFramesForThisCall+1); - //if (!realClass.getName().equals(className)) { - // int i = 0; - //} try { return Class.forName(className); } catch (ClassNotFoundException ignored) { } + ClassLoader pluginClassLoader = PLUGIN_CLASS_LOADER_DETECTOR.fun(className); + if (pluginClassLoader != null) { + try { + return Class.forName(className, false, pluginClassLoader); + } + catch (ClassNotFoundException ignored) { + } + } + LOG.error("Could not load class '" + className + "' using classLoader " + ReflectionUtil.class.getClassLoader() + "." + + (stackTrace[1].getClassName().equals("com.intellij.openapi.util.IconLoader") ? " Use getIcon(String, Class) instead." : "")); return null; } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeManagerImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeManagerImpl.java index 8ffa72209ea7..a5d4a011ae42 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeManagerImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeManagerImpl.java @@ -30,10 +30,10 @@ import com.intellij.openapi.vcs.ProjectLevelVcsManager; import com.intellij.openapi.vcs.VcsRoot; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Consumer; +import com.intellij.util.ReflectionUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import sun.reflect.Reflection; import java.util.ArrayList; import java.util.Collection; @@ -105,7 +105,7 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr if ((! myProject.isOpen()) || myProject.isDisposed() || myVcsManager.getAllActiveVcss().length == 0) return; if (LOG.isDebugEnabled()) { - LOG.debug("everything dirty: " + Reflection.getCallerClass(1)); + LOG.debug("everything dirty: " + ReflectionUtil.getCallerClass(1)); } final LifeDrop lifeDrop = myLife.doIfAlive(new Runnable() { @@ -169,7 +169,7 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr if (! haveStuff) return; if (LOG.isDebugEnabled()) { - LOG.debug("paths dirty: " + filesConverted + "; " + dirsConverted + "; " + Reflection.getCallerClass(2)); + LOG.debug("paths dirty: " + filesConverted + "; " + dirsConverted + "; " + ReflectionUtil.getCallerClass(2)); } takeDirt(new Consumer() { @@ -231,7 +231,7 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr if (! haveStuff) return; if (LOG.isDebugEnabled()) { - LOG.debug("files dirty: " + filesConverted + "; " + dirsConverted + "; " + Reflection.getCallerClass(2)); + LOG.debug("files dirty: " + filesConverted + "; " + dirsConverted + "; " + ReflectionUtil.getCallerClass(2)); } takeDirt(new Consumer() { @@ -257,7 +257,7 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr final AbstractVcs vcs = myGuess.getVcsForDirty(file); if (vcs == null) return; if (LOG.isDebugEnabled()) { - LOG.debug("file dirty: " + file + "; " + Reflection.getCallerClass(2)); + LOG.debug("file dirty: " + file + "; " + ReflectionUtil.getCallerClass(2)); } final VcsRoot root = new VcsRoot(vcs, file); takeDirt(new Consumer() { @@ -274,7 +274,7 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr final AbstractVcs vcs = myGuess.getVcsForDirty(file); if (vcs == null) return; if (LOG.isDebugEnabled()) { - LOG.debug("file dirty: " + file + "; " + Reflection.getCallerClass(1)); + LOG.debug("file dirty: " + file + "; " + ReflectionUtil.getCallerClass(1)); } final FilePathUnderVcs root = new FilePathUnderVcs(file, vcs); takeDirt(new Consumer() { @@ -295,7 +295,7 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr final AbstractVcs vcs = myGuess.getVcsForDirty(dir); if (vcs == null) return; if (LOG.isDebugEnabled()) { - LOG.debug("dir dirty recursively: " + dir + "; " + Reflection.getCallerClass(2)); + LOG.debug("dir dirty recursively: " + dir + "; " + ReflectionUtil.getCallerClass(2)); } final VcsRoot root = new VcsRoot(vcs, dir); takeDirt(new Consumer() { @@ -312,7 +312,7 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr final AbstractVcs vcs = myGuess.getVcsForDirty(path); if (vcs == null) return; if (LOG.isDebugEnabled()) { - LOG.debug("dir dirty recursively: " + path + "; " + Reflection.getCallerClass(2)); + LOG.debug("dir dirty recursively: " + path + "; " + ReflectionUtil.getCallerClass(2)); } final FilePathUnderVcs root = new FilePathUnderVcs(path, vcs); takeDirt(new Consumer() {