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