How to load resources from base module

Peter Levart peter.levart at gmail.com
Thu May 18 08:31:22 UTC 2017


Hi Wolfgang,

You are using instance method Class#getResource(String) which states in 
javadoc:

    /If this class is in a named Module then this method will attempt to
    find the resource *in the module*./

"this class" is the class represented by the Class object which is the 
receiver of the instance method invocation. In your below case, when you 
invoke getClass().getResource(), "this class" represents the runtime 
class of "this" object (ClassB in your case, since you create an 
instance of ClassB), but when you invoke ClassA.class.getResource(), 
"this class" represents ClassA.

So 1st attempt succeeds, bacause you are looking for a resource in the 
correct module (which contains it), while the 2nd attempt fails, because 
you are looking into the wrong module which doesn't contain the resource.

Class#getResource(String) instance method, in case of "this class" being 
in a named module, delegates to special (new in JDK 9) module's class 
loader method:

    /This is done by delegating to the module's class loader
    findResource(String,String) method, invoking it with the module name
    and the absolute name of the resource./

In addition to looking for resource "only" in a particular module, 
standard resource encapsulation rules apply:
//

    /Resources in named modules are subject to the rules for
    encapsulation specified in the Module getResourceAsStream method and
    so this method returns null when the resource is a non-".class"
    resource in a package that is not open to the caller's module./

So you are correctly opening the com.b.resources package to module com.a 
(which is the caller's module - the module containing the class with 
code invoking the Class::getResource(String) method). You just have to 
look up into the correct module too. Or if you don't want to bother with 
identifying the module where the resource lives but just with the 
"resource path" of the resource, then you can still use the 
ClassLoader#getResource(String) method, which will look up the resource 
in the class loader (with parents 1st delegation order) regardless of in 
which module the resource lives. Standard resource encapsulation rules 
still apply though.

Regards, Peter

On 05/18/2017 09:16 AM, wzberger wrote:
> Here is a simple example which demonstrates the issue - still 
> something missing?
>
> //------------ MODULE A
> module com.a {
>   exports com.a;
> }
>
> package com.a;
>
> public class ClassA{
>   public ClassA() {
>     //success
> System.out.println(getClass().getResource("/com/b/resources/test.txt"));
>
>     //fail - null
> System.out.println(ClassA.class.getResource("/com/b/resources/test.txt")); 
>
>   }
> }
>
> //------------ MODULE B
> module com.b {
>   requires com.a;
>   exports com.b;
>   opens com.b.resources to com.a;
> }
>
> package com.b;
>
> import com.a.ClassA;
>
> public class ClassB extends ClassA{
>   public ClassB(){
>   }
> }
>
> //------------ MODULE C
> module com.c {
>   requires com.a;
>   requires com.b;
> }
>
> package com.c;
>
> import com.b.ClassB;
>
> public class ModuleTest{
>   public static void main(String[] args){
>     new ClassB();
>   }
> }
>
> -Wolfgang
>
>> On 17/05/2017 18:22, wzberger wrote:
>>
>>> The resources are mainly images and XML files, located in separate 
>>> packages. By adding the opens clause it works fine for Class B 
>>> (called from module a) - however, it does not work for Class A 
>>> (returns null). I wonder if this is the intended behavior?
>> I'm not aware of any bugs in this area. Can you expand a bit more on 
>> "returns null" case. If the packages are open as you say then code in 
>> both `a` and `b` should be able to locate the resources in `b`.
>>
>> -Alan
>>
>>
>



More information about the jigsaw-dev mailing list