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 9db2bfad4..f2c2c1ee7 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 @@ -10,9 +10,14 @@ import java.util.UUID; interface ArrayElementConverter { /** - * Convert the array element to the logical type. + * Convert element it's json serialized form. */ - T toElement(Object rawValue); + T fromSerialized(Object rawValue); + + /** + * Convert the array element from it's DB array form. + */ + T fromDbArray(Object rawValue); default Object[] toDbArray(Object[] objects) { return objects; @@ -46,7 +51,12 @@ interface ArrayElementConverter { class LongConverter implements ArrayElementConverter { @Override - public Long toElement(Object rawValue) { + public Long fromSerialized(Object rawValue) { + return fromDbArray(rawValue); + } + + @Override + public Long fromDbArray(Object rawValue) { if (rawValue instanceof Long) { return (Long) rawValue; } else { @@ -58,7 +68,12 @@ interface ArrayElementConverter { class IntegerConverter implements ArrayElementConverter { @Override - public Integer toElement(Object rawValue) { + public Integer fromSerialized(Object rawValue) { + return ((Number) rawValue).intValue(); + } + + @Override + public Integer fromDbArray(Object rawValue) { if (rawValue instanceof Integer) { return (Integer) rawValue; } else { @@ -70,7 +85,12 @@ interface ArrayElementConverter { class DoubleConverter implements ArrayElementConverter { @Override - public Double toElement(Object rawValue) { + public Double fromSerialized(Object rawValue) { + return fromDbArray(rawValue); + } + + @Override + public Double fromDbArray(Object rawValue) { if (rawValue instanceof Double) { return (Double) rawValue; } else { @@ -82,21 +102,34 @@ interface ArrayElementConverter { /** * String converter (noop based). */ - class StringConverter extends NoopConverter { + class StringConverter implements ArrayElementConverter { + + public String fromDbArray(Object rawValue) { + return (String) rawValue; + } + + @Override + public String fromSerialized(Object rawValue) { + return (String) rawValue; + } } /** - * UUID converter (noop based). + * UUID converter. */ - class UuidConverter extends NoopConverter { - } + class UuidConverter implements ArrayElementConverter { - class NoopConverter implements ArrayElementConverter { - - @SuppressWarnings("unchecked") @Override - public T toElement(Object rawValue) { - return (T) rawValue; + public java.util.UUID fromSerialized(Object rawValue) { + return java.util.UUID.fromString((String)rawValue); + } + + @Override + public java.util.UUID fromDbArray(Object rawValue) { + if (rawValue instanceof UUID) { + return (java.util.UUID) rawValue; + } + return java.util.UUID.fromString(rawValue.toString()); } } @@ -113,7 +146,12 @@ interface ArrayElementConverter { } @Override - public Object toElement(Object rawValue) { + public Object fromSerialized(Object rawValue) { + return scalarType.parse((String) rawValue); + } + + @Override + public Object fromDbArray(Object rawValue) { return scalarType.toBeanType(rawValue); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ArrayElementConverterEnum.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ArrayElementConverterEnum.java deleted file mode 100644 index e7bfe5606..000000000 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ArrayElementConverterEnum.java +++ /dev/null @@ -1,25 +0,0 @@ -package io.ebeaninternal.server.type; - -import io.ebean.core.type.ScalarType; - -public class ArrayElementConverterEnum implements ArrayElementConverter { - - final ScalarType scalarType; - - final Class> valueType1; - - public ArrayElementConverterEnum(ScalarType scalarType, Class> valueType1) { - this.scalarType = scalarType; - this.valueType1 = valueType1; - } - - @Override - public String toElement(Object rawValue) { - // FIXME: Don't understand for what is this. - Enum[] enumConstants = valueType1.getEnumConstants(); - if (scalarType == null) { - return rawValue.toString(); - } - return scalarType.format(rawValue); - } -} 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 736cd94eb..6ee64d5cf 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 @@ -105,7 +105,7 @@ public class ScalarTypeArrayList extends ScalarTypeArrayBase implements Sc if (element == null) { list.add(null); } else { - list.add(converter.toElement(element)); + list.add(converter.fromDbArray(element)); } } return new ModifyAwareList(list); @@ -145,15 +145,27 @@ public class ScalarTypeArrayList extends ScalarTypeArrayBase implements Sc @Override public List parse(String value) { try { - return EJson.parseList(value, false); + return convert(EJson.parseList(value, false)); } catch (IOException e) { throw new TextException("Failed to parse JSON [{}] as List", value, e); } } + /** + * Convert from the json types to the proper scalar types (uuid, enum, double etc) + */ + @SuppressWarnings("rawtypes") + private List convert(List rawList) { + List list = new ArrayList(rawList.size()); + for (Object rawVal : rawList) { + list.add(converter.fromSerialized(rawVal)); + } + return new ModifyAwareList(list); + } + @Override public List jsonRead(JsonParser parser) throws IOException { - return EJson.parseList(parser, parser.getCurrentToken()); + return convert(EJson.parseList(parser, parser.getCurrentToken())); } @Override diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeArraySet.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeArraySet.java index fd0b7dd41..90f592428 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeArraySet.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeArraySet.java @@ -17,6 +17,7 @@ import java.sql.SQLException; import java.sql.Types; import java.util.HashMap; import java.util.LinkedHashSet; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; @@ -101,7 +102,7 @@ public class ScalarTypeArraySet extends ScalarTypeArrayBase implements Scal protected Set fromArray(Object[] array1) { Set set = new LinkedHashSet(); for (Object element : array1) { - set.add(converter.toElement(element)); + set.add(converter.fromDbArray(element)); } return new ModifyAwareSet(set); } @@ -140,15 +141,26 @@ public class ScalarTypeArraySet extends ScalarTypeArrayBase implements Scal @Override public Set parse(String value) { try { - return EJson.parseSet(value, false); + return convert(EJson.parseList(value, false)); } catch (IOException e) { throw new TextException("Failed to parse JSON [{}] as Set", value, e); } } + /** + * Convert from the json types to the proper scalar types (uuid, enum, double etc) + */ + private Set convert(List rawList) { + Set asSet = new LinkedHashSet(); + for (Object rawVal : rawList) { + asSet.add(converter.fromSerialized(rawVal)); + } + return new ModifyAwareSet(asSet); + } + @Override public Set jsonRead(JsonParser parser) throws IOException { - return EJson.parseSet(parser, parser.getCurrentToken()); + return convert(EJson.parseList(parser, parser.getCurrentToken())); } @Override diff --git a/ebean-core/src/test/java/io/ebeaninternal/server/type/ScalarTypeArrayListTest.java b/ebean-core/src/test/java/io/ebeaninternal/server/type/ScalarTypeArrayListTest.java index 5e9a99645..13496e407 100644 --- a/ebean-core/src/test/java/io/ebeaninternal/server/type/ScalarTypeArrayListTest.java +++ b/ebean-core/src/test/java/io/ebeaninternal/server/type/ScalarTypeArrayListTest.java @@ -1,13 +1,18 @@ package io.ebeaninternal.server.type; +import com.fasterxml.jackson.core.JsonParser; +import io.ebean.DB; import io.ebean.core.type.DataReader; import io.ebean.core.type.ScalarType; +import io.ebean.text.json.EJson; import org.junit.Test; import org.mockito.Mockito; +import java.io.IOException; +import java.io.StringReader; import java.sql.SQLException; -import java.util.UUID; +import java.util.*; import static org.assertj.core.api.Assertions.assertThat; @@ -63,4 +68,82 @@ public class ScalarTypeArrayListTest extends BasePlatformArrayTypeFactoryTest { assertBindNullTo_Null(factory.typeFor(UUID.class, true)); } + @Test + @SuppressWarnings("unchecked") + public void parse_withUuidType_expect_uuidTypeReturned() { + + ScalarType scalarType = factory.typeFor(UUID.class, true); + + List input = new ArrayList<>(); + input.add(UUID.randomUUID()); + input.add(UUID.randomUUID()); + + String formatToJson = scalarType.format(input); + + Object parsed = scalarType.parse(formatToJson); + assertThat(parsed).isEqualTo(input); + } + + @Test + @SuppressWarnings("unchecked") + public void parse_withIntegerType_expect_longIntegerReturned() { + + ScalarType scalarType = factory.typeFor(Integer.class, true); + + List input = new ArrayList<>(); + input.add(2); + input.add(4); + + String formatToJson = scalarType.format(input); + + Object parsed = scalarType.parse(formatToJson); + assertThat(parsed).isEqualTo(input); + } + + @Test + @SuppressWarnings("unchecked") + public void parse_withLongType_expect_longTypeReturned() { + + ScalarType scalarType = factory.typeFor(Long.class, true); + + List input = new ArrayList<>(); + input.add(2L); + input.add(4L); + + String formatToJson = scalarType.format(input); + + Object parsed = scalarType.parse(formatToJson); + assertThat(parsed).isEqualTo(input); + } + + @Test + public void parse_withDoubleType_expect_longTypeReturned() { + + ScalarType scalarType = factory.typeFor(Double.class, true); + + List input = new ArrayList<>(); + input.add(2D); + input.add(4D); + + String formatToJson = scalarType.format(input); + + Object parsed = scalarType.parse(formatToJson); + assertThat(parsed).isEqualTo(input); + } + + @Test + public void jsonRead_withUuidType() throws IOException { + + ScalarType scalarType = factory.typeFor(UUID.class, true); + + List input = new ArrayList<>(); + input.add(UUID.randomUUID()); + input.add(UUID.randomUUID()); + String asJson = EJson.write(input); + + JsonParser parser = DB.json().createParser(new StringReader(asJson)); + + Object parsed = scalarType.jsonRead(parser); + assertThat(parsed).isEqualTo(input); + } } diff --git a/ebean-core/src/test/java/io/ebeaninternal/server/type/ScalarTypeArraySetH2Test.java b/ebean-core/src/test/java/io/ebeaninternal/server/type/ScalarTypeArraySetH2Test.java index 0e2e14fa9..ece3a122b 100644 --- a/ebean-core/src/test/java/io/ebeaninternal/server/type/ScalarTypeArraySetH2Test.java +++ b/ebean-core/src/test/java/io/ebeaninternal/server/type/ScalarTypeArraySetH2Test.java @@ -1,8 +1,16 @@ package io.ebeaninternal.server.type; +import com.fasterxml.jackson.core.JsonParser; +import io.ebean.DB; +import io.ebean.core.type.ScalarType; +import io.ebean.text.json.EJson; import org.junit.Test; +import java.io.IOException; +import java.io.StringReader; import java.sql.SQLException; +import java.util.LinkedHashSet; +import java.util.Set; import java.util.UUID; import static org.assertj.core.api.Assertions.assertThat; @@ -49,4 +57,82 @@ public class ScalarTypeArraySetH2Test extends BasePlatformArrayTypeFactoryTest { assertBindNullTo_Null(factory.typeFor(UUID.class, true)); } + @Test + @SuppressWarnings("unchecked") + public void parse_withUuidType_expect_uuidTypeReturned() { + + ScalarType scalarType = factory.typeFor(UUID.class, true); + + Set input = new LinkedHashSet<>(); + input.add(UUID.randomUUID()); + input.add(UUID.randomUUID()); + + String formatToJson = scalarType.format(input); + + Set parsed = (Set)scalarType.parse(formatToJson); + assertThat(parsed).isEqualTo(input); + } + + @Test + @SuppressWarnings("unchecked") + public void parse_withIntegerType_expect_longIntegerReturned() { + + ScalarType scalarType = factory.typeFor(Integer.class, true); + + Set input = new LinkedHashSet<>(); + input.add(2); + input.add(4); + + String formatToJson = scalarType.format(input); + + Set parsed = (Set)scalarType.parse(formatToJson); + assertThat(parsed).isEqualTo(input); + } + + @Test + @SuppressWarnings("unchecked") + public void parse_withLongType_expect_longTypeReturned() { + + ScalarType scalarType = factory.typeFor(Long.class, true); + + Set input = new LinkedHashSet<>(); + input.add(2L); + input.add(4L); + + String formatToJson = scalarType.format(input); + + Set parsed = (Set)scalarType.parse(formatToJson); + assertThat(parsed).isEqualTo(input); + } + + @Test + public void parse_withDoubleType_expect_longTypeReturned() { + + ScalarType scalarType = factory.typeFor(Double.class, true); + + Set input = new LinkedHashSet<>(); + input.add(2D); + input.add(4D); + + String formatToJson = scalarType.format(input); + + Object parsed = scalarType.parse(formatToJson); + assertThat(parsed).isEqualTo(input); + } + + @Test + public void jsonRead_withUuidType() throws IOException { + + ScalarType scalarType = factory.typeFor(UUID.class, true); + + Set input = new LinkedHashSet<>(); + input.add(UUID.randomUUID()); + input.add(UUID.randomUUID()); + String asJson = EJson.write(input); + + JsonParser parser = DB.json().createParser(new StringReader(asJson)); + + Object parsed = scalarType.jsonRead(parser); + assertThat(parsed).isEqualTo(input); + } } diff --git a/ebean-core/src/test/java/org/tests/model/array/EArrayBean.java b/ebean-core/src/test/java/org/tests/model/array/EArrayBean.java index 956134f3c..dfe91a27b 100644 --- a/ebean-core/src/test/java/org/tests/model/array/EArrayBean.java +++ b/ebean-core/src/test/java/org/tests/model/array/EArrayBean.java @@ -1,6 +1,7 @@ package org.tests.model.array; +import io.ebean.annotation.Cache; import io.ebean.annotation.DbArray; import io.ebean.annotation.NotNull; @@ -13,6 +14,7 @@ import java.util.Set; import java.util.UUID; @Entity +@Cache public class EArrayBean { enum Status { diff --git a/ebean-core/src/test/java/org/tests/model/array/EArraySetBean.java b/ebean-core/src/test/java/org/tests/model/array/EArraySetBean.java index 585256a79..523fa3436 100644 --- a/ebean-core/src/test/java/org/tests/model/array/EArraySetBean.java +++ b/ebean-core/src/test/java/org/tests/model/array/EArraySetBean.java @@ -1,6 +1,7 @@ package org.tests.model.array; +import io.ebean.annotation.Cache; import io.ebean.annotation.DbArray; import javax.persistence.Entity; @@ -11,6 +12,7 @@ import java.util.Set; import java.util.UUID; @Entity +@Cache public class EArraySetBean { @Id @@ -30,6 +32,9 @@ public class EArraySetBean { @DbArray Set doubs; + @DbArray + Set status; + @Version Long version; @@ -81,6 +86,14 @@ public class EArraySetBean { this.doubs = doubs; } + public Set getStatus() { + return status; + } + + public void setStatus(Set status) { + this.status = status; + } + public Long getVersion() { return version; } diff --git a/ebean-core/src/test/java/org/tests/model/array/TestDbArray_asSet.java b/ebean-core/src/test/java/org/tests/model/array/TestDbArray_asSet.java index 4a1cb7aec..36b917c36 100644 --- a/ebean-core/src/test/java/org/tests/model/array/TestDbArray_asSet.java +++ b/ebean-core/src/test/java/org/tests/model/array/TestDbArray_asSet.java @@ -46,6 +46,11 @@ public class TestDbArray_asSet extends BaseTestCase { bean.getOtherIds().add(97L); bean.setDoubs(doubles); + Set status = new LinkedHashSet<>(); + status.add(EArrayBean.Status.ONE); + status.add(EArrayBean.Status.TWO); + bean.setStatus(status); + Ebean.save(bean); found = Ebean.find(EArraySetBean.class, bean.getId()); @@ -154,4 +159,31 @@ public class TestDbArray_asSet extends BaseTestCase { Ebean.saveAll(all); Ebean.deleteAll(all); } + + @Test + @IgnorePlatform(Platform.HANA) + public void hitCache() { + + Set uids = new LinkedHashSet<>(); + uids.add(UUID.randomUUID()); + uids.add(UUID.randomUUID()); + + Set statuses = new LinkedHashSet<>(); + statuses.add(EArrayBean.Status.ONE); + statuses.add(EArrayBean.Status.THREE); + + EArraySetBean bean = new EArraySetBean(); + bean.setName("hitCache"); + bean.setUids(uids); + bean.setStatus(statuses); + + Ebean.save(bean); + // load cache + Ebean.find(EArraySetBean.class, bean.getId()); + // hit cache + EArraySetBean found = Ebean.find(EArraySetBean.class, bean.getId()); + + assertThat(found.getUids()).isEqualTo(uids); + assertThat(found.getStatus()).isEqualTo(statuses); + } } diff --git a/ebean-core/src/test/java/org/tests/model/array/TestDbArray_basic.java b/ebean-core/src/test/java/org/tests/model/array/TestDbArray_basic.java index 40a10e494..69796b6a3 100644 --- a/ebean-core/src/test/java/org/tests/model/array/TestDbArray_basic.java +++ b/ebean-core/src/test/java/org/tests/model/array/TestDbArray_basic.java @@ -249,4 +249,31 @@ public class TestDbArray_basic extends BaseTestCase { assertThat(found.getIntEnums()).containsExactly(null, IntEnum.ZERO, null, IntEnum.TWO); Ebean.delete(bean); } + + @Test + @IgnorePlatform(Platform.HANA) + public void hitCache() { + + List uids = new ArrayList<>(); + uids.add(UUID.randomUUID()); + uids.add(UUID.randomUUID()); + + List statuses = new ArrayList<>(); + statuses.add(EArrayBean.Status.ONE); + statuses.add(EArrayBean.Status.THREE); + + EArrayBean bean = new EArrayBean(); + bean.setName("hitCache"); + bean.setUids(uids); + bean.setStatuses(statuses); + + Ebean.save(bean); + // load cache + Ebean.find(EArrayBean.class, bean.getId()); + // hit cache + EArrayBean found = Ebean.find(EArrayBean.class, bean.getId()); + + assertThat(found.getUids()).isEqualTo(uids); + assertThat(found.getStatuses()).isEqualTo(statuses); + } }