Resolution exception when service interface gets exposed via --add-exports

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

Resolution exception when service interface gets exposed via --add-exports

Gunnar Morling
Hi,

I'm having one module which defines a service interface but does not export
that interface's package. In another module I wish to create an
implementation of that service, which should be possible via --add-exports.

I can successfully compile that second module, but running it fails:

    Error occurred during initialization of boot layer
    j.l.m.ResolutionException: Module com.example.b does not read a module
that exports com.example.a

It seems as if the service binding happens before the --add-exports of the
java invocation is processed. Please see below for the steps to reproduce.

Is it a bug or am I trying to do something unsupported here?

Thanks,

--Gunnar

=====
mkdir -p sources/com.example.a/src/main/java/a/
mkdir -p sources/com.example.b/src/main/java/b/

cat > sources/com.example.a/src/main/java/a/Hello.java << EOF
package a;

public interface Hello {
    void world();
}
EOF

cat > sources/com.example.a/src/main/java/module-info.java << EOF
module com.example.a {}
EOF

cat > sources/com.example.b/src/main/java/b/HelloImpl.java << EOF
package b;

public class HelloImpl implements a.Hello {

    public void world() { System.out.println( "Hello"); }

    public static void main(String... args) {
        java.util.ServiceLoader.load( a.Hello.class ).findFirst().get()
            .world();
    }
}
EOF

cat > sources/com.example.b/src/main/java/module-info.java << EOF
module com.example.b {
    requires com.example.a;
    provides a.Hello with b.HelloImpl;
    uses a.Hello;
}
EOF

cd sources/com.example.a && javac -g -d ../../modules/com.example.a $(find
src/main/java -name "*.java") && cd ../..

cd sources/com.example.b && javac -g --add-exports
com.example.a/a=com.example.b --module-path ../../modules -d
../../modules/com.example.b $(find src/main/java -name "*.java") && cd ../..

java --add-exports com.example.a/a=com.example.b --module-path modules -m
com.example.b/b.HelloImpl
Reply | Threaded
Open this post in threaded view
|

Re: Resolution exception when service interface gets exposed via --add-exports

Alan Bateman
On 20/11/2017 21:04, Gunnar Morling wrote:

