MethodHandles.Lookup.defineResource?

Peter Levart peter.levart at gmail.com
Wed Aug 29 09:37:46 UTC 2018


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



More information about the core-libs-dev mailing list