You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by st...@apache.org on 2019/01/25 18:11:55 UTC

[openjpa] branch master updated (9e22265 -> 5079209)

This is an automated email from the ASF dual-hosted git repository.

struberg pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/openjpa.git.


    from 9e22265  OPENJPA-2770 ensure equal(xxx, literal(boolean)) works in criteria builder
     new e57fd51  OPENJPA-2713 implement native java8 types
     new dbfb360  OPENJPA-2713 add OffsetTime support
     new 6d2544f  OPENJPA-2713 properly handle WITH TIME ZONE if supported by db
     new 5079209  Merge branch 'OPENJPA-2713'

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../openjpa/jdbc/meta/MappingDefaultsImpl.java     |   6 -
 .../openjpa/jdbc/meta/MappingRepository.java       |   5 +
 .../openjpa/jdbc/meta/strats/BlobValueHandler.java |   7 +-
 .../jdbc/meta/strats/ImmutableValueHandler.java    |   5 +
 .../jdbc/meta/strats/LocalDateValueHandler.java    |  81 -------
 .../apache/openjpa/jdbc/sql/AbstractResult.java    |  89 +++++++-
 .../org/apache/openjpa/jdbc/sql/DBDictionary.java  | 237 ++++++++++++++++-----
 .../apache/openjpa/jdbc/sql/DerbyDictionary.java   |  18 ++
 .../org/apache/openjpa/jdbc/sql/MergedResult.java  |  33 ++-
 .../openjpa/jdbc/sql/PostgresDictionary.java       |  69 +++++-
 .../java/org/apache/openjpa/jdbc/sql/Result.java   |  35 +++
 .../apache/openjpa/jdbc/sql/ResultSetResult.java   |  48 ++++-
 .../org/apache/openjpa/kernel/AttachStrategy.java  |   7 +-
 .../java/org/apache/openjpa/kernel/BrokerImpl.java |   2 +-
 .../java/org/apache/openjpa/meta/JavaTypes.java    |  28 ++-
 .../openjpa/lib/jdbc/DelegatingResultSet.java      |   4 +-
 .../openjpa/persistence/simple/Java8TimeTypes.java | 102 +++++++++
 .../persistence/simple/TestBasicAnnotation.java    |   4 +
 .../persistence/simple/TestJava8TimeTypes.java     |  82 +++++++
 .../strategy/value/ValueStrategyHandler.java       |  50 ++---
 .../persistence/PersistenceMetaDataDefaults.java   |   5 +
 .../persistence/meta/AbstractManagedType.java      |  20 ++
 openjpa-project/supportedJava8TimeTypes.adoc       | 118 ++++++++++
 23 files changed, 857 insertions(+), 198 deletions(-)
 delete mode 100644 openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/LocalDateValueHandler.java
 create mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/simple/Java8TimeTypes.java
 create mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/simple/TestJava8TimeTypes.java
 create mode 100644 openjpa-project/supportedJava8TimeTypes.adoc


[openjpa] 01/04: OPENJPA-2713 implement native java8 types

Posted by st...@apache.org.
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

commit e57fd518b32d1ebc85fbdb818b1ca818d1abe46a
Author: Mark Struberg <st...@apache.org>
AuthorDate: Sun Jan 20 23:51:10 2019 +0100

    OPENJPA-2713 implement native java8 types
    
    Since some DBs (e.g. PostgreSQL) do support LocalDate, etc
    in their JDBC drivers, it's probably the best to support it
    on a way deeper level.
---
 .../openjpa/jdbc/meta/MappingDefaultsImpl.java     |   6 -
 .../openjpa/jdbc/meta/MappingRepository.java       |   5 +
 .../openjpa/jdbc/meta/strats/BlobValueHandler.java |   7 +-
 .../jdbc/meta/strats/ImmutableValueHandler.java    |   5 +
 .../jdbc/meta/strats/LocalDateValueHandler.java    |  81 ------------
 .../apache/openjpa/jdbc/sql/AbstractResult.java    |  57 ++++++++-
 .../org/apache/openjpa/jdbc/sql/DBDictionary.java  | 140 ++++++++++++++++-----
 .../org/apache/openjpa/jdbc/sql/MergedResult.java  |  21 +++-
 .../java/org/apache/openjpa/jdbc/sql/Result.java   |  21 ++++
 .../apache/openjpa/jdbc/sql/ResultSetResult.java   |  31 ++++-
 .../org/apache/openjpa/kernel/AttachStrategy.java  |   7 +-
 .../java/org/apache/openjpa/meta/JavaTypes.java    |  28 ++++-
 .../openjpa/persistence/simple/Java8TimeTypes.java |  82 ++++++++++++
 .../persistence/simple/TestBasicAnnotation.java    |   4 +
 .../persistence/simple/TestJava8TimeTypes.java     |  65 ++++++++++
 .../strategy/value/ValueStrategyHandler.java       |  50 ++++----
 .../persistence/PersistenceMetaDataDefaults.java   |   5 +
 .../persistence/meta/AbstractManagedType.java      |  20 +++
 18 files changed, 474 insertions(+), 161 deletions(-)

diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MappingDefaultsImpl.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MappingDefaultsImpl.java
index fe4f5bc..ca1bf38 100644
--- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MappingDefaultsImpl.java
+++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MappingDefaultsImpl.java
@@ -27,7 +27,6 @@ import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
 import org.apache.openjpa.jdbc.identifier.DBIdentifier;
 import org.apache.openjpa.jdbc.identifier.Normalizer;
 import org.apache.openjpa.jdbc.meta.strats.EnumValueHandler;
-import org.apache.openjpa.jdbc.meta.strats.LocalDateValueHandler;
 import org.apache.openjpa.jdbc.meta.strats.UntypedPCValueHandler;
 import org.apache.openjpa.jdbc.schema.Column;
 import org.apache.openjpa.jdbc.schema.ForeignKey;
@@ -537,11 +536,6 @@ public class MappingDefaultsImpl
             return enumHandler;
         }
 
-        if (java.time.LocalDate.class == type) {
-            // we can compare with == since LocalDate is final
-            return new LocalDateValueHandler();
-        }
-
         return null;
     }
 
diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MappingRepository.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MappingRepository.java
index 66f6970..b62cdbb 100644
--- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MappingRepository.java
+++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MappingRepository.java
@@ -1356,6 +1356,11 @@ public class MappingRepository extends MetaDataRepository {
             case JavaTypes.DATE:
             case JavaTypes.CALENDAR:
             case JavaTypes.LOCALE:
+            case JavaTypes.LOCAL_DATE:
+            case JavaTypes.LOCAL_TIME:
+            case JavaTypes.LOCAL_DATETIME:
+            case JavaTypes.OFFSET_TIME:
+            case JavaTypes.OFFSET_DATETIME:
                 return ImmutableValueHandler.getInstance();
             case JavaTypes.STRING:
                 if (isClob(val, true))
diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/BlobValueHandler.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/BlobValueHandler.java
index ed76deb..def2112 100644
--- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/BlobValueHandler.java
+++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/BlobValueHandler.java
@@ -29,8 +29,7 @@ import org.apache.openjpa.meta.JavaTypes;
  * Handler for blob values.
  *
  */
-public class BlobValueHandler
-    extends AbstractValueHandler {
+public class BlobValueHandler extends AbstractValueHandler {
 
     
     private static final long serialVersionUID = 1L;
@@ -43,10 +42,6 @@ public class BlobValueHandler
         return _instance;
     }
 
-    /**
-     * @deprecated
-     */
-    @Deprecated
     @Override
     public Column[] map(ValueMapping vm, String name, ColumnIO io,
         boolean adapt) {
diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/ImmutableValueHandler.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/ImmutableValueHandler.java
index e148963..362d18d 100644
--- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/ImmutableValueHandler.java
+++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/ImmutableValueHandler.java
@@ -87,6 +87,11 @@ public class ImmutableValueHandler extends AbstractValueHandler {
             case JavaTypes.SHORT_OBJ:
             case JavaTypes.STRING:
             case JavaTypes.DATE:
+            case JavaTypes.LOCAL_DATE:
+            case JavaTypes.LOCAL_TIME:
+            case JavaTypes.LOCAL_DATETIME:
+            case JavaTypes.OFFSET_TIME:
+            case JavaTypes.OFFSET_DATETIME:
             case JavaTypes.BIGINTEGER:
             case JavaTypes.LOCALE:
                 return true;
diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/LocalDateValueHandler.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/LocalDateValueHandler.java
deleted file mode 100644
index 1701dbf..0000000
--- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/LocalDateValueHandler.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.openjpa.jdbc.meta.strats;
-
-import java.sql.Types;
-import java.time.LocalDate;
-
-import org.apache.openjpa.jdbc.identifier.DBIdentifier;
-import org.apache.openjpa.jdbc.kernel.JDBCStore;
-import org.apache.openjpa.jdbc.meta.JavaSQLTypes;
-import org.apache.openjpa.jdbc.meta.ValueMapping;
-import org.apache.openjpa.jdbc.schema.Column;
-import org.apache.openjpa.jdbc.schema.ColumnIO;
-import org.apache.openjpa.jdbc.sql.DBDictionary;
-import org.apache.openjpa.lib.util.Localizer;
-
-/**
- * Value handler for JDK8 java.time.LocalDate field types.
- *
- */
-public class LocalDateValueHandler extends AbstractValueHandler {
-    private static final long serialVersionUID = 1L;
-    private static final Localizer _loc = Localizer.forPackage(LocalDateValueHandler.class);
-
-    /**
-     * @deprecated
-     */
-    @Deprecated
-    @Override
-    public Column[] map(ValueMapping vm, String name, ColumnIO io,
-        boolean adapt) {
-        DBDictionary dict = vm.getMappingRepository().getDBDictionary();
-        DBIdentifier colName = DBIdentifier.newColumn(name, dict != null ? dict.delimitAll() : false);
-
-        Column column = new Column();
-        column.setIdentifier(colName);
-        column.setJavaType(JavaSQLTypes.SQL_DATE);
-        column.setType(Types.DATE);
-
-        return new Column[]{column};
-    }
-
-    @Override
-    public boolean isVersionable(ValueMapping vm) {
-        return true;
-    }
-
-    @Override
-    public Object toDataStoreValue(ValueMapping vm, Object val, JDBCStore store) {
-        if (val == null) {
-            return null;
-        }
-
-        return java.sql.Date.valueOf((LocalDate) val);
-    }
-
-    @Override
-    public Object toObjectValue(ValueMapping vm, Object val) {
-        if (val == null) {
-            return null;
-        }
-
-        return ((java.sql.Date) val).toLocalDate();
-    }
-}
diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/AbstractResult.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/AbstractResult.java
index 61f3143..ab925f1 100644
--- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/AbstractResult.java
+++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/AbstractResult.java
@@ -31,6 +31,9 @@ import java.sql.SQLException;
 import java.sql.Time;
 import java.sql.Timestamp;
 import java.sql.Types;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
 import java.util.Calendar;
 import java.util.Date;
 import java.util.HashMap;
@@ -502,8 +505,7 @@ public abstract class AbstractResult
 
     protected Calendar getCalendarInternal(Object obj, Joins joins)
         throws SQLException {
-        Object val = checkNull(getObjectInternal(obj, JavaTypes.CALENDAR,
-            null, joins));
+        Object val = checkNull(getObjectInternal(obj, JavaTypes.CALENDAR, null, joins));
         if (val == null)
             return null;
         if (val instanceof Calendar)
@@ -515,6 +517,51 @@ public abstract class AbstractResult
     }
 
     @Override
+    public LocalDate getLocalDate(Object obj) throws SQLException {
+        return getLocalDateInternal(translate(obj, null), null);
+    }
+
+    protected LocalDate getLocalDateInternal(Object obj, Joins joins) throws SQLException {
+        Object val = checkNull(getObjectInternal(obj, JavaTypes.LOCAL_DATE, null, joins));
+        if (val == null)
+            return null;
+        if (val instanceof LocalDate)
+            return (LocalDate) val;
+
+        return LocalDate.parse(val.toString());
+    }
+
+    @Override
+    public LocalTime getLocalTime(Object obj) throws SQLException {
+        return getLocalTimeInternal(translate(obj, null), null);
+    }
+
+    protected LocalTime getLocalTimeInternal(Object obj, Joins joins) throws SQLException {
+        Object val = checkNull(getObjectInternal(obj, JavaTypes.LOCAL_TIME, null, joins));
+        if (val == null)
+            return null;
+        if (val instanceof LocalTime)
+            return (LocalTime) val;
+
+        return LocalTime.parse(val.toString());
+    }
+
+    @Override
+    public LocalDateTime getLocalDateTime(Object obj) throws SQLException {
+        return getLocalDateTimeInternal(translate(obj, null), null);
+    }
+
+    protected LocalDateTime getLocalDateTimeInternal(Object obj, Joins joins) throws SQLException {
+        Object val = checkNull(getObjectInternal(obj, JavaTypes.LOCAL_DATETIME, null, joins));
+        if (val == null)
+            return null;
+        if (val instanceof LocalDateTime)
+            return (LocalDateTime) val;
+
+        return LocalDateTime.parse(val.toString());
+    }
+
+    @Override
     public char getChar(Object obj)
         throws SQLException {
         return getCharInternal(translate(obj, null), null);
@@ -594,8 +641,7 @@ public abstract class AbstractResult
 
     protected Date getDateInternal(Object obj, Joins joins)
         throws SQLException {
-        Object val = checkNull(getObjectInternal(obj, JavaTypes.DATE,
-            null, joins));
+        Object val = checkNull(getObjectInternal(obj, JavaTypes.DATE, null, joins));
         if (val == null)
             return null;
         if (val instanceof Date)
@@ -615,8 +661,7 @@ public abstract class AbstractResult
         return getDateInternal(translate(col, joins), cal, joins);
     }
 
-    protected java.sql.Date getDateInternal(Object obj, Calendar cal,
-        Joins joins)
+    protected java.sql.Date getDateInternal(Object obj, Calendar cal, Joins joins)
         throws SQLException {
         return (java.sql.Date) checkNull(getObjectInternal(obj,
             JavaSQLTypes.SQL_DATE, cal, joins));
diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
index 3f02899..81d249f 100644
--- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
+++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
@@ -45,6 +45,9 @@ import java.sql.Time;
 import java.sql.Timestamp;
 import java.sql.Types;
 import java.text.MessageFormat;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Calendar;
@@ -775,6 +778,33 @@ public class DBDictionary
         return cal;
     }
 
+    /**
+     * Retrieve the specified column of the SQL ResultSet to the proper
+     * {@link LocalDate} java type.
+     */
+    public LocalDate getLocalDate(ResultSet rs, int column) throws SQLException {
+        java.sql.Date date = rs.getDate(column);
+        return date != null ? date.toLocalDate() : null;
+    }
+
+    /**
+     * Retrieve the specified column of the SQL ResultSet to the proper
+     * {@link LocalTime} java type.
+     */
+    public LocalTime getLocalTime(ResultSet rs, int column) throws SQLException {
+        java.sql.Time time = rs.getTime(column);
+        return time != null ? time.toLocalTime() : null;
+    }
+
+    /**
+     * Retrieve the specified column of the SQL ResultSet to the proper
+     * {@link LocalDateTime} java type.
+     */
+    public LocalDateTime getLocalDateTime(ResultSet rs, int column) throws SQLException {
+        Timestamp tst = rs.getTimestamp(column);
+        return tst != null ? tst.toLocalDateTime() : null;
+    }
+
     private ProxyManager getProxyManager() {
         if (_proxyManager == null) {
             _proxyManager = conf.getProxyManagerInstance();
@@ -1006,8 +1036,7 @@ public class DBDictionary
     /**
      * Set the given value as a parameter to the statement.
      */
-    public void setAsciiStream(PreparedStatement stmnt, int idx,
-        InputStream val, int length, Column col)
+    public void setAsciiStream(PreparedStatement stmnt, int idx, InputStream val, int length, Column col)
         throws SQLException {
         stmnt.setAsciiStream(idx, val, length);
     }
@@ -1015,47 +1044,48 @@ public class DBDictionary
     /**
      * Set the given value as a parameter to the statement.
      */
-    public void setBigDecimal(PreparedStatement stmnt, int idx, BigDecimal val,
-        Column col)
+    public void setBigDecimal(PreparedStatement stmnt, int idx, BigDecimal val, Column col)
         throws SQLException {
         if ((col != null && col.isCompatible(Types.VARCHAR, null, 0, 0))
-            || (col == null && storeLargeNumbersAsStrings))
+            || (col == null && storeLargeNumbersAsStrings)) {
             setString(stmnt, idx, val.toString(), col);
-        else
+        }
+        else {
             stmnt.setBigDecimal(idx, val);
+        }
     }
 
     /**
      * Set the given value as a parameter to the statement.
      */
-    public void setBigInteger(PreparedStatement stmnt, int idx, BigInteger val,
-        Column col)
+    public void setBigInteger(PreparedStatement stmnt, int idx, BigInteger val, Column col)
         throws SQLException {
         if ((col != null && col.isCompatible(Types.VARCHAR, null, 0, 0))
-            || (col == null && storeLargeNumbersAsStrings))
+            || (col == null && storeLargeNumbersAsStrings)) {
             setString(stmnt, idx, val.toString(), col);
-        else
+        }
+        else {
             setBigDecimal(stmnt, idx, new BigDecimal(val), col);
+        }
     }
 
     /**
      * Set the given value as a parameter to the statement.
      */
-    public void setBinaryStream(PreparedStatement stmnt, int idx,
-        InputStream val, int length, Column col)
+    public void setBinaryStream(PreparedStatement stmnt, int idx, InputStream val, int length, Column col)
         throws SQLException {
 
-    	//OPENJPA-2067: If the user has set the 'useJDBC4SetBinaryStream' property
-    	//then lets use the JDBC 4.0 version of the setBinaryStream method.
-		if (useJDBC4SetBinaryStream) {
-			if (isJDBC4){
-				stmnt.setBinaryStream(idx, val);
-				return;
-			}
-			else {
-				log.trace(_loc.get("jdbc4-setbinarystream-unsupported"));
-			}
-		}
+        //OPENJPA-2067: If the user has set the 'useJDBC4SetBinaryStream' property
+        //then lets use the JDBC 4.0 version of the setBinaryStream method.
+        if (useJDBC4SetBinaryStream) {
+            if (isJDBC4){
+                stmnt.setBinaryStream(idx, val);
+                return;
+            }
+            else {
+                log.trace(_loc.get("jdbc4-setbinarystream-unsupported"));
+            }
+        }
 
         stmnt.setBinaryStream(idx, val, length);
     }
@@ -1072,8 +1102,7 @@ public class DBDictionary
      * Set the given value as a parameter to the statement. Uses the
      * {@link #serialize} method to serialize the value.
      */
-    public void setBlobObject(PreparedStatement stmnt, int idx, Object val,
-        Column col, JDBCStore store)
+    public void setBlobObject(PreparedStatement stmnt, int idx, Object val, Column col, JDBCStore store)
         throws SQLException {
         setBytes(stmnt, idx, serialize(val, store), col);
     }
@@ -1169,8 +1198,7 @@ public class DBDictionary
     /**
      * Set the given value as a parameter to the statement.
      */
-    public void setDate(PreparedStatement stmnt, int idx, java.sql.Date val,
-        Calendar cal, Column col)
+    public void setDate(PreparedStatement stmnt, int idx, java.sql.Date val, Calendar cal, Column col)
         throws SQLException {
         if (cal == null)
             stmnt.setDate(idx, val);
@@ -1181,14 +1209,40 @@ public class DBDictionary
     /**
      * Set the given value as a parameter to the statement.
      */
-    public void setCalendar(PreparedStatement stmnt, int idx, Calendar val,
-        Column col)
+    public void setCalendar(PreparedStatement stmnt, int idx, Calendar val, Column col)
         throws SQLException {
         // by default we merely delegate to the Date parameter
         setDate(stmnt, idx, val.getTime(), col);
     }
 
     /**
+     * Set the given LocalDate value as a parameter to the statement.
+     *
+     */
+    public void setLocalDate(PreparedStatement stmnt, int idx, LocalDate val, Column col)
+        throws SQLException {
+        setDate(stmnt, idx, java.sql.Date.valueOf(val), null, col);
+    }
+
+    /**
+     * Set the given LocalTime value as a parameter to the statement.
+     *
+     */
+    public void setLocalTime(PreparedStatement stmnt, int idx, LocalTime val, Column col)
+        throws SQLException {
+        setTime(stmnt, idx, java.sql.Time.valueOf(val), null, col);
+    }
+
+    /**
+     * Set the given LocalTime value as a parameter to the statement.
+     *
+     */
+    public void setLocalDateTime(PreparedStatement stmnt, int idx, LocalDateTime val, Column col)
+        throws SQLException {
+        setTimestamp(stmnt, idx, java.sql.Timestamp.valueOf(val), null, col);
+    }
+
+    /**
      * Set the given value as a parameter to the statement.
      */
     public void setDouble(PreparedStatement stmnt, int idx, double val,
@@ -1398,6 +1452,15 @@ public class DBDictionary
             case JavaTypes.CALENDAR:
                 setCalendar(stmnt, idx, (Calendar) val, col);
                 break;
+            case JavaTypes.LOCAL_DATE:
+                setLocalDate(stmnt, idx, (LocalDate) val, col);
+                break;
+            case JavaTypes.LOCAL_TIME:
+                setLocalTime(stmnt, idx, (LocalTime) val, col);
+                break;
+            case JavaTypes.LOCAL_DATETIME:
+                setLocalDateTime(stmnt, idx, (LocalDateTime) val, col);
+                break;
             case JavaTypes.BIGDECIMAL:
                 setBigDecimal(stmnt, idx, (BigDecimal) val, col);
                 break;
@@ -1547,6 +1610,15 @@ public class DBDictionary
             setDate(stmnt, idx, (Date) val, col);
         else if (val instanceof Calendar)
             setDate(stmnt, idx, ((Calendar) val).getTime(), col);
+        else if (val instanceof LocalDate) {
+            setLocalDate(stmnt, idx, (LocalDate) val, col);
+        }
+        else if (val instanceof LocalTime) {
+            setLocalTime(stmnt, idx, (LocalTime) val, col);
+        }
+        else if (val instanceof LocalDateTime) {
+            setLocalDateTime(stmnt, idx, (LocalDateTime) val, col);
+        }
         else if (val instanceof Reader)
             setCharacterStream(stmnt, idx, (Reader) val,
                 (sized == null) ? 0 : sized.size, col);
@@ -1725,6 +1797,16 @@ public class DBDictionary
             case JavaTypes.CALENDAR:
             case JavaTypes.DATE:
                 return getPreferredType(Types.TIMESTAMP);
+            case JavaTypes.LOCAL_DATE:
+                return getPreferredType(Types.DATE);
+            case JavaTypes.LOCAL_TIME:
+                return getPreferredType(Types.TIME);
+            case JavaTypes.LOCAL_DATETIME:
+                return getPreferredType(Types.TIMESTAMP);
+            case JavaTypes.OFFSET_TIME:
+                return getPreferredType(Types.TIME);
+            case JavaTypes.OFFSET_DATETIME:
+                return getPreferredType(Types.TIMESTAMP);
             case JavaSQLTypes.SQL_ARRAY:
                 return getPreferredType(Types.ARRAY);
             case JavaSQLTypes.BINARY_STREAM:
diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/MergedResult.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/MergedResult.java
index 3334399..c22539e 100644
--- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/MergedResult.java
+++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/MergedResult.java
@@ -29,6 +29,9 @@ import java.sql.Ref;
 import java.sql.SQLException;
 import java.sql.Time;
 import java.sql.Timestamp;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
 import java.util.Calendar;
 import java.util.Comparator;
 import java.util.Date;
@@ -49,8 +52,7 @@ import org.apache.openjpa.util.UnsupportedException;
  *
  * @author Abe White
  */
-public class MergedResult
-    implements Result {
+public class MergedResult implements Result {
 
     private static final byte NEXT = 0;
     private static final byte CURRENT = 1;
@@ -338,6 +340,21 @@ public class MergedResult
     }
 
     @Override
+    public LocalDate getLocalDate(Object obj) throws SQLException {
+        return _res[_idx].getLocalDate(obj);
+    }
+
+    @Override
+    public LocalTime getLocalTime(Object obj) throws SQLException {
+        return _res[_idx].getLocalTime(obj);
+    }
+
+    @Override
+    public LocalDateTime getLocalDateTime(Object obj) throws SQLException {
+        return _res[_idx].getLocalDateTime(obj);
+    }
+
+    @Override
     public char getChar(Object obj)
         throws SQLException {
         return _res[_idx].getChar(obj);
diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Result.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Result.java
index f803e42..35abde7 100644
--- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Result.java
+++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Result.java
@@ -29,6 +29,9 @@ import java.sql.Ref;
 import java.sql.SQLException;
 import java.sql.Time;
 import java.sql.Timestamp;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
 import java.util.Calendar;
 import java.util.Date;
 import java.util.Locale;
@@ -285,6 +288,24 @@ public interface Result
     /**
      * Return the value stored in the given column or id.
      */
+    LocalDate getLocalDate(Object obj)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column or id.
+     */
+    LocalTime getLocalTime(Object obj)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column or id.
+     */
+    LocalDateTime getLocalDateTime(Object obj)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column or id.
+     */
     char getChar(Object obj)
         throws SQLException;
 
diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ResultSetResult.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ResultSetResult.java
index 9b5a1aa..143c524 100644
--- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ResultSetResult.java
+++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ResultSetResult.java
@@ -33,6 +33,9 @@ import java.sql.Statement;
 import java.sql.Time;
 import java.sql.Timestamp;
 import java.sql.Types;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
 import java.util.Calendar;
 import java.util.Date;
 import java.util.Locale;
@@ -318,6 +321,25 @@ public class ResultSetResult
     }
 
     @Override
+    protected LocalDate getLocalDateInternal(Object obj, Joins joins)
+            throws SQLException {
+        return _dict.getLocalDate(_rs, ((Number) obj).intValue());
+    }
+
+    @Override
+    protected LocalTime getLocalTimeInternal(Object obj, Joins joins)
+            throws SQLException {
+        return _dict.getLocalTime(_rs, ((Number) obj).intValue());
+    }
+
+    @Override
+    protected LocalDateTime getLocalDateTimeInternal(Object obj, Joins joins)
+            throws SQLException {
+        return _dict.getLocalDateTime(_rs, ((Number) obj).intValue());
+    }
+
+
+    @Override
     protected char getCharInternal(Object obj, Joins joins)
         throws SQLException {
         return _dict.getChar(_rs, ((Number) obj).intValue());
@@ -385,8 +407,7 @@ public class ResultSetResult
     }
 
     @Override
-    protected Object getObjectInternal(Object obj, int metaTypeCode,
-        Object arg, Joins joins)
+    protected Object getObjectInternal(Object obj, int metaTypeCode, Object arg, Joins joins)
         throws SQLException {
         if (metaTypeCode == -1 && obj instanceof Column)
             metaTypeCode = ((Column) obj).getJavaType();
@@ -439,6 +460,12 @@ public class ResultSetResult
                 return getDateInternal(obj, joins);
             case JavaTypes.CALENDAR:
                 return getCalendarInternal(obj, joins);
+            case JavaTypes.LOCAL_DATE:
+                return getLocalDateInternal(obj, joins);
+            case JavaTypes.LOCAL_TIME:
+                return getLocalTimeInternal(obj, joins);
+            case JavaTypes.LOCAL_DATETIME:
+                return getLocalDateTimeInternal(obj, joins);
             case JavaTypes.BIGDECIMAL:
                 return getBigDecimalInternal(obj, joins);
             case JavaTypes.NUMBER:
diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AttachStrategy.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AttachStrategy.java
index 4cefe80..349f244 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AttachStrategy.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AttachStrategy.java
@@ -181,6 +181,11 @@ abstract class AttachStrategy
                 break;
             case JavaTypes.DATE:
             case JavaTypes.CALENDAR:
+            case JavaTypes.LOCAL_DATE:
+            case JavaTypes.LOCAL_TIME:
+            case JavaTypes.LOCAL_DATETIME:
+            case JavaTypes.OFFSET_TIME:
+            case JavaTypes.OFFSET_DATETIME:
             case JavaTypes.NUMBER:
             case JavaTypes.BOOLEAN_OBJ:
             case JavaTypes.BYTE_OBJ:
@@ -219,7 +224,7 @@ abstract class AttachStrategy
                         if (cpy != null) {
                             frmpc = cpy;
                         } else {
-                        	frmpc = getReference(manager, frmpc, sm, fmd);
+                            frmpc = getReference(manager, frmpc, sm, fmd);
                         }
                     }
                     else {
diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/meta/JavaTypes.java b/openjpa-kernel/src/main/java/org/apache/openjpa/meta/JavaTypes.java
index c2ffd07..c1c9f8f 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/meta/JavaTypes.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/meta/JavaTypes.java
@@ -24,6 +24,11 @@ import java.io.Serializable;
 import java.lang.reflect.Array;
 import java.math.BigDecimal;
 import java.math.BigInteger;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.OffsetDateTime;
+import java.time.OffsetTime;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Calendar;
@@ -84,6 +89,15 @@ public class JavaTypes {
     public static final int INPUT_READER = 31;
     public static final int ENUM = 32;
 
+    // Java8 time API
+    public static final int LOCAL_DATE = 33;
+    public static final int LOCAL_TIME = 34;
+    public static final int LOCAL_DATETIME = 35;
+    public static final int OFFSET_TIME = 36;
+    public static final int OFFSET_DATETIME = 37;
+
+
+
     private static final Localizer _loc = Localizer.forPackage(JavaTypes.class);
 
     private static final Map<Class<?>, Integer> _typeCodes = new HashMap<>();
@@ -110,6 +124,13 @@ public class JavaTypes {
         _typeCodes.put(PersistenceCapable.class, PC_UNTYPED);
         _typeCodes.put(Properties.class, MAP);
         _typeCodes.put(Calendar.class, CALENDAR);
+
+        // Java8 time API
+        _typeCodes.put(LocalDate.class, LOCAL_DATE);
+        _typeCodes.put(LocalTime.class, LOCAL_TIME);
+        _typeCodes.put(LocalDateTime.class, LOCAL_DATETIME);
+        _typeCodes.put(OffsetTime.class, OFFSET_TIME);
+        _typeCodes.put(OffsetDateTime.class, OFFSET_DATETIME);
     }
 
     /**
@@ -139,9 +160,10 @@ public class JavaTypes {
             }
         }
 
-        Integer code = (Integer) _typeCodes.get(type);
-        if (code != null)
+        Integer code = _typeCodes.get(type);
+        if (code != null) {
             return code.intValue();
+        }
 
         // have to do this first to catch custom collection and map types;
         // on resolve we figure out if these custom types are
@@ -238,7 +260,7 @@ public class JavaTypes {
      */
     private static Class<?> classForName(String name, ClassMetaData meta,
             Class<?> dec, ValueMetaData vmd, ClassLoader loader) {
-    	return classForName(name, meta, dec, vmd,  loader, true);
+        return classForName(name, meta, dec, vmd,  loader, true);
     }
 
     /**
diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/simple/Java8TimeTypes.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/simple/Java8TimeTypes.java
new file mode 100644
index 0000000..d5b1681
--- /dev/null
+++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/simple/Java8TimeTypes.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.openjpa.persistence.simple;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.util.Date;
+
+/**
+ * Java8 DateTime types which are required by the JPA-2.2 spec
+ */
+@Entity
+public class Java8TimeTypes {
+
+    @Id
+    private int id;
+
+    private java.util.Date oldDateField;
+
+    private LocalTime localTimeField;
+    private LocalDate localDateField;
+    private LocalDateTime localDateTimeField;
+
+    public int getId() {
+        return id;
+    }
+
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    public Date getOldDateField() {
+        return oldDateField;
+    }
+
+    public void setOldDateField(Date oldDateField) {
+        this.oldDateField = oldDateField;
+    }
+
+    public LocalTime getLocalTimeField() {
+        return localTimeField;
+    }
+
+    public void setLocalTimeField(LocalTime localTimeField) {
+        this.localTimeField = localTimeField;
+    }
+
+    public LocalDate getLocalDateField() {
+        return localDateField;
+    }
+
+    public void setLocalDateField(LocalDate localDateField) {
+        this.localDateField = localDateField;
+    }
+
+    public LocalDateTime getLocalDateTimeField() {
+        return localDateTimeField;
+    }
+
+    public void setLocalDateTimeField(LocalDateTime localDateTimeField) {
+        this.localDateTimeField = localDateTimeField;
+    }
+}
diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/simple/TestBasicAnnotation.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/simple/TestBasicAnnotation.java
index 754e30c..c0f0d90 100644
--- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/simple/TestBasicAnnotation.java
+++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/simple/TestBasicAnnotation.java
@@ -20,6 +20,7 @@ package org.apache.openjpa.persistence.simple;
 
 import java.math.BigDecimal;
 import java.time.LocalDate;
+import java.time.LocalTime;
 import java.util.Calendar;
 import java.util.Date;
 
@@ -35,6 +36,7 @@ import org.apache.openjpa.persistence.test.SingleEMFTestCase;
  */
 public class TestBasicAnnotation extends SingleEMFTestCase {
     private static String VAL_LOCAL_DATE = "2019-01-01";
+    private static String VAL_LOCAL_TIME = "14:57:15";
 
     @Override
     public void setUp() {
@@ -61,6 +63,7 @@ public class TestBasicAnnotation extends SingleEMFTestCase {
         aft.setWDoubleField(new Double(1));
 
         aft.setLocalDateField(LocalDate.parse(VAL_LOCAL_DATE));
+        aft.setLocalTimeField(LocalTime.parse(VAL_LOCAL_TIME));
 
 
         em.persist(aft);
@@ -87,6 +90,7 @@ public class TestBasicAnnotation extends SingleEMFTestCase {
         assertNotNull(aftQuery.getWDoubleField());
 
         assertEquals(LocalDate.parse(VAL_LOCAL_DATE), aftQuery.getLocalDateField());
+        assertEquals(LocalTime.parse(VAL_LOCAL_TIME), aftQuery.getLocalTimeField());
 
         em.close();
     }
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
new file mode 100644
index 0000000..3de2258
--- /dev/null
+++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/simple/TestJava8TimeTypes.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.openjpa.persistence.simple;
+
+import org.apache.openjpa.persistence.test.SingleEMFTestCase;
+
+import javax.persistence.EntityManager;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.util.Date;
+
+/**
+ * Test for JPA-2.2 java.time.* functionality
+ */
+public class TestJava8TimeTypes extends SingleEMFTestCase {
+    private static String VAL_LOCAL_DATE = "2019-01-01";
+    private static String VAL_LOCAL_TIME = "14:57:15";
+    private static String VAL_LOCAL_DATETIME = "2019-01-01T01:00:00";
+
+    @Override
+    public void setUp() {
+        setUp(CLEAR_TABLES, Java8TimeTypes.class);
+    }
+
+    public void testJava8Types() throws Exception {
+        EntityManager em = emf.createEntityManager();
+        em.getTransaction().begin();
+        Java8TimeTypes e = new Java8TimeTypes();
+        e.setId(1);
+        e.setOldDateField(new Date());
+        e.setLocalTimeField(LocalTime.parse(VAL_LOCAL_TIME));
+        e.setLocalDateField(LocalDate.parse(VAL_LOCAL_DATE));
+        e.setLocalDateTimeField(LocalDateTime.parse(VAL_LOCAL_DATETIME));
+
+        em.persist(e);
+        em.getTransaction().commit();
+        em.close();
+
+        // now read it back.
+        em = emf.createEntityManager();
+        Java8TimeTypes eRead = em.find(Java8TimeTypes.class, 1);
+
+        assertEquals(LocalTime.parse(VAL_LOCAL_TIME), eRead.getLocalTimeField());
+        assertEquals(LocalDate.parse(VAL_LOCAL_DATE), eRead.getLocalDateField());
+        assertEquals(LocalDateTime.parse(VAL_LOCAL_DATETIME), eRead.getLocalDateTimeField());
+    }
+
+}
diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/strategy/value/ValueStrategyHandler.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/strategy/value/ValueStrategyHandler.java
index 26d2ea1..2017c24 100644
--- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/strategy/value/ValueStrategyHandler.java
+++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/strategy/value/ValueStrategyHandler.java
@@ -27,42 +27,42 @@ import org.apache.openjpa.meta.JavaTypes;
 
 public class ValueStrategyHandler extends AbstractValueHandler {
 
-	private static final long serialVersionUID = 8371304701543038775L;
+    private static final long serialVersionUID = 8371304701543038775L;
 
-	private static final ValueStrategyHandler _instance = new ValueStrategyHandler();
+    private static final ValueStrategyHandler _instance = new ValueStrategyHandler();
 
-	public static ValueStrategyHandler getInstance(){
-		return _instance;
-	}
+    public static ValueStrategyHandler getInstance(){
+        return _instance;
+    }
 
-	@Override
-	public Column[] map(ValueMapping arg0, String name, ColumnIO arg2,
-			boolean arg3) {
+    @Override
+    public Column[] map(ValueMapping arg0, String name, ColumnIO arg2,
+                        boolean arg3) {
 
-		Column col = new Column();
-		col.setName(name);
-		col.setJavaType(JavaTypes.STRING);
+        Column col = new Column();
+        col.setName(name);
+        col.setJavaType(JavaTypes.STRING);
 
-		return new Column[]{col};
-	}
+        return new Column[]{col};
+    }
 
-	@Override
+    @Override
     public Object toDataStoreValue(ValueMapping vm, Object val, JDBCStore store){
 
-		if(val == null){
-			return null;
-		}
+        if(val == null){
+            return null;
+        }
 
-		return val.toString();
-	}
+        return val.toString();
+    }
 
-	@Override
+    @Override
     public Object toObjectValue(ValueMapping vm, Object val){
-		if(val == null){
-			return null;
-		}
+        if(val == null){
+            return null;
+        }
 
-		return val.toString();
-	}
+        return val.toString();
+    }
 
 }
diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataDefaults.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataDefaults.java
index 21e9358..6953db7 100644
--- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataDefaults.java
+++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataDefaults.java
@@ -227,6 +227,11 @@ public class PersistenceMetaDataDefaults
             case JavaTypes.BIGDECIMAL:
             case JavaTypes.BIGINTEGER:
             case JavaTypes.DATE:
+            case JavaTypes.LOCAL_DATE:
+            case JavaTypes.LOCAL_TIME:
+            case JavaTypes.LOCAL_DATETIME:
+            case JavaTypes.OFFSET_TIME:
+            case JavaTypes.OFFSET_DATETIME:
                 return BASIC;
             case JavaTypes.OBJECT:
                 if (Enum.class.isAssignableFrom(type))
diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/meta/AbstractManagedType.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/meta/AbstractManagedType.java
index 56b0a37..a3b0dee 100644
--- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/meta/AbstractManagedType.java
+++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/meta/AbstractManagedType.java
@@ -20,6 +20,11 @@ package org.apache.openjpa.persistence.meta;
 
 import java.math.BigDecimal;
 import java.math.BigInteger;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.OffsetDateTime;
+import java.time.OffsetTime;
 import java.util.Arrays;
 import java.util.Calendar;
 import java.util.Collection;
@@ -137,6 +142,21 @@ public abstract class AbstractManagedType<X> extends Types.BaseType<X>
             case JavaTypes.DATE:
                 attrs.add(new Members.SingularAttributeImpl<X, Date>(this, f));
                 break;
+            case JavaTypes.LOCAL_DATE:
+                attrs.add(new Members.SingularAttributeImpl<X, LocalDate>(this, f));
+                break;
+            case JavaTypes.LOCAL_TIME:
+                attrs.add(new Members.SingularAttributeImpl<X, LocalTime>(this, f));
+                break;
+            case JavaTypes.LOCAL_DATETIME:
+                attrs.add(new Members.SingularAttributeImpl<X, LocalDateTime>(this, f));
+                break;
+            case JavaTypes.OFFSET_TIME:
+                attrs.add(new Members.SingularAttributeImpl<X, OffsetTime>(this, f));
+                break;
+            case JavaTypes.OFFSET_DATETIME:
+                attrs.add(new Members.SingularAttributeImpl<X, OffsetDateTime>(this, f));
+                break;
             case JavaTypes.CALENDAR:
                 attrs.add(new Members.SingularAttributeImpl<X, Calendar>(this, f));
                 break;


[openjpa] 02/04: OPENJPA-2713 add OffsetTime support

Posted by st...@apache.org.
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

commit dbfb360e85bb29bb11f87e3d5406a4edd4e51bd3
Author: Mark Struberg <st...@apache.org>
AuthorDate: Tue Jan 22 22:07:32 2019 +0100

    OPENJPA-2713 add OffsetTime support
    
    Works, but something is a bit fishy still.
---
 .../apache/openjpa/jdbc/sql/AbstractResult.java    | 32 +++++++++++++
 .../org/apache/openjpa/jdbc/sql/DBDictionary.java  | 53 ++++++++++++++++++++++
 .../org/apache/openjpa/jdbc/sql/MergedResult.java  | 12 +++++
 .../java/org/apache/openjpa/jdbc/sql/Result.java   | 14 ++++++
 .../apache/openjpa/jdbc/sql/ResultSetResult.java   | 17 +++++++
 .../openjpa/persistence/simple/Java8TimeTypes.java | 20 ++++++++
 .../persistence/simple/TestJava8TimeTypes.java     |  7 ++-
 7 files changed, 154 insertions(+), 1 deletion(-)

diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/AbstractResult.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/AbstractResult.java
index ab925f1..8b2a01a 100644
--- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/AbstractResult.java
+++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/AbstractResult.java
@@ -34,6 +34,8 @@ import java.sql.Types;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
+import java.time.OffsetDateTime;
+import java.time.OffsetTime;
 import java.util.Calendar;
 import java.util.Date;
 import java.util.HashMap;
@@ -562,6 +564,36 @@ public abstract class AbstractResult
     }
 
     @Override
+    public OffsetTime getOffsetTime(Object obj) throws SQLException {
+        return getOffsetTimeInternal(translate(obj, null), null);
+    }
+
+    protected OffsetTime getOffsetTimeInternal(Object obj, Joins joins) throws SQLException {
+        Object val = checkNull(getObjectInternal(obj, JavaTypes.OFFSET_TIME, null, joins));
+        if (val == null)
+            return null;
+        if (val instanceof OffsetTime)
+            return (OffsetTime) val;
+
+        return OffsetTime.parse(val.toString());
+    }
+
+    @Override
+    public OffsetDateTime getOffsetDateTime(Object obj) throws SQLException {
+        return getOffsetDateTimeInternal(translate(obj, null), null);
+    }
+
+    protected OffsetDateTime getOffsetDateTimeInternal(Object obj, Joins joins) throws SQLException {
+        Object val = checkNull(getObjectInternal(obj, JavaTypes.OFFSET_DATETIME, null, joins));
+        if (val == null)
+            return null;
+        if (val instanceof OffsetDateTime)
+            return (OffsetDateTime) val;
+
+        return OffsetDateTime.parse(val.toString());
+    }
+
+    @Override
     public char getChar(Object obj)
         throws SQLException {
         return getCharInternal(translate(obj, null), null);
diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
index 81d249f..0fe52d5 100644
--- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
+++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
@@ -48,6 +48,10 @@ import java.text.MessageFormat;
 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.ArrayList;
 import java.util.Arrays;
 import java.util.Calendar;
@@ -805,6 +809,24 @@ public class DBDictionary
         return tst != null ? tst.toLocalDateTime() : null;
     }
 
+    /**
+     * Retrieve the specified column of the SQL ResultSet to the proper
+     * {@link OffsetTime} java type.
+     */
+    public OffsetTime getOffsetTime(ResultSet rs, int column) throws SQLException {
+        java.sql.Time time = rs.getTime(column);
+        return time != null ? time.toLocalTime().atOffset(OffsetDateTime.now().getOffset()) : null;
+    }
+
+    /**
+     * Retrieve the specified column of the SQL ResultSet to the proper
+     * {@link OffsetDateTime} java type.
+     */
+    public OffsetDateTime getOffsetDateTime(ResultSet rs, int column) throws SQLException {
+        Timestamp tst = rs.getTimestamp(column);
+        return tst != null ? tst.toLocalDateTime().atOffset(OffsetDateTime.now().getOffset()) : null;
+    }
+
     private ProxyManager getProxyManager() {
         if (_proxyManager == null) {
             _proxyManager = conf.getProxyManagerInstance();
@@ -1242,6 +1264,31 @@ public class DBDictionary
         setTimestamp(stmnt, idx, java.sql.Timestamp.valueOf(val), null, col);
     }
 
+
+    /**
+     * Set the given LocalTime value as a parameter to the statement.
+     *
+     */
+    public void setOffsetTime(PreparedStatement stmnt, int idx, OffsetTime val, Column col)
+            throws SQLException {
+        // adjust to the default timezone right now.
+        // This is an ugly hack and cries for troubles in case the daylight saving changes...
+        // Which is also the reason why we cannot cache the offset.
+        // According to the Oracle docs the JDBC driver always assumes 'local time' ...
+        LocalTime localTime = val.withOffsetSameInstant(OffsetDateTime.now().getOffset()).toLocalTime();
+        setLocalTime(stmnt, idx, localTime, col);
+    }
+
+    /**
+     * Set the given LocalTime value as a parameter to the statement.
+     *
+     */
+    public void setOffsetDateTime(PreparedStatement stmnt, int idx, OffsetDateTime val, Column col)
+            throws SQLException {
+        LocalDateTime localdt = val.atZoneSameInstant(ZoneId.systemDefault()).toLocalDateTime();
+        setLocalDateTime(stmnt, idx, localdt, col);
+    }
+
     /**
      * Set the given value as a parameter to the statement.
      */
@@ -1461,6 +1508,12 @@ public class DBDictionary
             case JavaTypes.LOCAL_DATETIME:
                 setLocalDateTime(stmnt, idx, (LocalDateTime) val, col);
                 break;
+            case JavaTypes.OFFSET_TIME:
+                setOffsetTime(stmnt, idx, (OffsetTime) val, col);
+                break;
+            case JavaTypes.OFFSET_DATETIME:
+                setOffsetDateTime(stmnt, idx, (OffsetDateTime) val, col);
+                break;
             case JavaTypes.BIGDECIMAL:
                 setBigDecimal(stmnt, idx, (BigDecimal) val, col);
                 break;
diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/MergedResult.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/MergedResult.java
index c22539e..237cc73 100644
--- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/MergedResult.java
+++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/MergedResult.java
@@ -32,6 +32,8 @@ 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.util.Calendar;
 import java.util.Comparator;
 import java.util.Date;
@@ -355,6 +357,16 @@ public class MergedResult implements Result {
     }
 
     @Override
+    public OffsetTime getOffsetTime(Object obj) throws SQLException {
+        return _res[_idx].getOffsetTime(obj);
+    }
+
+    @Override
+    public OffsetDateTime getOffsetDateTime(Object obj) throws SQLException {
+        return _res[_idx].getOffsetDateTime(obj);
+    }
+
+    @Override
     public char getChar(Object obj)
         throws SQLException {
         return _res[_idx].getChar(obj);
diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Result.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Result.java
index 35abde7..8f28a33 100644
--- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Result.java
+++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Result.java
@@ -32,6 +32,8 @@ 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.util.Calendar;
 import java.util.Date;
 import java.util.Locale;
@@ -306,6 +308,18 @@ public interface Result
     /**
      * Return the value stored in the given column or id.
      */
+    OffsetTime getOffsetTime(Object obj)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column or id.
+     */
+    OffsetDateTime getOffsetDateTime(Object obj)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column or id.
+     */
     char getChar(Object obj)
         throws SQLException;
 
diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ResultSetResult.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ResultSetResult.java
index 143c524..ee7ddd3 100644
--- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ResultSetResult.java
+++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ResultSetResult.java
@@ -36,6 +36,8 @@ import java.sql.Types;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
+import java.time.OffsetDateTime;
+import java.time.OffsetTime;
 import java.util.Calendar;
 import java.util.Date;
 import java.util.Locale;
@@ -338,6 +340,17 @@ public class ResultSetResult
         return _dict.getLocalDateTime(_rs, ((Number) obj).intValue());
     }
 
+    @Override
+    protected OffsetTime getOffsetTimeInternal(Object obj, Joins joins)
+            throws SQLException {
+        return _dict.getOffsetTime(_rs, ((Number) obj).intValue());
+    }
+
+    @Override
+    protected OffsetDateTime getOffsetDateTimeInternal(Object obj, Joins joins)
+            throws SQLException {
+        return _dict.getOffsetDateTime(_rs, ((Number) obj).intValue());
+    }
 
     @Override
     protected char getCharInternal(Object obj, Joins joins)
@@ -466,6 +479,10 @@ public class ResultSetResult
                 return getLocalTimeInternal(obj, joins);
             case JavaTypes.LOCAL_DATETIME:
                 return getLocalDateTimeInternal(obj, joins);
+            case JavaTypes.OFFSET_TIME:
+                return getOffsetTimeInternal(obj, joins);
+            case JavaTypes.OFFSET_DATETIME:
+                return getOffsetDateTimeInternal(obj, joins);
             case JavaTypes.BIGDECIMAL:
                 return getBigDecimalInternal(obj, joins);
             case JavaTypes.NUMBER:
diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/simple/Java8TimeTypes.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/simple/Java8TimeTypes.java
index d5b1681..bfce8e3 100644
--- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/simple/Java8TimeTypes.java
+++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/simple/Java8TimeTypes.java
@@ -23,6 +23,8 @@ import javax.persistence.Id;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
+import java.time.OffsetDateTime;
+import java.time.OffsetTime;
 import java.util.Date;
 
 /**
@@ -39,6 +41,8 @@ public class Java8TimeTypes {
     private LocalTime localTimeField;
     private LocalDate localDateField;
     private LocalDateTime localDateTimeField;
+    private OffsetTime offsetTimeField;
+    private OffsetDateTime offsetDateTimeField;
 
     public int getId() {
         return id;
@@ -79,4 +83,20 @@ public class Java8TimeTypes {
     public void setLocalDateTimeField(LocalDateTime localDateTimeField) {
         this.localDateTimeField = localDateTimeField;
     }
+
+    public OffsetTime getOffsetTimeField() {
+        return offsetTimeField;
+    }
+
+    public void setOffsetTimeField(OffsetTime offsetTimeField) {
+        this.offsetTimeField = offsetTimeField;
+    }
+
+    public OffsetDateTime getOffsetDateTimeField() {
+        return offsetDateTimeField;
+    }
+
+    public void setOffsetDateTimeField(OffsetDateTime offsetDateTimeField) {
+        this.offsetDateTimeField = offsetDateTimeField;
+    }
 }
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 3de2258..8175036 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
@@ -24,6 +24,7 @@ import javax.persistence.EntityManager;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
+import java.time.ZoneOffset;
 import java.util.Date;
 
 /**
@@ -31,7 +32,7 @@ import java.util.Date;
  */
 public class TestJava8TimeTypes extends SingleEMFTestCase {
     private static String VAL_LOCAL_DATE = "2019-01-01";
-    private static String VAL_LOCAL_TIME = "14:57:15";
+    private static String VAL_LOCAL_TIME = "04:57:15";
     private static String VAL_LOCAL_DATETIME = "2019-01-01T01:00:00";
 
     @Override
@@ -48,6 +49,8 @@ public class TestJava8TimeTypes extends SingleEMFTestCase {
         e.setLocalTimeField(LocalTime.parse(VAL_LOCAL_TIME));
         e.setLocalDateField(LocalDate.parse(VAL_LOCAL_DATE));
         e.setLocalDateTimeField(LocalDateTime.parse(VAL_LOCAL_DATETIME));
+        e.setOffsetTimeField(e.getLocalTimeField().atOffset(ZoneOffset.ofHours(-9)));
+        e.setOffsetDateTimeField(e.getLocalDateTimeField().atOffset(ZoneOffset.ofHours(-9)));
 
         em.persist(e);
         em.getTransaction().commit();
@@ -60,6 +63,8 @@ public class TestJava8TimeTypes extends SingleEMFTestCase {
         assertEquals(LocalTime.parse(VAL_LOCAL_TIME), eRead.getLocalTimeField());
         assertEquals(LocalDate.parse(VAL_LOCAL_DATE), eRead.getLocalDateField());
         assertEquals(LocalDateTime.parse(VAL_LOCAL_DATETIME), eRead.getLocalDateTimeField());
+        assertEquals(e.getOffsetTimeField(), eRead.getOffsetTimeField());
+        assertEquals(e.getOffsetDateTimeField(), eRead.getOffsetDateTimeField());
     }
 
 }


[openjpa] 03/04: OPENJPA-2713 properly handle WITH TIME ZONE if supported by db

Posted by st...@apache.org.
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

commit 6d2544f390a53b8e7a8891ca5c025961dda948cc
Author: Mark Struberg <st...@apache.org>
AuthorDate: Fri Jan 25 16:42:15 2019 +0100

    OPENJPA-2713 properly handle WITH TIME ZONE if supported by db
    
    This includes handling the  new java.sql.Types.TIME_WITH_ZONE
    and DATE_WITH_ZONE.
---
 .../org/apache/openjpa/jdbc/sql/DBDictionary.java  |  50 ++++-----
 .../apache/openjpa/jdbc/sql/DerbyDictionary.java   |  18 ++++
 .../openjpa/jdbc/sql/PostgresDictionary.java       |  69 ++++++++++--
 .../java/org/apache/openjpa/kernel/BrokerImpl.java |   2 +-
 .../openjpa/lib/jdbc/DelegatingResultSet.java      |   4 +-
 .../persistence/simple/TestJava8TimeTypes.java     |  18 +++-
 openjpa-project/supportedJava8TimeTypes.adoc       | 118 +++++++++++++++++++++
 7 files changed, 236 insertions(+), 43 deletions(-)

diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
index 0fe52d5..f9bc575 100644
--- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
+++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
@@ -51,7 +51,6 @@ import java.time.LocalTime;
 import java.time.OffsetDateTime;
 import java.time.OffsetTime;
 import java.time.ZoneId;
-import java.time.ZoneOffset;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Calendar;
@@ -370,6 +369,8 @@ public class DBDictionary
     public String structTypeName = "STRUCT";
     public String timeTypeName = "TIME";
     public String timestampTypeName = "TIMESTAMP";
+    public String timeWithZoneTypeName = "TIME WITH TIME ZONE";
+    public String timestampWithZoneTypeName = "TIMESTAMP WITH TIME ZONE";
     public String tinyintTypeName = "TINYINT";
     public String varbinaryTypeName = "VARBINARY";
     public String varcharTypeName = "VARCHAR";
@@ -1222,10 +1223,12 @@ public class DBDictionary
      */
     public void setDate(PreparedStatement stmnt, int idx, java.sql.Date val, Calendar cal, Column col)
         throws SQLException {
-        if (cal == null)
+        if (cal == null) {
             stmnt.setDate(idx, val);
-        else
+        }
+        else {
             stmnt.setDate(idx, val, cal);
+        }
     }
 
     /**
@@ -1292,8 +1295,7 @@ public class DBDictionary
     /**
      * Set the given value as a parameter to the statement.
      */
-    public void setDouble(PreparedStatement stmnt, int idx, double val,
-        Column col)
+    public void setDouble(PreparedStatement stmnt, int idx, double val, Column col)
         throws SQLException {
         stmnt.setDouble(idx, val);
     }
@@ -1301,8 +1303,7 @@ public class DBDictionary
     /**
      * Set the given value as a parameter to the statement.
      */
-    public void setFloat(PreparedStatement stmnt, int idx, float val,
-        Column col)
+    public void setFloat(PreparedStatement stmnt, int idx, float val, Column col)
         throws SQLException {
         stmnt.setFloat(idx, val);
     }
@@ -1326,8 +1327,7 @@ public class DBDictionary
     /**
      * Set the given value as a parameter to the statement.
      */
-    public void setLocale(PreparedStatement stmnt, int idx, Locale val,
-        Column col)
+    public void setLocale(PreparedStatement stmnt, int idx, Locale val, Column col)
         throws SQLException {
         setString(stmnt, idx, val.getLanguage() + "_" + val.getCountry()
             + "_" + val.getVariant(), col);
@@ -1337,8 +1337,7 @@ public class DBDictionary
      * Set null as a parameter to the statement. The column
      * type will come from {@link Types}.
      */
-    public void setNull(PreparedStatement stmnt, int idx, int colType,
-        Column col)
+    public void setNull(PreparedStatement stmnt, int idx, int colType, Column col)
         throws SQLException {
         stmnt.setNull(idx, colType);
     }
@@ -1346,8 +1345,7 @@ public class DBDictionary
     /**
      * Set the given value as a parameter to the statement.
      */
-    public void setNumber(PreparedStatement stmnt, int idx, Number num,
-        Column col)
+    public void setNumber(PreparedStatement stmnt, int idx, Number num, Column col)
         throws SQLException {
         // check for known floating point types to give driver a chance to
         // handle special numbers like NaN and infinity; bug #1053
@@ -1363,8 +1361,7 @@ public class DBDictionary
      * Set the given value as a parameter to the statement. The column
      * type will come from {@link Types}.
      */
-    public void setObject(PreparedStatement stmnt, int idx, Object val,
-        int colType, Column col)
+    public void setObject(PreparedStatement stmnt, int idx, Object val, int colType, Column col)
         throws SQLException {
         if (colType == -1 || colType == Types.OTHER)
             stmnt.setObject(idx, val);
@@ -1383,8 +1380,7 @@ public class DBDictionary
     /**
      * Set the given value as a parameter to the statement.
      */
-    public void setShort(PreparedStatement stmnt, int idx, short val,
-        Column col)
+    public void setShort(PreparedStatement stmnt, int idx, short val, Column col)
         throws SQLException {
         stmnt.setShort(idx, val);
     }
@@ -1392,8 +1388,7 @@ public class DBDictionary
     /**
      * Set the given value as a parameter to the statement.
      */
-    public void setString(PreparedStatement stmnt, int idx, String val,
-        Column col)
+    public void setString(PreparedStatement stmnt, int idx, String val, Column col)
         throws SQLException {
         stmnt.setString(idx, val);
     }
@@ -1401,8 +1396,7 @@ public class DBDictionary
     /**
      * Set the given value as a parameter to the statement.
      */
-    public void setTime(PreparedStatement stmnt, int idx, Time val,
-        Calendar cal, Column col)
+    public void setTime(PreparedStatement stmnt, int idx, Time val, Calendar cal, Column col)
         throws SQLException {
         if (cal == null)
             stmnt.setTime(idx, val);
@@ -1413,8 +1407,7 @@ public class DBDictionary
     /**
      * Set the given value as a parameter to the statement.
      */
-    public void setTimestamp(PreparedStatement stmnt, int idx,
-        Timestamp val, Calendar cal, Column col)
+    public void setTimestamp(PreparedStatement stmnt, int idx, Timestamp val, Calendar cal, Column col)
         throws SQLException {
 
         val = StateManagerImpl.roundTimestamp(val, datePrecision);
@@ -1435,8 +1428,7 @@ public class DBDictionary
      * @param type the field mapping type code for the value
      * @param store the store manager for the current context
      */
-    public void setTyped(PreparedStatement stmnt, int idx, Object val,
-        Column col, int type, JDBCStore store)
+    public void setTyped(PreparedStatement stmnt, int idx, Object val, Column col, int type, JDBCStore store)
         throws SQLException {
         if (val == null) {
             setNull(stmnt, idx, (col == null) ? Types.OTHER : col.getType(),
@@ -1857,9 +1849,9 @@ public class DBDictionary
             case JavaTypes.LOCAL_DATETIME:
                 return getPreferredType(Types.TIMESTAMP);
             case JavaTypes.OFFSET_TIME:
-                return getPreferredType(Types.TIME);
+                return getPreferredType(Types.TIME_WITH_TIMEZONE);
             case JavaTypes.OFFSET_DATETIME:
-                return getPreferredType(Types.TIMESTAMP);
+                return getPreferredType(Types.TIMESTAMP_WITH_TIMEZONE);
             case JavaSQLTypes.SQL_ARRAY:
                 return getPreferredType(Types.ARRAY);
             case JavaSQLTypes.BINARY_STREAM:
@@ -1962,6 +1954,10 @@ public class DBDictionary
                 return timeTypeName;
             case Types.TIMESTAMP:
                 return timestampTypeName;
+            case Types.TIME_WITH_TIMEZONE:
+                return timeWithZoneTypeName;
+            case Types.TIMESTAMP_WITH_TIMEZONE:
+                return timestampWithZoneTypeName;
             case Types.TINYINT:
                 return tinyintTypeName;
             case Types.VARBINARY:
diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DerbyDictionary.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DerbyDictionary.java
index 5c139de..63b996e 100644
--- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DerbyDictionary.java
+++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DerbyDictionary.java
@@ -21,6 +21,7 @@ package org.apache.openjpa.jdbc.sql;
 import java.sql.Connection;
 import java.sql.DriverManager;
 import java.sql.SQLException;
+import java.sql.Types;
 import java.util.Arrays;
 
 import javax.sql.DataSource;
@@ -69,6 +70,8 @@ public class DerbyDictionary
 
         supportsComments = true;
 
+        // Derby does still not support 'WITH TIMEZONE' from the SQL92 standard
+
         fixedSizeTypeNameSet.addAll(Arrays.asList(new String[]{
             "BIGINT", "INTEGER", "TEXT"
         }));
@@ -223,4 +226,19 @@ public class DerbyDictionary
         }
         return count;
     }
+
+    /**
+     * Derby doesn't support SQL-2003 'WITH TIMEZONE' nor the respective JDBC types.
+     */
+    @Override
+    public int getPreferredType(int type) {
+        switch (type) {
+            case Types.TIME_WITH_TIMEZONE:
+                return Types.TIME;
+            case Types.TIMESTAMP_WITH_TIMEZONE:
+                return Types.TIMESTAMP;
+            default:
+                return type;
+        }
+    }
 }
diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/PostgresDictionary.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/PostgresDictionary.java
index 2ba03e0..e64d1de 100644
--- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/PostgresDictionary.java
+++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/PostgresDictionary.java
@@ -34,6 +34,10 @@ import java.sql.Statement;
 import java.sql.Types;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.OffsetDateTime;
 import java.util.Arrays;
 import java.util.Date;
 import java.util.HashSet;
@@ -64,11 +68,9 @@ import org.postgresql.largeobject.LargeObjectManager;
 /**
  * Dictionary for PostgreSQL.
  */
-public class PostgresDictionary
-    extends DBDictionary {
+public class PostgresDictionary extends DBDictionary {
 
-    private static final Localizer _loc = Localizer.forPackage
-        (PostgresDictionary.class);
+    private static final Localizer _loc = Localizer.forPackage(PostgresDictionary.class);
 
 
     private Method dbcpGetDelegate;
@@ -122,6 +124,13 @@ public class PostgresDictionary
      */
     public String isOwnedSequenceSQL = "SELECT pg_get_serial_sequence(?, ?)";
 
+
+    /**
+     * Since PostgreSQL
+     */
+    private boolean supportsTimezone;
+
+
     public PostgresDictionary() {
         platform = "PostgreSQL";
         validationSQL = "SELECT NOW()";
@@ -411,14 +420,15 @@ public class PostgresDictionary
                     }
                 }
             } catch (Throwable t) {
-                if (log.isWarnEnabled())
+                if (log.isWarnEnabled()) {
                     log.warn(_loc.get("psql-owned-seq-warning"), t);
+                }
                 return isOwnedSequence(strName);
             }
         } else {
             if(log.isTraceEnabled()) {
                 log.trace(String.format("Unable to query ownership for sequence %s using the connection. " +
-                		"Falling back to simpler detection based on the name",
+                                "Falling back to simpler detection based on the name",
                     name.getName()));
             }
 
@@ -723,6 +733,47 @@ public class PostgresDictionary
         }
     }
 
+
+    @Override
+    public LocalDate getLocalDate(ResultSet rs, int column) throws SQLException {
+        return rs.getObject(column, LocalDate.class);
+    }
+
+    @Override
+    public LocalTime getLocalTime(ResultSet rs, int column) throws SQLException {
+        return rs.getObject(column, LocalTime.class);
+    }
+
+    @Override
+    public LocalDateTime getLocalDateTime(ResultSet rs, int column) throws SQLException {
+        return rs.getObject(column, LocalDateTime.class);
+    }
+
+    @Override
+    public OffsetDateTime getOffsetDateTime(ResultSet rs, int column) throws SQLException {
+        return rs.getObject(column, OffsetDateTime.class);
+    }
+
+    @Override
+    public void setLocalDate(PreparedStatement stmnt, int idx, LocalDate val, Column col) throws SQLException {
+        stmnt.setObject(idx, val);
+    }
+
+    @Override
+    public void setLocalTime(PreparedStatement stmnt, int idx, LocalTime val, Column col) throws SQLException {
+        stmnt.setObject(idx, val);
+    }
+
+    @Override
+    public void setLocalDateTime(PreparedStatement stmnt, int idx, LocalDateTime val, Column col) throws SQLException {
+        stmnt.setObject(idx, val);
+    }
+
+    @Override
+    public void setOffsetDateTime(PreparedStatement stmnt, int idx, OffsetDateTime val, Column col) throws SQLException {
+        stmnt.setObject(idx, val);
+    }
+
     /**
      * Determine XML column support and backslash handling.
      */
@@ -967,8 +1018,7 @@ public class PostgresDictionary
     /**
      * Connection wrapper to work around the postgres empty result set bug.
      */
-    protected static class PostgresConnection
-        extends DelegatingConnection {
+    protected static class PostgresConnection extends DelegatingConnection {
 
         private final PostgresDictionary _dict;
 
@@ -996,8 +1046,7 @@ public class PostgresDictionary
     /**
      * Statement wrapper to work around the postgres empty result set bug.
      */
-    protected static class PostgresPreparedStatement
-        extends DelegatingPreparedStatement {
+    protected static class PostgresPreparedStatement extends DelegatingPreparedStatement {
 
         private final PostgresDictionary _dict;
 
diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java
index bfa1ef9..a1a7680 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java
@@ -2464,7 +2464,7 @@ public class BrokerImpl implements Broker, FindCallbacks, Cloneable, Serializabl
 
         Object failedObject = null;
         if (t[0] instanceof OpenJPAException){
-        	failedObject = ((OpenJPAException)t[0]).getFailedObject();
+            failedObject = ((OpenJPAException)t[0]).getFailedObject();
         }
 
         return new StoreException(_loc.get("rolled-back")).
diff --git a/openjpa-lib/src/main/java/org/apache/openjpa/lib/jdbc/DelegatingResultSet.java b/openjpa-lib/src/main/java/org/apache/openjpa/lib/jdbc/DelegatingResultSet.java
index b12422c..63172d9 100644
--- a/openjpa-lib/src/main/java/org/apache/openjpa/lib/jdbc/DelegatingResultSet.java
+++ b/openjpa-lib/src/main/java/org/apache/openjpa/lib/jdbc/DelegatingResultSet.java
@@ -1077,12 +1077,12 @@ public class DelegatingResultSet implements ResultSet, Closeable {
 
     @Override
     public <T>T getObject(String columnLabel, Class<T> type) throws SQLException{
-    	throw new UnsupportedOperationException();
+        return _rs.getObject(columnLabel, type);
     }
 
     @Override
     public <T>T getObject(int columnIndex, Class<T> type) throws SQLException{
-    	throw new UnsupportedOperationException();
+        return _rs.getObject(columnIndex, type);
     }
 }
 
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 8175036..f0c5637 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,6 +21,8 @@ package org.apache.openjpa.persistence.simple;
 import org.apache.openjpa.persistence.test.SingleEMFTestCase;
 
 import javax.persistence.EntityManager;
+
+import java.time.Instant;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
@@ -35,12 +37,13 @@ public class TestJava8TimeTypes extends SingleEMFTestCase {
     private static String VAL_LOCAL_TIME = "04:57:15";
     private static String VAL_LOCAL_DATETIME = "2019-01-01T01:00:00";
 
+
     @Override
     public void setUp() {
         setUp(CLEAR_TABLES, Java8TimeTypes.class);
     }
 
-    public void testJava8Types() throws Exception {
+    public void testJava8Types() {
         EntityManager em = emf.createEntityManager();
         em.getTransaction().begin();
         Java8TimeTypes e = new Java8TimeTypes();
@@ -63,8 +66,17 @@ public class TestJava8TimeTypes extends SingleEMFTestCase {
         assertEquals(LocalTime.parse(VAL_LOCAL_TIME), eRead.getLocalTimeField());
         assertEquals(LocalDate.parse(VAL_LOCAL_DATE), eRead.getLocalDateField());
         assertEquals(LocalDateTime.parse(VAL_LOCAL_DATETIME), eRead.getLocalDateTimeField());
-        assertEquals(e.getOffsetTimeField(), eRead.getOffsetTimeField());
-        assertEquals(e.getOffsetDateTimeField(), eRead.getOffsetDateTimeField());
+
+
+        // Many databases do not support WITH TIMEZONE syntax.
+        // Thus we can only portably ensure tha the same instant is used at least.
+        assertEquals(Instant.from(e.getOffsetDateTimeField()),
+                Instant.from(eRead.getOffsetDateTimeField()));
+
+        assertEquals(e.getOffsetTimeField().withOffsetSameInstant(eRead.getOffsetTimeField().getOffset()),
+                eRead.getOffsetTimeField());
     }
 
+
+
 }
diff --git a/openjpa-project/supportedJava8TimeTypes.adoc b/openjpa-project/supportedJava8TimeTypes.adoc
new file mode 100644
index 0000000..0a18a07
--- /dev/null
+++ b/openjpa-project/supportedJava8TimeTypes.adoc
@@ -0,0 +1,118 @@
+= Supported Java8 Time types
+
+This is a temporary document to describe the state of the java.time.* integration in Apache OpenJPA.
+
+== JPA-2.2 required types
+
+The following java.time types have to be supported mandatorily in JPA-2.2:
+
+* java.time.LocalDate
+* java.time.LocalTime
+* java.time.LocalDateTime
+* java.time.OffsetTime
+* java.time.OffsetDateTime
+
+Apache OpenJPA additionally supports the following types:
+
+* TODO java.time.Instant etc
+
+Not every database supports all those types natively though.
+Some cannot store them at all, others have a mode which e.g. doesn't store the Offset part.
+
+For our example we assume we live in Europe (+1 timezone).
+If you store 04:12-9 then you might actually end up with 14:12+1 when retrieving the value from the database.
+That means that OpenJPA tries to at least keep the instant correct if the database doesn't support zones natively.
+
+== Database Support matrix:
+
+
+[cols=6*,options=header]
+|===
+| DBName
+| LocalDate
+| LocalTime
+| LocalDateTime
+| OffsetTime
+| OffsetDateTime
+
+| Derby
+| DATE
+| TIME
+| TIMESTAMP
+| not natively supported
+| not natively supported
+
+| PostgreSQL
+| DATE
+| TIME
+| TIMESTAMP
+| TIME WITH TIME ZONE
+| TIMESTAMP WITH TIME ZONE
+
+| MySQL
+| DATE
+| TIME
+| DATETIME
+| not natively supported, fallback to TIME
+| not natively supported, fallback to DATETIME
+
+| MariaDB
+| DATE
+| TIME
+| DATETIME
+| not natively supported, fallback to TIME
+| not natively supported, fallback to DATETIME
+
+| Microsoft SQLServer
+| DATE
+| TIME
+| DATETIME2
+|
+|
+
+| Oracle
+| DATE
+| TIME
+| DATE
+| TIME WITH TIME ZONE
+| TIMESTAMP WITH TIME ZONE
+
+| H2
+| DATE
+| TIME
+| DATE
+|
+|
+
+
+...
+|===
+
+
+=== Notes
+
+==== PostgreSQL
+
+PostgreSQL supports some of the types natively in the JDBC driver:
+* LocalDate
+* LocalTime
+* LocalDateTime
+* OffsetDateTime
+
+Note that `OffsetTime` is not supported in `setObject/getObject`.
+
+Also note that PostgreSQL always stores DateTime values internally as UTC.
+Thus when retrieving the date back from the Database again you will get the same Instant representation, but in a the local TimeZone!
+
+
+
+==== MySQL & MariaDB
+
+MySQL supports LocalDate, LocalTime and LocalDateTime in `setObject/getObject`.
+It also supports OffsetTime and OffsetDateTime in `setObject/getObject`, but only via conversion.
+So the MySQL JDBC driver will effectively convert them to the local timezone and keep the 'Instant'.
+
+MariaDB does basically the same.
+
+==== Oracle
+


[openjpa] 04/04: Merge branch 'OPENJPA-2713'

Posted by st...@apache.org.
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

commit 5079209823654d8d99d28f0bb3f3466243e457fd
Merge: 9e22265 6d2544f
Author: Mark Struberg <st...@apache.org>
AuthorDate: Fri Jan 25 17:13:55 2019 +0100

    Merge branch 'OPENJPA-2713'

 .../openjpa/jdbc/meta/MappingDefaultsImpl.java     |   6 -
 .../openjpa/jdbc/meta/MappingRepository.java       |   5 +
 .../openjpa/jdbc/meta/strats/BlobValueHandler.java |   7 +-
 .../jdbc/meta/strats/ImmutableValueHandler.java    |   5 +
 .../jdbc/meta/strats/LocalDateValueHandler.java    |  81 -------
 .../apache/openjpa/jdbc/sql/AbstractResult.java    |  89 +++++++-
 .../org/apache/openjpa/jdbc/sql/DBDictionary.java  | 237 ++++++++++++++++-----
 .../apache/openjpa/jdbc/sql/DerbyDictionary.java   |  18 ++
 .../org/apache/openjpa/jdbc/sql/MergedResult.java  |  33 ++-
 .../openjpa/jdbc/sql/PostgresDictionary.java       |  69 +++++-
 .../java/org/apache/openjpa/jdbc/sql/Result.java   |  35 +++
 .../apache/openjpa/jdbc/sql/ResultSetResult.java   |  48 ++++-
 .../org/apache/openjpa/kernel/AttachStrategy.java  |   7 +-
 .../java/org/apache/openjpa/kernel/BrokerImpl.java |   2 +-
 .../java/org/apache/openjpa/meta/JavaTypes.java    |  28 ++-
 .../openjpa/lib/jdbc/DelegatingResultSet.java      |   4 +-
 .../openjpa/persistence/simple/Java8TimeTypes.java | 102 +++++++++
 .../persistence/simple/TestBasicAnnotation.java    |   4 +
 .../persistence/simple/TestJava8TimeTypes.java     |  82 +++++++
 .../strategy/value/ValueStrategyHandler.java       |  50 ++---
 .../persistence/PersistenceMetaDataDefaults.java   |   5 +
 .../persistence/meta/AbstractManagedType.java      |  20 ++
 openjpa-project/supportedJava8TimeTypes.adoc       | 118 ++++++++++
 23 files changed, 857 insertions(+), 198 deletions(-)