"exports" directive does not open module's resources for dependent modules

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

"exports" directive does not open module's resources for dependent modules

Alexander Udalov
It looks like exporting a package from a (non-open) module with an
"exports" directive is not enough to ensure that
Module.getResourceAsStream on that module would load resources from
the module. Surprisingly, adding an "opens" directive for the same
package to the module declaration allows resources to be found.

I've put up a simple project to demonstrate this issue:
https://github.com/udalov/jigsaw-resources-are-not-exported

I'm wondering whether this is a bug or expected behavior? I would
expect that exporting a package would also open it not only for uses
of reflection, but for resource loading. I can't find anything related
to resources in the JLS, but p.7.7 "Module Declarations" gives a clear
impression that the "exports" directive gives a superset of
functionality of the "opens" directive in this regard.

Looking at the implementation of Module.getResourceAsStream, I see
that it calls Module.isOpen(String, Module) which returns false in
case the package name is exported by an "exports" directive. Which
raises another question: is Module.isOpen supposed to return whether
the package has been explicitly opened by an "opens" directive (or via
being in an open module)? Or is it supposed to also return true if the
package has been opened as a consequence of the fact that it's
exported (e.g. by an "exports" directive)? If the former is true, I
suppose there may be other usages of Module.isOpen, including in the
JDK, which (incorrectly) do not also check if the package name is
exported with Module.isExported.

The real-world case where I met this issue is in kotlin.stdlib where
we store metadata of Kotlin declarations in resource files per package
(only of those declarations which are not representable by JVM class
files), and kotlin.reflect (which is another module) reaches out to
those resource files in kotlin.stdlib. To make them reachable thus
along with every "exports XXX" in kotlin.stdlib's module declaration
I'm adding "opens XXX to kotlin.reflect", which looks cumbersome.

Thanks!

Alexander
Reply | Threaded
Open this post in threaded view
|

RE: "exports" directive does not open module's resources for dependent modules

Stephen Felts
"opens" is a superset of "exports".


-----Original Message-----
From: Alexander Udalov [mailto:[hidden email]]
Sent: Friday, September 15, 2017 8:14 AM
To: jigsaw-dev <[hidden email]>
Subject: "exports" directive does not open module's resources for dependent modules

It looks like exporting a package from a (non-open) module with an "exports" directive is not enough to ensure that Module.getResourceAsStream on that module would load resources from the module. Surprisingly, adding an "opens" directive for the same package to the module declaration allows resources to be found.

I've put up a simple project to demonstrate this issue:
https://github.com/udalov/jigsaw-resources-are-not-exported

I'm wondering whether this is a bug or expected behavior? I would expect that exporting a package would also open it not only for uses of reflection, but for resource loading. I can't find anything related to resources in the JLS, but p.7.7 "Module Declarations" gives a clear impression that the "exports" directive gives a superset of functionality of the "opens" directive in this regard.

Looking at the implementation of Module.getResourceAsStream, I see that it calls Module.isOpen(String, Module) which returns false in case the package name is exported by an "exports" directive. Which raises another question: is Module.isOpen supposed to return whether the package has been explicitly opened by an "opens" directive (or via being in an open module)? Or is it supposed to also return true if the package has been opened as a consequence of the fact that it's exported (e.g. by an "exports" directive)? If the former is true, I suppose there may be other usages of Module.isOpen, including in the JDK, which (incorrectly) do not also check if the package name is exported with Module.isExported.

The real-world case where I met this issue is in kotlin.stdlib where we store metadata of Kotlin declarations in resource files per package (only of those declarations which are not representable by JVM class files), and kotlin.reflect (which is another module) reaches out to those resource files in kotlin.stdlib. To make them reachable thus along with every "exports XXX" in kotlin.stdlib's module declaration I'm adding "opens XXX to kotlin.reflect", which looks cumbersome.

Thanks!

Alexander
Reply | Threaded
Open this post in threaded view
|

Re: "exports" directive does not open module's resources for dependent modules

Alan Bateman
In reply to this post by Alexander Udalov
On 15/09/2017 13:14, Alexander Udalov wrote:

