Cross module single ServiceProvider for JPMS services

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

Cross module single ServiceProvider for JPMS services

Alex Sviridov

Hi all,
 
Let's suppose we have modules (A, B, C..) and every module consumes and provides services.
To find these services I want to create one util class, for example ServiceProvider that will be used
by all modules to get necessary services. There are two ideas:
*  to have one point to control providing services within system
*  to avoid code duplication.
However, I can't do it. The problem is that if we put ServiceProvider, for example, in module A,
then it can find only services that module A uses (service is declared in  uses in module A module-info).
Is it possible to do, if yes, then how?
 
 
--
Alex Sviridov
Reply | Threaded
Open this post in threaded view
|

Re: Cross module single ServiceProvider for JPMS services

Uwe Schindler
Hi,

The problem you see is that ServiceLoader.load() is caller-sensitive, so it has to be called from the exact module that will use the service.

You can still have some utility method that works on an already instantiated service loader:

1. The utility class/method just takes a ServiceLoader instance to consume and do you common stuff. 2. The instance is created inside the module that uses it and passes to the common utility class.

Uwe

Am April 19, 2020 2:00:01 PM UTC schrieb Alex Sviridov <[hidden email]>:

>
>Hi all,

>Let's suppose we have modules (A, B, C..) and every module consumes and
>provides services.
>To find these services I want to create one util class, for example
>ServiceProvider that will be used
>by all modules to get necessary services. There are two ideas:
>*  to have one point to control providing services within system
>*  to avoid code duplication.
>However, I can't do it. The problem is that if we put ServiceProvider,
>for example, in module A,
>then it can find only services that module A uses (service is declared
>in  uses in module A module-info).
>Is it possible to do, if yes, then how?


>--
>Alex Sviridov
Reply | Threaded
Open this post in threaded view
|

Re: Cross module single ServiceProvider for JPMS services

Alan Bateman
In reply to this post by Alex Sviridov
On 19/04/2020 15:00, Alex Sviridov wrote:

> Hi all,
>  
> Let's suppose we have modules (A, B, C..) and every module consumes and provides services.
> To find these services I want to create one util class, for example ServiceProvider that will be used
> by all modules to get necessary services. There are two ideas:
> *  to have one point to control providing services within system
> *  to avoid code duplication.
> However, I can't do it. The problem is that if we put ServiceProvider, for example, in module A,
> then it can find only services that module A uses (service is declared in  uses in module A module-info).
> Is it possible to do, if yes, then how?
If I read this correctly then we have code in module A looking to load
service provider of type S but A's module declaration doesn't declares
`uses S`. Have you tried the Module addUses method? That will add the
"use" edge at run-time that should make this work.

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

Re[2]: Cross module single ServiceProvider for JPMS services

Alex Sviridov

Hi Alan
 
Yes, you read that correctly. Do you mean that in ServiceProvider that is in moduleA we
will do something like this:
 
if (!SerivceProvider.class.getModule().canUse(S)) {
     SerivceProvider.class.getModule().addUses(S)
}
//here we some logic and return S service.
 
Best regards

>Воскресенье, 19 апреля 2020, 17:22 +03:00 от Alan Bateman <[hidden email]>:

>On 19/04/2020 15:00, Alex Sviridov wrote:
>> Hi all,
>>
>> Let's suppose we have modules (A, B, C..) and every module consumes and provides services.
>> To find these services I want to create one util class, for example ServiceProvider that will be used
>> by all modules to get necessary services. There are two ideas:
>> * to have one point to control providing services within system
>> * to avoid code duplication.
>> However, I can't do it. The problem is that if we put ServiceProvider, for example, in module A,
>> then it can find only services that module A uses (service is declared in uses in module A module-info).
>> Is it possible to do, if yes, then how? If I read this correctly then we have code in module A looking to load
>service provider of type S but A's module declaration doesn't declares
>`uses S`. Have you tried the Module addUses method? That will add the
>"use" edge at run-time that should make this work.
>
>-Alan.
 
 
--
Alex Sviridov
 
Reply | Threaded
Open this post in threaded view
|

RE: Cross module single ServiceProvider for JPMS services

Uwe Schindler
In reply to this post by Alan Bateman
Hi Alan,

from what I understood: He has some utility method in a shared class that wraps ServiceLoader to discover services and do something with it (the usual way to prevent code duplication). Problem is that ServiceLoade.load() is caller-sensitive, so a shared utility method only sees the services that the modules is allowed to see.

I answered on this in another mail: He can have a shared utility class, but the ServiceLoader instance should NOT be instantiated inside the utility class. What you suggest is to additionally open the shared module to allow reading services, which looks wrong.

Unfortunately, the caller-sensitiveness of ServiceLoader.load() cannot easily be seen from the Javadocs. IMHO there should be some improvements on this. I was stumbling on this, too.

Uwe

-----
Uwe Schindler
[hidden email]
ASF Member, Apache Lucene PMC / Committer
Bremen, Germany
https://lucene.apache.org/

> -----Original Message-----
> From: jigsaw-dev <[hidden email]> On Behalf Of Alan
> Bateman
> Sent: Sunday, April 19, 2020 4:23 PM
> To: Alex Sviridov <[hidden email]>; jigsaw-dev <jigsaw-
> [hidden email]>
> Subject: Re: Cross module single ServiceProvider for JPMS services
>
> On 19/04/2020 15:00, Alex Sviridov wrote:
> > Hi all,
> >
> > Let's suppose we have modules (A, B, C..) and every module consumes and
> provides services.
> > To find these services I want to create one util class, for example
> ServiceProvider that will be used
> > by all modules to get necessary services. There are two ideas:
> > *  to have one point to control providing services within system
> > *  to avoid code duplication.
> > However, I can't do it. The problem is that if we put ServiceProvider, for
> example, in module A,
> > then it can find only services that module A uses (service is declared in  uses
> in module A module-info).
> > Is it possible to do, if yes, then how?
> If I read this correctly then we have code in module A looking to load
> service provider of type S but A's module declaration doesn't declares
> `uses S`. Have you tried the Module addUses method? That will add the
> "use" edge at run-time that should make this work.
>
> -Alan.

Reply | Threaded
Open this post in threaded view
|

Re: Cross module single ServiceProvider for JPMS services

Alan Bateman
On 19/04/2020 16:05, Uwe Schindler wrote:
> Hi Alan,
>
> from what I understood: He has some utility method in a shared class that wraps ServiceLoader to discover services and do something with it (the usual way to prevent code duplication). Problem is that ServiceLoade.load() is caller-sensitive, so a shared utility method only sees the services that the modules is allowed to see.
>
> I answered on this in another mail: He can have a shared utility class, but the ServiceLoader instance should NOT be instantiated inside the utility class. What you suggest is to additionally open the shared module to allow reading services, which looks wrong.
>
> Unfortunately, the caller-sensitiveness of ServiceLoader.load() cannot easily be seen from the Javadocs. IMHO there should be some improvements on this. I was stumbling on this, too.
>
The ServiceConfigurationError specified by each of the load methods does
try to make it clear it will be thrown when the module does not declare
that is uses the service. The exception should be clear too. I agree
that addUses is not easy to find but it is right method for these scenarios:

"This method is intended for use by frameworks that invoke ServiceLoader
on behalf of other modules or where the framework is passed a reference
to the service type by other code. This method is a no-op when invoked
on an unnamed module or an automatic module."

So it's just adding a use-edge at run-time, it's not opening any
packages or changing the readability.

-Alan.