Handle unstable external APIs in custom plugin

I am currently developing a Gradle plugin that interfaces with other plugins which are out of my control. In this context I am facing the issue that those external plugins regularly break their APIs in arbitrary ways and I can not directly influence their versions.

To make life easier for my plugin users I had the idea of providing a stub plugin that just checks the versions of the external plugins and pulls in a compatible version of the actual plugin logic as additional build-time dependency. Now I am struggling with resolving the dependency during the execution of the stub plugin. Despite a lot of trial-and-error I could not find a way to eagerly resolve the logic dependency and add it to the classpath so far. Actually the worker API provides a way to modify the classpath dynamically, but to my understanding this only works within tasks while I would need this functionality also outside of tasks.

Do you have any recommendations on how to implement this functionality? The following thread discusses this topic a bit, but does not provide a solution for my case:

Just have a class LogicForPluginXVersion2 and a class LogicForPluginXVersion3 in your plugin jar and use the according one at runtime.

Thanks for your suggestion. LogicForPluginXVersion2 and LogicForPluginXVersion3 then depend on different versions of the external plugin at the compile-time of the custom plugin. How would you handle multiple versions of the same dependency?

In this case probably just simply separate source sets as you didn’t want full feature variants.

An alternative would be to use reflection or some dynamic duck-typed language like Groovy.