Skip to content

Commit 44c854c

Browse files
authored
Update Hibernate version to 6.3.1 (#397)
* Add support JPA temporal annotation * Update JavaScalars with JPA Temporal types support for Time, Date, Timestamp * Add GraphQLTimeScalar unit tests * Add ThreadLocalDateFormatTest * Add temporal types unit tests to EntityIntrospector * update GraphQLDateCoercing to parse Java Date * Refactor Date type to use GraphQLTimestampScalar coercing * Revert GraphQLTimestampCoercing name to GraphQLSqlTimestampCoercing * Revert remove GraphQLDateCoercing * Refine GraphQLSqlDateCoercing and GraphQLDateCoercing unit tests * fix duplicate rebase conflicts in test data.sql * update hibernate.version to 6.3.1.Final
1 parent 2888d39 commit 44c854c

File tree

10 files changed

+485
-149
lines changed

10 files changed

+485
-149
lines changed

dependencies/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
<joda-time.version>2.12.5</joda-time.version>
2121
<graphql-java-extended-scalars.version>21.0</graphql-java-extended-scalars.version>
2222
<jakarta.persistence-api.version>3.1.0</jakarta.persistence-api.version>
23-
<hibernate.version>6.2.13.Final</hibernate.version>
23+
<hibernate.version>6.3.1.Final</hibernate.version>
2424
</properties>
2525

2626
<dependencyManagement>

scalars/src/main/java/com/introproventures/graphql/jpa/query/schema/JavaScalars.java

Lines changed: 196 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,72 @@
7878
*/
7979
public 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

Comments
 (0)