diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/InvocableHandlerMethodSupport.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/InvocableHandlerMethodSupport.java index 02f64ce59..4b4263496 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/InvocableHandlerMethodSupport.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/InvocableHandlerMethodSupport.java @@ -26,6 +26,7 @@ import graphql.GraphQLContext; import io.micrometer.context.ContextSnapshot; +import org.springframework.data.util.KotlinReflectionUtils; import reactor.core.publisher.Mono; import org.springframework.core.CoroutinesUtils; @@ -81,7 +82,18 @@ protected Object doInvoke(GraphQLContext graphQLContext, Object... argValues) { Method method = getBridgedMethod(); try { if (KotlinDetector.isSuspendingFunction(method)) { - return CoroutinesUtils.invokeSuspendingFunction(method, getBean(), argValues); + Object result = CoroutinesUtils.invokeSuspendingFunction(method, getBean(), argValues); + + Class returnType = KotlinReflectionUtils.getReturnType(method); + + if (CompletableFuture.class.isAssignableFrom(returnType)) { + @SuppressWarnings("unchecked") + Mono> mono = (Mono>)result; + // Unwrap nested CompletableFuture + return mono.flatMap(Mono::fromFuture); + } + + return result; } Object result = method.invoke(getBean(), argValues); return handleReturnValue(graphQLContext, result);