Optional plugin dependency

I'm writing a plugin A which optionally uses a service provided by plugin B. So plugin A has some more features if plugin B is installed as well, but it still works (with a limited feature set) without plugin B.

Giving plugin A access to plugin B's classes by means of the depends tag doesn't work, since then plugin B isn't optional anymore. Using the extensions framework doesn't work either, since I still need a common class known to both plugins.

Is there any clean solution to this problem? Or do I really have to use reflection for it?

9 comments
Comment actions Permalink

It not possible at all. Even via reflection. Plugin A will not have access to classes of plugin B without depends tag.

But i guess, if you used depends tag, IntelliJ IDEA will control that you have both plugins installed.

0
Comment actions Permalink

It not possible at all. Even via reflection. Plugin A
will not have access to classes of plugin B without
depends tag.


With reflection and some ugly code it's no problem. See the code snippet below.

But i guess, if you used depends tag, IntelliJ IDEA
will control that you have both plugins installed.


IDEA displays an ugly error message and doesn't start up if the second plugin is missing. And anyway that's not what I want. I don't want users to be forced to install plugin B, it should be optional.

Here's the solution using reflection:

[]{Service.class}, new InvocationHandler() {
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            return extension.getClass().getMethod(method.getName(), method.getParameterTypes()).invoke(extension, args);
        }
    });
    service.getService();
}]]>

0
Comment actions Permalink

Hm...
Why ugly code? :)
Nice trick! :)

Just forgot about proxies. But, this proxy will used system classloader. Maybe for extensions is used different algorithm, but system classloader have no access to plugins classes.

0
Comment actions Permalink

Just forgot about proxies. But, this proxy will used
system classloader. Maybe for extensions is used
different algorithm, but system classloader have no
access to plugins classes.


I'm calling this code from inside a class of plugin A, and the classloader used to create the proxy class is passed as getClass().getClassLoader(). Therefore the proxy has access to all classes of plugin A. And access to the classes of plugin B, well, that's done by reflection.

0
Comment actions Permalink

This is http://jetbrains.net/jira/browse/IDEA-6284

Martin Fuhrer wrote:

I'm writing a plugin A which optionally uses a service provided by plugin B. So plugin A has some more features if plugin B is installed as well, but it still works (with a limited feature set) without plugin B.

Giving plugin A access to plugin B's classes by means of the depends tag doesn't work, since then plugin B isn't optional anymore. Using the extensions framework doesn't work either, since I still need a common class known to both plugins.

Is there any clean solution to this problem? Or do I really have to use reflection for it?

0
Comment actions Permalink

Exactly! I knew I'm not the first one... :)

This is http://jetbrains.net/jira/browse/IDEA-6284

Martin Fuhrer wrote:

I'm writing a plugin A which optionally uses a

service provided by plugin B. So plugin A has some
more features if plugin B is installed as well, but
it still works (with a limited feature set) without
plugin B.


Giving plugin A access to plugin B's classes by

means of the depends tag doesn't work, since then
plugin B isn't optional anymore. Using the extensions
framework doesn't work either, since I still need a
common class known to both plugins.


Is there any clean solution to this problem? Or do

I really have to use reflection for it?


0
Comment actions Permalink

Hmm... Does it mean that IDEA's SystemClassloader have access to all plugin classes?

0
Comment actions Permalink

Hmm... Does it mean that IDEA's SystemClassloader
have access to all plugin classes?


No, IDEA's system classloader has only access to IDEA's internal classes and OpenAPI. But since I'm calling the code from inside plugin A I'm not using IDEA's system classloader but the classloader of plugin A. I don't have access to the classes of plugin B, neither has IDEA's system classloader. That's why I'm using reflection to invoke methods there.

0
Comment actions Permalink

It is a very old question but I thought it could be good to leave a comment here to redirect other plugin developers to the up-to-date solution.

In such case, you can use optional dependency mechanism, which is explained here: https://www.jetbrains.org/intellij/sdk/docs/basics/plugin_structure/plugin_dependencies.html#optional-plugin-dependencies.

 

 

0

Please sign in to leave a comment.