<div dir="ltr"><div><i><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px">> </span><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px">Optional dependencies are meant to support annotations and other limited use cases.</span></i></div><br class="gmail-Apple-interchange-newline"><div>FWIW to me <i>maven</i> <i>optional true</i> dependencies map to requires static</div><div><br></div><div><p style="margin:0px;font-stretch:normal;font-size:11px;line-height:normal;font-family:Menlo;font-size-adjust:none;font-kerning:auto;font-variant-alternates:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-east-asian:normal;font-feature-settings:normal;color:rgb(0,0,0)"><span style="font-variant-ligatures:no-common-ligatures"><span class="gmail-Apple-converted-space">  </span><dependency></span></p>
<p style="margin:0px;font-stretch:normal;font-size:11px;line-height:normal;font-family:Menlo;font-size-adjust:none;font-kerning:auto;font-variant-alternates:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-east-asian:normal;font-feature-settings:normal;color:rgb(0,0,0)"><span style="font-variant-ligatures:no-common-ligatures"><span class="gmail-Apple-converted-space">    </span>...</span></p>
<p style="margin:0px;font-stretch:normal;font-size:11px;line-height:normal;font-family:Menlo;font-size-adjust:none;font-kerning:auto;font-variant-alternates:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-east-asian:normal;font-feature-settings:normal;color:rgb(0,0,0)"><span style="font-variant-ligatures:no-common-ligatures"><span class="gmail-Apple-converted-space">    </span><i><optional>true</optional></i></span></p>
<p style="margin:0px;font-stretch:normal;font-size:11px;line-height:normal;font-family:Menlo;font-size-adjust:none;font-kerning:auto;font-variant-alternates:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-east-asian:normal;font-feature-settings:normal;color:rgb(0,0,0)"><span style="font-variant-ligatures:no-common-ligatures"><span class="gmail-Apple-converted-space">  </span></dependency></span></p></div><div><br></div><div><br></div><div>When we are in the mode of translating from <i>'classpath only'</i> to<i> 'classpath + module-path'</i> support, whenever we see maven optional dependencies we expect to use requires static.</div><div><br></div><div><br></div><div><i>> <span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px">A class that `implements` an interface is not an optional dependency situation -- loading the class *always* causing loading of the interface, which will fail, so we make module resolution fail fast to ensure the loading failure never happens.</span></i></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px"><br></span></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px">It is an optional dependency for classpath.</span></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px"><br></span></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px">In terms of classpath we do not have any fail fast for this, IF something tries to new up the service implementation AND the p.S interface type is not in the classpath we get an exception (with the cause being ClassNotFoundException for p.S). This is expected and all good. </span><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px"><br></span></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px"><br></span></div><div><font color="#172b4d" face="DejaVu Sans, sans-serif"><span style="font-size:14px">With module-path the </span></font><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px"><i>module fail fast resolution  </i>actually prevents this pattern / use case that works with classpath from working. Code using this pattern </span><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px">with classpath will no longer work with module-path due to the fail fast resolution error. </span><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px">The effect of the fail fast resolution on p.S is that we have turned an optional dependency (in classpath) into a non-optional dependency (the p.S interface<span class="gmail-Apple-converted-space"> </span></span><i style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px">MUST</i><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px"><span class="gmail-Apple-converted-space"> </span>be in the module-path).</span></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px"><br></span></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px"><br></span></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px">To be clear, the pattern with classpath and maven is that:</span></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px">We have a maven dependency with <optional>true</optional> that has the p.S interface type. The p.S type exists at compile time so we can compile the implementation of the service interface but we understand that p.S might not exist at runtime as we have explicitly stated that the dependency that has p.S is a maven optional dependency. We have an implementation of p.S that we expect to be optionally created via ServiceLoader. Yes this implementation is only expected to be created by ServiceLoader. We see an exception at runtime if code tries to instantiate the implementation when the p.S type is not in the classpath and that is expected and all good.</span></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px"><br></span></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px">With module-path this now does not work (due to the fail fast on p.S interface type). </span></div><div><br></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px">With module-path, IF</span><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px"> module resolution was changed to tolerate a `provides` that specifies a missing service interface, I'd argue that we'd get the same behaviour that we get with classpath. That is, if this was allowed then if something tried to create a new instance of the implementation we would expect the same behaviour that we see in classpath and </span><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px">the same or similar error would be thrown as what is thrown when running with classpath (cause </span><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px">ClassNotFoundException for p.S</span><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px">).</span></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px"><br></span></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px"><br></span></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px">Cheers, Rob.</span></div><div><br></div><div><br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, 18 Apr 2023 at 02:20, Rob Bygrave <<a href="mailto:robin.bygrave@gmail.com">robin.bygrave@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="ltr"><i>> <span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px">really a request to allow more usage of `requires static` and specifically to allow `provides p.S with ...`<span> </span></span></i><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px"><span><br></span></span></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px"><span>Yes, that's my case.</span></span></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px"><span><br></span></span></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px"><span><br></span></span></div><div><i><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px"><span>> </span></span><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px">If Foo isn't available, then (so the thinking goes) the `provides` is moot, and the implementation's dependence on Foo should be ignored.</span></i></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px"><br></span></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px">Yes!!.</span></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px"><br></span></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px"><br></span></div><div><i><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px">> </span><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px">However, this desire is not clearly communicated by the implementation module expressing `requires static <interface-module>` -- the interface-module could export many packages, not just one package containing one interface Foo, so the `requires static` is not flagging anything about the service interface per se.</span></i></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px"><br></span></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px">Hmmm, my thinking was going the other direction. With the provides  <i>p.S</i> uses ...  the p.S is <b><i>ONLY</i></b> visible to the module at compile time via the requires <b style="font-style:italic">static </b>[so at compile time we can infer that the p.S type is optional and might not exist at runtime based on the requires <i>static</i>].</span></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px"><br></span></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px"><br></span></div><div><i><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px">> </span><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px">Optional dependencies are meant to support annotations and other limited use cases.</span></i></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px"><br></span></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px">Ok ... umm.</span></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px"><br></span></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px"><br></span></div><div><i><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px">> </span><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px">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. If no ...</span></i></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px"><br></span></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px">Yes, I follow this and agree.</span></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px"><br></span></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px"><br></span></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px">> </span><i><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px">is it reasonable to consider that ServiceLoader is the *only* vector by which the implementation class will be instantiated?<span> </span></span></i></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px"><br></span></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px">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 - <i>the use of requires static for this case is explicit and intentional</i>.  </span></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px"><br></span></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px">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. <i>IF</i> 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.</span></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px"><br></span></div><div><br></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px">Cheers, Rob.</span></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px"><br></span></div><div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px">Would a real world example help?</span></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px"><br></span></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px">- avaje-inject has a Plugin interface, and will look to load Plugin implementations at runtime.</span></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px">- avaje-config is a module that has its own functions (external configuration) but can also provide a Plugin for avaje-inject (provide external configuration for dependency injection).</span></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px">- avaje-jsonb is a module that has its own functions (json marshalling) but can also provide a Plugin for avaje-inject (provide default json marshalling implementation for dependency injection).</span></div><br></div><div><span style="color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px"><br></span></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, 18 Apr 2023 at 01:23, Alan Bateman <<a href="mailto:Alan.Bateman@oracle.com" target="_blank">Alan.Bateman@oracle.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">

  
  <div>
    On 17/04/2023 14:14, Rob Bygrave wrote:<br>
    <blockquote type="cite">
      
      <div dir="ltr">I'm seeing a runtime error I was not expecting.
        <div><br>
        </div>
        <div><i>Error occurred during initialization of boot layer<br>
            java.lang.module.ResolutionException: Module io.avaje.config
            does not read a module that exports io.avaje.inject.spi</i><br>
        </div>
        <div><br>
        </div>
      </div>
    </blockquote>
    <br>
    JDK-8299504 [1] captures a number of comments on this scenario. <br>
    <br>
    -Alan<br>
    <br>
    [1] <a href="https://bugs.openjdk.org/browse/JDK-8299504" target="_blank">https://bugs.openjdk.org/browse/JDK-8299504</a><br>
  </div>

</blockquote></div>
</blockquote></div>