> Hi,
>
> I'm having one module which defines a service interface but does not export
> that interface's package. In another module I wish to create an
> implementation of that service, which should be possible via --add-exports.
>
> I can successfully compile that second module, but running it fails:
>
>      Error occurred during initialization of boot layer
>      j.l.m.ResolutionException: Module com.example.b does not read a module
> that exports com.example.a
>
> It seems as if the service binding happens before the --add-exports of the
> java invocation is processed. Please see below for the steps to reproduce.
>
> Is it a bug or am I trying to do something unsupported here?
>
At run-time, the --add-reads/--add-exports options are the equivalent of
the module invoking addReads or addExports. So yes, they come into
effect after resolution and service binding (and so after the resolution
consistency check that detects that a module uses a service type in a
package that isn't exported by anyone to the module).

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

Re: Resolution exception when service interface gets exposed via --add-exports

Gunnar Morling
I see, thanks for the clarification.

It's a pity, though, I hoped to employ that approach for providing a custom
jlink plug-in (implementation of jdk.tools.jlink.plugin.Plugin). So it
seems that's not possible until jdk.jlink exports j.t.j.plugin? Are there
any plans to do so some time soon?

Even if it was marked as experimental/incubating, being able to provide
custom jlink plug-ins would enable interesting use cases.

2017-11-20 22:24 GMT+01:00 Alan Bateman <[hidden email]>:

> On 20/11/2017 21:04, Gunnar Morling wrote:
>
>> Hi,
>>
>> I'm having one module which defines a service interface but does not
>> export
>> that interface's package. In another module I wish to create an
>> implementation of that service, which should be possible via
>> --add-exports.
>>
>> I can successfully compile that second module, but running it fails:
>>
>>      Error occurred during initialization of boot layer
>>      j.l.m.ResolutionException: Module com.example.b does not read a
>> module
>> that exports com.example.a
>>
>> It seems as if the service binding happens before the --add-exports of the
>> java invocation is processed. Please see below for the steps to reproduce.
>>
>> Is it a bug or am I trying to do something unsupported here?
>>
>> At run-time, the --add-reads/--add-exports options are the equivalent of
> the module invoking addReads or addExports. So yes, they come into effect
> after resolution and service binding (and so after the resolution
> consistency check that detects that a module uses a service type in a
> package that isn't exported by anyone to the module).
>
> -Alan
>
Reply | Threaded
Open this post in threaded view
|

Re: Resolution exception when service interface gets exposed via --add-exports

Remi Forax
Hi Gunnar,
you can use --patch-module to add your plugin inside jdk.jlink if you want to experiment.

Rémi

----- Mail original -----
> De: "Gunnar Morling" <[hidden email]>
> À: "Alan Bateman" <[hidden email]>
> Cc: "jigsaw-dev" <[hidden email]>
> Envoyé: Lundi 20 Novembre 2017 22:56:35
> Objet: Re: Resolution exception when service interface gets exposed via --add-exports

> I see, thanks for the clarification.
>
> It's a pity, though, I hoped to employ that approach for providing a custom
> jlink plug-in (implementation of jdk.tools.jlink.plugin.Plugin). So it
> seems that's not possible until jdk.jlink exports j.t.j.plugin? Are there
> any plans to do so some time soon?
>
> Even if it was marked as experimental/incubating, being able to provide
> custom jlink plug-ins would enable interesting use cases.
>
> 2017-11-20 22:24 GMT+01:00 Alan Bateman <[hidden email]>:
>
>> On 20/11/2017 21:04, Gunnar Morling wrote:
>>
>>> Hi,
>>>
>>> I'm having one module which defines a service interface but does not
>>> export
>>> that interface's package. In another module I wish to create an
>>> implementation of that service, which should be possible via
>>> --add-exports.
>>>
>>> I can successfully compile that second module, but running it fails:
>>>
>>>      Error occurred during initialization of boot layer
>>>      j.l.m.ResolutionException: Module com.example.b does not read a
>>> module
>>> that exports com.example.a
>>>
>>> It seems as if the service binding happens before the --add-exports of the
>>> java invocation is processed. Please see below for the steps to reproduce.
>>>
>>> Is it a bug or am I trying to do something unsupported here?
>>>
>>> At run-time, the --add-reads/--add-exports options are the equivalent of
>> the module invoking addReads or addExports. So yes, they come into effect
>> after resolution and service binding (and so after the resolution
>> consistency check that detects that a module uses a service type in a
>> package that isn't exported by anyone to the module).
>>
>> -Alan
Reply | Threaded
Open this post in threaded view
|

Re: Resolution exception when service interface gets exposed via --add-exports

Alan Bateman
In reply to this post by Gunnar Morling
On 20/11/2017 21:56, Gunnar Morling wrote:

> I see, thanks for the clarification.
>
> It's a pity, though, I hoped to employ that approach for providing a
> custom jlink plug-in (implementation of
> jdk.tools.jlink.plugin.Plugin). So it seems that's not possible until
> jdk.jlink exports j.t.j.plugin? Are there any plans to do so some time
> soon?
>
> Even if it was marked as experimental/incubating, being able to
> provide custom jlink plug-ins would enable interesting use cases.
>
There was interest in creating an incubating module in JDK 9 but it was
put aside due to the issues of tool modules depending on an incubating
module. The other issue is that most of the interesting plugins to date
do code generation at link time and are deeply tied to specific areas of
java.base and other core modules (they can't really live outside of the
jdk repo). So while it might be desirable to expose the interface for
plugins, I think it will need further exploration to see if it makes
sense or not.

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

Re: Resolution exception when service interface gets exposed via --add-exports

Remi Forax
Hi Alan,
I use jlink plugins for 2 things,
- code generation, i.e. find patterns in the bytecode and optimize them because at link time you are in a closed world, so something that was dynamic is not anymore.
- just bytecode crawling to find specific annotations to improve startup.

I believe implementation like Weld or Spring should have access to an open API to be able to do thing kind of optimizations, imagine, you could create all proxies upfront or better use invokedynamic to even avoid proxy creation at all.

The plugin API doesn't have to be complex, it's a read/replace/append of bytecode files.

Rémi

----- Mail original -----
> De: "Alan Bateman" <[hidden email]>
> À: "Gunnar Morling" <[hidden email]>
> Cc: "jigsaw-dev" <[hidden email]>
> Envoyé: Mardi 21 Novembre 2017 09:33:33
> Objet: Re: Resolution exception when service interface gets exposed via --add-exports

> On 20/11/2017 21:56, Gunnar Morling wrote:
>> I see, thanks for the clarification.
>>
>> It's a pity, though, I hoped to employ that approach for providing a
>> custom jlink plug-in (implementation of
>> jdk.tools.jlink.plugin.Plugin). So it seems that's not possible until
>> jdk.jlink exports j.t.j.plugin? Are there any plans to do so some time
>> soon?
>>
>> Even if it was marked as experimental/incubating, being able to
>> provide custom jlink plug-ins would enable interesting use cases.
>>
> There was interest in creating an incubating module in JDK 9 but it was
> put aside due to the issues of tool modules depending on an incubating
> module. The other issue is that most of the interesting plugins to date
> do code generation at link time and are deeply tied to specific areas of
> java.base and other core modules (they can't really live outside of the
> jdk repo). So while it might be desirable to expose the interface for
> plugins, I think it will need further exploration to see if it makes
> sense or not.
>
> -Alan
Reply | Threaded
Open this post in threaded view
|

Re: Resolution exception when service interface gets exposed via --add-exports

Gunnar Morling
Thanks for the patching idea, Remi. I'll try that.

> So while it might be desirable to expose the interface for plugins, I
think it will need further exploration to see if it makes sense or not.

Understood, it's just that in the current form I don't think many people
(outside of the JDK) will ever try it out and give feedback. Having a
public incubating API might help with that.

In terms of use cases I was thinking of generating annotation indexes and
adding them to the image, removing unused code or applying byte code
enhancements e.g. for Hibernate entities. Currently, plug-ins for the
specific build system are used in such cases (e.g. Maven/Gradle plug-ins),
but providing this functionality via generally usable jlink plug-ins would
be awesome.

2017-11-21 10:29 GMT+01:00 Remi Forax <[hidden email]>:

> Hi Alan,
> I use jlink plugins for 2 things,
> - code generation, i.e. find patterns in the bytecode and optimize them
> because at link time you are in a closed world, so something that was
> dynamic is not anymore.
> - just bytecode crawling to find specific annotations to improve startup.
>
> I believe implementation like Weld or Spring should have access to an open
> API to be able to do thing kind of optimizations, imagine, you could create
> all proxies upfront or better use invokedynamic to even avoid proxy
> creation at all.
>
> The plugin API doesn't have to be complex, it's a read/replace/append of
> bytecode files.
>
> Rémi
>
> ----- Mail original -----
> > De: "Alan Bateman" <[hidden email]>
> > À: "Gunnar Morling" <[hidden email]>
> > Cc: "jigsaw-dev" <[hidden email]>
> > Envoyé: Mardi 21 Novembre 2017 09:33:33
> > Objet: Re: Resolution exception when service interface gets exposed via
> --add-exports
>
> > On 20/11/2017 21:56, Gunnar Morling wrote:
> >> I see, thanks for the clarification.
> >>
> >> It's a pity, though, I hoped to employ that approach for providing a
> >> custom jlink plug-in (implementation of
> >> jdk.tools.jlink.plugin.Plugin). So it seems that's not possible until
> >> jdk.jlink exports j.t.j.plugin? Are there any plans to do so some time
> >> soon?
> >>
> >> Even if it was marked as experimental/incubating, being able to
> >> provide custom jlink plug-ins would enable interesting use cases.
> >>
> > There was interest in creating an incubating module in JDK 9 but it was
> > put aside due to the issues of tool modules depending on an incubating
> > module. The other issue is that most of the interesting plugins to date
> > do code generation at link time and are deeply tied to specific areas of
> > java.base and other core modules (they can't really live outside of the
> > jdk repo). So while it might be desirable to expose the interface for
> > plugins, I think it will need further exploration to see if it makes
> > sense or not.
> >
> > -Alan
>
Reply | Threaded
Open this post in threaded view
|

Re: Resolution exception when service interface gets exposed via --add-exports

Alan Bateman
In reply to this post by Remi Forax
On 21/11/2017 09:29, Remi Forax wrote:
> Hi Alan,
> I use jlink plugins for 2 things,
> - code generation, i.e. find patterns in the bytecode and optimize them because at link time you are in a closed world, so something that was dynamic is not anymore.
> - just bytecode crawling to find specific annotations to improve startup.
>
> I believe implementation like Weld or Spring should have access to an open API to be able to do thing kind of optimizations, imagine, you could create all proxies upfront or better use invokedynamic to even avoid proxy creation at all.
>
> The plugin API doesn't have to be complex, it's a read/replace/append of bytecode files.
>
Good work was done in JDK 9 to get the plugin API to its current state.
We had hoped to expose it in an incubating module but it didn't happen
as it would have required splitting the jdk.jlink module in an awkward
way. Yes, it should be revisited.

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

Re: Resolution exception when service interface gets exposed via --add-exports

Gunnar Morling
Just in case others end up in the same situation: --patch-module (alone)
doesn't do the trick as it can't be used to override the module-info.class
of the jdk.jlink module. So I'm just using it to inject my plug-in and then
use a Java Agent to register that one as a service provider (via
Instrumentation#redefineModule()).

If I find the time I'll try and blog about it; needless to say, that a
public, supported API would be much appreciated :) Thanks Alan and Remi for
your help!


2017-11-21 11:46 GMT+01:00 Alan Bateman <[hidden email]>:

> On 21/11/2017 09:29, Remi Forax wrote:
>
>> Hi Alan,
>> I use jlink plugins for 2 things,
>> - code generation, i.e. find patterns in the bytecode and optimize them
>> because at link time you are in a closed world, so something that was
>> dynamic is not anymore.
>> - just bytecode crawling to find specific annotations to improve startup.
>>
>> I believe implementation like Weld or Spring should have access to an
>> open API to be able to do thing kind of optimizations, imagine, you could
>> create all proxies upfront or better use invokedynamic to even avoid proxy
>> creation at all.
>>
>> The plugin API doesn't have to be complex, it's a read/replace/append of
>> bytecode files.
>>
>> Good work was done in JDK 9 to get the plugin API to its current state.
> We had hoped to expose it in an incubating module but it didn't happen as
> it would have required splitting the jdk.jlink module in an awkward way.
> Yes, it should be revisited.




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

Re: Resolution exception when service interface gets exposed via --add-exports

Remi Forax
My opinion is that we should fix --patch-module to allow to patch the module-info.class,
you always end up with this restriction once you use --patch-module.

Rémi

> De: "Gunnar Morling" <[hidden email]>
> À: "Alan Bateman" <[hidden email]>
> Cc: "Remi Forax" <[hidden email]>, "jigsaw-dev" <[hidden email]>
> Envoyé: Mercredi 22 Novembre 2017 12:49:10
> Objet: Re: Resolution exception when service interface gets exposed via
> --add-exports

> Just in case others end up in the same situation: --patch-module (alone) doesn't
> do the trick as it can't be used to override the module-info.class of the
> jdk.jlink module. So I'm just using it to inject my plug-in and then use a Java
> Agent to register that one as a service provider (via
> Instrumentation#redefineModule()).
> If I find the time I'll try and blog about it; needless to say, that a public,
> supported API would be much appreciated :) Thanks Alan and Remi for your help!

> 2017-11-21 11:46 GMT+01:00 Alan Bateman < [ mailto:[hidden email] |
> [hidden email] ] > :

>> On 21/11/2017 09:29, Remi Forax wrote:

>>> Hi Alan,
>>> I use jlink plugins for 2 things,
>>> - code generation, i.e. find patterns in the bytecode and optimize them because
>>> at link time you are in a closed world, so something that was dynamic is not
>>> anymore.
>>> - just bytecode crawling to find specific annotations to improve startup.

>>> I believe implementation like Weld or Spring should have access to an open API
>>> to be able to do thing kind of optimizations, imagine, you could create all
>>> proxies upfront or better use invokedynamic to even avoid proxy creation at
>>> all.

>>> The plugin API doesn't have to be complex, it's a read/replace/append of
>>> bytecode files.

>> Good work was done in JDK 9 to get the plugin API to its current state. We had
>> hoped to expose it in an incubating module but it didn't happen as it would
>> have required splitting the jdk.jlink module in an awkward way. Yes, it should
>> be revisited.
>> -Alan
Reply | Threaded
Open this post in threaded view
|

Re: Resolution exception when service interface gets exposed via --add-exports

Gunnar Morling
Finally got to write about my explorations of the jlink plug-in API:
http://in.relation.to/2017/12/12/exploring-jlink-plugin-api-in-java-9/.

I found the API good to work with overall, implementing my use case (adding
an annotation index for given modules) was straight-forward.

One useful change could be to split up
ResourcePoolEntry$Type#CLASS_OR_RESOURCE into two separate enum members. I
think it's a common requirement to perform some action *only* for class
files, I found myself checking the entry path for the "class" suffix to do
so.

It'd be fantastic if the API could be promoted to "Incubating", perhaps in
Java 11?

--Gunnar




2017-11-22 12:59 GMT+01:00 <[hidden email]>:

> My opinion is that we should fix --patch-module to allow to patch the
> module-info.class,
> you always end up with this restriction once you use --patch-module.
>
> Rémi
>
> ------------------------------
>
> *De: *"Gunnar Morling" <[hidden email]>
> *À: *"Alan Bateman" <[hidden email]>
> *Cc: *"Remi Forax" <[hidden email]>, "jigsaw-dev" <
> [hidden email]>
> *Envoyé: *Mercredi 22 Novembre 2017 12:49:10
> *Objet: *Re: Resolution exception when service interface gets exposed via
> --add-exports
>
> Just in case others end up in the same situation: --patch-module (alone)
> doesn't do the trick as it can't be used to override the module-info.class
> of the jdk.jlink module. So I'm just using it to inject my plug-in and then
> use a Java Agent to register that one as a service provider (via
> Instrumentation#redefineModule()).
>
> If I find the time I'll try and blog about it; needless to say, that a
> public, supported API would be much appreciated :) Thanks Alan and Remi for
> your help!
>
>
> 2017-11-21 11:46 GMT+01:00 Alan Bateman <[hidden email]>:
>
>> On 21/11/2017 09:29, Remi Forax wrote:
>>
>>> Hi Alan,
>>> I use jlink plugins for 2 things,
>>> - code generation, i.e. find patterns in the bytecode and optimize them
>>> because at link time you are in a closed world, so something that was
>>> dynamic is not anymore.
>>> - just bytecode crawling to find specific annotations to improve startup.
>>>
>>> I believe implementation like Weld or Spring should have access to an
>>> open API to be able to do thing kind of optimizations, imagine, you could
>>> create all proxies upfront or better use invokedynamic to even avoid proxy
>>> creation at all.
>>>
>>> The plugin API doesn't have to be complex, it's a read/replace/append of
>>> bytecode files.
>>>
>>> Good work was done in JDK 9 to get the plugin API to its current state.
>> We had hoped to expose it in an incubating module but it didn't happen as
>> it would have required splitting the jdk.jlink module in an awkward way.
>> Yes, it should be revisited.
>
>
>
>
>>
>>
>> -Alan
>>
>
>
Reply | Threaded
Open this post in threaded view
|

Re: Resolution exception when service interface gets exposed via --add-exports

Alan Bateman
On 12/12/2017 20:42, Gunnar Morling wrote:
> Finally got to write about my explorations of the jlink plug-in API:
> http://in.relation.to/2017/12/12/exploring-jlink-plugin-api-in-java-9/.
>
> I found the API good to work with overall, implementing my use case
> (adding an annotation index for given modules) was straight-forward.
Thanks for the forwarding the link to the blog. It's not clear to me why
the jlink wrapper is needed, I would expect `jlink
-J-javaagent:agent.jar` should work.

For the use-case then another approach would be create/replace the index
when creating or updating a modular JAR with the `jar` tool. That would
help for the case that the module is on the module path (in addition to
helping the case where the module is linked into the run-time image).

>
> One useful change could be to split up
> ResourcePoolEntry$Type#CLASS_OR_RESOURCE into two separate enum
> members. I think it's a common requirement to perform some action
> *only* for class files, I found myself checking the entry path for the
> "class" suffix to do so.
I think it may stem from the JMOD format where classes and resources are
the same section. I agree it should be re-examined.

-Alan.