Hi Stephen,

On 08/28/2018 11:21 PM, Stephen Colebourne wrote:
On Tue, 28 Aug 2018 at 20:43, Peter Levart <peter.lev...@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

Reply via email to