Skip to content

Commit 14c87b0

Browse files
committed
Polishing in GraphQlHttpHandler
1 parent 1ea64dc commit 14c87b0

File tree

3 files changed

+52
-34
lines changed

3 files changed

+52
-34
lines changed

spring-graphql/src/main/java/org/springframework/graphql/server/webflux/AbstractGraphQlHttpHandler.java

+5-3
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,15 @@ public Mono<ServerResponse> handleRequest(ServerRequest request) {
7676
return readRequest(request)
7777
.flatMap((body) -> {
7878
WebGraphQlRequest graphQlRequest = new WebGraphQlRequest(
79-
request.uri(), request.headers().asHttpHeaders(),
80-
request.cookies(), request.remoteAddress().orElse(null),
81-
request.attributes(), body,
79+
request.uri(), request.headers().asHttpHeaders(), request.cookies(),
80+
request.remoteAddress().orElse(null), request.attributes(), body,
8281
request.exchange().getRequest().getId(),
8382
request.exchange().getLocaleContext().getLocale());
83+
8484
if (this.logger.isDebugEnabled()) {
8585
this.logger.debug("Executing: " + graphQlRequest);
8686
}
87+
8788
return this.graphQlHandler.handleRequest(graphQlRequest);
8889
})
8990
.flatMap((response) -> {
@@ -92,6 +93,7 @@ public Mono<ServerResponse> handleRequest(ServerRequest request) {
9293
this.logger.debug("Execution result " +
9394
(!CollectionUtils.isEmpty(errors) ? "has errors: " + errors : "is ready") + ".");
9495
}
96+
9597
return prepareResponse(request, response);
9698
});
9799
}

spring-graphql/src/main/java/org/springframework/graphql/server/webmvc/AbstractGraphQlHttpHandler.java

+35-5
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,12 @@
1818

1919
import java.io.IOException;
2020
import java.util.List;
21+
import java.util.Map;
2122

2223
import jakarta.servlet.ServletException;
2324
import jakarta.servlet.http.Cookie;
25+
import jakarta.servlet.http.HttpServletRequest;
26+
import jakarta.servlet.http.HttpServletResponse;
2427
import org.apache.commons.logging.Log;
2528
import org.apache.commons.logging.LogFactory;
2629
import reactor.core.publisher.Mono;
@@ -36,7 +39,9 @@
3639
import org.springframework.http.HttpHeaders;
3740
import org.springframework.http.MediaType;
3841
import org.springframework.http.converter.HttpMessageConverter;
42+
import org.springframework.http.server.ServerHttpRequest;
3943
import org.springframework.http.server.ServletServerHttpRequest;
44+
import org.springframework.http.server.ServletServerHttpResponse;
4045
import org.springframework.lang.Nullable;
4146
import org.springframework.util.AlternativeJdkIdGenerator;
4247
import org.springframework.util.Assert;
@@ -46,6 +51,7 @@
4651
import org.springframework.util.MultiValueMap;
4752
import org.springframework.web.HttpMediaTypeNotSupportedException;
4853
import org.springframework.web.server.ServerWebInputException;
54+
import org.springframework.web.servlet.ModelAndView;
4955
import org.springframework.web.servlet.function.ServerRequest;
5056
import org.springframework.web.servlet.function.ServerResponse;
5157

