Eliminate silent dependencies was: Mandatory service requirement
Jesse Glick
jesse.glick at oracle.com
Tue Feb 21 16:31:37 PST 2012
Alan Bateman wrote:
> "requires service S" means >= 1 implementations of S required.
But there is a difference between saying "you must somehow provide an implementation of S if this module is to be used or the system will report an error", which can
arguably be useful (in my experience rarely); and actually going out and silently picking one from the repository when none was provided, which is not obviously implied
by the above declaration and might be bad.
> "requires optional service S" means >= 0 implementations of S required.
Which means nothing at all :-) as I noted at the end of my original post "Mandatory service requirement" - there is no reason why you should have to declare that you
might load a service, if you can gracefully handle zero implementations.
Jaroslav Tulach wrote:
> is your suggestion to force the my.corp.app module to always have a direct
> dependency on explicit implementation of a parser (e.g. saxon)?
Exactly. If Saxon works, why would you want the app to run with something else? If you do, just change the dep (and retest the app). Here "the app" can just be a shell
module that assembles all the reusable pieces it needs, so it is really just a module configuration.
(There are cases mainly arising I think in the Java Platform where there is just one implementation of an API available for a given system and this depends on the host
operating system or the Java vendor; but these situations exist even without ServiceLoader, in fact more commonly, and would probably be handled via module aliases.)
For large apps with a user-level plugin system, I would expect Jigsaw to offer reflective APIs so you could build a UI to load named modules and make their services
available.
> Otherwise others, reusing jaxp or my.corp.wsparser will find out
> only during runtime that the execution environment is insufficient.
Yes, but compared to other problems this is a very simple one to solve - add the desired implementation. It would just be part of the documentation of an API that calling
it (or a certain subset of it!) presumes an implementation of a particular service, and what happens if no implementation is present.
> we simplified the usage of that API a lot by replacing this with
>
> module org.netbeans.projectuiapi {
> requires service optional org.netbeans.project.uiapi.ActionsFactory; ...
> }
This is misleading because there is no equivalent in NB APIs to "requires service optional" ("requires optional service"?): if you do not really "require" it then there
is nothing to declare (see discussion above). Rather, what we _had_ was like a (mandatory) "requires service", which made unit tests painful and also forced you to turn
on projectui (the impl module) even when none of the above services were to be called in a particular application. That is why I removed the token requirement and wrote
no-op fallback implementations of these services.
David M. Lloyd wrote:
> use its own class loader to locate it
Agreed that there are a lot of different variants. However we should not advocate using old-style ClassLoader hacks (especially Thread.contextClassLoader), which can
break in all sorts of tricky ways and do not compose well - part of the justification for an official module system in Java is to simplify this kind of thing in the
future. I think plain ServiceLoader.load(Class), understood to search in all modules in the loaded configuration, can work for all of the cases where available services
must be discovered; if you need to discriminate among implementations, call some method on each (e.g. String[] supportedDigestImplementations()).
Or ask your own caller to pass in an implementation in dependency injection style. Unfortunately it seems that Jigsaw offers no integration point for DI frameworks.
More information about the jigsaw-dev
mailing list