JetBrains / intellij-ui-test-robot

The library allows you to write and execute UI tests among IntelliJ IDEA. You can test your Plugin.

Home Page:https://jetbrains-platform.slack.com/archives/C026SVA9MMM

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Is it possible for switch the classloader in Rhino code?

PawelLipski opened this issue · comments

AFAICS Rhino executed via com.intellij.remoterobot.RemoteRobot#callJs(java.lang.String, boolean) (or runJs) is executed with PluginClassLoader for Robot server as context classloader. Attempt to setContextClassLoader to the PluginClassLoader of the tested plugin's don't seem to work:

Rhino code:

  const pluginId = PluginId.getId('com.virtuslab.git-machete');
  const pluginClassLoader = PluginManagerCore.getPlugin(pluginId).getPluginClassLoader();
  Thread.currentThread().setContextClassLoader(pluginClassLoader);
  const providerClass = Class.forName('com.virtuslab.gitmachete.frontend.ui.providerservice.SelectedGitRepositoryProvider'); // some class from my plugin

results in:

        java.lang.Throwable: Wrapped java.lang.ClassNotFoundException: com.virtuslab.gitmachete.frontend.ui.providerservice.SelectedGitRepositoryProvider
 PluginClassLoader(plugin=PluginDescriptor(name=Robot server, id=com.jetbrains.test.robot-server-plugin, 
descriptorPath=plugin.xml, path=/tmp/ide-probe/instances/intellij-instance-2022.1--QLOZN9sdT3iaH2Vwk9Djew/plugins/robot-server-plugin, 
version=0.11.13, package=null, isBundled=true), packagePrefix=null, instanceId=20, state=active)

So it seems that Rhino uses Robot server's PluginClassLoader, no matter what setContextClassLoader points to. Is there any way around that?

Hi, can you try to do it this way?

  const pluginId = PluginId.getId('com.virtuslab.git-machete');
  const pluginClassLoader = PluginManagerCore.getPlugin(pluginId).getPluginClassLoader();
  const providerClass = Class.forName('com.virtuslab.gitmachete.frontend.ui.providerservice.SelectedGitRepositoryProvider', true, pluginClassLoader); // some class from my plugin

Yes! I can alternatively load a single class explicitly pointing to pluginClassLoader also by:

  const providerClass = pluginClassLoader.loadClass('com.virtuslab.gitmachete.frontend.ui.providerservice.SelectedGitRepositoryProvider', true, pluginClassLoader); // some class from my plugin

but what I'm aiming at is to switch the default classloader used by Rhino! I tried Thread.currentThread().setContextClassLoader(pluginClassLoader); but to now avail, Rhino still seems to use the classloader associated with Robot Server plugin, not the plugin I've pointed to ☹️

So I can provide a workaround by using more reflection (relying on Class and Method objects in Rhino code)... but curious if it's possible to just re-wire Rhino to use a different classloader completely 🤔

I've tried to pass plugin classloader to rhino execution context and unfortunately it failed with Loader can not resolve Rhino classes error.
As for setContextClassLoader way, seems that Rhino caches it and keeps using the one was set on context creating. And if not I guess we would have the same error.
It might work if we run Robot Server not as a plugin but in the premain of Idea launching somewhere on early stage and it would be loaded by classloader which would be an ancestor for all plugin classloaders. But I guess it's to much for this task

Okay, that's roughly what I was afraid of... lemme close this issue then and fall back to explicit pluginClassLoader.loadClass(...) calls indeed