Read method name from configuration file and call it dynamically

Hi there,

I have a requirement as below. Can anyone share some ideas or point the direction of the solution?

I have a SchemaEntryPoint class which contains some internal DSL scripts:

class SchemaEntryPoint (implicit var ctxMeta: PayrollEngineContextMeta)
  extends PySchemaDsl
{
  def schema_cn28 = {
    // ----------------Schema Scripts Begins Here----------
    IMPORT(IT0008)
    PIT(PCR1("NORM"))
    IF(OFF_CYCLE){
      BLOCK("Off-cycle schema block"){
        PIT(PCR1("NORM"))
      }
    } ELSE {
      IMPORT(IT0008)
    }
    PIT(PCR1("NORM"))
    IF(TERM_MONTH){
      PIT(PCR1("WFWF"))
    }
    // ----------------Schema Scripts Ends Here----------
  }

  def schema_cn29 = {
     ....
     ....
  }
}

The SchemaEntryPoint.scala file will be modified by business specialist who only knows the DSL syntax.

Then in the main program, class SchemaEntryPoint will be instantiated and the schema_cnXX method will be called as the entry point of DSL script. Like this:

  private def runForOnePeriod(period: PyPeriod): LogNode = {
    // Prepare payroll engine meta info
    implicit val pyMeta: PayrollEngineContextMeta = PayrollEngineContextMeta(pernr, period)

    val schemaEntryPoint = new SchemaEntryPoint() 
    schemaEntryPoint.schema_cn28  <-- DSL schema script entry point here
    schemaEntryPoint.outputSchmLog()
  }

Since the DSL script will be changed a lot by the business specialist, every time a new entry point method “schema_cnXX” created, we have to modify the main program and rebuild the whole project.

For this reason, I want the main program to read the name string of schema entry point from conf configuration file, and call it dynamically with the name string

Can anyone shed some light?
Not sure if reflection or macros can do this? I

If you’re doing it based on the config file, that means runtime; if it’s at runtime, then macros can’t help, since those run at compile time. So it sounds to me like reflection may be necessary…

I think there’s two good options and one unromantic one for this: read the business specialist’s scala script in and interpret it at run time, compile the business specialist’s scala and use reflection to load the right thing, and (less romantic) just link their code into the project when you rebuild it. (I don’t think macros are a good fit.)

Programmatic Use of Scala REPL | REPL | Scala Documentation has a good start on interpretting scala as a script. You’ll need to study that IMain class in some depth, but it works well.

For my hobby project I keep things pretty spartan due to really limited hardware - a very slow file system - but once I’ve got the JVM started I don’t want to stop. I stripped it down to just calling java reflection via scala. It’s not pretty, but it gets the job done. Scala has its own reflection library which is a bit cleaner, but heavier on the file system. My code to load and run a Runnable object looks like this:

        val classLoader = new URLClassLoader(Array(jarFile.toUri.toURL))
        classLoader.loadClass(className + "$").getField("MODULE$").get(Array.empty[Object]).asInstanceOf[Runnable].run()

Using reflection means compiling the code anyway. It might be as easy to rebuild your program all the way and give it a name specific to the business specialist’s needs.Not romantic, but possibly the simplest way.