Guard MVC auto-configuration with WebSocket classes

This commit ensures that the WebSocket auto-configuration is guarded
with class conditions on WebSocket classes (from the javax API and the
spring-websocket artifact).

This prevents issues where application without such dependencies are
failing at startup.
This commit is contained in:
Brian Clozel
2021-02-02 10:03:43 +01:00
parent abad0e1b80
commit 2990df6c43
2 changed files with 35 additions and 25 deletions

View File

@@ -36,6 +36,7 @@ dependencies {
compileOnly 'org.springframework:spring-webmvc'
compileOnly 'org.springframework:spring-websocket'
compileOnly 'javax.servlet:javax.servlet-api'
compileOnly 'javax.websocket:javax.websocket-api'
compileOnly 'io.micrometer:micrometer-core'
compileOnly 'org.springframework.boot:spring-boot-actuator-autoconfigure'

View File

@@ -18,6 +18,8 @@ package org.springframework.graphql.boot;
import java.util.Collections;
import java.util.Map;
import javax.websocket.server.ServerContainer;
import graphql.GraphQL;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
@@ -39,6 +41,7 @@ import org.springframework.web.servlet.function.RouterFunction;
import org.springframework.web.servlet.function.RouterFunctions;
import org.springframework.web.servlet.function.ServerResponse;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.support.DefaultHandshakeHandler;
import org.springframework.web.socket.server.support.WebSocketHttpRequestHandler;
@@ -58,22 +61,6 @@ public class WebMvcGraphQLAutoConfiguration {
return new GraphQLHttpHandler(graphQLBuilder.build(), Collections.emptyList());
}
@Bean
@ConditionalOnMissingBean
public GraphQLWebSocketHandler graphQLWebSocketHandler(
GraphQL.Builder graphQLBuilder, GraphQLProperties properties, HttpMessageConverters converters) {
HttpMessageConverter<?> converter = converters.getConverters().stream()
.filter(candidate -> candidate.canRead(Map.class, MediaType.APPLICATION_JSON))
.findFirst()
.orElseThrow(() -> new IllegalStateException("No JSON converter"));
return new GraphQLWebSocketHandler(
graphQLBuilder.build(), Collections.emptyList(),
converter, properties.getConnectionInitTimeoutDuration()
);
}
@Bean
public RouterFunction<ServerResponse> graphQLQueryEndpoint(
ResourceLoader resourceLoader, GraphQLHttpHandler handler, GraphQLProperties properties) {
@@ -87,16 +74,38 @@ public class WebMvcGraphQLAutoConfiguration {
.build();
}
@Bean
public HandlerMapping graphQLWebSocketEndpoint(GraphQLWebSocketHandler handler, GraphQLProperties properties) {
WebSocketHttpRequestHandler httpRequestHandler =
new WebSocketHttpRequestHandler(handler, new DefaultHandshakeHandler());
String path = properties.getWebSocketPath();
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
mapping.setUrlMap(Collections.singletonMap(path, httpRequestHandler));
mapping.setOrder(-1); // Ahead of annotated controllers
return mapping;
@ConditionalOnClass({ServerContainer.class, WebSocketHandler.class})
static class WebSocketConfiguration {
@Bean
@ConditionalOnMissingBean
public GraphQLWebSocketHandler graphQLWebSocketHandler(
GraphQL.Builder graphQLBuilder, GraphQLProperties properties, HttpMessageConverters converters) {
HttpMessageConverter<?> converter = converters.getConverters().stream()
.filter(candidate -> candidate.canRead(Map.class, MediaType.APPLICATION_JSON))
.findFirst()
.orElseThrow(() -> new IllegalStateException("No JSON converter"));
return new GraphQLWebSocketHandler(
graphQLBuilder.build(), Collections.emptyList(),
converter, properties.getConnectionInitTimeoutDuration()
);
}
@Bean
public HandlerMapping graphQLWebSocketEndpoint(GraphQLWebSocketHandler handler, GraphQLProperties properties) {
WebSocketHttpRequestHandler httpRequestHandler =
new WebSocketHttpRequestHandler(handler, new DefaultHandshakeHandler());
String path = properties.getWebSocketPath();
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
mapping.setUrlMap(Collections.singletonMap(path, httpRequestHandler));
mapping.setOrder(-1); // Ahead of annotated controllers
return mapping;
}
}
}