mirror of https://github.com/apache/openjpa.git
OPENJPA-2849 coerc native java.sql types to java.time
Many JDBC driver support old java.sql types for select max, min, etc. Those need to get converted to java.time.* on demand.
This commit is contained in:
parent
aeb333fb3a
commit
72df0228ca
|
@ -25,6 +25,13 @@ import java.security.AccessController;
|
|||
import java.security.PrivilegedActionException;
|
||||
import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.OffsetTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.temporal.Temporal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collection;
|
||||
|
@ -266,6 +273,8 @@ public class Filters {
|
|||
|
||||
/**
|
||||
* Convert the given value to the given type.
|
||||
* @param o the given value
|
||||
* @param type the target type
|
||||
*/
|
||||
public static Object convert(Object o, Class<?> type, boolean strictNumericConversion) {
|
||||
if (o == null)
|
||||
|
@ -283,42 +292,93 @@ public class Filters {
|
|||
// String to Integer
|
||||
boolean num = o instanceof Number;
|
||||
if (!num) {
|
||||
if (type == String.class)
|
||||
if (type == String.class) {
|
||||
return o.toString();
|
||||
else if (type == Boolean.class && o instanceof String)
|
||||
}
|
||||
else if (type == Boolean.class && o instanceof String) {
|
||||
return Boolean.valueOf(o.toString());
|
||||
else if (type == Integer.class && o instanceof String)
|
||||
}
|
||||
else if (type == Integer.class && o instanceof String) {
|
||||
try {
|
||||
return new Integer(o.toString());
|
||||
} catch (NumberFormatException e) {
|
||||
throw new ClassCastException(_loc.get("cant-convert", o,
|
||||
o.getClass(), type).getMessage());
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
throw new ClassCastException(_loc.get("cant-convert", o, o.getClass(), type).getMessage());
|
||||
}
|
||||
}
|
||||
else if (type == Character.class) {
|
||||
String str = o.toString();
|
||||
if (str != null && str.length() == 1)
|
||||
if (str != null && str.length() == 1) {
|
||||
return Character.valueOf(str.charAt(0));
|
||||
} else if (Calendar.class.isAssignableFrom(type) &&
|
||||
o instanceof Date) {
|
||||
}
|
||||
}
|
||||
else if (Calendar.class.isAssignableFrom(type) && o instanceof Date) {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.setTime((Date) o);
|
||||
return cal;
|
||||
} else if (Date.class.isAssignableFrom(type) &&
|
||||
o instanceof Calendar) {
|
||||
}
|
||||
else if (Date.class.isAssignableFrom(type) && o instanceof Calendar) {
|
||||
return ((Calendar) o).getTime();
|
||||
} else if (Number.class.isAssignableFrom(type)) {
|
||||
}
|
||||
else if (Number.class.isAssignableFrom(type)) {
|
||||
Integer i = null;
|
||||
if (o instanceof Character) {
|
||||
i = Integer.valueOf((Character)o);
|
||||
i = Integer.valueOf((Character) o);
|
||||
}
|
||||
else if (o instanceof String && ((String) o).length() == 1) {
|
||||
i = Integer.valueOf(((String) o));
|
||||
}
|
||||
else if (o instanceof String && ((String) o).length() == 1)
|
||||
i = Integer.valueOf(((String)o));
|
||||
|
||||
if (i != null) {
|
||||
if (type == Integer.class)
|
||||
if (type == Integer.class) {
|
||||
return i;
|
||||
}
|
||||
num = true;
|
||||
}
|
||||
} else if (Temporal.class.isAssignableFrom(type)) {
|
||||
// handling of Java8 time API.
|
||||
if (LocalDate.class.equals(type)) {
|
||||
if (o instanceof java.sql.Date) {
|
||||
return ((java.sql.Date) o).toLocalDate();
|
||||
} else if (o instanceof java.util.Date) {
|
||||
return new java.sql.Date(((java.util.Date)o).getTime()).toLocalDate();
|
||||
} else if (o instanceof CharSequence) {
|
||||
return LocalDate.parse((CharSequence) o);
|
||||
}
|
||||
} else if (LocalDateTime.class.equals(type)) {
|
||||
if (o instanceof java.sql.Timestamp) {
|
||||
return ((java.sql.Timestamp) o).toLocalDateTime();
|
||||
} else if (o instanceof java.util.Date) {
|
||||
return ((java.util.Date)o).toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
|
||||
} else if (o instanceof CharSequence) {
|
||||
return LocalDateTime.parse((CharSequence) o);
|
||||
}
|
||||
} else if (LocalTime.class.equals(type)) {
|
||||
if (o instanceof java.sql.Time) {
|
||||
return ((java.sql.Time) o).toLocalTime();
|
||||
} else if (o instanceof java.util.Date) {
|
||||
return ((java.util.Date)o).toInstant().atZone(ZoneId.systemDefault()).toLocalTime();
|
||||
} else if (o instanceof CharSequence) {
|
||||
return LocalTime.parse((CharSequence) o);
|
||||
}
|
||||
} else if (OffsetTime.class.equals(type)) {
|
||||
if (o instanceof java.sql.Time) {
|
||||
return ((java.sql.Time) o).toLocalTime().atOffset(OffsetDateTime.now().getOffset());
|
||||
} else if (o instanceof java.util.Date) {
|
||||
return ((java.util.Date)o).toInstant().atZone(ZoneId.systemDefault()).toOffsetDateTime().toOffsetTime();
|
||||
} else if (o instanceof CharSequence) {
|
||||
return OffsetTime.parse((CharSequence) o);
|
||||
}
|
||||
} else if (OffsetDateTime.class.equals(type)) {
|
||||
if (o instanceof java.sql.Timestamp) {
|
||||
return ((java.sql.Timestamp) o).toInstant().atZone(ZoneId.systemDefault()).toOffsetDateTime();
|
||||
} else if (o instanceof java.util.Date) {
|
||||
return ((java.util.Date)o).toInstant().atZone(ZoneId.systemDefault()).toOffsetDateTime();
|
||||
} else if (o instanceof CharSequence) {
|
||||
return LocalTime.parse((CharSequence) o);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (o instanceof String && isJDBCTemporalSyntax(o.toString())) {
|
||||
try {
|
||||
Object temporal = parseJDBCTemporalSyntax(o.toString());
|
||||
|
@ -331,9 +391,9 @@ public class Filters {
|
|||
return Enum.valueOf((Class<Enum>)type, o.toString());
|
||||
}
|
||||
}
|
||||
if (!num)
|
||||
throw new ClassCastException(_loc.get("cant-convert", o,
|
||||
o.getClass(), type).getMessage());
|
||||
if (!num) {
|
||||
throw new ClassCastException(_loc.get("cant-convert", o, o.getClass(), type).getMessage());
|
||||
}
|
||||
|
||||
if (type == Integer.class && allowNumericConversion(o.getClass(), type, strictNumericConversion)) {
|
||||
return ((Number) o).intValue();
|
||||
|
@ -349,12 +409,13 @@ public class Filters {
|
|||
// does it handle infinity; we need to instead use the Double
|
||||
// and Float versions, despite wanting to cast it to BigDecimal
|
||||
double dval = ((Number) o).doubleValue();
|
||||
if (Double.isNaN(dval) || Double.isInfinite(dval))
|
||||
if (Double.isNaN(dval) || Double.isInfinite(dval)) {
|
||||
return Double.valueOf(dval);
|
||||
|
||||
}
|
||||
float fval = ((Number) o).floatValue();
|
||||
if (Float.isNaN(fval) || Float.isInfinite(fval))
|
||||
if (Float.isNaN(fval) || Float.isInfinite(fval)) {
|
||||
return Float.valueOf(fval);
|
||||
}
|
||||
|
||||
return new BigDecimal(o.toString());
|
||||
} else if (type == BigInteger.class) {
|
||||
|
@ -364,7 +425,7 @@ public class Filters {
|
|||
} else if (type == Byte.class && allowNumericConversion(o.getClass(), type, strictNumericConversion)) {
|
||||
return Byte.valueOf(((Number) o).byteValue());
|
||||
} else if (type == Character.class) {
|
||||
return (char) ((Number) o).intValue();
|
||||
return (char) ((Number) o).intValue();
|
||||
} else if (!strictNumericConversion) {
|
||||
return ((Number) o).intValue();
|
||||
} else {
|
||||
|
|
|
@ -21,11 +21,15 @@ package org.apache.openjpa.persistence.simple;
|
|||
import org.apache.openjpa.persistence.test.SingleEMFTestCase;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.TypedQuery;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.OffsetTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.Date;
|
||||
|
||||
|
@ -75,6 +79,67 @@ public class TestJava8TimeTypes extends SingleEMFTestCase {
|
|||
|
||||
assertEquals(e.getOffsetTimeField().withOffsetSameInstant(eRead.getOffsetTimeField().getOffset()),
|
||||
eRead.getOffsetTimeField());
|
||||
|
||||
// we've got reports from various functions not properly working with Java8 Dates.
|
||||
|
||||
// max function
|
||||
{
|
||||
final TypedQuery<LocalDate> qry = em.createQuery("select max(t.localDateField) from Java8TimeTypes AS t", LocalDate.class);
|
||||
final LocalDate max = qry.getSingleResult();
|
||||
assertEquals(LocalDate.parse(VAL_LOCAL_DATE), max);
|
||||
}
|
||||
{
|
||||
final TypedQuery<LocalDateTime> qry = em.createQuery("select max(t.localDateTimeField) from Java8TimeTypes AS t", LocalDateTime.class);
|
||||
final LocalDateTime max = qry.getSingleResult();
|
||||
assertEquals(LocalDateTime.parse(VAL_LOCAL_DATETIME), max);
|
||||
}
|
||||
{
|
||||
final TypedQuery<LocalTime> qry = em.createQuery("select max(t.localTimeField) from Java8TimeTypes AS t", LocalTime.class);
|
||||
final LocalTime max = qry.getSingleResult();
|
||||
assertEquals(LocalTime.parse(VAL_LOCAL_TIME), max);
|
||||
}
|
||||
{
|
||||
final TypedQuery<OffsetTime> qry = em.createQuery("select max(t.offsetTimeField) from Java8TimeTypes AS t", OffsetTime.class);
|
||||
final OffsetTime max = qry.getSingleResult();
|
||||
assertEquals(e.getOffsetTimeField().withOffsetSameInstant(eRead.getOffsetTimeField().getOffset()),
|
||||
max.withOffsetSameInstant(eRead.getOffsetTimeField().getOffset()));
|
||||
}
|
||||
{
|
||||
final TypedQuery<OffsetDateTime> qry = em.createQuery("select max(t.offsetDateTimeField) from Java8TimeTypes AS t", OffsetDateTime.class);
|
||||
final OffsetDateTime max = qry.getSingleResult();
|
||||
assertEquals(Instant.from(e.getOffsetDateTimeField()),
|
||||
Instant.from(max));
|
||||
}
|
||||
|
||||
// min function
|
||||
{
|
||||
final TypedQuery<LocalDate> qry = em.createQuery("select min(t.localDateField) from Java8TimeTypes AS t", LocalDate.class);
|
||||
final LocalDate min = qry.getSingleResult();
|
||||
assertEquals(LocalDate.parse(VAL_LOCAL_DATE), min);
|
||||
}
|
||||
{
|
||||
final TypedQuery<LocalDateTime> qry = em.createQuery("select min(t.localDateTimeField) from Java8TimeTypes AS t", LocalDateTime.class);
|
||||
final LocalDateTime min = qry.getSingleResult();
|
||||
assertEquals(LocalDateTime.parse(VAL_LOCAL_DATETIME), min);
|
||||
}
|
||||
{
|
||||
final TypedQuery<LocalTime> qry = em.createQuery("select min(t.localTimeField) from Java8TimeTypes AS t", LocalTime.class);
|
||||
final LocalTime min = qry.getSingleResult();
|
||||
assertEquals(LocalTime.parse(VAL_LOCAL_TIME), min);
|
||||
}
|
||||
{
|
||||
final TypedQuery<OffsetTime> qry = em.createQuery("select min(t.offsetTimeField) from Java8TimeTypes AS t", OffsetTime.class);
|
||||
final OffsetTime min = qry.getSingleResult();
|
||||
assertEquals(e.getOffsetTimeField().withOffsetSameInstant(eRead.getOffsetTimeField().getOffset()),
|
||||
min.withOffsetSameInstant(eRead.getOffsetTimeField().getOffset()));
|
||||
}
|
||||
{
|
||||
final TypedQuery<OffsetDateTime> qry = em.createQuery("select min(t.offsetDateTimeField) from Java8TimeTypes AS t", OffsetDateTime.class);
|
||||
final OffsetDateTime min = qry.getSingleResult();
|
||||
assertEquals(Instant.from(e.getOffsetDateTimeField()),
|
||||
Instant.from(min));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue