MethodHandles.Lookup.defineResource? (original) (raw)
Peter Levart peter.levart at gmail.com
Wed Aug 29 09:37:46 UTC 2018
- Previous message: MethodHandles.Lookup.defineResource?
- Next message: MethodHandles.Lookup.defineResource?
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Hi Stephen,
On 08/28/2018 11:21 PM, Stephen Colebourne wrote:
On Tue, 28 Aug 2018 at 20:43, Peter Levart <peter.levart at gmail.com> wrote:
Do you think this functionality is really needed in programs? It seems useful just for testing. Why do people add classes at runtime? Might they not reasonably want to also add resources for those classes? The key point here is that this all worked before Java 9 modules. But since resources are now encapsulated, adding a new ClassLoader is no longer sufficient to inject a resource, as it doesn't get the right module encapsulation that way.
This all worked before Java 9 module by adding a new ClassLoader only if all of the following was true:
- you added a new ClassLoader that resolved a resource
- you passed the instance of that loader to the library method
- the library method used this loader instance to resolve the resource
I claim that this still works in Java 9 regardless of whether the library method is located in a module or not.
Before Java 9 modules you couldn't just magically "inject" a resource by adding new ClassLoader if the library code used Class.getResource() with a Class instance of some class residing in the library itself. For this to work, the library class would also have to be loaded by this new ClassLoader or by a child of this new ClassLoader. The assumption that the library is loaded by the same (or even child of) class loader that also resolves the resources of user artifacts is easily broken even before Java 9 modules. Imagine deploying user artifacts as a plug-in in some container while the library is in the parent "container" class-loader.
My experience more generally has been that encapsulating resources in Java 9 modules has broken key assumptions in almost every library I maintain.
Every module decides by itself whether it wants to encapsulate resources or not. If some resources of some module are meant to be resolved by a library, they will not be encapsulated and your assumptions (of non-encapsulation) will still hold. The encapsulation is not a problem. The problem is the assumption that the library and user artifacts are always collocated (in the same class loader before JDK 9 or in the same module post JDK 9). The correct library API that resolves user artifact resources is always such that takes as a parameter either ClassLoader or Class of the user artifact. And this should still work even if user artifact is a module and/or if library is a module, providing that resources are not encapsulated in case of user artifact being a module.
Remember that library maintainers now have to to develop and test code like this for three different environments, Java 8, Java 9 classpath and Java 9 modulepath - its very painful.
I think that by testing artifact being a Java 9 module and being on Java 9 class path is enough. If it works in the later case it should also work in Java 8. At least as far as resolving resources is the concern.
So is there a way to achieve what you want for your test with existing API? Probably. I could have a separate maven module creating a separate modular jar file with the testing resource in it, and run the test using both the classpath mode and modulepath. I'm not going to be doing that as the benefits are too low compared to the cost.
Compared to that, what would be the testing setup if you had a .defineResource() method?
Regards, Peter
- Previous message: MethodHandles.Lookup.defineResource?
- Next message: MethodHandles.Lookup.defineResource?
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]