Peter Levart
2018-05-23 14:29:45 UTC
Hi,
I stumbled on a problem of a maven plugin that uses JDK's JavaScript
engine and doesn't work when maven is run with JDK 9 or 10. The code in
plugin to initialize the JavaScript engine is as follows:
jsEngine = new
ScriptEngineManager().getEngineByName("JavaScript");
if (jsEngine == null) {
throw new MojoExecutionException("Can't create
JavaScript engine");
}
ScriptEngineManager uses thread's context ClassLoader by default to
initialize script service providers:
public ScriptEngineManager() {
ClassLoader ctxtLoader =
Thread.currentThread().getContextClassLoader();
init(ctxtLoader);
}
...and delegates location of providers to ServiceLoader API:
private ServiceLoader<ScriptEngineFactory> getServiceLoader(final
ClassLoader loader) {
if (loader != null) {
return ServiceLoader.load(ScriptEngineFactory.class, loader);
} else {
return ServiceLoader.loadInstalled(ScriptEngineFactory.class);
}
}
Maven seems to load plugins in a child class loader of the "system"
(application) class loader and also sets this class loader as thread
context class loader. ServiceLoader does not find any
ScriptEngineFactory services when using this class loader.
The question is: Is this maven plugin's fault? Should the plugin load
services using explicit "system" (application) class loader or should
the ServiceLoader lookup strategy climb the class loader delegation
chain and include service providers that are registered in system Layer
too if given class loader is a descendant of "system" (application)
class loader?
Before JDK 9, using an child class loader of "system" (application)
class loader would locate system services, but since JDK 9, they are
invisible to such child class loaders. Is this intentional? Would it be
wrong if the lookup strategy was more "backwards compatible" ?
Regards, Peter
I stumbled on a problem of a maven plugin that uses JDK's JavaScript
engine and doesn't work when maven is run with JDK 9 or 10. The code in
plugin to initialize the JavaScript engine is as follows:
jsEngine = new
ScriptEngineManager().getEngineByName("JavaScript");
if (jsEngine == null) {
throw new MojoExecutionException("Can't create
JavaScript engine");
}
ScriptEngineManager uses thread's context ClassLoader by default to
initialize script service providers:
public ScriptEngineManager() {
ClassLoader ctxtLoader =
Thread.currentThread().getContextClassLoader();
init(ctxtLoader);
}
...and delegates location of providers to ServiceLoader API:
private ServiceLoader<ScriptEngineFactory> getServiceLoader(final
ClassLoader loader) {
if (loader != null) {
return ServiceLoader.load(ScriptEngineFactory.class, loader);
} else {
return ServiceLoader.loadInstalled(ScriptEngineFactory.class);
}
}
Maven seems to load plugins in a child class loader of the "system"
(application) class loader and also sets this class loader as thread
context class loader. ServiceLoader does not find any
ScriptEngineFactory services when using this class loader.
The question is: Is this maven plugin's fault? Should the plugin load
services using explicit "system" (application) class loader or should
the ServiceLoader lookup strategy climb the class loader delegation
chain and include service providers that are registered in system Layer
too if given class loader is a descendant of "system" (application)
class loader?
Before JDK 9, using an child class loader of "system" (application)
class loader would locate system services, but since JDK 9, they are
invisible to such child class loaders. Is this intentional? Would it be
wrong if the lookup strategy was more "backwards compatible" ?
Regards, Peter