1

I'm using Groovy 4.0.2 as a runtime scripting environment for my application. My goal is to introduce timeout handling into user-provided scripts, but depending on what the script is used for, different timeouts should apply. My compiler configuration looks as follows:

var config = new CompilerConfiguration();
var extensions = new ArrayList<String>()
var timedInterruptParams = new HashMap<String, Object>()
// TimedInterrupt is an annotation with multiple parameters. We're only interested
// in the "value" and the "unit" parameters. For now, let's only set the "value"...
timedInterruptParams.put("value", myTimeout);

config.addCompilationCustomizers(
    new ASTTransformationCustomizer(CompileStatic.class),
    new ASTTransformationCustomizer(timedInterruptParams, TimedInterrupt.class)
);

The above configuration works, but it fixes the unit of the TimedInterrupt to its default (which is TimeUnit.SECONDS). I would like to overwrite this value in the timedInterruptParams map. However, none of the following works:

  • timedInterruptParams.put("unit", TimeUnit.MILLISECONDS)

    Produces an error during script compilation, claiming that MILLISECONDS is not a supported constant expression.

  • timedInterruptParams.put("unit", new ConstantExpression(TimeUnit.MILLISECONDS)

    Same as above

  • timedInterruptParams.put("unit", "MILLISECONDS")

    Causes the groovy compiler to bug out completely with "this method should not have been called".

  • timedInterruptParams.put("unit", "java.util.concurrent.TimeUnit.MILLISECONDS")

    Same as above

So... I'm running out of options here. Which value am I supposed to pass into the "unit" value of the parameter map?

Martin Häusler
  • 6,544
  • 8
  • 39
  • 66
  • Could you please create a ticket in the Groovy JIRA so we can fix the handling of enum values? It should work for TimeUnit.MILLISECONDS with no ast wrapping, but as mentioned below fails to be converted. – emilles Jun 09 '22 at 12:09

1 Answers1

1

It took quite a bit of digging, but the answer lied within TimedInterruptibleASTTransformation, the class which actually interprets the @TimedInterrupt annotation. There, the unit value was interpreted as follows:

Expression unit = node.getMember('unit') ?: propX(classX(TimeUnit), 'SECONDS')

... and propX and classX are static helper methods from org.codehaus.groovy.ast.tools.GeneralUtils. With this information, it was relatively easy to make my code work. The line I was missing is:

timedInterruptParams.put("unit", propX(classX(TimeUnit.class), TimeUnit.MILLISECONDS.toString()),

It turns out that groovy interprets enum literals not as constants, but as properties of a class. This case sadly isn't covered by the auto-converter that applies to the object values of the parameter maps.

Martin Häusler
  • 6,544
  • 8
  • 39
  • 66