@@ -79,11 +85,19 @@ protected AbstractGraphQlHttpHandler(
7985

8086

8187
/**
82-
* Return the custom message converter, if configured, to read and write with.
88+
* Exposes a {@link ServerResponse.HeadersBuilder.WriteFunction} that writes
89+
* with the {@code HttpMessageConverter} provided to the constructor.
90+
* @param resultMap the result map to write
91+
* @param contentType to set the response content type to
92+
* @return the write function, or {@code null} if a
93+
* {@code HttpMessageConverter} was not provided to the constructor
8394
*/
8495
@Nullable
85-
public HttpMessageConverter<Object> getMessageConverter() {
86-
return this.messageConverter;
96+
protected ServerResponse.HeadersBuilder.WriteFunction getWriteFunction(
97+
Map<String, Object> resultMap, MediaType contentType) {
98+
99+
return (this.messageConverter != null) ?
100+
new MessageConverterWriteFunction(resultMap, contentType, this.messageConverter) : null;
87101
}
88102

89103

@@ -133,8 +147,8 @@ private GraphQlRequest readBody(ServerRequest request) throws ServletException {
133147
if (this.messageConverter != null) {
134148
MediaType contentType = request.headers().contentType().orElse(MediaType.APPLICATION_JSON);
135149
if (this.messageConverter.canRead(SerializableGraphQlRequest.class, contentType)) {
136-
return (GraphQlRequest) this.messageConverter.read(SerializableGraphQlRequest.class,
137-
new ServletServerHttpRequest(request.servletRequest()));
150+
ServerHttpRequest httpRequest = new ServletServerHttpRequest(request.servletRequest());
151+
return (GraphQlRequest) this.messageConverter.read(SerializableGraphQlRequest.class, httpRequest);
138152
}
139153
throw new HttpMediaTypeNotSupportedException(
140154
contentType, this.messageConverter.getSupportedMediaTypes(), request.method());
@@ -181,4 +195,20 @@ private static SerializableGraphQlRequest applyApplicationGraphQlFallback(
181195
protected abstract ServerResponse prepareResponse(
182196
ServerRequest request, Mono<WebGraphQlResponse> responseMono) throws ServletException;
183197

198+
199+
/**
200+
* WriteFunction that writes with a given, fixed {@link HttpMessageConverter}.
201+
*/
202+
private record MessageConverterWriteFunction(
203+
Map<String, Object> resultMap, MediaType contentType, HttpMessageConverter<Object> converter)
204+
implements ServerResponse.HeadersBuilder.WriteFunction {
205+
206+
@Override
207+
public ModelAndView write(HttpServletRequest request, HttpServletResponse response) throws Exception {
208+
ServletServerHttpResponse httpResponse = new ServletServerHttpResponse(response);
209+
this.converter.write(this.resultMap, this.contentType, httpResponse);
210+
return null;
211+
}
212+
}
213+
184214
}

spring-graphql/src/main/java/org/springframework/graphql/server/webmvc/GraphQlHttpHandler.java

+12-26
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
import org.springframework.graphql.server.WebGraphQlResponse;
2828
import org.springframework.http.MediaType;
2929
import org.springframework.http.converter.HttpMessageConverter;
30-
import org.springframework.http.server.ServletServerHttpResponse;
3130
import org.springframework.lang.Nullable;
3231
import org.springframework.web.servlet.function.ServerRequest;
3332
import org.springframework.web.servlet.function.ServerResponse;
@@ -56,12 +55,12 @@ public GraphQlHttpHandler(WebGraphQlHandler graphQlHandler) {
5655
}
5756

5857
/**
59-
* Create a new instance with a custom message converter.
60-
* <p>If no converter is provided, this will use
58+
* Create a new instance with a custom message converter for GraphQL payloads.
59+
* <p>If no converter is provided, the handler will use
6160
* {@link org.springframework.web.servlet.config.annotation.WebMvcConfigurer#configureMessageConverters(List)
62-
* the one configured in the web framework}.
61+
* the one configured for web use}.
6362
* @param graphQlHandler common handler for GraphQL over HTTP requests
64-
* @param converter custom {@link HttpMessageConverter} to read and write GraphQL payloads
63+
* @param converter the converter to use to read and write GraphQL payloads
6564
*/
6665
public GraphQlHttpHandler(WebGraphQlHandler graphQlHandler, @Nullable HttpMessageConverter<?> converter) {
6766
super(graphQlHandler, converter);
@@ -77,15 +76,12 @@ protected ServerResponse prepareResponse(ServerRequest request, Mono<WebGraphQlR
7776
builder.headers((headers) -> headers.putAll(response.getResponseHeaders()));
7877
builder.contentType(contentType);
7978

80-
if (getMessageConverter() != null) {
81-
return builder.build(writeFunction(getMessageConverter(), contentType, response.toMap()));
82-
}
83-
else {
84-
return builder.body(response.toMap());
85-
}
79+
Map<String, Object> resultMap = response.toMap();
80+
ServerResponse.HeadersBuilder.WriteFunction writer = getWriteFunction(resultMap, contentType);
81+
return (writer != null) ? builder.build(writer) : builder.body(resultMap);
8682
}).toFuture();
8783

88-
// This won't be needed with a Spring Framework 6.2 baseline:
84+
// This won't be needed on a Spring Framework 6.2 baseline:
8985
// https://github.com/spring-projects/spring-framework/issues/32223
9086

9187
if (future.isDone() && !future.isCancelled() && !future.isCompletedExceptionally()) {
@@ -100,23 +96,13 @@ protected ServerResponse prepareResponse(ServerRequest request, Mono<WebGraphQlR
10096
return ServerResponse.async(future);
10197
}
10298

103-
private static MediaType selectResponseMediaType(ServerRequest serverRequest) {
104-
for (MediaType accepted : serverRequest.headers().accept()) {
105-
if (SUPPORTED_MEDIA_TYPES.contains(accepted)) {
106-
return accepted;
99+
private static MediaType selectResponseMediaType(ServerRequest request) {
100+
for (MediaType mediaType : request.headers().accept()) {
101+
if (SUPPORTED_MEDIA_TYPES.contains(mediaType)) {
102+
return mediaType;
107103
}
108104
}
109105
return MediaType.APPLICATION_JSON;
110106
}
111107

112-
private static ServerResponse.HeadersBuilder.WriteFunction writeFunction(
113-
HttpMessageConverter<Object> converter, MediaType contentType, Map<String, Object> resultMap) {
114-
115-
return (servletRequest, servletResponse) -> {
116-
ServletServerHttpResponse httpResponse = new ServletServerHttpResponse(servletResponse);
117-
converter.write(resultMap, contentType, httpResponse);
118-
return null;
119-
};
120-
}
121-
122108
}

0 commit comments

Comments
 (0)