Skip to content

Commit

Permalink
Jakarta Persistence 3.2: java.time.Instant and java.time.Year support…
Browse files Browse the repository at this point in the history
… as a basic types (#2078)

* Jakarta Persistence 3.2: java.time.Instant and java.time.Year support as a basic types

This change adds support for java.time.Instant and java.time.Year classes according
spec 2.6. Basic Types, 11.1.6. Basic Annotation
https://jakartaee.github.io/persistence/latest-nightly/nightly.html#a486
https://jakartaee.github.io/persistence/latest-nightly/nightly.html#a14205
or see Specification appendix A.1. Jakarta Persistence 3.2
https://jakartaee.github.io/persistence/latest-nightly/nightly.html#jakarta-persistence-3-2

Signed-off-by: Radek Felcman <radek.felcman@oracle.com>
  • Loading branch information
rfelcman committed Feb 28, 2024
1 parent 9c3c30c commit 33339de
Show file tree
Hide file tree
Showing 10 changed files with 387 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -565,11 +565,13 @@ protected Hashtable<Class<?>, FieldTypeDefinition> buildFieldTypes() {
fieldTypeMapping.put(java.util.Date.class, new FieldTypeDefinition("TIMESTAMP"));
fieldTypeMapping.put(java.lang.Number.class, new FieldTypeDefinition("NUMBER", 10));

fieldTypeMapping.put(java.time.Instant.class, new FieldTypeDefinition("TIMESTAMP"));
fieldTypeMapping.put(java.time.LocalDate.class, new FieldTypeDefinition("DATE"));
fieldTypeMapping.put(java.time.LocalDateTime.class, new FieldTypeDefinition("TIMESTAMP"));
fieldTypeMapping.put(java.time.LocalTime.class, new FieldTypeDefinition("TIME"));
fieldTypeMapping.put(java.time.OffsetDateTime.class, new FieldTypeDefinition("TIMESTAMP"));
fieldTypeMapping.put(java.time.OffsetTime.class, new FieldTypeDefinition("TIME"));
fieldTypeMapping.put(java.time.Year.class, new FieldTypeDefinition("NUMBER", 10));
// Mapping for JSON type.
getJsonPlatform().updateFieldTypes(fieldTypeMapping);

Expand Down Expand Up @@ -1127,6 +1129,8 @@ public int getJDBCType(Class<?> javaType) {
return Types.TIMESTAMP;
} else if (javaType == ClassConstants.UTILDATE ) {//bug 5237080, return TIMESTAMP for java.util.Date as well
return Types.TIMESTAMP;
} else if (javaType == ClassConstants.TIME_INSTANT ) {
return Types.TIMESTAMP;
} else if (javaType == ClassConstants.TIME ||
javaType == ClassConstants.TIME_LTIME) { //bug 546312
return Types.TIME;
Expand All @@ -1140,6 +1144,8 @@ public int getJDBCType(Class<?> javaType) {
return Types.TIME_WITH_TIMEZONE;
} else if(javaType == ClassConstants.TIME_ODATETIME) { //bug 546312
return Types.TIMESTAMP_WITH_TIMEZONE;
} else if (javaType == ClassConstants.TIME_YEAR ) {
return Types.INTEGER;
}else if (javaType == ClassConstants.ABYTE) {
return Types.LONGVARBINARY;
} else if (javaType == ClassConstants.APBYTE) {
Expand Down Expand Up @@ -2417,10 +2423,14 @@ public void setParameterValueInDatabaseCall(Object parameter,
statement.setDate(index, java.sql.Date.valueOf((java.time.LocalDate) parameter));
} else if (parameter instanceof java.sql.Timestamp){
statement.setTimestamp(index,(java.sql.Timestamp)parameter);
} else if (parameter instanceof java.time.Instant){
statement.setTimestamp(index, java.sql.Timestamp.from((java.time.Instant)parameter));
} else if (parameter instanceof java.time.LocalDateTime){
statement.setTimestamp(index, java.sql.Timestamp.valueOf((java.time.LocalDateTime) parameter));
} else if (parameter instanceof java.time.OffsetDateTime) {
statement.setTimestamp(index, java.sql.Timestamp.from(((java.time.OffsetDateTime) parameter).toInstant()));
} else if (parameter instanceof java.time.Year) {
statement.setInt(index, ((java.time.Year)parameter).getValue());
} else if (parameter instanceof java.sql.Time){
statement.setTime(index,(java.sql.Time)parameter);
} else if (parameter instanceof java.time.LocalTime lt){
Expand Down Expand Up @@ -2521,6 +2531,8 @@ public void setParameterValueInDatabaseCall(Object parameter,
statement.setDate(name,(java.sql.Date)parameter);
} else if (parameter instanceof java.time.LocalDate){
statement.setDate(name, java.sql.Date.valueOf((java.time.LocalDate) parameter));
} else if (parameter instanceof java.time.Instant){
statement.setTimestamp(name, java.sql.Timestamp.from((java.time.Instant)parameter));
} else if (parameter instanceof java.sql.Timestamp){
statement.setTimestamp(name,(java.sql.Timestamp)parameter);
} else if (parameter instanceof java.time.LocalDateTime){
Expand All @@ -2535,6 +2547,8 @@ public void setParameterValueInDatabaseCall(Object parameter,
} else if (parameter instanceof java.time.OffsetTime ot) {
java.sql.Timestamp ts = java.sql.Timestamp.valueOf(java.time.LocalDateTime.of(java.time.LocalDate.ofEpochDay(0), ot.toLocalTime()));
statement.setTimestamp(name, ts);
} else if (parameter instanceof java.time.Year) {
statement.setInt(name, ((java.time.Year)parameter).getValue());
} else if (parameter instanceof Boolean) {
statement.setBoolean(name, (Boolean) parameter);
} else if (parameter == null) {
Expand Down Expand Up @@ -2655,6 +2669,8 @@ public int appendParameterInternal(Call call, Writer writer, Object parameter) {
appendTime((java.sql.Time)dbValue, writer);
} else if (dbValue instanceof java.sql.Timestamp) {
appendTimestamp((java.sql.Timestamp)dbValue, writer);
} else if (dbValue instanceof java.time.Instant){
appendTimestamp(java.sql.Timestamp.from((java.time.Instant) dbValue), writer);
} else if (dbValue instanceof java.time.LocalDate){
appendDate(java.sql.Date.valueOf((java.time.LocalDate) dbValue), writer);
} else if (dbValue instanceof java.time.LocalDateTime){
Expand All @@ -2667,6 +2683,8 @@ public int appendParameterInternal(Call call, Writer writer, Object parameter) {
} else if (dbValue instanceof java.time.OffsetTime ot) {
java.sql.Timestamp ts = java.sql.Timestamp.valueOf(java.time.LocalDateTime.of(java.time.LocalDate.ofEpochDay(0), ot.toLocalTime()));
appendTimestamp(ts, writer);
} else if (dbValue instanceof java.time.Year){
appendNumber((Number)dbValue, writer);
} else if (dbValue instanceof java.sql.Date) {
appendDate((java.sql.Date)dbValue, writer);
} else if (dbValue == null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2023 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
Expand Down Expand Up @@ -61,11 +61,13 @@
import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.OffsetTime;
import java.time.Year;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Hashtable;
Expand Down Expand Up @@ -145,11 +147,13 @@ public final class ClassConstants extends CoreClassConstants {
// Moved from ConversionManager
public static final Class<?> AOBJECT = Object[].class;
public static final Class<?> ACHAR = Character[].class;
public static final Class<Instant> TIME_INSTANT = Instant.class;
public static final Class<LocalDate> TIME_LDATE = LocalDate.class;
public static final Class<LocalTime> TIME_LTIME = LocalTime.class;
public static final Class<LocalDateTime> TIME_LDATETIME = LocalDateTime.class;
public static final Class<OffsetDateTime> TIME_ODATETIME = OffsetDateTime.class;
public static final Class<OffsetTime> TIME_OTIME = OffsetTime.class;
public static final Class<Year> TIME_YEAR = Year.class;

//LOB support types
public static final Class<Blob> BLOB = Blob.class;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.Year;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.Calendar;
Expand Down Expand Up @@ -190,6 +192,8 @@ public <T> T convertObject(Object sourceObject, Class<T> javaClass) throws Conve
return (T) convertObjectToTime(sourceObject);
} else if (javaClass == ClassConstants.TIMESTAMP) {
return (T) convertObjectToTimestamp(sourceObject);
} else if (javaClass == ClassConstants.TIME_INSTANT) {
return (T) convertObjectToInstant(sourceObject);
} else if (javaClass == ClassConstants.TIME_LDATE) {
return (T) convertObjectToLocalDate(sourceObject);
} else if (javaClass == ClassConstants.TIME_LDATETIME) {
Expand All @@ -200,6 +204,8 @@ public <T> T convertObject(Object sourceObject, Class<T> javaClass) throws Conve
return (T) convertObjectToOffsetDateTime(sourceObject);
} else if (javaClass == ClassConstants.TIME_OTIME) {
return (T) convertObjectToOffsetTime(sourceObject);
} else if (javaClass == ClassConstants.TIME_YEAR) {
return (T) convertObjectToYear(sourceObject);
} else if ((javaClass == ClassConstants.CALENDAR) || (javaClass == ClassConstants.GREGORIAN_CALENDAR)) {
return (T) convertObjectToCalendar(sourceObject);
} else if ((javaClass == ClassConstants.CHAR) || (javaClass == ClassConstants.PCHAR && !(sourceObject instanceof Character))) {
Expand Down Expand Up @@ -838,6 +844,42 @@ protected java.sql.Timestamp convertObjectToTimestamp(Object sourceObject) throw
return timestamp;
}

/**
* INTERNAL: Build a valid instance of java.time.Instant from the given
* source object.
*
* @param sourceObject
* Valid object of class java.sql.Timestamp, String,
* java.util.Date, or Long
*/
protected java.time.Instant convertObjectToInstant(Object sourceObject) throws ConversionException {
java.time.Instant instant = null;

if (sourceObject instanceof java.time.Instant) {
return (java.time.Instant) sourceObject;
}

if (sourceObject instanceof String) {
instant = java.time.Instant.parse((String) sourceObject);
} else if (sourceObject instanceof java.sql.Date) {
instant = Instant.ofEpochMilli(((java.sql.Date) sourceObject).getTime());
} else if (sourceObject instanceof java.sql.Timestamp) {
instant = ((java.sql.Timestamp) sourceObject).toInstant();
} else if (sourceObject instanceof java.util.Date) {
// handles sql.Time too
instant = ((java.util.Date) sourceObject).toInstant();
} else if (sourceObject instanceof Calendar cal) {
instant = cal.toInstant();
} else if (sourceObject instanceof java.time.LocalDateTime) {
instant = ((LocalDateTime) sourceObject).toInstant(ZoneOffset.UTC);
} else if (sourceObject instanceof Long) {
instant = java.time.Instant.ofEpochSecond((Long) sourceObject);
} else {
throw ConversionException.couldNotBeConverted(sourceObject, ClassConstants.TIME_LDATE);
}
return instant;
}

/**
* INTERNAL: Build a valid instance of java.time.LocalDate from the given
* source object.
Expand Down Expand Up @@ -1040,6 +1082,48 @@ protected java.time.OffsetTime convertObjectToOffsetTime(Object sourceObject) th
return offsetTime;
}

/**
* INTERNAL: Build a valid instance of java.time.Year from the given
* source object.
*
* @param sourceObject
* Valid object of class java.sql.Timestamp, String,
* java.util.Date or Int
*/
protected java.time.Year convertObjectToYear(Object sourceObject) throws ConversionException {
java.time.Year year = null;

if (sourceObject instanceof java.time.Year) {
return (java.time.Year) sourceObject;
}

if (sourceObject instanceof String) {
try {
year = java.time.Year.of(Integer.valueOf((String) sourceObject));
} catch (Exception e) {
year = java.time.Year.parse(((String) sourceObject).replace(' ', 'T'), Helper.getDefaultDateTimeFormatter());
java.time.LocalTime localTime = java.time.LocalTime.parse(((String) sourceObject).replace(' ', 'T'), Helper.getDefaultDateTimeFormatter());
}
} else if (sourceObject instanceof java.util.Date) {
// handles sql.Time, sql.Date, sql.Timestamp
Calendar cal = Helper.allocateCalendar();
cal.setTime((java.util.Date) sourceObject);
year = Year.of(cal.get(Calendar.YEAR));
Helper.releaseCalendar(cal);
} else if (sourceObject instanceof Calendar cal) {
year = Year.of(cal.get(Calendar.YEAR));
} else if (sourceObject instanceof Integer) {
year = Year.of((Integer)sourceObject);
} else if (sourceObject instanceof Long) {
//Not 100% safe, but JDBC should return Long, but java.time.Year keeps value internally in int variable.
year = Year.of(((Long)sourceObject).intValue());
} else {
throw ConversionException.couldNotBeConverted(sourceObject, ClassConstants.TIME_OTIME);
}

return year;
}

/**
* INTERNAL:
* Build a valid instance of java.net.URL from the given source object.
Expand Down

0 comments on commit 33339de

Please sign in to comment.