<!DOCTYPE html><html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
On 11/12/2024 19:31, David Lloyd wrote:<br>
<blockquote type="cite" cite="mid:CANghgrRDcJieY7XhibMnxpH2GXT7+zdy8iv7zCf6RKSAkTsgjA@mail.gmail.com">
<div dir="ltr">
<div>
<div class="gmail_default" style="font-family:arial,helvetica,sans-serif">I'm once
again experimenting with modularizing some of our runtime
projects (Quarkus, WildFly) using JDK modules. Among the
various problems I've encountered, this one is one I haven't
cracked yet and seems like an oversight.</div>
<div class="gmail_default" style="font-family:arial,helvetica,sans-serif"><br>
</div>
<div class="gmail_default" style="font-family:arial,helvetica,sans-serif">I am
currently experimenting with a one-module-per-layer design
which allows us certain capabilities (like lazy loading of
modules, late binding of dependencies, and circularity in
dependencies), and also allows us to create module graphs
that can mix in "unnamed" modules for libraries which don't
yet work properly as named modules, as well as automatic
modules for libraries which can work as modules but don't
yet define a descriptor.</div>
<div class="gmail_default" style="font-family:arial,helvetica,sans-serif"><br>
</div>
<div class="gmail_default" style="font-family:arial,helvetica,sans-serif">However I
have discovered an important difference between service
loaders which load services by class loader (for example,
those found in Microprofile and Jakarta frameworks) and
those which load by module layer (none?) which is preventing
things from working properly.</div>
<div class="gmail_default" style="font-family:arial,helvetica,sans-serif"><br>
</div>
<div class="gmail_default" style="font-family:arial,helvetica,sans-serif">When I load a
service by layer, after searching the given layer, the
parent layers of that layer are then searched in order,
recursing up the graph. (Sometimes the same service could be
returned multiple times when there are diamonds in the layer
graph, but that's a different problem.)</div>
<div class="gmail_default" style="font-family:arial,helvetica,sans-serif"><br>
</div>
<div class="gmail_default" style="font-family:arial,helvetica,sans-serif">When I load a
service by class loader, if the service is not found in the
class loader's defined layers, then the search terminates
and the service is considered not found, even if the service
provider exists in a parent layer of one of those layers.
This essentially means that all frameworks which are loading
services by class loader (and using the class loader of the
framework itself is typical here) will also need all of
their implementations to coexist in one of the layers
defined by that class loader - or else they must be defined
in the unnamed module (in which case it will always be
found).</div>
<div class="gmail_default" style="font-family:arial,helvetica,sans-serif"><br>
</div>
<div class="gmail_default" style="font-family:arial,helvetica,sans-serif">Ironically,
it *will* search the parent class loading delegation chain
for layers which contain service implementations. The point
of using module layers though is that they can have multiple
parents, departing from this single-delegation model. In our
class-loader-per-module setup, we do not use the parent
class loader delegation as it would be meaningless in that
context.</div>
<div class="gmail_default" style="font-family:arial,helvetica,sans-serif"><br>
</div>
<div class="gmail_default" style="font-family:arial,helvetica,sans-serif">A good
solution would be to modify service loading by class loader
to also search parent layers of each layer defined to that
class loader. This seems like it would be fairly easy to
implement, but might possibly have subtle compatibility
implications for very specific environments which have a
module-per-class-loader situation along with multiple
layers.</div>
<br>
</div>
</div>
</blockquote>
If ServiceLoader.load is invoked with a ClassLoader then it lazily
iterates through the class loader delegation chain. If
ServiceLoader.load is invoked with a ModuleLayer then it iterates
through the module layers. The former has deliberately limited
support for cases where a class loader is used by a module layer but
doing what you propose is adding more complexity for what seems like
a really niche usage. I would worry that changing it along the lines
you propose would result in something that only a few people could
understand.<br>
<br>
Have you looked at changing these frameworks to work with modules
and specify a module layer to ServiceLoader.load?<br>
<br>
-Alan<br>
</body>
</html>