ModuleResource was added in ver. 6.1. However, there is still no default ResourceLoader that uses ModuleResource.

So, I suggest to add default implementation of module ResourceLoader, for example, ModuleResourceLoader.

Comment From: snicoll

We cant' really proceed until we have a concrete use case that would justify adding such an implementation in the core framework. Please explain why you think it should be added.

Comment From: snicoll

I know about your issue. Since it looks like you've figured it out, what does the code look like?

Comment From: jhoeller

Arguably, the above is not a general pattern for JPMS applications but rather a workaround for limited external visibility in a JPMS setup. By design, resources in a package which has not been explicitly opened to another package are not visible by default. See e.g. https://stackoverflow.com/questions/46861589/accessing-resource-files-from-external-modules and https://stackoverflow.com/questions/48673769/java-9-module-system-resources-files-location for some common context.

Automatically parsing "classpath:..." locations into module usage through loading the class and accessing clazz.getModule() effectively works around the module system which tries to hide module-internal resources from general access. For ClassLoader.getResourceAsStream to find such resources as well, the containing package rather needs to be declared as open in the module descriptor, then regular ClassPathResource access should work fine for it. Alternatively, you may use Class.getResourceAsStream on a class from the target module, e.g. through the ClassPathResource(String, Class) constructor; this should work without an open declaration in the target module as well.

ModuleResource is able to see all resources for a given Module but this is meant to be used with code that is being configured with that Module or can programmatically derive it. If a dedicated ResourceLoader for it is desirable, then I rather envision a "module:moduleName/resourceName" location scheme where we do ModuleLayer.findModule(moduleName) and then build a straight ModuleResource for it. In practice, I rather recommend ClassPathResource with corresponding open declarations since this is portable across classpath and module path setups.

Comment From: jhoeller

You could try to declare module-info in modulex/moduley as generally open, or with an opens declaration for the package that you are trying to see. See https://stackoverflow.com/questions/46482364/what-is-an-open-module-in-java-9-and-how-do-i-use-it

Let me add that module layer usage is rather uncommon, and that's applying within the generally rather low usage of the module system in general. I have only really seen the module system being used with several modules at the same level in the boot layer. Specific concerns could apply for custom module layer scenarios.

Comment From: jhoeller

From a technical perspective, layers complicate the module system arrangement quite a bit and might have an effect on open declarations as well. Opening might only work at the peer module level in the same layer; I'm not familiar with the behavior in the details there myself. I suppose that's why we see module system layouts typically with the framework modules and the application modules in the same layer, closely interacting with each other.

That said, from a design perspective, even declaring a module as open is a bit of a workaround. A module should provide all of its relevant components to collaborating modules, not require other modules to peek into the internal resources of the module itself. A classpath:... location is arguably not module system friendly in general, trying to uniformly find globally available resources across all modules. So I would argue there is an inherent design conflict when using classpath:... for internal resources in a module, and in the case of layers, there may be no way to work around it - other than retrieving a resource from a Class that the module exports or from a Module reference directly, using ClassPathResource(String, Class) and ModuleResource respectively.

So generally speaking, ResourceLoader.getResource is a global lookup mechanism for resolving String locations. If you have programmatic access to the target component, you can build the Resource instance programmatically instead and pass it into a constructor or method of the target component. There is no need to go via a location String then. Common Spring components that accept resource locations usually also accept a Resource argument directly, and I would recommend the same for custom components.

Comment From: snicoll

I think Juergen forgot to close this so I am going to do that. See the above for the explanation.

Comment From: jhoeller

All in all, the only module-based resource lookup that seems straightforward in the module system is a "module:moduleName/resourceName" location scheme as mentioned above, and even that is questionable since it would still perform a hard lookup for an internal resource into a specific module. Architecturally, it would be idiomatic for a module to be self-contained in that respect as well, internally loading its resources or exposing them through dedicated facilities in the module.

From that perspective, we have no plans to act here. If some common need emerges among module system users in the Spring community, we are happy to revisit the topic, but for the time being we do not see consensus for module layer usage specifically.