jigsaw-dev Digest, Vol 151, Issue 3

Rob Bygrave robin.bygrave at gmail.com
Tue Apr 18 11:18:58 UTC 2023


*> In this case, it amounts to giving up on a post resolution check and
allowing all service providers to have a dangling reference to a service
type.*

Noting that the effect of this is also that use of ServiceLoader works
differently in module-path compared to classpath for this case. Use of
ServiceLoader
wrt optional service loading that works in classpath will not work in
module-path (resolution error).

I come back to Alex's comment in the bug report:

*> Alex: All of this boils down to: if the implementation module says
`provides`, then is it reasonable to consider that ServiceLoader is the
*only* vector by which the implementation class will be instantiated? If
yes, then module resolution should perhaps be tolerant of a `provides` that
specifies a missing service interface. *

Obviously I'm in the *"module resolution should be tolerant of a `provides`
that specifies a missing service interface. "* camp. I'd happily trade the
runtime resolution error (that fails fast) for the "consistent with
classpath" only error if something else tries to instantiate the service
(and p.S isn't in module-path).

The workarounds at this point look like:
- Don't use module-path, just stick to classpath
- Re-design, likely extracting out the service interface into its own
artifact and make it a hard dependency of the module implementing the
service
- Don't use ServiceLoader



On Tue, 18 Apr 2023 at 22:50, <jigsaw-dev-request at openjdk.org> wrote:

> Send jigsaw-dev mailing list submissions to
>         jigsaw-dev at openjdk.org
>
> To subscribe or unsubscribe via the World Wide Web, visit
>         https://mail.openjdk.org/mailman/listinfo/jigsaw-dev
> or, via email, send a message with subject or body 'help' to
>         jigsaw-dev-request at openjdk.org
>
> You can reach the person managing the list at
>         jigsaw-dev-owner at openjdk.org
>
> When replying, please edit your Subject line so it is more specific
> than "Re: Contents of jigsaw-dev digest..."
> Today's Topics:
>
>    1. Re: provides and requires static ... runtime error (Alan Bateman)
>    2. Re: provides and requires static ... runtime error (Rob Bygrave)
>
>
>
> ---------- Forwarded message ----------
> From: Alan Bateman <Alan.Bateman at oracle.com>
> To: Rob Bygrave <robin.bygrave at gmail.com>
> Cc: jigsaw-dev at openjdk.java.net
> Bcc:
> Date: Tue, 18 Apr 2023 09:05:06 +0100
> Subject: Re: provides and requires static ... runtime error
>
> On 17/04/2023 15:20, Rob Bygrave wrote:
>
> *:*
>
>
> > *is it reasonable to consider that ServiceLoader is the *only* vector
> by which the implementation class will be instantiated? *
>
> In my view this is expected and imo I get there by thinking in the
> opposite direction from the provides p.S type to the requires static rather
> than the other way around. That is, the p.S type is only available via
> requires static hence it is expected to potentially not exist at runtime in
> the module-path. That is, if p.S was expected to exist at runtime it would
> be "read" via a requires or requires transient clause and not via a
> requires static - *the use of requires static for this case is explicit
> and intentional*.
>
> In using requires static ... imo we are explicitly going out-of-our-way to
> say "the types here might not be available at runtime" and the classic case
> for this as I see it is this case of providing an optional service, that
> will only be service loaded if the user of that service is in the classpath
> / module-path. *IF* the module that is the user of a service is in the
> classpath / module-path then that module will ensure that the p.S type is
> in the module-path.
>
>
> In your example, module io.avaje.config declares that it provides an
> implementation of io.avaje.inject.spi.PropertyRequiresPlugin. There is
> nothing to connect this to `requires static io.avaje.inject`. The module
> system would need to search "far and wide" for io.avaje.inject to see if
> exports io.avaje.inject.spi to io.avaje.config, otherwise there is no way
> for it to know that the "missing package" is in a module that is not
> required to be present at run-time. In other words, `requires static io.avaje.inject`
> does not convey to the module system that io.avaje.inject exports
> packages with service types.
>
> I understand there is a temptation to compare `requires static` with
> optional dependences in Maven but they are not the same thing. `requires
> static` is more for use-cases like annotations that do not need to be
> present at run-time. It could of course be extended but it's a slippery
> slope that ultimately amounts to giving up on reliability. In this case, it
> amounts to giving up on a post resolution check and allowing all service
> providers to have a dangling reference to a service type.
>
> -Alan
>
>
>
> ---------- Forwarded message ----------
> From: Rob Bygrave <robin.bygrave at gmail.com>
> To: Alan Bateman <Alan.Bateman at oracle.com>
> Cc: jigsaw-dev at openjdk.java.net
> Bcc:
> Date: Tue, 18 Apr 2023 22:50:30 +1200
> Subject: Re: provides and requires static ... runtime error
> *> `requires static` is more for use-cases like annotations that do not
> need to be present at run-time*
>
> I am aware that annotations have a retention policy but otherwise why are
> we specifically saying "like annotations" here as opposed to just saying
> "types"?
>
>
> *> I understand there is a temptation to compare `requires static` with
> optional dependences in Maven but they are not the same thing. `requires
> static` is more for use-cases like annotations that do not need to be
> present at run-time. It could of course be extended but it's a slippery
> slope that ultimately amounts to giving up on reliability.*
>
> Background:  I also maintain Ebean ORM which is made up of 20+ modules (+
> 3rd party dependencies) and works with classpath and module-path. A quick
> search for "requires static" there shows me 25 uses of requires static (192
> requires clauses in total on the core modules, I'm suggesting this is a
> non-trivial use of module-path that uses a decent amount of requires
> static).
>
> Of those 25 requires static, 5 of those are dependencies on optional
> annotations and 20 are optional dependencies that are *NOT* annotations.
> They all match to maven optional true dependencies (self fulfilling I know).
>
> For all these cases requires static has worked exactly as I expect and
> exactly the same with classpath and module-path. There have been no
> issues.  No issues when the requires static was for annotations and no
> issues when the requires static was for normal types (not annotations).
>
>
> > *do not need to be present at run-time.*
>
> So for ebean orm, it is using [requires static / optional at runtime]
> types that are both annotations and normal class types and they are all
> potentially not present at run-time. There is a suggestion there is a
> slippery slope for the requires static types that are not annotations? I'm
> wondering why? As in, optional dependencies have been reasonably
> extensively used and there has been no issue hit here with module-path and
> requires static and everything has worked as expected*.
>
> *Except the issue noted in this thread which imo isn't an issue with
> requires static. That is, I'm now aware of the issue with ServiceLoader in
> module-path not working when provides p.S is via requires static (unlike
> classpath) ... but in my mind that issue isn't really an issue with
> requires static per say but instead it is an issue with the runtime module
> resolution (by not allowing *provides p.S* to be optional).
>
>
> > *It could of course be extended *
>
> Extended? What is wrong with how requires static works now? How
> are you suggesting it could be extended and for what purpose?
>
>
> > *but it's a slippery slope that ultimately amounts to giving up on
> reliability.*
>
> Well, optional dependencies by their nature are sometimes dynamically
> determined at runtime which isn't ideal but also not difficult or new. Can
> you give an example of what you mean by this?
>
>
> Thanks, Rob.
>
> On Tue, 18 Apr 2023 at 20:05, Alan Bateman <Alan.Bateman at oracle.com>
> wrote:
>
>>
>> On 17/04/2023 15:20, Rob Bygrave wrote:
>>
>> *:*
>>
>>
>> > *is it reasonable to consider that ServiceLoader is the *only* vector
>> by which the implementation class will be instantiated? *
>>
>> In my view this is expected and imo I get there by thinking in the
>> opposite direction from the provides p.S type to the requires static rather
>> than the other way around. That is, the p.S type is only available via
>> requires static hence it is expected to potentially not exist at runtime in
>> the module-path. That is, if p.S was expected to exist at runtime it would
>> be "read" via a requires or requires transient clause and not via a
>> requires static - *the use of requires static for this case is explicit
>> and intentional*.
>>
>> In using requires static ... imo we are explicitly going out-of-our-way
>> to say "the types here might not be available at runtime" and the classic
>> case for this as I see it is this case of providing an optional service,
>> that will only be service loaded if the user of that service is in the
>> classpath / module-path. *IF* the module that is the user of a service
>> is in the classpath / module-path then that module will ensure that the p.S
>> type is in the module-path.
>>
>>
>> In your example, module io.avaje.config declares that it provides an
>> implementation of io.avaje.inject.spi.PropertyRequiresPlugin. There is
>> nothing to connect this to `requires static io.avaje.inject`. The module
>> system would need to search "far and wide" for io.avaje.inject to see if
>> exports io.avaje.inject.spi to io.avaje.config, otherwise there is no
>> way for it to know that the "missing package" is in a module that is not
>> required to be present at run-time. In other words, `requires static io.avaje.inject`
>> does not convey to the module system that io.avaje.inject exports
>> packages with service types.
>>
>> I understand there is a temptation to compare `requires static` with
>> optional dependences in Maven but they are not the same thing. `requires
>> static` is more for use-cases like annotations that do not need to be
>> present at run-time. It could of course be extended but it's a slippery
>> slope that ultimately amounts to giving up on reliability. In this case, it
>> amounts to giving up on a post resolution check and allowing all service
>> providers to have a dangling reference to a service type.
>>
>> -Alan
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/jigsaw-dev/attachments/20230418/699795ac/attachment-0001.htm>


More information about the jigsaw-dev mailing list