I’d like to enable some unique functionality in my module depending on whether Vision or Perspective are installed, and this unique functionality needs to access the SDK for the respective module (i.e. if Perspective is installed, my module will need to access classes in com.inductiveautomation.perspective. If Perspective is not installed, it should hide all Perspective related functions).
With reflective access only, yes. You can use your context to dynamically look up another module, which gives you that module’s gateway hook. From that, you can get its classloader, and ask that classloader to retrieve classes for you. To access more than trivial stuff, you will need “shim” classes in your module that delegate to the real, reflectively retrieved classes. Nowhere in your own classes can you refer to the actual Perspective classes–they won’t be available at runtime.
Uhm, I don't think you can do that. The whole point of declaring a dependency is to have your module's classloader created under that module's classloader.
So, I was under the same impression as Phil, which lead me down a bit of a rabbit hole, but it turns out specifically because of this lack of multi-inheritance, we changed things around on our end. So if you declare, say, Perspective, as a “dependency” of your module, even if Perspective isn’t found your module will still be given a chance to load. The main thing is that Perspective is guaranteed to load before your module, preventing things like trying to register components with Perspective’s component registry before it exists. That’s exactly why we had to change things - the Reporting module adds components to Perspective, but we want Perspective and Reporting to be able to be installed independently.
Wait, does this mean I can make my NoteChart module conditionally supply a component to the Reporting module? (I hadn’t tackled that because I thought the classloader situation would be a nightmare.)
Your module ClassLoader now has a List of parent ClassLoader that are consulted in the order they are present in the list. It’s not really that tricky.
The trickier part was that all the module management code was rewritten to use a proper graph to track and derive dependencies.
So, I can declare any module dependencies I want access to? Then I’d just have to make the hook look up the optional classes dynamically, skipping on ClassNotFound …
If your code that references an optional module dependency is well enough separated you can avoid reflection all together by checking if the other module is installed during startup and then if it’s not, be sure never to invoke that code that references classes that will fail to load.