From 7cd9e5ee030ad46bc0e60aae11cc7516323d910f Mon Sep 17 00:00:00 2001 From: "robin.bygrave" Date: Wed, 6 Dec 2023 14:54:30 +1300 Subject: [PATCH] Add support for LocalDate and Instant with DbArray --- .../server/type/ArrayElementConverter.java | 51 ++++++++++++++++++- .../server/type/ScalarTypeArrayList.java | 8 +++ .../server/type/ScalarTypeArrayListH2.java | 8 +++ .../org/tests/model/array/EArrayBean.java | 26 ++++++++++ .../tests/model/array/TestDbArray_basic.java | 6 +++ 5 files changed, 97 insertions(+), 2 deletions(-) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ArrayElementConverter.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ArrayElementConverter.java index 12e5e6b17..7d1e75c6f 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ArrayElementConverter.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ArrayElementConverter.java @@ -1,9 +1,12 @@ package io.ebeaninternal.server.type; -import io.ebean.core.type.ScalarType; import io.ebean.core.type.BasicTypeConverter; +import io.ebean.core.type.ScalarType; import java.math.BigDecimal; +import java.sql.Timestamp; +import java.time.Instant; +import java.time.LocalDate; import java.util.UUID; /** @@ -32,6 +35,8 @@ interface ArrayElementConverter { ArrayElementConverter DOUBLE = new DoubleConverter(); ArrayElementConverter FLOAT = new FloatConverter(); ArrayElementConverter BIG_DECIMAL = new BigDecimalConverter(); + ArrayElementConverter INSTANT = new InstantConverter(); + ArrayElementConverter LOCAL_DATE = new LocalDateConverter(); class LongConverter implements ArrayElementConverter { @@ -101,6 +106,48 @@ interface ArrayElementConverter { } } + class InstantConverter implements ArrayElementConverter { + + @Override + public Instant fromSerialized(Object rawValue) { + return fromDbArray(rawValue); + } + + @Override + public Instant fromDbArray(Object rawValue) { + if (rawValue instanceof Instant) { + return (Instant) rawValue; + } else if (rawValue instanceof Timestamp) { + return ((Timestamp) rawValue).toInstant(); + } else if (rawValue instanceof String) { + return Instant.parse((String) rawValue); + } else { + throw new IllegalStateException("Instant fromDbArray unsupported for " + rawValue); + } + } + } + + class LocalDateConverter implements ArrayElementConverter { + + @Override + public LocalDate fromSerialized(Object rawValue) { + return fromDbArray(rawValue); + } + + @Override + public LocalDate fromDbArray(Object rawValue) { + if (rawValue instanceof LocalDate) { + return (LocalDate) rawValue; + } else if (rawValue instanceof java.sql.Date) { + return ((java.sql.Date) rawValue).toLocalDate(); + } else if (rawValue instanceof String) { + return LocalDate.parse((String) rawValue); + } else { + throw new IllegalStateException("Instant fromDbArray unsupported for " + rawValue); + } + } + } + class BigDecimalConverter implements ArrayElementConverter { @Override @@ -141,7 +188,7 @@ interface ArrayElementConverter { @Override public java.util.UUID fromSerialized(Object rawValue) { - return java.util.UUID.fromString((String)rawValue); + return java.util.UUID.fromString((String) rawValue); } @Override diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeArrayList.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeArrayList.java index b2be8d63c..59e85b54a 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeArrayList.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeArrayList.java @@ -16,6 +16,8 @@ import java.lang.reflect.Type; import java.math.BigDecimal; import java.sql.SQLException; import java.sql.Types; +import java.time.Instant; +import java.time.LocalDate; import java.util.*; import java.util.concurrent.locks.ReentrantLock; @@ -63,6 +65,12 @@ class ScalarTypeArrayList extends ScalarTypeArrayBase implements ScalarTyp if (valueType.equals(String.class)) { return cache.computeIfAbsent(key, s -> new ScalarTypeArrayList(nullable, "varchar", DocPropertyType.TEXT, ArrayElementConverter.STRING)); } + if (valueType.equals(Instant.class)) { + return cache.computeIfAbsent(key, s -> new ScalarTypeArrayList(nullable, "timestamptz", DocPropertyType.TEXT, ArrayElementConverter.INSTANT)); + } + if (valueType.equals(LocalDate.class)) { + return cache.computeIfAbsent(key, s -> new ScalarTypeArrayList(nullable, "date", DocPropertyType.TEXT, ArrayElementConverter.LOCAL_DATE)); + } throw new IllegalArgumentException("Type [" + valueType + "] not supported for @DbArray mapping"); } finally { lock.unlock(); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeArrayListH2.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeArrayListH2.java index a72c5ec6e..220f29d73 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeArrayListH2.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeArrayListH2.java @@ -8,6 +8,8 @@ import java.lang.reflect.Type; import java.math.BigDecimal; import java.sql.SQLException; import java.sql.Types; +import java.time.Instant; +import java.time.LocalDate; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -58,6 +60,12 @@ final class ScalarTypeArrayListH2 extends ScalarTypeArrayList { if (valueType.equals(String.class)) { return cache.computeIfAbsent(key, s -> new ScalarTypeArrayListH2(nullable, "varchar", DocPropertyType.TEXT, ArrayElementConverter.STRING)); } + if (valueType.equals(Instant.class)) { + return cache.computeIfAbsent(key, s -> new ScalarTypeArrayListH2(nullable, "timestamp", DocPropertyType.TEXT, ArrayElementConverter.INSTANT)); + } + if (valueType.equals(LocalDate.class)) { + return cache.computeIfAbsent(key, s -> new ScalarTypeArrayListH2(nullable, "date", DocPropertyType.TEXT, ArrayElementConverter.LOCAL_DATE)); + } throw new IllegalArgumentException("Type [" + valueType + "] not supported for @DbArray mapping"); } finally { lock.unlock(); diff --git a/ebean-test/src/test/java/org/tests/model/array/EArrayBean.java b/ebean-test/src/test/java/org/tests/model/array/EArrayBean.java index 14cea519e..b24ebaa79 100644 --- a/ebean-test/src/test/java/org/tests/model/array/EArrayBean.java +++ b/ebean-test/src/test/java/org/tests/model/array/EArrayBean.java @@ -9,6 +9,8 @@ import jakarta.persistence.Entity; import jakarta.persistence.Id; import jakarta.persistence.Version; import java.math.BigDecimal; +import java.time.Instant; +import java.time.LocalDate; import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -58,6 +60,12 @@ public class EArrayBean { @DbArray Set status2; + @DbArray + List times; + + @DbArray + List dates; + @Version Long version; @@ -165,6 +173,24 @@ public class EArrayBean { this.status2 = status2; } + public List getTimes() { + return times; + } + + public EArrayBean setTimes(List times) { + this.times = times; + return this; + } + + public List getDates() { + return dates; + } + + public EArrayBean setDates(List dates) { + this.dates = dates; + return this; + } + public Long getVersion() { return version; } diff --git a/ebean-test/src/test/java/org/tests/model/array/TestDbArray_basic.java b/ebean-test/src/test/java/org/tests/model/array/TestDbArray_basic.java index 89cd68095..dcbbde859 100644 --- a/ebean-test/src/test/java/org/tests/model/array/TestDbArray_basic.java +++ b/ebean-test/src/test/java/org/tests/model/array/TestDbArray_basic.java @@ -10,6 +10,8 @@ import org.junit.jupiter.api.Test; import java.math.BigDecimal; import java.sql.SQLException; +import java.time.Instant; +import java.time.LocalDate; import java.util.*; import static org.assertj.core.api.Assertions.assertThat; @@ -58,6 +60,8 @@ class TestDbArray_basic extends BaseTestCase { bean.setStatus2(new LinkedHashSet<>()); bean.getStatus2().add(EArrayBean.Status.TWO); bean.getStatus2().add(EArrayBean.Status.ONE); + bean.setTimes(List.of(Instant.now(), Instant.now().minusSeconds(60))); + bean.setDates(List.of(LocalDate.now(), LocalDate.now().minusDays(1))); DB.save(bean); @@ -66,6 +70,8 @@ class TestDbArray_basic extends BaseTestCase { assertThat(found.getPhoneNumbers()).containsExactly("4321", "9823"); assertThat(found.getDoubs()).hasSize(2); assertThat(found.getFloats()).hasSize(2); + assertThat(found.getTimes()).hasSize(2); + assertThat(found.getDates()).hasSize(2); if (isPostgresCompatible()) { Query query = DB.find(EArrayBean.class)