Search code examples
scriptingjythondsl

Delegating global functions to Java with Jython


I would like to bind my functions implemented in Java into the global scope of a Jython interpreter instance (so I don't need to manually import them first in my scripts).

If this helps, I'm looking for a similar thing to Groovy's DelegatingScript, where you can set the delegate of the script body to a Java/Groovy object, so the objects functions are directly callable inside the DSL script.

Is there any way to achieve this?


Solution

  • Turned out this is rather easy to do. You can put static functions into the Dsl class and those can be directly invoked inside the script.

    Note: this is not exactly the same what Groovy does, because there you bind the local scope to an object rather than a class, but with some thinking this can be still very useful.

    App.java

    public final class App {
      public static void main(String[] args) throws Exception {
        try (PythonInterpreter py = new PythonInterpreter()) {
          py.exec("from hu.company.jythontest.Dsl import *");
          try (FileInputStream script = new FileInputStream("./etc/test.py")) {
            py.execfile(script);
          }
          var blocks = py.get("blocks", List.class);
          System.out.println(blocks.toString());
        }
      }
    }
    

    Dsl.java

    public final class Dsl {
      public static class Block {
        private final String id;
        public Block(String id) {
          this.id = id;
        }
        public String getId() {
          return id;
        }
        @Override
        public String toString() {
          return id;
        }
      }
    }
    

    test.py

    blocks = [Block('%d' % i) for i in range(10)]
    

    Output:

    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]