> It looks like exporting a package from a (non-open) module with an
> "exports" directive is not enough to ensure that
> Module.getResourceAsStream on that module would load resources from
> the module. Surprisingly, adding an "opens" directive for the same
> package to the module declaration allows resources to be found.
>
> I've put up a simple project to demonstrate this issue:
> https://github.com/udalov/jigsaw-resources-are-not-exported
>
> I'm wondering whether this is a bug or expected behavior?
Yes, this is expected behavior. The javadoc has all details. In your
example, if kotlin.reflect is using Class.getResourceXXX or
Module.getResourceAsStream to locate a non .class resource in module X
then module X needs to open the package with the resource to at least
kotlin.reflect.


> I would
> expect that exporting a package would also open it not only for uses
> of reflection, but for resource loading. I can't find anything related
> to resources in the JLS, but p.7.7 "Module Declarations" gives a clear
> impression that the "exports" directive gives a superset of
> functionality of the "opens" directive in this regard.
I think you need to re-read JLS 7.7.2. As `opens` doesn't grant any
access at compile-time then you think of it as being a subset of
`exports` in this phase.  On the other hand, `opens` grants access to
the public classes/members and additionally reflective access to all
members of all classes at run-time so you can think of it as a superset
in this phase. The resource APIs just build on this.

-Alan
Reply | Threaded
Open this post in threaded view
|

Re: "exports" directive does not open module's resources for dependent modules

Sander Mak
In reply to this post by Stephen Felts

> On 15 Sep 2017, at 14:32, Stephen Felts <[hidden email]> wrote:
>
> "opens" is a superset of "exports".

Only when qualified with 'at run-time'.


Sander
Reply | Threaded
Open this post in threaded view
|

Re: "exports" directive does not open module's resources for dependent modules

Alexander Udalov
In reply to this post by Alan Bateman
Thank you, I've re-read JLS 7.7.2 and understand now that it behaves
as expected. I'll continue exporting and opening every package then.

Alexander

On Fri, Sep 15, 2017 at 3:52 PM, Alan Bateman <[hidden email]> wrote:

> On 15/09/2017 13:14, Alexander Udalov wrote:
>>
>> It looks like exporting a package from a (non-open) module with an
>> "exports" directive is not enough to ensure that
>> Module.getResourceAsStream on that module would load resources from
>> the module. Surprisingly, adding an "opens" directive for the same
>> package to the module declaration allows resources to be found.
>>
>> I've put up a simple project to demonstrate this issue:
>> https://github.com/udalov/jigsaw-resources-are-not-exported
>>
>> I'm wondering whether this is a bug or expected behavior?
>
> Yes, this is expected behavior. The javadoc has all details. In your
> example, if kotlin.reflect is using Class.getResourceXXX or
> Module.getResourceAsStream to locate a non .class resource in module X then
> module X needs to open the package with the resource to at least
> kotlin.reflect.
>
>
>> I would
>> expect that exporting a package would also open it not only for uses
>> of reflection, but for resource loading. I can't find anything related
>> to resources in the JLS, but p.7.7 "Module Declarations" gives a clear
>> impression that the "exports" directive gives a superset of
>> functionality of the "opens" directive in this regard.
>
> I think you need to re-read JLS 7.7.2. As `opens` doesn't grant any access
> at compile-time then you think of it as being a subset of `exports` in this
> phase.  On the other hand, `opens` grants access to the public
> classes/members and additionally reflective access to all members of all
> classes at run-time so you can think of it as a superset in this phase. The
> resource APIs just build on this.
>
> -Alan
Reply | Threaded
Open this post in threaded view
|

Re: "exports" directive does not open module's resources for dependent modules

Sander Mak

> On 15 Sep 2017, at 15:17, Alexander Udalov <[hidden email]> wrote:
>
> Thank you, I've re-read JLS 7.7.2 and understand now that it behaves
> as expected. I'll continue exporting and opening every package then.

If you open *every* package, you could create an open module as well. Might be less annoying, at the risk of accidentally opening new packages added latre to the module as well even though they might not need to be open.


Sander