From 339f75d309c0a70f5ce8ac093255505905423255 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Mon, 16 Oct 2023 12:11:31 +0200 Subject: [PATCH] Fix GraphQL WebSocket HandlerMapping bean ordering Prior to this commit, the GraphQL WebSocket HandlerMapping bean would be ordered at position "2", before the RouterFunction variant defined by Spring Framework at position "3". Since then, the Spring Framework team changed the default order value for this one at "-1", see spring-projects/spring-framework#30278. This prevents the WebSocket upgrade, as the request is handled by the RouterFunction instead of the WebSocket handler. This commit updates the handlermapping order and introduces a test to prevent issues in the future. Fixes gh-37892 --- .../servlet/GraphQlWebMvcAutoConfiguration.java | 2 +- .../servlet/GraphQlWebMvcAutoConfigurationTests.java | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/servlet/GraphQlWebMvcAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/servlet/GraphQlWebMvcAutoConfiguration.java index 29d0c53c24..4c82ba3b51 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/servlet/GraphQlWebMvcAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/servlet/GraphQlWebMvcAutoConfiguration.java @@ -195,7 +195,7 @@ public class GraphQlWebMvcAutoConfiguration { mapping.setWebSocketUpgradeMatch(true); mapping.setUrlMap(Collections.singletonMap(path, handler.initWebSocketHttpRequestHandler(new DefaultHandshakeHandler()))); - mapping.setOrder(2); // Ahead of HTTP endpoint ("routerFunctionMapping" bean) + mapping.setOrder(-2); // Ahead of HTTP endpoint ("routerFunctionMapping" bean) return mapping; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/graphql/servlet/GraphQlWebMvcAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/graphql/servlet/GraphQlWebMvcAutoConfigurationTests.java index e99c778746..6df0fdff74 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/graphql/servlet/GraphQlWebMvcAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/graphql/servlet/GraphQlWebMvcAutoConfigurationTests.java @@ -45,7 +45,11 @@ import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.servlet.HandlerMapping; import org.springframework.web.servlet.function.RouterFunction; +import org.springframework.web.servlet.function.support.RouterFunctionMapping; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; +import org.springframework.web.socket.server.support.WebSocketHandlerMapping; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.asyncDispatch; @@ -162,8 +166,12 @@ class GraphQlWebMvcAutoConfigurationTests { @Test void shouldConfigureWebSocketBeans() { - this.contextRunner.withPropertyValues("spring.graphql.websocket.path=/ws") - .run((context) -> assertThat(context).hasSingleBean(GraphQlWebSocketHandler.class)); + this.contextRunner.withPropertyValues("spring.graphql.websocket.path=/ws").run((context) -> { + assertThat(context).hasSingleBean(GraphQlWebSocketHandler.class); + assertThat(context.getBeanProvider(HandlerMapping.class).orderedStream().toList()).containsSubsequence( + context.getBean(WebSocketHandlerMapping.class), context.getBean(RouterFunctionMapping.class), + context.getBean(RequestMappingHandlerMapping.class)); + }); } @Test