1414 */
1515package graphql .servlet ;
1616
17+ import com .fasterxml .jackson .annotation .JacksonInject ;
1718import com .fasterxml .jackson .core .JsonParser ;
1819import com .fasterxml .jackson .core .type .TypeReference ;
1920import com .fasterxml .jackson .databind .DeserializationContext ;
21+ import com .fasterxml .jackson .databind .InjectableValues ;
2022import com .fasterxml .jackson .databind .JsonDeserializer ;
2123import com .fasterxml .jackson .databind .ObjectMapper ;
22- import com .fasterxml .jackson .databind .SerializationFeature ;
24+ import com .fasterxml .jackson .databind .ObjectReader ;
2325import com .fasterxml .jackson .databind .annotation .JsonDeserialize ;
2426import graphql .ExecutionInput ;
2527import graphql .ExecutionResult ;
@@ -69,8 +71,6 @@ public abstract class GraphQLServlet extends HttpServlet implements Servlet, Gra
6971 public static final int STATUS_OK = 200 ;
7072 public static final int STATUS_BAD_REQUEST = 400 ;
7173
72- private static final ObjectMapper mapper = new ObjectMapper ().disable (SerializationFeature .FAIL_ON_EMPTY_BEANS );
73-
7474 protected abstract GraphQLSchemaProvider getSchemaProvider ();
7575 protected abstract GraphQLContext createContext (Optional <HttpServletRequest > request , Optional <HttpServletResponse > response );
7676 protected abstract Object createRootObject (Optional <HttpServletRequest > request , Optional <HttpServletResponse > response );
@@ -79,17 +79,19 @@ public abstract class GraphQLServlet extends HttpServlet implements Servlet, Gra
7979 protected abstract Map <String , Object > transformVariables (GraphQLSchema schema , String query , Map <String , Object > variables );
8080 protected abstract GraphQLErrorHandler getGraphQLErrorHandler ();
8181
82+ private final LazyObjectMapperBuilder lazyObjectMapperBuilder ;
8283 private final List <GraphQLServletListener > listeners ;
8384 private final ServletFileUpload fileUpload ;
8485
8586 private final RequestHandler getHandler ;
8687 private final RequestHandler postHandler ;
8788
8889 public GraphQLServlet () {
89- this (null , null );
90+ this (null , null , null );
9091 }
9192
92- public GraphQLServlet (List <GraphQLServletListener > listeners , FileItemFactory fileItemFactory ) {
93+ public GraphQLServlet (ObjectMapperConfigurer objectMapperConfigurer , List <GraphQLServletListener > listeners , FileItemFactory fileItemFactory ) {
94+ this .lazyObjectMapperBuilder = new LazyObjectMapperBuilder (objectMapperConfigurer != null ? objectMapperConfigurer : new DefaultObjectMapperConfigurer ());
9395 this .listeners = listeners != null ? new ArrayList <>(listeners ) : new ArrayList <>();
9496 this .fileUpload = new ServletFileUpload (fileItemFactory != null ? fileItemFactory : new DiskFileItemFactory ());
9597
@@ -172,7 +174,7 @@ public GraphQLServlet(List<GraphQLServletListener> listeners, FileItemFactory fi
172174 }
173175
174176 if (graphQLRequest == null ) {
175- graphQLRequest = mapper .readValue (inputStream , GraphQLRequest . class );
177+ graphQLRequest = getGraphQLRequestMapper () .readValue (inputStream );
176178 }
177179
178180 } catch (Exception e ) {
@@ -190,6 +192,21 @@ public GraphQLServlet(List<GraphQLServletListener> listeners, FileItemFactory fi
190192 };
191193 }
192194
195+ private ObjectMapper getMapper () {
196+ return lazyObjectMapperBuilder .getMapper ();
197+ }
198+
199+ /**
200+ * Creates an {@link ObjectReader} for deserializing {@link GraphQLRequest}
201+ */
202+ private ObjectReader getGraphQLRequestMapper () {
203+ // Add object mapper to injection so VariablesDeserializer can access it...
204+ InjectableValues .Std injectableValues = new InjectableValues .Std ();
205+ injectableValues .addValue (ObjectMapper .class , getMapper ());
206+
207+ return getMapper ().reader (injectableValues ).forType (GraphQLRequest .class );
208+ }
209+
193210 public void addListener (GraphQLServletListener servletListener ) {
194211 listeners .add (servletListener );
195212 }
@@ -211,8 +228,8 @@ public String[] getMutations() {
211228 @ Override
212229 public String executeQuery (String query ) {
213230 try {
214- final ExecutionResult result = newGraphQL (getSchemaProvider ().getSchema ()).execute (query , createContext (Optional .empty (), Optional .empty ()), new HashMap <>());
215- return mapper .writeValueAsString (createResultFromDataAndErrors (result .getData (), result .getErrors ()));
231+ final ExecutionResult result = newGraphQL (getSchemaProvider ().getSchema ()).execute (new ExecutionInput ( query , null , createContext (Optional .empty (), Optional .empty ()), createRootObject ( Optional . empty (), Optional . empty ()), new HashMap <>() ));
232+ return getMapper () .writeValueAsString (createResultFromDataAndErrors (result .getData (), result .getErrors ()));
216233 } catch (Exception e ) {
217234 return e .getMessage ();
218235 }
@@ -282,7 +299,7 @@ private void query(String query, String operationName, Map<String, Object> varia
282299 final List <GraphQLError > errors = executionResult .getErrors ();
283300 final Object data = executionResult .getData ();
284301
285- final String response = mapper .writeValueAsString (createResultFromDataAndErrors (data , errors ));
302+ final String response = getMapper () .writeValueAsString (createResultFromDataAndErrors (data , errors ));
286303
287304 resp .setContentType (APPLICATION_JSON_UTF8 );
288305 resp .setStatus (STATUS_OK );
@@ -339,21 +356,28 @@ private <T> void runCallbacks(List<T> callbacks, Consumer<T> action) {
339356 }
340357
341358 protected static class VariablesDeserializer extends JsonDeserializer <Map <String , Object >> {
359+
360+ private final ObjectMapper mapper ;
361+
362+ public VariablesDeserializer (@ JacksonInject ObjectMapper mapper ) {
363+ this .mapper = mapper ;
364+ }
365+
342366 @ Override
343367 public Map <String , Object > deserialize (JsonParser p , DeserializationContext ctxt ) throws IOException {
344- return deserializeVariablesObject (p .readValueAs (Object .class ));
368+ return deserializeVariablesObject (p .readValueAs (Object .class ), mapper );
345369 }
346370 }
347371
348- private static Map <String , Object > deserializeVariables (String variables ) {
372+ private Map <String , Object > deserializeVariables (String variables ) {
349373 try {
350- return deserializeVariablesObject (mapper .readValue (variables , Object .class ));
374+ return deserializeVariablesObject (getMapper () .readValue (variables , Object .class ), getMapper ( ));
351375 } catch (IOException e ) {
352376 throw new RuntimeException (e );
353377 }
354378 }
355379
356- private static Map <String , Object > deserializeVariablesObject (Object variables ) {
380+ private static Map <String , Object > deserializeVariablesObject (Object variables , ObjectMapper mapper ) {
357381 if (variables instanceof Map ) {
358382 @ SuppressWarnings ("unchecked" )
359383 Map <String , Object > genericVariables = (Map <String , Object >) variables ;
0 commit comments