Is it possible to inherit reflective access to anonymous child module?

Viewed 112

Let's say I write a module/library named mylib that uses an internal/hidden third party module/library named internal. The API of mylib does not expose any functionality from that third party library and it may be replaced by something else in the near future.

module mylib {
    requires internal;
    exports some.pgk.from.mylib;
}

But here is my problem. The internal library needs reflective access to the classes/objects that are passed through the public API of mylib to do it's work.

An example application/module named app that utilizes my library would have to define the following moduleinfo.java

module app {
    requires mylib;
    opens some.pkg.from.app to internal;
}

But this is bad, because it exposes the internally used module to the users of my library, and I would not be able to remove/change it in the future without breaking app. Ideally i would like to allow the module internal reflective access to all modules that are open to mylib instead:

module app {
    requires mylib;
    opens some.pkg.from.app to mylib; // also open to internal without naming it
}

Can this be done with the current (Java 17) module system? Is there a good workaround in case this is not possible?

1 Answers

I see four possible solutions:

  1. Call appModule.addOpens("some.pkg.from.app", internalModule) from mylib.

    If this module has opened a package to at least the caller module then update this module to open the package to the given module.

    This works because myapp has opened the package some.pkg.from.app to the mylib module - which is the caller module.
    You have to repeat it for every package that has been opened to your module.
    If you don't deal with module layers, you can reflectively enumerate all packages that are open to your module.
    If you have to deal with layers - you have to enumerate all the layers - and those can be added at runtime.

  2. Pass a Consumer<AccessibleObject> makeAccessible = ao -> ao.setAccessible(true); to internal.

    This works because now the caller of setAccessible is now mylib.
    (Or myapp, if the consumer came from there.)

  3. Pass a full privilege lookup from mylib to internal.

    You can use this Lookup to call AccessibleObject.setAccessible.
    Or maybe do something else, like calling Module.addOpens.

  4. Pass a full privilege lookup from myapp to mylib, which in turn passes it to internal.

    The benefit here is that you do not need to declare that you open a package - as any MethodHandle you lookup through the passed lookup will work as if it was called from myapp.
    You may even be able to restrict this lookup.

Related