2222import java .util .List ;
2323import java .util .Map ;
2424import java .util .Optional ;
25- import java .util .regex .Pattern ;
2625
2726import javax .servlet .ServletException ;
2827
2928import com .fasterxml .jackson .core .JsonProcessingException ;
3029import com .fasterxml .jackson .core .type .TypeReference ;
30+ import com .fasterxml .jackson .databind .ObjectMapper ;
3131import org .apache .commons .logging .Log ;
3232import org .apache .commons .logging .LogFactory ;
33+ import org .springframework .graphql .server .support .MultipartVariableMapper ;
3334import org .springframework .web .multipart .MultipartFile ;
3435import org .springframework .web .multipart .support .AbstractMultipartHttpServletRequest ;
3536import reactor .core .publisher .Mono ;
@@ -69,15 +70,32 @@ public class GraphQlHttpHandler {
6970
7071 private final WebGraphQlHandler graphQlHandler ;
7172
73+ private final ObjectMapper objectMapper ;
74+
7275 /**
7376 * Create a new instance.
7477 * @param graphQlHandler common handler for GraphQL over HTTP requests
78+ * @deprecated Use GraphQlHttpHandler(WebGraphQlHandler graphQlHandler, ObjectMapper objectMapper) instead.
7579 */
76- public GraphQlHttpHandler (WebGraphQlHandler graphQlHandler ) {
80+ @ Deprecated
81+ public GraphQlHttpHandler (WebGraphQlHandler graphQlHandler ) {
7782 Assert .notNull (graphQlHandler , "WebGraphQlHandler is required" );
7883 this .graphQlHandler = graphQlHandler ;
84+ this .objectMapper = new ObjectMapper ();
7985 }
8086
87+ /**
88+ * Create a new instance.
89+ * @param graphQlHandler common handler for GraphQL over HTTP requests
90+ * @param objectMapper ObjectMapper used for parsing form parts
91+ */
92+ public GraphQlHttpHandler (WebGraphQlHandler graphQlHandler , ObjectMapper objectMapper ) {
93+ Assert .notNull (graphQlHandler , "WebGraphQlHandler is required" );
94+ Assert .notNull (objectMapper , "ObjectMapper is required" );
95+ this .graphQlHandler = graphQlHandler ;
96+ this .objectMapper = objectMapper ;
97+ }
98+
8199 /**
82100 * Handle GraphQL requests over HTTP.
83101 * @param serverRequest the incoming HTTP request
@@ -112,7 +130,7 @@ public ServerResponse handleRequest(ServerRequest serverRequest) throws ServletE
112130 public ServerResponse handleMultipartRequest (ServerRequest serverRequest ) throws ServletException {
113131 Optional <String > operation = serverRequest .param ("operations" );
114132 Optional <String > mapParam = serverRequest .param ("map" );
115- Map <String , Object > inputQuery = readJson (operation , new TypeReference <>() {});
133+ Map <String , Object > inputQuery = readJson (operation , new TypeReference <Map < String , Object > >() {});
116134 final Map <String , Object > queryVariables ;
117135 if (inputQuery .containsKey ("variables" )) {
118136 queryVariables = (Map <String , Object >)inputQuery .get ("variables" );
@@ -125,7 +143,7 @@ public ServerResponse handleMultipartRequest(ServerRequest serverRequest) throws
125143 }
126144
127145 Map <String , MultipartFile > fileParams = getMultipartMap (serverRequest );
128- Map <String , List <String >> fileMapInput = readJson (mapParam , new TypeReference <>() {});
146+ Map <String , List <String >> fileMapInput = readJson (mapParam , new TypeReference <Map < String , List < String >> >() {});
129147 fileMapInput .forEach ((String fileKey , List <String > objectPaths ) -> {
130148 MultipartFile file = fileParams .get (fileKey );
131149 if (file != null ) {
@@ -210,83 +228,3 @@ private static MediaType selectResponseMediaType(ServerRequest serverRequest) {
210228 }
211229
212230}
213-
214- // As in DGS, this is borrowed from https://github.com/graphql-java-kickstart/graphql-java-servlet/blob/eb4dfdb5c0198adc1b4d4466c3b4ea4a77def5d1/graphql-java-servlet/src/main/java/graphql/kickstart/servlet/core/internal/VariableMapper.java
215- class MultipartVariableMapper {
216-
217- private static final Pattern PERIOD = Pattern .compile ("\\ ." );
218-
219- private static final Mapper <Map <String , Object >> MAP_MAPPER =
220- new Mapper <Map <String , Object >>() {
221- @ Override
222- public Object set (Map <String , Object > location , String target , MultipartFile value ) {
223- return location .put (target , value );
224- }
225-
226- @ Override
227- public Object recurse (Map <String , Object > location , String target ) {
228- return location .get (target );
229- }
230- };
231- private static final Mapper <List <Object >> LIST_MAPPER =
232- new Mapper <List <Object >>() {
233- @ Override
234- public Object set (List <Object > location , String target , MultipartFile value ) {
235- return location .set (Integer .parseInt (target ), value );
236- }
237-
238- @ Override
239- public Object recurse (List <Object > location , String target ) {
240- return location .get (Integer .parseInt (target ));
241- }
242- };
243-
244- @ SuppressWarnings ({"unchecked" , "rawtypes" })
245- public static void mapVariable (String objectPath , Map <String , Object > variables , MultipartFile part ) {
246- String [] segments = PERIOD .split (objectPath );
247-
248- if (segments .length < 2 ) {
249- throw new RuntimeException ("object-path in map must have at least two segments" );
250- } else if (!"variables" .equals (segments [0 ])) {
251- throw new RuntimeException ("can only map into variables" );
252- }
253-
254- Object currentLocation = variables ;
255- for (int i = 1 ; i < segments .length ; i ++) {
256- String segmentName = segments [i ];
257- Mapper mapper = determineMapper (currentLocation , objectPath , segmentName );
258-
259- if (i == segments .length - 1 ) {
260- if (null != mapper .set (currentLocation , segmentName , part )) {
261- throw new RuntimeException ("expected null value when mapping " + objectPath );
262- }
263- } else {
264- currentLocation = mapper .recurse (currentLocation , segmentName );
265- if (null == currentLocation ) {
266- throw new RuntimeException (
267- "found null intermediate value when trying to map " + objectPath );
268- }
269- }
270- }
271- }
272-
273- private static Mapper <?> determineMapper (
274- Object currentLocation , String objectPath , String segmentName ) {
275- if (currentLocation instanceof Map ) {
276- return MAP_MAPPER ;
277- } else if (currentLocation instanceof List ) {
278- return LIST_MAPPER ;
279- }
280-
281- throw new RuntimeException (
282- "expected a map or list at " + segmentName + " when trying to map " + objectPath );
283- }
284-
285- interface Mapper <T > {
286-
287- Object set (T location , String target , MultipartFile value );
288-
289- Object recurse (T location , String target );
290- }
291- }
292-
0 commit comments