Search code examples
groovyevallazy-evaluationgroovyshell

Lazy GString evaluation while being executed by Eval or GroovyShell


For a monitoring system, I need to evaluate custom checks which are represented by boolean expressions. For example, I have a simple pseudocode condition (they can be more complex):

if (webservice is unavailable) and (there are no emails about planned downtime)

If possible, I'd like to use short-circuit evaluation here, so that if webservice is available (and the first condition is false), the second part won't be evaluated, as the overall result will be false anyway. Due to this, I can avoid connecting to mail server (and other time-consuming operations) when it's unnecessary.

Here is an example of what I'm trying to achieve:

class WebserviceDownCheck {
  boolean check() { 
    println 'Checking webservice'
    return false 
  }
}

class NoDowntimeEmailCheck {
  boolean check() { //shouldn't be executed
    println 'Checking emails'
    return true 
  }
}
//using string evaluation, because conditions are constructed during runtime
Eval.me("${new WebserviceDownCheck().check()} && ${new NoDowntimeEmailCheck().check()}")

The output is:

Checking webservice
Checking emails //shouldn't be there
Result: false

NoDowntimeEmailCheck().check() shouldn't be executed, because the first condition is already false. I've tried:

  • using GroovyShell instead of Eval
  • changing check() methods to fields and applying @Lazy transformation
  • changing ${new WebserviceDownCheck().check()} to ${ -> new WebserviceDownCheck().check()} (saw it here)

Seems that I need some lazy mechanism which will allow me to initialize GString while Eval (or GroovyShell) is already executing it. Maybe something like lazy Binding for GroovyShell.

I wonder, is it somehow possible without writing custom string evaluation logic?


Solution

  • Combine it into one expression, like this:

    Eval.me("${new WebserviceDownCheck().check() && new NoDowntimeEmailCheck().check()}")
    

    and only the first will be evaluated if the result is false.