ClassCastException when accessing JAR resources in Clojure dependency for JetBrains Plugin

Answered

Hello, I am developing a plugin for IntelliJ that depends on my company's proprietary library (written in Clojure). However, I keep encountering the following error when trying to access resources from the Clojure dependency:

Caused by: java.lang.ClassCastException: class com.intellij.util.lang.ZipResourceFile$MyUrlConnection cannot be cast to class java.net.JarURLConnection (com.intellij.util.lang.ZipResourceFile$MyUrlConnection is in unnamed module of loader 'app'; java.net.JarURLConnection is in module java.base of loader 'bootstrap')
    at clojure.lang.RT.lastModified(RT.java:396)
    at clojure.lang.RT.load(RT.java:442)
    at clojure.lang.RT.load(RT.java:424)
    at clojure.lang.RT.<clinit>(RT.java:338)
    ... 82 more

The error seems to originate from the following code in the Clojure library, where resources are accessed using JarURLConnection:

static public long lastModified(URL url, String libfile) throws IOException {
    URLConnection connection = url.openConnection();
    try {
        if (url.getProtocol().equals("jar"))
            return ((JarURLConnection) connection).getJarFile().getEntry(libfile).getTime();
        else
            return connection.getLastModified();
    }
    finally {
        InputStream ins = connection.getInputStream();
        if (ins != null)
            ins.close();
    }
}

It looks like the internal class loader uses com.intellij.util.lang.ZipResourceFile$MyUrlConnection instead of java.net.JarURLConnection, causing the cast to fail.

I'm wondering if there is a recommended workaround for this issue. Am I missing any configuration or setup in the plugin environment that would help resolve this? 
I was considering forking a custom implementation of the Clojure dependency where this condition is adapted to avoid casting issues, but I am not in control of the API I am using, so this isn't a viable long-term solution for me.

 

Any guidance on this issue would be greatly appreciated!

1
4 comments

Sorry for the delay.

There is idea.mimic.jar.url.connection  system property (you can try to set it explicitly and see if it works). It is by default false for core classloader and depends on val mimicJarUrlConnection = !module.isBundled && module.vendor != "JetBrains" for plugin classloader.

Please try debugging `com.intellij.util.lang.ClassPath#ClassPath` constructor for your plugin otherwise.

0

Hello Yann Cebron, I've tried setting 

-Didea.mimic.jar.url.connection=true

in Help > Edit Custom VM Options, however when I'm debugging com.intellij.util.lang.URLClassLoader#UrlClassLoader, I can see that 

this.classPath = new ClassPath(builder.files, builder, resourceFileFactory, mimicJarUrlConnection);

has false set for mimicJarUrlConnection. Am I missing something?

0

What's the value of `mimicJarUrlConnection` on `new ClassPath` creation for your plugin? We have logic `val mimicJarUrlConnection = !module.isBundled && module.vendor != "JetBrains"` and I am wondering why it doesn't help in your case.

0

 Vladimir Krivosheev 

When debugging this:

    protected UrlClassLoader(@NotNull @NotNull Builder builder, @Nullable Function<Path, ResourceFile> resourceFileFactory, boolean isParallelCapable) {
		...
        this.classPath = new ClassPath(builder.files, builder, resourceFileFactory, mimicJarUrlConnection);
        ...
    }

    mimicJarUrlConnection is false.  I’m unsure how to check the values of module.isBundled or module.vendor in this context.

0

Please sign in to leave a comment.