Suppose you want submit job to ExecutorService.
The Baroque version
You could create a class that implements Callable:
class MyJob implements Callable<Integer>{ @Override Integer call() throws Exception { return 42 } }
and give it to the executor service:
def 'submit callable as MyJob object'() { expect: executorService.submit(new MyJob()).get() == 42 }
The response is, as expected, 42.
Map as Callable version
You want to use this job only in one place so why not inline this class:
def 'submit callable as map'() { expect: executorService.submit([call: { 42 }] as Callable).get() == 42 }
The response is again 42.
Groovy closure version
Why not use closure instead of map?
def 'submit callable as closure'(){ expect: executorService.submit { 42 }.get() == 42 }
The response is … null.
Condition not satisfied: executorService.submit { 42 }.get() == 42 | | | | | | | false | | null | java.util.concurrent.FutureTask@21de60b4 java.util.concurrent.Executors$FinalizableDelegatedExecutorService@1700915
Why? It is because Groovy treats this closure as Runnable, not Callable and Future#get returns null when task is complete.
Groovy closure version with cast
We have to cast our closure before submiting to executor service:
def 'submit callable as closure with cast'() { when: int result = executorService.submit({ return 42 } as Callable<Integer>).get() then: result == 42 }
The response is, as expected, again 42.
What interesting, the same test with inlined result variable fails… Strange… It could be Spock framework error.
Source code is available here.