[External] : Re: provides and requires static ... runtime error

Alex Buckley alex.buckley at oracle.com
Thu Apr 20 18:07:35 UTC 2023


On 4/20/2023 8:03 AM, Josiah Noel wrote:
> We're talking about a case where module Y's primary purpose is not to 
> implement SPI from X, but to provide its own packages/functionality 
> unrelated to X. The classes in Y that use X should not be exported, and 
> should only be loaded when X service-loads them. Hence, the Y module 
> will use requires static to clearly inform that the classes are required 
> at build time, but not for Y's normal operation.

We understand the scenario, which involves the module system allowing 
optionality not only of service providers for a given service, but also 
of the service itself.

However, as Alan has been saying, `requires static` doesn't have the 
precise, clear meaning that you think. When the module system sees the 
directive `requires static X;` in some module Z, the module system 
doesn't know the reason for the directive:

- Perhaps code in Z is annotated using annotation interfaces from X.
- Perhaps code in Z is going to reflect over the classes in X.
- Perhaps code in Z is implementing X's exported interfaces and the 
owner of Z is really sure that whenever Z is resolved, X is also 
resolved. (No use of ServiceLoader is intended in this item.)

You're going to say, "But that's Z, not Y! Y doesn't do any of those 
things! Y uses `requires static X;` to get a light touch on a service in 
X, and Y's service provision should be considered optional if X isn't 
available."

But Y and Z are the same to the module system -- each directs the module 
system to allow itself to be resolved even if X is not resolved. The 
module system then sees that Y wants to provide a service, but the 
module system has no idea where the service is, so fails fast at 
startup. This is a feature, not a bug. The classpath behavior, of only 
discovering that a service provider can't provide a service during run 
time (because the service is missing), is not what we wanted for modular 
services. If `provides` directives were treated as optional, i.e., 
ignored when the service can't be found at startup, people would say 
"Why bother with `provides`? It's no more reliable than putting 
everything on the classpath, when ServiceLoader throws because it can't 
instantiate the service provider."

So, I hope you can see why we are extremely cautious about acceding to 
requests to relax the checking of `provides`. In your scenario, Y is 
pulling double duty, which makes it harder to understand overall, and 
you'll benefit a lot more from breaking it up than from a more relaxed 
module system.

Alex


More information about the jigsaw-dev mailing list