gtache / intellij-lsp

Plugin adding Language Server Protocol support for IntelliJ

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Linkage error

jeffmaury opened this issue · comments

I have build an LSP plugin that registers an node based LSP server.
My plugin has the sole dependency on the intellij-lsp plugin.
When I test it through the Gradle runIde task, everything is fine.
Now I install the zip file into an installation of IJ or WebStorm, after installing the LSP plugin as well, when I open a file that is supported by my plugin (pom.xml,...), I get this error:

java.lang.LinkageError: loader constraint violation: loader (instance of com/intellij/ide/plugins/cl/PluginClassLoader) previously initiated loading for a different type with name "org/eclipse/lsp4j/services/LanguageServer"
	at java.lang.Class.getDeclaredMethods0(Native Method)
	at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
	at java.lang.Class.getDeclaredMethods(Class.java:1975)
	at org.eclipse.lsp4j.jsonrpc.services.AnnotationUtil.findRpcMethods(AnnotationUtil.java:63)
	at org.eclipse.lsp4j.jsonrpc.services.ServiceEndpoints.getSupportedMethods(ServiceEndpoints.java:90)
	at org.eclipse.lsp4j.jsonrpc.services.ServiceEndpoints.getSupportedMethods(ServiceEndpoints.java:82)
	at org.eclipse.lsp4j.jsonrpc.Launcher$Builder.getSupportedMethods(Launcher.java:370)
	at org.eclipse.lsp4j.jsonrpc.Launcher$Builder.createJsonHandler(Launcher.java:381)
	at org.eclipse.lsp4j.jsonrpc.Launcher$Builder.create(Launcher.java:305)
	at org.eclipse.lsp4j.launch.LSPLauncher.createClientLauncher(LSPLauncher.java:106)
	at com.github.gtache.lsp.client.languageserver.wrapper.LanguageServerWrapperImpl.start(LanguageServerWrapperImpl.scala:300)
	at com.github.gtache.lsp.client.languageserver.wrapper.LanguageServerWrapperImpl.connect(LanguageServerWrapperImpl.scala:172)
	at com.github.gtache.lsp.PluginMain$.$anonfun$editorOpened$2(PluginMain.scala:137)
	at com.github.gtache.lsp.PluginMain$.$anonfun$editorOpened$2$adapted(PluginMain.scala:133)
	at scala.Option.foreach(Option.scala:257)
	at com.github.gtache.lsp.PluginMain$.$anonfun$editorOpened$1(PluginMain.scala:133)
	at com.intellij.openapi.application.impl.ApplicationImpl$1.run(ApplicationImpl.java:314)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)

I have not clue how to fix it. Any idea ?

Seems I found the problem: JetBrains products bundle LSP4J version 0.3.0 and we're using 0.6.0. But the plugin class loader gives preference to the JetBrains distribution. We should probably do some kind of shading, will try to play with shadowJar

Realize that the LSP4J classes may be exposed to plugin developers so that would be a breaking change. Looking for an alternate solution

OK I have more details: my plugin extends the LanguageClientImpl in order to implement LSP specific notifications. It overrides some methods and thus import some LSP4J classes. But IJ creates a class loader for each plugin and according to the docs, the class loader gives preferences to JAR in the plugin when loading a class (thus it's ok for intellij-lsp to have LSP4J different from the one bundled by IJ)
The problem is when a plugin depends on another plugin (the case for my plugin). In that case, the class loader created is assigned to my plugin has 2 parent class loaders in an array the first one being the IJ one the second one is the intellij-lsp one so when we load LSP4J we will get them from IJ.

Closing it as it's a IJ classloading issue and found a (dirty) way to fix it.