JSR-223 - Scripting for the Java Platform

Joe Eckard
  • Joe Eckard
    Joe Eckard

    I was wondering if you had considered using the JSR-223 API for running

    It seems like you could pick up support for new languages for free (ruby,
    python, php, etc.), and get a standard method for generating output with
    templates (there are engines for freemarker & velocity).

    import javax.script.Bindings;
    import javax.script.ScriptContext;
    import javax.script.ScriptEngine;
    import javax.script.ScriptEngineManager;
    ScriptEngineManager engineManager = new ScriptEngineManager();
    ScriptEngine scriptEngine = engineManager.getEngineByName("groovy"); // OR getEngineByExtension(".groovy")
    Bindings binding = scriptEngine.createBindings();
    binding.put("FIVE", 5);
    scriptEngine.setBindings(binding, ScriptContext.GLOBAL_SCOPE);
    Object retVal = scriptEngine.eval(formula);
  • David E. Jones
    David E. Jones

    I looked into JSR-223 a little since it is a nice (somewhat) recent addition
    to Java.

    What I couldn't find was a way to compile scripts and get an object that can
    be cached that represents the compiled script so that it can be run more
    efficiently. If there is a way to do that, it would make implementations of
    the "ScriptRunner" interface easier, or perhaps make that interface

    For now, and if there is indeed no way to get a compiled/interpreted
    representation of a script back from JSR-223 APIs, then implementing the
    ScriptRunner interface and adding a reference to it in the moqui-conf XML file
    is the way to add scripting language support to Moqui.

  • Joe Eckard
    Joe Eckard

    Oh, right - good point. Actually, it looks like you can do this if the engine
    implements the Compilable interface. (The Groovy and Freemarker engines do
    implement this interface.)

    ScriptEngineManager mgr = new ScriptEngineManager(); 
    ScriptEngine engine = mgr.getEngineByName("FreeMarker"); 
    engine.put("who", "World"); 
    CompiledScript script = ((Compilable) engine).compile("Hello ${who}!"); 
  • David E. Jones
    David E. Jones

    Thanks again for this idea Joe, and for the code snippets.

    In commit e4119f1 I added support for using JSR-223 (javax.script) compatible
    scripting engines through configuration only, so that implementation of the
    ScriptRunner interface is not required.

    That means that the configuration for groovy can look like:

            <script-runner extension=".groovy" engine="groovy"/>

    instead of:

            <script-runner extension=".groovy" class="org.moqui.impl.context.runner.GroovyScriptRunner"/>

    However, Moqui is still using the ScriptRunner interface by default for Moqui
    because the JSR-223 (javax.script) interface does not support pre-compiled
    class scripts and calling methods within that class as groovy does.

    This still works fine for other languages, and on that note I added support
    for the embedded JavaScript (Rhino) engine in Java. The configuration for it
    in the MoquiDefaultConf.xml file is just:

            <script-runner extension=".js" engine="javascript"/>

  • Anonymous

    Hi David,

    the ScriptEngineManager has a method getEngineByExtension that you can use to
    get the engine by file extension:


    Without looking at the details, this could be used to avoid the need to
    configurations like:

    <script-runner extension=".js" engine="javascript"/>

    <script-runner extension=".groovy" engine="groovy"/>


  • David E. Jones
    David E. Jones

    Thanks Jacopo, this is a good idea. I changed the ResourceFacade to support
    this, and as of commit 619c2ff it is now supported (and the moqui-conf.xsd
    annotation is updated to mention it). Here is the annotation for a short

    NOTE: If you use a default extension supported in JSR-223 for the desired
    scripting language you do

    not need a script-runner element. The ScriptEngine will be looked up using the

    ScriptEngineManager.getEngineByExtension() method and the script (pre-compiled
    if supported) will

    be cached in the "resource.script${extension}.location" cache.