This is an automated email from the ASF dual-hosted git repository.
struberg pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/openjpa.git
The following commit(s) were added to refs/heads/master by this push:
new 72df022 OPENJPA-2849 coerc native java.sql types to java.time
72df022 is described below
commit 72df0228cab9637e23b4a7a3aa90b7e11b0fd7cf
Author: Mark Struberg <[email protected]>
AuthorDate: Sun Mar 28 19:36:32 2021 +0200
OPENJPA-2849 coerc native java.sql types to java.time
Many JDBC driver support old java.sql types for select max, min, etc.
Those need to get converted to java.time.* on demand.
---
.../java/org/apache/openjpa/kernel/Filters.java | 107 ++++++++++++++++-----
.../persistence/simple/TestJava8TimeTypes.java | 65 +++++++++++++
2 files changed, 149 insertions(+), 23 deletions(-)
diff --git
a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/Filters.java
b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/Filters.java
index d41a8bc..a63ae1a 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/Filters.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/Filters.java
@@ -25,6 +25,13 @@ import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.sql.Time;
import java.sql.Timestamp;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.OffsetDateTime;
+import java.time.OffsetTime;
+import java.time.ZoneId;
+import java.time.temporal.Temporal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
@@ -266,6 +273,8 @@ public class Filters {
/**
* Convert the given value to the given type.
+ * @param o the given value
+ * @param type the target type
*/
public static Object convert(Object o, Class<?> type, boolean
strictNumericConversion) {
if (o == null)
@@ -283,42 +292,93 @@ public class Filters {
// String to Integer
boolean num = o instanceof Number;
if (!num) {
- if (type == String.class)
+ if (type == String.class) {
return o.toString();
- else if (type == Boolean.class && o instanceof String)
+ }
+ else if (type == Boolean.class && o instanceof String) {
return Boolean.valueOf(o.toString());
- else if (type == Integer.class && o instanceof String)
+ }
+ else if (type == Integer.class && o instanceof String) {
try {
return new Integer(o.toString());
- } catch (NumberFormatException e) {
- throw new ClassCastException(_loc.get("cant-convert", o,
- o.getClass(), type).getMessage());
}
+ catch (NumberFormatException e) {
+ throw new ClassCastException(_loc.get("cant-convert", o,
o.getClass(), type).getMessage());
+ }
+ }
else if (type == Character.class) {
String str = o.toString();
- if (str != null && str.length() == 1)
+ if (str != null && str.length() == 1) {
return Character.valueOf(str.charAt(0));
- } else if (Calendar.class.isAssignableFrom(type) &&
- o instanceof Date) {
+ }
+ }
+ else if (Calendar.class.isAssignableFrom(type) && o instanceof
Date) {
Calendar cal = Calendar.getInstance();
cal.setTime((Date) o);
return cal;
- } else if (Date.class.isAssignableFrom(type) &&
- o instanceof Calendar) {
+ }
+ else if (Date.class.isAssignableFrom(type) && o instanceof
Calendar) {
return ((Calendar) o).getTime();
- } else if (Number.class.isAssignableFrom(type)) {
+ }
+ else if (Number.class.isAssignableFrom(type)) {
Integer i = null;
if (o instanceof Character) {
- i = Integer.valueOf((Character)o);
+ i = Integer.valueOf((Character) o);
+ }
+ else if (o instanceof String && ((String) o).length() == 1) {
+ i = Integer.valueOf(((String) o));
}
- else if (o instanceof String && ((String) o).length() == 1)
- i = Integer.valueOf(((String)o));
if (i != null) {
- if (type == Integer.class)
+ if (type == Integer.class) {
return i;
+ }
num = true;
}
+ } else if (Temporal.class.isAssignableFrom(type)) {
+ // handling of Java8 time API.
+ if (LocalDate.class.equals(type)) {
+ if (o instanceof java.sql.Date) {
+ return ((java.sql.Date) o).toLocalDate();
+ } else if (o instanceof java.util.Date) {
+ return new
java.sql.Date(((java.util.Date)o).getTime()).toLocalDate();
+ } else if (o instanceof CharSequence) {
+ return LocalDate.parse((CharSequence) o);
+ }
+ } else if (LocalDateTime.class.equals(type)) {
+ if (o instanceof java.sql.Timestamp) {
+ return ((java.sql.Timestamp) o).toLocalDateTime();
+ } else if (o instanceof java.util.Date) {
+ return
((java.util.Date)o).toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
+ } else if (o instanceof CharSequence) {
+ return LocalDateTime.parse((CharSequence) o);
+ }
+ } else if (LocalTime.class.equals(type)) {
+ if (o instanceof java.sql.Time) {
+ return ((java.sql.Time) o).toLocalTime();
+ } else if (o instanceof java.util.Date) {
+ return
((java.util.Date)o).toInstant().atZone(ZoneId.systemDefault()).toLocalTime();
+ } else if (o instanceof CharSequence) {
+ return LocalTime.parse((CharSequence) o);
+ }
+ } else if (OffsetTime.class.equals(type)) {
+ if (o instanceof java.sql.Time) {
+ return ((java.sql.Time)
o).toLocalTime().atOffset(OffsetDateTime.now().getOffset());
+ } else if (o instanceof java.util.Date) {
+ return
((java.util.Date)o).toInstant().atZone(ZoneId.systemDefault()).toOffsetDateTime().toOffsetTime();
+ } else if (o instanceof CharSequence) {
+ return OffsetTime.parse((CharSequence) o);
+ }
+ } else if (OffsetDateTime.class.equals(type)) {
+ if (o instanceof java.sql.Timestamp) {
+ return ((java.sql.Timestamp)
o).toInstant().atZone(ZoneId.systemDefault()).toOffsetDateTime();
+ } else if (o instanceof java.util.Date) {
+ return
((java.util.Date)o).toInstant().atZone(ZoneId.systemDefault()).toOffsetDateTime();
+ } else if (o instanceof CharSequence) {
+ return LocalTime.parse((CharSequence) o);
+ }
+ }
+
} else if (o instanceof String &&
isJDBCTemporalSyntax(o.toString())) {
try {
Object temporal = parseJDBCTemporalSyntax(o.toString());
@@ -331,9 +391,9 @@ public class Filters {
return Enum.valueOf((Class<Enum>)type, o.toString());
}
}
- if (!num)
- throw new ClassCastException(_loc.get("cant-convert", o,
- o.getClass(), type).getMessage());
+ if (!num) {
+ throw new ClassCastException(_loc.get("cant-convert", o,
o.getClass(), type).getMessage());
+ }
if (type == Integer.class && allowNumericConversion(o.getClass(),
type, strictNumericConversion)) {
return ((Number) o).intValue();
@@ -349,12 +409,13 @@ public class Filters {
// does it handle infinity; we need to instead use the Double
// and Float versions, despite wanting to cast it to BigDecimal
double dval = ((Number) o).doubleValue();
- if (Double.isNaN(dval) || Double.isInfinite(dval))
+ if (Double.isNaN(dval) || Double.isInfinite(dval)) {
return Double.valueOf(dval);
-
+ }
float fval = ((Number) o).floatValue();
- if (Float.isNaN(fval) || Float.isInfinite(fval))
+ if (Float.isNaN(fval) || Float.isInfinite(fval)) {
return Float.valueOf(fval);
+ }
return new BigDecimal(o.toString());
} else if (type == BigInteger.class) {
@@ -364,7 +425,7 @@ public class Filters {
} else if (type == Byte.class && allowNumericConversion(o.getClass(),
type, strictNumericConversion)) {
return Byte.valueOf(((Number) o).byteValue());
} else if (type == Character.class) {
- return (char) ((Number) o).intValue();
+ return (char) ((Number) o).intValue();
} else if (!strictNumericConversion) {
return ((Number) o).intValue();
} else {
diff --git
a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/simple/TestJava8TimeTypes.java
b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/simple/TestJava8TimeTypes.java
index f0c5637..17b76ca 100644
---
a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/simple/TestJava8TimeTypes.java
+++
b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/simple/TestJava8TimeTypes.java
@@ -21,11 +21,15 @@ package org.apache.openjpa.persistence.simple;
import org.apache.openjpa.persistence.test.SingleEMFTestCase;
import javax.persistence.EntityManager;
+import javax.persistence.TypedQuery;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
+import java.time.OffsetDateTime;
+import java.time.OffsetTime;
+import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.Date;
@@ -75,6 +79,67 @@ public class TestJava8TimeTypes extends SingleEMFTestCase {
assertEquals(e.getOffsetTimeField().withOffsetSameInstant(eRead.getOffsetTimeField().getOffset()),
eRead.getOffsetTimeField());
+
+ // we've got reports from various functions not properly working with
Java8 Dates.
+
+ // max function
+ {
+ final TypedQuery<LocalDate> qry = em.createQuery("select
max(t.localDateField) from Java8TimeTypes AS t", LocalDate.class);
+ final LocalDate max = qry.getSingleResult();
+ assertEquals(LocalDate.parse(VAL_LOCAL_DATE), max);
+ }
+ {
+ final TypedQuery<LocalDateTime> qry = em.createQuery("select
max(t.localDateTimeField) from Java8TimeTypes AS t", LocalDateTime.class);
+ final LocalDateTime max = qry.getSingleResult();
+ assertEquals(LocalDateTime.parse(VAL_LOCAL_DATETIME), max);
+ }
+ {
+ final TypedQuery<LocalTime> qry = em.createQuery("select
max(t.localTimeField) from Java8TimeTypes AS t", LocalTime.class);
+ final LocalTime max = qry.getSingleResult();
+ assertEquals(LocalTime.parse(VAL_LOCAL_TIME), max);
+ }
+ {
+ final TypedQuery<OffsetTime> qry = em.createQuery("select
max(t.offsetTimeField) from Java8TimeTypes AS t", OffsetTime.class);
+ final OffsetTime max = qry.getSingleResult();
+
assertEquals(e.getOffsetTimeField().withOffsetSameInstant(eRead.getOffsetTimeField().getOffset()),
+
max.withOffsetSameInstant(eRead.getOffsetTimeField().getOffset()));
+ }
+ {
+ final TypedQuery<OffsetDateTime> qry = em.createQuery("select
max(t.offsetDateTimeField) from Java8TimeTypes AS t", OffsetDateTime.class);
+ final OffsetDateTime max = qry.getSingleResult();
+ assertEquals(Instant.from(e.getOffsetDateTimeField()),
+ Instant.from(max));
+ }
+
+ // min function
+ {
+ final TypedQuery<LocalDate> qry = em.createQuery("select
min(t.localDateField) from Java8TimeTypes AS t", LocalDate.class);
+ final LocalDate min = qry.getSingleResult();
+ assertEquals(LocalDate.parse(VAL_LOCAL_DATE), min);
+ }
+ {
+ final TypedQuery<LocalDateTime> qry = em.createQuery("select
min(t.localDateTimeField) from Java8TimeTypes AS t", LocalDateTime.class);
+ final LocalDateTime min = qry.getSingleResult();
+ assertEquals(LocalDateTime.parse(VAL_LOCAL_DATETIME), min);
+ }
+ {
+ final TypedQuery<LocalTime> qry = em.createQuery("select
min(t.localTimeField) from Java8TimeTypes AS t", LocalTime.class);
+ final LocalTime min = qry.getSingleResult();
+ assertEquals(LocalTime.parse(VAL_LOCAL_TIME), min);
+ }
+ {
+ final TypedQuery<OffsetTime> qry = em.createQuery("select
min(t.offsetTimeField) from Java8TimeTypes AS t", OffsetTime.class);
+ final OffsetTime min = qry.getSingleResult();
+
assertEquals(e.getOffsetTimeField().withOffsetSameInstant(eRead.getOffsetTimeField().getOffset()),
+
min.withOffsetSameInstant(eRead.getOffsetTimeField().getOffset()));
+ }
+ {
+ final TypedQuery<OffsetDateTime> qry = em.createQuery("select
min(t.offsetDateTimeField) from Java8TimeTypes AS t", OffsetDateTime.class);
+ final OffsetDateTime min = qry.getSingleResult();
+ assertEquals(Instant.from(e.getOffsetDateTimeField()),
+ Instant.from(min));
+ }
+
}