openjpa-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From strub...@apache.org
Subject [openjpa] branch master updated: OPENJPA-2849 coerc native java.sql types to java.time
Date Sun, 28 Mar 2021 17:38:36 GMT
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 <struberg@apache.org>
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));
+        }
+
     }
 
 

Mime
View raw message