mercredi 28 août 2019

Java - Relocate references at runtime

So first off I know that you can relocate all references your compiled jar with various shadow plugins on different build systems. I know how that works and am already using it. However I ran into a problem where I can't do that at compile time.

I'll simplify my situation so it's easier to understand (but I'll explaining the full picture at the bottom, in case you are curious).
I'm writing a plugin for two different (but similar) systems (one jar forall). Those platforms are in charge of starting the underlying software and loading/starting all plugins (so I don't have control over the application).
Platform A offers me a library (let's call it com.example.lib). And so does platform B. But it decided to relocate it to org.b.shadow.com.example.lib.
Now in the core code (the code used on both platforms) of my plugin I use the library. Now while I can detect on which platform I am on, I currently do not know how I can rewrite all references in my code to the library at runtime so it works on platform B.

From what I've found it seems like I need to use a custom ClassLoader to achieve that. The issue here being that I don't know I could make the runtime use my custom ClassLoader. Or where to start really.
One important thing is that those relocations may only affect references in classes from my packages (me.brainstone.project for example).
Another dependency I use (and have shaded in) uses ASM and ASM Commons, so if it is possible doing it with those, that would be amazing!

So in summary. I would like to optionally relocate references (to other classes) in only my classes at runtime.


Now here is a a bit more detailed explanation of my setup.
Fist I'd like to preface that I am aware that I can just create two different jars for the different platforms. And I am already doing that. But since surprisingly many people can't seem to figure that out and I'm getting tired of explaining it over and over again (those are the people that wouldn't read docs to save their lives) I'd like to just offer a single jar for both, even if it means I need to spend a significant time on getting it to work (I much prefer this over constantly explaining it).
Now my actual setup looks like this: On platform A the library is provided but on platform B it isn't. I know that other plugins often use the library by shading it in (many not relocating causing all kinds of issues). So to prevent any conflicts I download the library, relocate the classes inside that jar with jar-relocator and then inject it into the classpath using reflections. Downside in this case I currently cannot use the library if it's relocated. That's why I'd like to change the references in my code at runtime. And it also explains why I don't want to change the references of other classes, because I don't want to accidentally break those other plugins. I also think that if I can somehow use my own ClassLoader that I don't need to inject jars into the main ClassLoader because then I can just tell that ClassLoader to use the additional jars without having to resort to reflections.
But as I said, from what I understand the problem is the same as in the simplified version.





Aucun commentaire:

Enregistrer un commentaire