<div dir="ltr"><i>> source of the problem:</i><div><br></div><div>I'll have a crack.</div><div><br></div><div>As I see it, I think this case is that some modules have "split personalities" in that they don't exist to provide a service as their <i>main goal</i> but it happens that they can also additionally provide a service IF they are used in an app configuration that uses and loads implementations of that service [and that service implementation would be left unused if it is used in a standalone configuration that does not include the service interface].</div><div><br></div><div>Y (service provider) has a main goal of doing "Y good stuff".</div><div>It really does not want a <i>hard</i> dependency to X, it can be used by itself completely standalone but IF it is used in an application configuration that includes X then ... it additionally happens to provide an implementation of an X service interface. Some people might call this "An optionally provided service" that might not be loaded.</div><div><br></div><div>e.g.</div><div><br></div><div>Module X has an interface x.spi.Plugin and will service load all the implementations.</div><div><br></div><div>Module Y exists to do "Y good stuff", exports y; and can be used completely by itself standalone. An application configuration that only includes Y is good and expected.</div><div>Module Y can also (as a secondary reason to exist) implement x.spi.Plugin to provide useful functionality to an application configuration that includes Y + X.</div><div><br></div><div>module y {</div><div> exports y; // Main reason to exist</div><div><br></div><div> // As a secondary reason to exist</div><div> requires static x;</div><div> provides x.spi.Plugin with ... <internal implementation></div><div>}</div><div><br></div><div><br></div><div>Application configuration using just Y standalone fails at startup based on the existence of "provides x.spi.Plugin".</div><div><br></div><div><br></div><div><br></div><div><i>> if they choose not to use X, Y would just sit there, unused.</i></div><div><br></div><div>Y still provides its main reason to exist, it's "Y good stuff". What is not used is that 1 class which is the implementation of x.spi.Plugin (and with module-path this implementation can be hidden / not exported and not open to abuse / accidental usage - yay!!).</div><div><br></div><div><br></div><div><br></div><div><br></div><div>Fixing a module with a split personality:</div><div>-----------------------------------------------</div><div>We could split the Y module into 2 modules - Y and Y-X-Plugin. The only classes in Y-X-Plugin are the implementation of x.spi.Plugin + module-info with the service loader configuration etc. Now we have 3 application configurations to consider:</div><div><br></div><div>- Y (now works)</div><div>- X + Y (might be confusing for users)<br></div><div>- X + Y + X-Y-Plugin (needs documentation)</div><div><br></div><div><br></div><div>What is mooted is to be able to just have the 2 configurations to consider:</div><div><br></div><div><div>- Y (standalone)</div><div>- X + Y (y provides its "Y good stuff" + acts as a x.spi.Plugin for X)</div><div><br></div><div><br></div><div>The reason why this could be considered acceptable is because the implementation of x.spi.Plugin that would exist in Y can be hidden / not exported and not open to abuse / accidental use.</div><div><br></div></div><div><br></div><div>Cheers, Rob.</div><div><br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, 19 Apr 2023 at 04:05, Ron Pressler <<a href="mailto:ron.pressler@oracle.com">ron.pressler@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 style="line-break:after-white-space">
<br>
<div><br>
<blockquote type="cite">
<div>On 18 Apr 2023, at 16:01, Josiah Noel <<a href="mailto:josiahnoel@gmail.com" target="_blank">josiahnoel@gmail.com</a>> wrote:</div>
<br>
<div>
<div dir="ltr">
<div dir="ltr">
<div dir="ltr" class="gmail_attr">On Tue, Apr 18, 2023 at 8:46 AM Ron Pressler <<a href="mailto:ron.pressler@oracle.com" target="_blank">ron.pressler@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><br>
</div>
<div>Which makes me wonder, what is the root of the optionality in your code? I.e. how does io.avaje.inject come to be resolved?<br>
</div>
</blockquote>
<div><br>
</div>
<div>So avaje jsonb/config/http implements SPI interfaces exported by avaje inject(which is added as a maven optional dependency). The idea here is that the plugin implementation would be loaded by avaje-inject to add to the DI scope.</div>
<div><br>
</div>
<div>Outside of avaje inject, these service implementation classes have no meaning and are not meant to be instantiated. In some cases, the service implementation package may not even be exported by the module, so even if you tried you couldn't instantiate
outside of a service loader.</div>
<div><br>
</div>
<div>Does this help answer your question? Or did I misread it?</div>
</div>
<input name="virtru-metadata" type="hidden" value="{"email-policy":{"disableCopyPaste":false,"disablePrint":false,"disableForwarding":false,"enableNoauth":false,"expandedWatermarking":false,"expires":false,"sms":false,"expirationNum":1,"expirationUnit":"days","isManaged":false,"persistentProtection":false},"attachments":{},"compose-id":"8","compose-window":{"secure":false}}"></div>
</div>
</blockquote>
</div>
<div><br>
</div>
I think so, thank you. But when the application runs in a particular configuration, the application deployer knows whether or not that configuration uses the avaje inject module. If it does not, why is the configuration including the service module?
<div><br>
</div>
<div>The class path has a loosy-goosey attitude, but modules are all about creating a proper configuration. Ideally, there shouldn’t be any modules that could not possibly be used.</div>
<div><br>
</div>
<div>We could discuss making modules more laid back in some specific situations, but generally, they exist so that we could have a strict configuration. So I guess my question now is, why would you want to allow a particular application configuration
to include a module that could not possibly be used in that configuration?</div>
<div><br>
</div>
<div>I assume the answer is to avoid the need to document to the user that if they choose to use some capability offered by module X (avaje inject) they should also add module Y (the service provider). If we were more lenient, you could just give them
module Y, and then all would work whether or not they choose to use X. But the flip side of that is that if they choose not to use X, Y would just sit there, unused. Best case scenario, it would just increase their image size; worst-case scenario is that it
could preclude some future optimisations that may require a full program analysis. </div>
<div><br>
</div>
<div>To do this properly, as Alan alluded, `requires static` is insufficient because the module doesn’t know where the service interface is supposed to come from. Rather, we would need a new specific mechanism that says “if module X is readable, then
provide this service”. To know how important such a feature is we need to understand the source of the problem: why is it hard to exclude unused modules? </div>
<div><br>
</div>
<div>— Ron</div>
</div>
</blockquote></div>