2424import java .time .Instant ;
2525import java .time .LocalDate ;
2626import java .time .LocalDateTime ;
27+ import java .time .LocalTime ;
28+ import java .time .ZoneOffset ;
29+ import java .time .format .DateTimeFormatter ;
2730import java .time .format .DateTimeParseException ;
2831import java .util .Collections ;
2932import java .util .Date ;
3538import java .util .UUID ;
3639import java .util .stream .Collectors ;
3740
38- import org .slf4j .Logger ;
39- import org .slf4j .LoggerFactory ;
40-
4141import graphql .Assert ;
4242import graphql .Scalars ;
4343import graphql .language .ArrayValue ;
5151import graphql .language .StringValue ;
5252import graphql .language .Value ;
5353import graphql .schema .Coercing ;
54+ import graphql .schema .CoercingParseValueException ;
55+ import graphql .schema .CoercingSerializeException ;
5456import graphql .schema .GraphQLScalarType ;
57+ import org .slf4j .Logger ;
58+ import org .slf4j .LoggerFactory ;
5559
5660/**
5761 * Provides Registry to resolve GraphQL Query Java Scalar Types
@@ -100,6 +104,7 @@ public class JavaScalars {
100104
101105 scalarsRegistry .put (LocalDateTime .class , new GraphQLScalarType ("LocalDateTime" , "LocalDateTime type" , new GraphQLLocalDateTimeCoercing ()));
102106 scalarsRegistry .put (LocalDate .class , new GraphQLScalarType ("LocalDate" , "LocalDate type" , new GraphQLLocalDateCoercing ()));
107+ scalarsRegistry .put (LocalTime .class , new GraphQLScalarType ("LocalTime" , "LocalTime type" , new GraphQLLocalTimeCoercing ()));
103108 scalarsRegistry .put (Date .class , new GraphQLScalarType ("Date" , "Date type" , new GraphQLDateCoercing ()));
104109 scalarsRegistry .put (UUID .class , new GraphQLScalarType ("UUID" , "UUID type" , new GraphQLUUIDCoercing ()));
105110 scalarsRegistry .put (Object .class , new GraphQLScalarType ("Object" , "Object type" , new GraphQLObjectCoercing ()));
@@ -212,6 +217,51 @@ private LocalDate parseStringToLocalDate(String input) {
212217 }
213218 }
214219 };
220+
221+ public static class GraphQLLocalTimeCoercing implements Coercing <LocalTime , String > {
222+
223+ public static final DateTimeFormatter FORMATTER = DateTimeFormatter .ISO_LOCAL_TIME .withZone (ZoneOffset .UTC );
224+
225+ private LocalTime convertImpl (Object input ) {
226+ if (input instanceof String ) {
227+ try {
228+ return LocalTime .parse ((String ) input , FORMATTER );
229+ } catch (DateTimeParseException ignored ) {
230+ }
231+ }
232+ return null ;
233+ }
234+
235+ @ Override
236+ public String serialize (Object input ) {
237+ if (input instanceof LocalTime ) {
238+ return DateTimeFormatter .ISO_LOCAL_TIME .format ((LocalTime ) input );
239+ } else {
240+ LocalTime result = convertImpl (input );
241+ if (result == null ) {
242+ throw new CoercingSerializeException ("Invalid value '" + input + "' for LocalTime" );
243+ }
244+ return DateTimeFormatter .ISO_LOCAL_TIME .format (result );
245+ }
246+ }
247+
248+ @ Override
249+ public LocalTime parseValue (Object input ) {
250+ LocalTime result = convertImpl (input );
251+ if (result == null ) {
252+ throw new CoercingParseValueException ("Invalid value '" + input + "' for LocalTime" );
253+ }
254+ return result ;
255+ }
256+
257+ @ Override
258+ public LocalTime parseLiteral (Object input ) {
259+ if (!(input instanceof StringValue )) return null ;
260+ String value = ((StringValue ) input ).getValue ();
261+ LocalTime result = convertImpl (value );
262+ return result ;
263+ }
264+ }
215265
216266 public static class GraphQLDateCoercing implements Coercing <Object , Object > {
217267 final DateFormat df ;
@@ -328,111 +378,125 @@ public Object parseLiteral(Object input) {
328378 };
329379
330380 public static class GraphQLSqlDateCoercing implements Coercing <Object , Object > {
381+
331382 @ Override
332- public Object serialize (Object input ) {
333- if (input instanceof String ) {
334- return parseStringToDate ((String ) input );
335- } else if (input instanceof Date ) {
336- return new java .sql .Date (((Date ) input ).getTime ());
337- } else if (input instanceof Long ) {
338- return new java .sql .Date (((Long ) input ).longValue ());
339- } else if (input instanceof Integer ) {
340- return new java .sql .Date (((Integer ) input ).longValue ());
341- }
342- return null ;
343- }
383+ public Object serialize (Object input ) {
384+ if (input instanceof String ) {
385+ return parseStringToDate ((String ) input );
386+ } else if (input instanceof Date ) {
387+ return new java .sql .Date (((Date ) input ).getTime ());
388+ } else if (input instanceof Long ) {
389+ return new java .sql .Date (((Long ) input ).longValue ());
390+ } else if (input instanceof Integer ) {
391+ return new java .sql .Date (((Integer ) input ).longValue ());
392+ }
393+ return null ;
394+ }
395+
344396 @ Override
345- public Object parseValue (Object input ) {
346- return serialize (input );
347- }
397+ public Object parseValue (Object input ) {
398+ return serialize (input );
399+ }
400+
348401 @ Override
349- public Object parseLiteral (Object input ) {
350- if (input instanceof StringValue ) {
351- return parseStringToDate (((StringValue ) input ).getValue ());
352- } else if (input instanceof IntValue ) {
353- BigInteger value = ((IntValue ) input ).getValue ();
354- return new java .sql .Date (value .longValue ());
355- }
356- return null ;
357- }
402+ public Object parseLiteral (Object input ) {
403+ if (input instanceof StringValue ) {
404+ return parseStringToDate (((StringValue ) input ).getValue ());
405+ } else if (input instanceof IntValue ) {
406+ BigInteger value = ((IntValue ) input ).getValue ();
407+ return new java .sql .Date (value .longValue ());
408+ }
409+ return null ;
410+ }
411+
358412 private java .sql .Date parseStringToDate (String input ) {
359- try {
360- return new java .sql .Date (DateFormat .getInstance ().parse (input ).getTime ());
361- } catch (ParseException e ) {
362- log .warn ("Failed to parse SQL Date from input: " + input , e );
363- return null ;
364- }
365- }
366- }
413+ try {
414+ return new java .sql .Date (DateFormat .getInstance ().parse (input ).getTime ());
415+ } catch (ParseException e ) {
416+ log .warn ("Failed to parse SQL Date from input: " + input , e );
417+ return null ;
418+ }
419+ }
420+ }
421+
367422 public static class GraphQLSqlTimestampCoercing implements Coercing <Object , Object > {
423+
368424 @ Override
369- public Object serialize (Object input ) {
370- if (input instanceof String ) {
371- return parseStringToTimestamp ((String ) input );
372- } else if (input instanceof Date ) {
373- return new java .sql .Timestamp (((Date ) input ).getTime ());
374- } else if (input instanceof Long ) {
375- return new java .sql .Timestamp (((Long ) input ).longValue ());
376- } else if (input instanceof Integer ) {
377- return new java .sql .Timestamp (((Integer ) input ).longValue ());
378- }
379- return null ;
380- }
425+ public Object serialize (Object input ) {
426+ if (input instanceof String ) {
427+ return parseStringToTimestamp ((String ) input );
428+ } else if (input instanceof Date ) {
429+ return new java .sql .Timestamp (((Date ) input ).getTime ());
430+ } else if (input instanceof Long ) {
431+ return new java .sql .Timestamp (((Long ) input ).longValue ());
432+ } else if (input instanceof Integer ) {
433+ return new java .sql .Timestamp (((Integer ) input ).longValue ());
434+ }
435+ return null ;
436+ }
437+
381438 @ Override
382- public Object parseValue (Object input ) {
383- return serialize (input );
384- }
439+ public Object parseValue (Object input ) {
440+ return serialize (input );
441+ }
442+
385443 @ Override
386- public Object parseLiteral (Object input ) {
387- if (input instanceof StringValue ) {
388- return parseStringToTimestamp (((StringValue ) input ).getValue ());
389- } else if (input instanceof IntValue ) {
390- BigInteger value = ((IntValue ) input ).getValue ();
391- return new java .sql .Date (value .longValue ());
392- }
393- return null ;
394- }
444+ public Object parseLiteral (Object input ) {
445+ if (input instanceof StringValue ) {
446+ return parseStringToTimestamp (((StringValue ) input ).getValue ());
447+ } else if (input instanceof IntValue ) {
448+ BigInteger value = ((IntValue ) input ).getValue ();
449+ return new java .sql .Date (value .longValue ());
450+ }
451+ return null ;
452+ }
453+
395454 private java .sql .Timestamp parseStringToTimestamp (String input ) {
396- try {
397- return new java .sql .Timestamp (DateFormat .getInstance ().parse (input ).getTime ());
398- } catch (ParseException e ) {
399- log .warn ("Failed to parse Timestamp from input: " + input , e );
400- return null ;
401- }
402- }
403- }
455+ try {
456+ return new java .sql .Timestamp (DateFormat .getInstance ().parse (input ).getTime ());
457+ } catch (ParseException e ) {
458+ log .warn ("Failed to parse Timestamp from input: " + input , e );
459+ return null ;
460+ }
461+ }
462+ }
463+
404464 public static class GraphQLLOBCoercing implements Coercing <Object , Object > {
465+
405466 @ Override
406- public Object serialize (Object input ) {
407- if (input .getClass () == byte [].class ) {
408- return input ;
409- }
410- return null ;
411- }
467+ public Object serialize (Object input ) {
468+ if (input .getClass () == byte [].class ) {
469+ return input ;
470+ }
471+ return null ;
472+ }
473+
412474 @ Override
413- public Object parseValue (Object input ) {
414- if (input instanceof String ) {
415- return parseStringToByteArray ((String ) input );
416- }
417- return null ;
418- }
475+ public Object parseValue (Object input ) {
476+ if (input instanceof String ) {
477+ return parseStringToByteArray ((String ) input );
478+ }
479+ return null ;
480+ }
481+
419482 @ Override
420- public Object parseLiteral (Object input ) {
421- if (input instanceof StringValue ) {
422- return parseStringToByteArray (((StringValue ) input ).getValue ());
423- }
424- return null ;
425- }
483+ public Object parseLiteral (Object input ) {
484+ if (input instanceof StringValue ) {
485+ return parseStringToByteArray (((StringValue ) input ).getValue ());
486+ }
487+ return null ;
488+ }
489+
426490 private byte [] parseStringToByteArray (String input ) {
427- try {
428- return input .getBytes (StandardCharsets .UTF_8 );
429- } catch (IllegalArgumentException e ) {
430- log .warn ("Failed to parse byte[] from input: " + input , e );
431- return null ;
432- }
433- }
434- }
435-
491+ try {
492+ return input .getBytes (StandardCharsets .UTF_8 );
493+ } catch (IllegalArgumentException e ) {
494+ log .warn ("Failed to parse byte[] from input: " + input , e );
495+ return null ;
496+ }
497+ }
498+ }
499+
436500 public static class GraphQLObjectCoercing implements Coercing <Object , Object > {
437501
438502 @ Override
@@ -447,17 +511,16 @@ public Object parseValue(Object input) {
447511
448512 @ Override
449513 public Object parseLiteral (Object input ) {
450- return parseFieldValue ((Value ) input , Collections .emptyMap ());
514+ return parseFieldValue ((Value ) input , Collections .emptyMap ());
451515 }
452516
453517 //recursively parse the input into a Map
454518 private Object parseFieldValue (Object value , Map <String , Object > variables ) {
455519 if (!(value instanceof Value )) {
456520 throw new IllegalArgumentException (
457- "Expected AST type 'StringValue' but was '" + value + "'."
458- );
459- }
460-
521+ "Expected AST type 'StringValue' but was '" + value + "'." );
522+ }
523+
461524 if (value instanceof StringValue ) {
462525 return ((StringValue ) value ).getValue ();
463526 }
@@ -477,27 +540,26 @@ private Object parseFieldValue(Object value, Map<String, Object> variables) {
477540 return null ;
478541 }
479542 if (value instanceof ArrayValue ) {
480- List <Value > values = ((ArrayValue ) value ).getValues ();
543+ List <Value > values = ((ArrayValue ) value ).getValues ();
481544 return values .stream ()
482- .map (v -> parseFieldValue (v , variables ))
483- .collect (Collectors .toList ());
545+ .map (v -> parseFieldValue (v , variables ))
546+ .collect (Collectors .toList ());
484547 }
485548 if (value instanceof ObjectValue ) {
486- List <ObjectField > values = ((ObjectValue ) value ).getObjectFields ();
549+ List <ObjectField > values = ((ObjectValue ) value ).getObjectFields ();
487550 Map <String , Object > parsedValues = new LinkedHashMap <>();
488-
551+
489552 values .forEach (field -> {
490553 Object parsedValue = parseFieldValue (field .getValue (), variables );
491554 parsedValues .put (field .getName (), parsedValue );
492555 });
493556 return parsedValues ;
494557 }
495-
558+
496559 //Should never happen, as it would mean the variable was not replaced by the parser
497560 throw new IllegalArgumentException ("Unsupported scalar value type: " + value .getClass ().getName ());
498561 }
499562
500563 }
501-
502564
503565}
0 commit comments