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 <[email protected]> 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;
