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




Reply via email to