0

I'm currently working on a program that is taken in by another program as a plugin. The parent program (the one that takes in the plugin) has it's own dependencies, in my case, the one of concern is Guava. The parent has a version of 21.0, while the plugin I'm creating has a dependency that requires version 20.0 and doesn't seem to cooperate with the newer version, and no matter what version is put in the pom of the plugin, it still seems to be using the parent version of 21.

Tl;dr: Is there any way with Maven to use a lower version (20.0 in my case) of a dependency when a parent program is using a higher version? (Is this even possible at all since the plugin is likely taken in with reflection and therefore will always use the parent dependency? The plugin is built with dependencies included.)

cameronlund4
  • 537
  • 1
  • 5
  • 27
  • 1
    You can't have use two versions of the same class side by side, unless they're in different packages. You may be able to extract the older version of that particular class/package to your own project for the sake of the dependent library, but it'll be used by your own code as well. – shmosel Jun 26 '17 at 20:43

1 Answers1

1

Maven is a build tool, it does not control your dependencies at runtime (i.e. when the application is already running). So this is not a maven issue, hence maven is not the place to look for the solution.

If you have no control on the hosting application but only on your plugin, then you have no choice rather than use the same versions of the dependencies your plugin and the application have in common.

If you own (control) both the hosting application and the plugin then you need to handle the plugins correctly. It is easy to say, but harder to do...
You should look for existing frameworks that already solve it for you.
Some examples are: OSGi, JPF, PF4J, and there are more...
Also, take a look in the following SOF question: Best way to build a Plugin system with Java

In a nutshell-

This is a classical issue of supporting plugins in an application.
The best solution, in my opinion, is to isolate the plugin from the hosting app. This can be achieved using different class loaders and of course - reflection.

Your application is running and its classes are loaded in the "regular" way - nothing fancy here. But, in order to isolate the plugin's code from your application's dependencies at runtime, you need to load the plugin classes and dependencies using a different class loader (e.g. a URLClassLoader). It is very important that this class loader does not have your application's class loader as a parent, otherwise you will still face the versioning issue with conflicts (as you have now).

EDIT:
Another option for handling this situation when you only have control over your plugin-
You can, for example, write your own class loader and use it in the entry-point of your plugin (so that all plugin classes except for the entry-point are loaded using this class loader). To do this you need to write the class loader in a way that it first tries to load a class from your plugin jar and then delegates to its parent loader. This is feasible (and actually not too difficult) but is going against the class loaders contract (first delegate to parent, load by yourself only if not found).
I still think it is much better and more robust to make sure to use the same dependencies, specially when the application has a newer version...

yinon
  • 1,418
  • 11
  • 14
  • Thanks, sadly the service taking the plugin is out of my control and I have to deal with the current system. So it wouldn't be possible to use a separate class loader to solve this issue still? My knowledge of them is limited, but could the lower version source be stored in the plugin jar and referenced only when loading classes from the lower requiring dependency? – cameronlund4 Jun 26 '17 at 21:31
  • You can, for example, write your own class loader and use it in the entry-point of your plugin (so that all plugin classes except for the entry-point are loaded using this class loader). To do this you need to write the class loader in a way that it first tries to load a class from your plugin jar and then delegates to its parent loader. This is feasible (and actually not too difficult) but is going against the class loaders contract. – yinon Jun 26 '17 at 21:39