I have been using Spock instead of JUnit for a few months now. Today, I’m trying something around thread safety and I found something about Groovy that annoyed me. In my unit test, I need to submit a Callable
task to ExecutorService
.
The Problem
In Java, normally we will normally do this:
1
2
3
4
ExecutorService executor = Executors.newSingleThreadExecutor();
Callable<Integer> c = () -> 1 + 2;
Future<Integer> future = executor.submit(c);
System.out.println("Result: " + future.get());
Output:
1
Result: 3
In Groovy(Spock),
1
2
3
4
ExecutorService executor = Executors.newSingleThreadExecutor()
Callable<Integer> c = { -> return 1 + 2 }
Future<Integer> future = executor.submit(c)
System.out.println("Result: " + future.get())
Output:
1
Result: null
Why??!?
Root Cause
In Groovy, the closure is always default as Runnable
instead of Callable
. (See more in ticket GROOVY-3295) Thus, when we execute submit
method Groovy will auto convert it to submit(Runnable)
instead of submit(Callable)
.
This happen even I assigned it to a variable c
with type Callable<Integer>
.
The Solution
Use as Callable
.
1
2
3
4
ExecutorService executor = Executors.newSingleThreadExecutor()
Callable<Integer> c = { -> return 1 + 2 }
Future<Integer> future = executor.submit(c as Callable<Integer>)
System.out.println("Result: " + future.get())
Output:
1
Result: 3