From 345052381df84675bfb0c4f0cae8f17ee1843827 Mon Sep 17 00:00:00 2001 From: Koen Punt Date: Thu, 2 Feb 2023 13:54:37 +0100 Subject: [PATCH 1/2] Fix issue returning CompletableFuture See gh-604 --- .../support/DataFetcherHandlerMethod.java | 11 +++++--- .../DataFetcherHandlerMethodTests.java | 26 ++++++++++++++++++- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/DataFetcherHandlerMethod.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/DataFetcherHandlerMethod.java index 89d35a0d..66528465 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/DataFetcherHandlerMethod.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/DataFetcherHandlerMethod.java @@ -16,6 +16,7 @@ package org.springframework.graphql.data.method.annotation.support; import java.util.Arrays; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import java.util.function.BiConsumer; @@ -128,12 +129,16 @@ public class DataFetcherHandlerMethod extends InvocableHandlerMethodSupport { if (result instanceof Mono) { return (Mono) result; } - else if (result instanceof Flux) { + + if (result instanceof Flux) { return Flux.from((Flux) result).collectList(); } - else { - return Mono.justOrEmpty(result); + + if (result instanceof CompletableFuture) { + return Mono.fromFuture((CompletableFuture) result); } + + return Mono.justOrEmpty(result); }); } diff --git a/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/DataFetcherHandlerMethodTests.java b/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/DataFetcherHandlerMethodTests.java index 74e4944c..518b26e4 100644 --- a/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/DataFetcherHandlerMethodTests.java +++ b/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/DataFetcherHandlerMethodTests.java @@ -24,7 +24,6 @@ import java.util.concurrent.CompletableFuture; import graphql.GraphQLContext; import graphql.schema.DataFetchingEnvironment; import graphql.schema.DataFetchingEnvironmentImpl; -import io.micrometer.context.ContextSnapshot; import org.junit.jupiter.api.Test; import org.mockito.Mockito; @@ -37,6 +36,7 @@ import org.springframework.graphql.data.method.annotation.Argument; import org.springframework.graphql.data.method.annotation.QueryMapping; import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; +import reactor.core.publisher.Mono; import static org.assertj.core.api.Assertions.assertThat; @@ -86,6 +86,27 @@ public class DataFetcherHandlerMethodTests { assertThat(future.get()).isEqualTo("A"); } + @Test + void completableFutureReturnValue() throws Exception { + + HandlerMethodArgumentResolverComposite resolvers = new HandlerMethodArgumentResolverComposite(); + resolvers.addResolver(new ArgumentMethodArgumentResolver(new GraphQlArgumentBinder())); + + DataFetcherHandlerMethod handlerMethod = new DataFetcherHandlerMethod( + handlerMethodFor(new TestController(), "handleAndReturnsCompletableFuture"), resolvers, null, + new SimpleAsyncTaskExecutor(), false); + + DataFetchingEnvironment environment = DataFetchingEnvironmentImpl + .newDataFetchingEnvironment() + .build(); + + Object result = handlerMethod.invoke(environment); + + assertThat(result).isInstanceOf(Mono.class); + Mono mono = (Mono) result; + assertThat(mono.block()).isEqualTo("B"); + } + private static HandlerMethod handlerMethodFor(Object controller, String methodName) { Method method = ClassUtils.getMethod(controller.getClass(), methodName, (Class[]) null); return new HandlerMethod(controller, method); @@ -112,6 +133,9 @@ public class DataFetcherHandlerMethodTests { return () -> "A"; } + public CompletableFuture handleAndReturnsCompletableFuture() { + return CompletableFuture.completedFuture("B"); + } } } From 2e229fec26d436de2e41618542be96f795cd3878 Mon Sep 17 00:00:00 2001 From: rstoyanchev Date: Wed, 8 Mar 2023 13:31:12 +0000 Subject: [PATCH 2/2] Polishing contribution Closes gh-604 --- .../support/DataFetcherHandlerMethod.java | 19 +++++++------- .../DataFetcherHandlerMethodTests.java | 25 +++++++++---------- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/DataFetcherHandlerMethod.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/DataFetcherHandlerMethod.java index 66528465..92ffe6d9 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/DataFetcherHandlerMethod.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/DataFetcherHandlerMethod.java @@ -126,19 +126,18 @@ public class DataFetcherHandlerMethod extends InvocableHandlerMethodSupport { }) : toArgsMono(args).flatMap(argValues -> { Object result = validateAndInvoke(argValues, environment); - if (result instanceof Mono) { - return (Mono) result; + if (result instanceof Mono mono) { + return mono; } - - if (result instanceof Flux) { - return Flux.from((Flux) result).collectList(); + else if (result instanceof Flux flux) { + return Flux.from(flux).collectList(); } - - if (result instanceof CompletableFuture) { - return Mono.fromFuture((CompletableFuture) result); + else if (result instanceof CompletableFuture future) { + return Mono.fromFuture(future); + } + else { + return Mono.justOrEmpty(result); } - - return Mono.justOrEmpty(result); }); } diff --git a/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/DataFetcherHandlerMethodTests.java b/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/DataFetcherHandlerMethodTests.java index 518b26e4..3c43c9e3 100644 --- a/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/DataFetcherHandlerMethodTests.java +++ b/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/DataFetcherHandlerMethodTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,6 +26,7 @@ import graphql.schema.DataFetchingEnvironment; import graphql.schema.DataFetchingEnvironmentImpl; import org.junit.jupiter.api.Test; import org.mockito.Mockito; +import reactor.core.publisher.Mono; import org.springframework.core.task.SimpleAsyncTaskExecutor; import org.springframework.graphql.data.GraphQlArgumentBinder; @@ -35,8 +36,9 @@ import org.springframework.graphql.data.method.HandlerMethodArgumentResolverComp import org.springframework.graphql.data.method.annotation.Argument; import org.springframework.graphql.data.method.annotation.QueryMapping; import org.springframework.lang.Nullable; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.core.userdetails.User; import org.springframework.util.ClassUtils; -import reactor.core.publisher.Mono; import static org.assertj.core.api.Assertions.assertThat; @@ -87,24 +89,20 @@ public class DataFetcherHandlerMethodTests { } @Test - void completableFutureReturnValue() throws Exception { + void completableFutureReturnValue() { HandlerMethodArgumentResolverComposite resolvers = new HandlerMethodArgumentResolverComposite(); + resolvers.addResolver(new AuthenticationPrincipalArgumentResolver((beanName, context) -> null)); resolvers.addResolver(new ArgumentMethodArgumentResolver(new GraphQlArgumentBinder())); DataFetcherHandlerMethod handlerMethod = new DataFetcherHandlerMethod( - handlerMethodFor(new TestController(), "handleAndReturnsCompletableFuture"), resolvers, null, - new SimpleAsyncTaskExecutor(), false); + handlerMethodFor(new TestController(), "handleAndReturnFuture"), resolvers, + null, null, false); - DataFetchingEnvironment environment = DataFetchingEnvironmentImpl - .newDataFetchingEnvironment() - .build(); - - Object result = handlerMethod.invoke(environment); + Object result = handlerMethod.invoke(DataFetchingEnvironmentImpl.newDataFetchingEnvironment().build()); assertThat(result).isInstanceOf(Mono.class); - Mono mono = (Mono) result; - assertThat(mono.block()).isEqualTo("B"); + assertThat(((Mono) result).block()).isEqualTo("B"); } private static HandlerMethod handlerMethodFor(Object controller, String methodName) { @@ -133,9 +131,10 @@ public class DataFetcherHandlerMethodTests { return () -> "A"; } - public CompletableFuture handleAndReturnsCompletableFuture() { + public CompletableFuture handleAndReturnFuture(@AuthenticationPrincipal User user) { return CompletableFuture.completedFuture("B"); } + } }