This is an automated email from the ASF dual-hosted git repository.
sunlan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/master by this push:
new ddf969a755 GROOVY-11681: add `ExecutorService#submit(Closure)`
extension
ddf969a755 is described below
commit ddf969a755f4778802975bbf72e922ba773cb034
Author: Eric Milles <[email protected]>
AuthorDate: Thu Jul 10 11:15:13 2025 -0500
GROOVY-11681: add `ExecutorService#submit(Closure)` extension
---
.../groovy/runtime/DefaultGroovyMethods.java | 28 ++++++++++++++++++++++
.../codehaus/groovy/runtime/MetaClassHelper.java | 20 +++++++++-------
.../groovy/transform/stc/ClosuresSTCTest.groovy | 15 ++++++++++++
.../groovy/groovy/transform/stc/LambdaTest.groovy | 16 +++++++++++++
4 files changed, 70 insertions(+), 9 deletions(-)
diff --git
a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
index 38e1e8f11a..838d327597 100644
--- a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
+++ b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
@@ -151,6 +151,9 @@ import java.util.TimerTask;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
import java.util.function.Predicate;
@@ -14081,6 +14084,31 @@ public class DefaultGroovyMethods extends
DefaultGroovyMethodsSupport {
return answer;
}
+
//--------------------------------------------------------------------------
+ // submit
+
+ /**
+ * Submits a value-returning task for execution and returns a {@link
Future}
+ * representing the pending results of the task.
+ *
+ * <pre class="groovyTestCase">
+ * def executor = java.util.concurrent.Executors.newSingleThreadExecutor()
+ * try {
+ * def future = executor.submit {
+ * return 'works'
+ * }
+ * assert future.get() == 'works'
+ * } finally {
+ * executor.shutdown()
+ * }
+ * </pre>
+ *
+ * @since 5.0.0
+ */
+ public static <T> Future<T> submit(ExecutorService self, Closure<T> task) {
+ return self.submit((Callable<T>) task);
+ }
+
//--------------------------------------------------------------------------
// subsequences
diff --git a/src/main/java/org/codehaus/groovy/runtime/MetaClassHelper.java
b/src/main/java/org/codehaus/groovy/runtime/MetaClassHelper.java
index d74e032a93..5aba7fc81f 100644
--- a/src/main/java/org/codehaus/groovy/runtime/MetaClassHelper.java
+++ b/src/main/java/org/codehaus/groovy/runtime/MetaClassHelper.java
@@ -282,20 +282,20 @@ public class MetaClassHelper {
// by any means could let it look like a direct match
// we want to add one, because there is an interface between
// the interface we search for and the interface we are in.
- if (sub != -1) sub++;
+ if (sub != -1) sub += 1;
// we are interested in the longest path only
max = Math.max(max, sub);
}
// we do not add one for super classes, only for interfaces
int superClassMax = getMaximumInterfaceDistance(c.getSuperclass(),
interfaceClass);
- if (superClassMax != -1) superClassMax++;
+ if (superClassMax != -1) superClassMax += 1;
return Math.max(max, superClassMax);
}
private static int getParameterCount(final Class<?> closureOrLambdaClass) {
int parameterCount = -2;
- if (GeneratedClosure.class.isAssignableFrom(closureOrLambdaClass)) {
- // determine parameter count from generated "doCall" method(s)
+ if (isClosureLiteral(closureOrLambdaClass)) {
+ // determine parameter count from generated "doCall" methods
for (Method m : closureOrLambdaClass.getDeclaredMethods()) {
if ("doCall".equals(m.getName())) {
if (parameterCount != -2) {
@@ -309,6 +309,10 @@ public class MetaClassHelper {
return parameterCount;
}
+ private static boolean isClosureLiteral(final Class<?> candidate) {
+ return candidate != null &&
GeneratedClosure.class.isAssignableFrom(candidate);
+ }
+
private static long calculateParameterDistance(final Class<?> argument,
final CachedClass parameter) {
/*
* note: when shifting with 32 bit, you should only shift on a long.
If you do
@@ -317,13 +321,13 @@ public class MetaClassHelper {
*/
Class<?> parameterClass = parameter.getTheClass();
- if (parameterClass == argument) {
+ if (parameterClass == argument || (parameterClass == Closure.class &&
isClosureLiteral(argument))) { // GROOVY-10714, GROOVY-11681
return 0; // exact match
}
if (parameter.isInterface()) {
- long dist = getMaximumInterfaceDistance(argument, parameterClass);
- if (dist >= 0 || (argument != null &&
!Closure.class.isAssignableFrom(argument))) {
+ long dist = argument == null ? 2 :
getMaximumInterfaceDistance(argument, parameterClass);
+ if (dist >= 0 || !Closure.class.isAssignableFrom(argument)) {
return dist << INTERFACE_SHIFT;
}
}
@@ -370,8 +374,6 @@ public class MetaClassHelper {
return 0; // exact match -- GROOVY-9367
} else if (parameterClass == Object.class) {
return 1; // tight match
- } else if (parameterClass.isInterface()) {
- return 2L << INTERFACE_SHIFT;
} else {
// compute the distance to Object
for (Class<?> c = parameterClass; c != null && c != Object.class;
c = c.getSuperclass()) {
diff --git a/src/test/groovy/groovy/transform/stc/ClosuresSTCTest.groovy
b/src/test/groovy/groovy/transform/stc/ClosuresSTCTest.groovy
index 856cc3c4bd..737a9c5243 100644
--- a/src/test/groovy/groovy/transform/stc/ClosuresSTCTest.groovy
+++ b/src/test/groovy/groovy/transform/stc/ClosuresSTCTest.groovy
@@ -915,6 +915,21 @@ class ClosuresSTCTest extends StaticTypeCheckingTestCase {
'''
}
+ // GROOVY-11681
+ void testSAMsInMethodSelection9() {
+ assertScript '''
+ def executor =
java.util.concurrent.Executors.newSingleThreadExecutor()
+ try {
+ def future = executor.submit { ->
+ return 'works'
+ }
+ assert future.get() == 'works'
+ } finally {
+ executor.shutdown()
+ }
+ '''
+ }
+
// GROOVY-6238
void testDirectMethodCallOnClosureExpression() {
assertScript '''
diff --git a/src/test/groovy/groovy/transform/stc/LambdaTest.groovy
b/src/test/groovy/groovy/transform/stc/LambdaTest.groovy
index 602f0c9335..d180174973 100644
--- a/src/test/groovy/groovy/transform/stc/LambdaTest.groovy
+++ b/src/test/groovy/groovy/transform/stc/LambdaTest.groovy
@@ -927,6 +927,22 @@ final class LambdaTest {
'''
}
+ // GROOVY-11681
+ @Test
+ void testFunctionalInterface10() {
+ assertScript shell, '''
+ def executor =
java.util.concurrent.Executors.newSingleThreadExecutor()
+ try {
+ def future = executor.submit(() -> {
+ return 'works'
+ })
+ assert future.get() == 'works'
+ } finally {
+ executor.shutdown()
+ }
+ '''
+ }
+
@Test
void testFunctionWithUpdatingLocalVariable() {
for (mode in ['','static']) {