7878 */
7979public class JavaScalars {
8080
81- static final Logger log = LoggerFactory .getLogger (JavaScalars .class );
82-
83- private static Map <Class <?>, GraphQLScalarType > scalarsRegistry = new HashMap <Class <?>, GraphQLScalarType >();
84-
85- private static JavaScalars instance = new JavaScalars ();
81+ private static final Logger log = LoggerFactory .getLogger (JavaScalars .class );
82+
83+ private static final Map <Class <?>, GraphQLScalarType > scalarsRegistry = new HashMap <Class <?>, GraphQLScalarType >();
84+
85+ private static final JavaScalars instance = new JavaScalars ();
86+
87+ public static final GraphQLScalarType GraphQLSqlDateScalar = newScalarType (
88+ "Date" ,
89+ "Date type" ,
90+ new GraphQLSqlDateCoercing ()
91+ );
92+ public static final GraphQLScalarType GraphQLSqlTimeScalar = newScalarType (
93+ "Time" ,
94+ "Time type" ,
95+ new GraphQLSqlTimeCoercing ()
96+ );
97+ public static final GraphQLScalarType GraphQLSqlTimestampScalar = newScalarType (
98+ "Timestamp" ,
99+ "Timestamp type" ,
100+ new GraphQLSqlTimestampCoercing ()
101+ );
102+ public static final GraphQLScalarType GraphQLLocalDateTimeScalar = newScalarType (
103+ "LocalDateTime" ,
104+ "LocalDateTime type" ,
105+ new GraphQLLocalDateTimeCoercing ()
106+ );
107+ public static final GraphQLScalarType GraphQLLocalDateScalar = newScalarType (
108+ "LocalDate" ,
109+ "LocalDate type" ,
110+ new GraphQLLocalDateCoercing ()
111+ );
112+ public static final GraphQLScalarType GraphQLLocalTimeScalar = newScalarType (
113+ "LocalTime" ,
114+ "LocalTime type" ,
115+ new GraphQLLocalTimeCoercing ()
116+ );
117+ public static final GraphQLScalarType GraphQLUUIDScalar = newScalarType (
118+ "UUID" ,
119+ "UUID type" ,
120+ new GraphQLUUIDCoercing ()
121+ );
122+ public static final GraphQLScalarType GraphQLObjectScalar = newScalarType (
123+ "Object" ,
124+ "Object type" ,
125+ new GraphQLObjectCoercing ()
126+ );
127+ public static final GraphQLScalarType GraphQLByteArrayScalar = newScalarType (
128+ "ByteArray" ,
129+ "ByteArray type" ,
130+ new GraphQLLOBCoercing ()
131+ );
132+ public static final GraphQLScalarType GraphQLZonedDateTimeScalar = newScalarType (
133+ "ZonedDateTime" ,
134+ "ZonedDateTime type" ,
135+ new GraphQLZonedDateTimeCoercing ()
136+ );
137+ public static final GraphQLScalarType GraphQLOffsetDateTimeScalar = newScalarType (
138+ "OffsetDateTime" ,
139+ "OffsetDateTime type" ,
140+ new GraphQLOffsetDateTimeCoercing ()
141+ );
142+ public static final GraphQLScalarType GraphQLInstantScalar = newScalarType (
143+ "Instant" ,
144+ "Instant type" ,
145+ new GraphQLInstantCoercing ()
146+ );
86147
87148 static {
88149 scalarsRegistry .put (String .class , Scalars .GraphQLString );
@@ -115,40 +176,20 @@ public class JavaScalars {
115176
116177 scalarsRegistry .put (BigDecimal .class , ExtendedScalars .GraphQLBigDecimal );
117178
118- scalarsRegistry .put (
119- LocalDateTime .class ,
120- newScalarType ("LocalDateTime" , "LocalDateTime type" , new GraphQLLocalDateTimeCoercing ())
121- );
122- scalarsRegistry .put (
123- LocalDate .class ,
124- newScalarType ("LocalDate" , "LocalDate type" , new GraphQLLocalDateCoercing ())
125- );
126- scalarsRegistry .put (
127- LocalTime .class ,
128- newScalarType ("LocalTime" , "LocalTime type" , new GraphQLLocalTimeCoercing ())
129- );
130- scalarsRegistry .put (Date .class , newScalarType ("Date" , "Date type" , new GraphQLDateCoercing ()));
131- scalarsRegistry .put (UUID .class , newScalarType ("UUID" , "UUID type" , new GraphQLUUIDCoercing ()));
132- scalarsRegistry .put (Object .class , newScalarType ("Object" , "Object type" , new GraphQLObjectCoercing ()));
133- scalarsRegistry .put (
134- java .sql .Date .class ,
135- newScalarType ("SqlDate" , "SQL Date type" , new GraphQLSqlDateCoercing ())
136- );
137- scalarsRegistry .put (
138- java .sql .Timestamp .class ,
139- newScalarType ("SqlTimestamp" , "SQL Timestamp type" , new GraphQLSqlTimestampCoercing ())
140- );
141- scalarsRegistry .put (Byte [].class , newScalarType ("ByteArray" , "ByteArray type" , new GraphQLLOBCoercing ()));
142- scalarsRegistry .put (byte [].class , newScalarType ("ByteArray" , "ByteArray type" , new GraphQLLOBCoercing ()));
143- scalarsRegistry .put (Instant .class , newScalarType ("Instant" , "Instant type" , new GraphQLInstantCoercing ()));
144- scalarsRegistry .put (
145- ZonedDateTime .class ,
146- newScalarType ("ZonedDateTime" , "ZonedDateTime type" , new GraphQLZonedDateTimeCoercing ())
147- );
148- scalarsRegistry .put (
149- OffsetDateTime .class ,
150- newScalarType ("OffsetDateTime" , "OffsetDateTime type" , new GraphQLOffsetDateTimeCoercing ())
151- );
179+ scalarsRegistry .put (LocalDateTime .class , GraphQLLocalDateTimeScalar );
180+ scalarsRegistry .put (LocalDate .class , GraphQLLocalDateScalar );
181+ scalarsRegistry .put (LocalTime .class , GraphQLLocalTimeScalar );
182+ scalarsRegistry .put (Date .class , GraphQLSqlTimestampScalar );
183+ scalarsRegistry .put (UUID .class , GraphQLUUIDScalar );
184+ scalarsRegistry .put (Object .class , GraphQLObjectScalar );
185+ scalarsRegistry .put (java .sql .Date .class , GraphQLSqlDateScalar );
186+ scalarsRegistry .put (java .sql .Time .class , GraphQLSqlTimeScalar );
187+ scalarsRegistry .put (java .sql .Timestamp .class , GraphQLSqlTimestampScalar );
188+ scalarsRegistry .put (Byte [].class , GraphQLByteArrayScalar );
189+ scalarsRegistry .put (byte [].class , GraphQLByteArrayScalar );
190+ scalarsRegistry .put (Instant .class , GraphQLInstantScalar );
191+ scalarsRegistry .put (ZonedDateTime .class , GraphQLZonedDateTimeScalar );
192+ scalarsRegistry .put (OffsetDateTime .class , GraphQLOffsetDateTimeScalar );
152193 }
153194
154195 public static Optional <GraphQLScalarType > of (String name ) {
@@ -333,13 +374,13 @@ public LocalTime parseLiteral(Object input) {
333374
334375 public static class GraphQLDateCoercing implements Coercing <Object , Object > {
335376
336- final String dateFormatString ;
377+ private final ThreadLocal < DateFormat > df ;
337378
338379 /**
339380 * Default to pattern 'yyyy-MM-dd'
340381 */
341382 public GraphQLDateCoercing () {
342- dateFormatString = "yyyy-MM-dd" ;
383+ this ( "yyyy-MM-dd'T'HH:mm:ss.SSSXXX" ) ;
343384 }
344385
345386 /**
@@ -348,19 +389,19 @@ public GraphQLDateCoercing() {
348389 * @param dateFormatString e.g. "yyyy-MM-dd'T'HH:mm:ss.SSSXXX" for "2001-07-04T12:08:56.235-07:00"
349390 */
350391 public GraphQLDateCoercing (String dateFormatString ) {
351- this .dateFormatString = dateFormatString ;
392+ this .df = ThreadLocal . withInitial (() -> new SimpleDateFormat ( dateFormatString )) ;
352393 }
353394
354395 @ Override
355396 public Object serialize (Object input ) {
356- if (input instanceof String ) {
357- return parseStringToDate (( String ) input );
397+ if (input instanceof String stringInput ) {
398+ return parseStringToDate (stringInput );
358399 } else if (input instanceof Date ) {
359- return new SimpleDateFormat ( dateFormatString ).format (input );
360- } else if (input instanceof Long ) {
361- return new Date ((( Long ) input ). longValue () );
362- } else if (input instanceof Integer ) {
363- return new Date ((( Integer ) input ) .longValue ());
400+ return df . get ( ).format (input );
401+ } else if (input instanceof Long longInput ) {
402+ return new Date (longInput );
403+ } else if (input instanceof Integer intInput ) {
404+ return new Date (intInput .longValue ());
364405 }
365406 return null ;
366407 }
@@ -382,10 +423,8 @@ public Object parseLiteral(Object input) {
382423 }
383424
384425 private Date parseStringToDate (String input ) {
385- DateFormat df = new SimpleDateFormat (dateFormatString );
386-
387426 try {
388- return df .parse (input );
427+ return df .get (). parse (input );
389428 } catch (ParseException e ) {
390429 log .warn ("Failed to parse Date from input: " + input , e );
391430 return null ;
@@ -576,16 +615,34 @@ public Object parseLiteral(Object input) {
576615
577616 public static class GraphQLSqlDateCoercing implements Coercing <Object , Object > {
578617
618+ private final ThreadLocal <DateFormat > df ;
619+
620+ /**
621+ * Default to pattern 'yyyy-MM-dd'
622+ */
623+ public GraphQLSqlDateCoercing () {
624+ this ("yyyy-MM-dd" );
625+ }
626+
627+ /**
628+ * Parse date strings according to the provided SimpleDateFormat pattern
629+ *
630+ * @param dateFormatString e.g. "yyyy-MM-dd'T'HH:mm:ss.SSSXXX" for "2001-07-04T12:08:56.235-07:00"
631+ */
632+ public GraphQLSqlDateCoercing (String dateFormatString ) {
633+ this .df = ThreadLocal .withInitial (() -> new SimpleDateFormat (dateFormatString ));
634+ }
635+
579636 @ Override
580637 public Object serialize (Object input ) {
581- if (input instanceof String ) {
582- return parseStringToDate (( String ) input );
638+ if (input instanceof String stringInput ) {
639+ return parseStringToDate (stringInput );
583640 } else if (input instanceof Date ) {
584- return new java . sql . Date ((( Date ) input ). getTime () );
585- } else if (input instanceof Long ) {
586- return new java .sql .Date ((( Long ) input ). longValue () );
587- } else if (input instanceof Integer ) {
588- return new java .sql .Date ((( Integer ) input ) .longValue ());
641+ return df . get (). format ( input );
642+ } else if (input instanceof Long longInput ) {
643+ return new java .sql .Date (longInput );
644+ } else if (input instanceof Integer intInput ) {
645+ return new java .sql .Date (intInput .longValue ());
589646 }
590647 return null ;
591648 }
@@ -597,18 +654,78 @@ public Object parseValue(Object input) {
597654
598655 @ Override
599656 public Object parseLiteral (Object input ) {
600- if (input instanceof StringValue ) {
601- return parseStringToDate ((( StringValue ) input ) .getValue ());
602- } else if (input instanceof IntValue ) {
603- BigInteger value = (( IntValue ) input ) .getValue ();
657+ if (input instanceof StringValue stringValue ) {
658+ return parseStringToDate (stringValue .getValue ());
659+ } else if (input instanceof IntValue intValue ) {
660+ BigInteger value = intValue .getValue ();
604661 return new java .sql .Date (value .longValue ());
605662 }
606663 return null ;
607664 }
608665
609666 private java .sql .Date parseStringToDate (String input ) {
610667 try {
611- return new java .sql .Date (DateFormat .getInstance ().parse (input ).getTime ());
668+ return new java .sql .Date (df .get ().parse (input ).getTime ());
669+ } catch (ParseException e ) {
670+ log .warn ("Failed to parse SQL Date from input: " + input , e );
671+ return null ;
672+ }
673+ }
674+ }
675+
676+ public static class GraphQLSqlTimeCoercing implements Coercing <Object , Object > {
677+
678+ private final ThreadLocal <DateFormat > df ;
679+
680+ /**
681+ * Default to pattern 'yyyy-MM-dd'
682+ */
683+ public GraphQLSqlTimeCoercing () {
684+ this ("HH:mm:ss" );
685+ }
686+
687+ /**
688+ * Parse time strings according to the provided SimpleDateFormat pattern
689+ *
690+ * @param timeFormatString e.g. "HH:mm:ss.SSSXXX"
691+ */
692+ public GraphQLSqlTimeCoercing (String timeFormatString ) {
693+ this .df = ThreadLocal .withInitial (() -> new SimpleDateFormat (timeFormatString ));
694+ }
695+
696+ @ Override
697+ public Object serialize (Object input ) {
698+ if (input instanceof String inputString ) {
699+ return parseStringToTime (inputString );
700+ } else if (input instanceof java .sql .Time ) {
701+ return df .get ().format (input );
702+ } else if (input instanceof Long longInput ) {
703+ return new java .sql .Time (longInput );
704+ } else if (input instanceof Integer integerInput ) {
705+ return new java .sql .Time (integerInput .longValue ());
706+ }
707+ return null ;
708+ }
709+
710+ @ Override
711+ public Object parseValue (Object input ) {
712+ return serialize (input );
713+ }
714+
715+ @ Override
716+ public Object parseLiteral (Object input ) {
717+ if (input instanceof StringValue stringValue ) {
718+ return parseStringToTime (stringValue .getValue ());
719+ } else if (input instanceof IntValue intValue ) {
720+ BigInteger value = intValue .getValue ();
721+ return new java .sql .Time (value .longValue ());
722+ }
723+ return null ;
724+ }
725+
726+ private java .sql .Time parseStringToTime (String input ) {
727+ try {
728+ return new java .sql .Time (df .get ().parse (input ).getTime ());
612729 } catch (ParseException e ) {
613730 log .warn ("Failed to parse SQL Date from input: " + input , e );
614731 return null ;
@@ -618,15 +735,18 @@ private java.sql.Date parseStringToDate(String input) {
618735
619736 public static class GraphQLSqlTimestampCoercing implements Coercing <Timestamp , Object > {
620737
621- private Timestamp doConvert (Object input ) {
622- if (input instanceof Long ) {
623- return new Timestamp (Long .class .cast (input ));
624- } else if (input instanceof String ) {
625- Instant instant = DateTimeHelper .parseDate (String .class .cast (input ));
738+ private final ThreadLocal <DateTimeFormatter > df = ThreadLocal .withInitial (() -> DateTimeFormatter .ISO_INSTANT );
626739
740+ private Timestamp doConvert (Object input ) {
741+ if (input instanceof Long longInput ) {
742+ return new Timestamp (longInput );
743+ } else if (input instanceof String stringInput ) {
744+ Instant instant = DateTimeHelper .parseDate (stringInput );
627745 return Timestamp .from (instant );
628- } else if (input instanceof Timestamp ) {
629- return Timestamp .class .cast (input );
746+ } else if (input instanceof Timestamp timestampInput ) {
747+ return timestampInput ;
748+ } else if (input instanceof Date dateInput ) {
749+ return new Timestamp (dateInput .getTime ());
630750 }
631751
632752 return null ;
@@ -640,7 +760,7 @@ public Object serialize(Object input) {
640760 throw new CoercingSerializeException ("Invalid value '" + input + "' for Timestamp" );
641761 }
642762
643- return DateTimeFormatter . ISO_INSTANT .format (result .toInstant ());
763+ return df . get () .format (result .toInstant ());
644764 }
645765
646766 @ Override
@@ -657,10 +777,10 @@ public Timestamp parseValue(Object input) {
657777 public Timestamp parseLiteral (Object input ) {
658778 Object value = null ;
659779
660- if (IntValue . class . isInstance ( input ) ) {
661- value = IntValue . class . cast ( input ) .getValue ().longValue ();
662- } else if (StringValue . class . isInstance ( input ) ) {
663- value = StringValue . class . cast ( input ) .getValue ();
780+ if (input instanceof IntValue intValue ) {
781+ value = intValue .getValue ().longValue ();
782+ } else if (input instanceof StringValue stringValue ) {
783+ value = stringValue .getValue ();
664784 } else {
665785 throw new CoercingParseLiteralException ("Invalid value '" + input + "' for Timestamp" );
666786 }
0 commit comments