diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/DeployUtil.java b/src/main/java/io/ebeaninternal/server/deploy/parse/DeployUtil.java
index ffcb90591..8f524f1ac 100644
--- a/src/main/java/io/ebeaninternal/server/deploy/parse/DeployUtil.java
+++ b/src/main/java/io/ebeaninternal/server/deploy/parse/DeployUtil.java
@@ -18,7 +18,6 @@ import io.ebeaninternal.server.deploy.meta.DeployBeanProperty;
import io.ebeaninternal.server.type.DataEncryptSupport;
import io.ebeaninternal.server.type.ScalarType;
import io.ebeaninternal.server.type.ScalarTypeArray;
-import io.ebeaninternal.server.type.ScalarTypeEnumStandard;
import io.ebeaninternal.server.type.SimpleAesEncryptor;
import io.ebeaninternal.server.type.TypeManager;
import org.slf4j.Logger;
@@ -121,14 +120,8 @@ public class DeployUtil {
if (scalarType == null) {
// look for @DbEnumValue or @EnumValue annotations etc
Class extends Enum>> enumClass = (Class extends Enum>>) enumType;
- scalarType = typeManager.createEnumScalarType(enumClass);
- if (scalarType == null) {
- // use JPA normal Enum type (without mapping)
- EnumType type = enumerated != null ? enumerated.value() : null;
- scalarType = createEnumScalarTypePerSpec(enumType, type);
- }
-
- typeManager.addEnumType(scalarType, enumClass);
+ EnumType type = enumerated != null ? enumerated.value() : null;
+ scalarType = typeManager.createEnumScalarType(enumClass, type);
}
prop.setScalarType(scalarType);
prop.setDbType(scalarType.getJdbcType());
@@ -145,20 +138,6 @@ public class DeployUtil {
&& scalarType.getJdbcType() != Types.VARCHAR;
}
- private ScalarType> createEnumScalarTypePerSpec(Class> enumType, EnumType type) {
-
- if (type == null) {
- // default as per spec is ORDINAL
- return new ScalarTypeEnumStandard.OrdinalEnum(enumType);
-
- } else if (type == EnumType.ORDINAL) {
- return new ScalarTypeEnumStandard.OrdinalEnum(enumType);
-
- } else {
- return new ScalarTypeEnumStandard.StringEnum(enumType);
- }
- }
-
/**
* Find the ScalarType for this property.
*
diff --git a/src/main/java/io/ebeaninternal/server/type/ArrayElementConverter.java b/src/main/java/io/ebeaninternal/server/type/ArrayElementConverter.java
index 9cad99fc8..e13a7d212 100644
--- a/src/main/java/io/ebeaninternal/server/type/ArrayElementConverter.java
+++ b/src/main/java/io/ebeaninternal/server/type/ArrayElementConverter.java
@@ -12,6 +12,10 @@ interface ArrayElementConverter {
*/
T toElement(Object rawValue);
+ default Object[] toDbArray(Object[] objects) {
+ return objects;
+ }
+
/**
* The UUID converter implementation.
*/
@@ -94,4 +98,30 @@ interface ArrayElementConverter {
}
}
+ /**
+ * String converter (noop based).
+ */
+ class EnumConverter implements ArrayElementConverter {
+
+ private final ScalarType> scalarType;
+
+ EnumConverter(ScalarType> scalarType) {
+ this.scalarType = scalarType;
+ }
+
+ @Override
+ public Object toElement(Object rawValue) {
+ return scalarType.parse(rawValue.toString());
+ }
+
+ @Override
+ public Object[] toDbArray(Object[] objects) {
+ Object[] dbArray = new Object[objects.length];
+ for (int i = 0; i < objects.length; i++) {
+ dbArray[i] = scalarType.format(objects[i]);
+ }
+ return dbArray;
+ }
+ }
+
}
diff --git a/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java b/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java
index bbb81b501..439b4f347 100644
--- a/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java
+++ b/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java
@@ -1,22 +1,22 @@
package io.ebeaninternal.server.type;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
import io.ebean.annotation.DbArray;
import io.ebean.annotation.DbEnumType;
import io.ebean.annotation.DbEnumValue;
import io.ebean.annotation.EnumValue;
-import io.ebean.config.JsonConfig;
import io.ebean.annotation.Platform;
+import io.ebean.config.JsonConfig;
import io.ebean.config.ScalarTypeConverter;
import io.ebean.config.ServerConfig;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.config.dbplatform.DbPlatformType;
import io.ebean.util.AnnotationUtil;
-import io.ebeaninternal.dbmigration.DbOffline;
import io.ebeaninternal.api.ExtraTypeFactory;
+import io.ebeaninternal.dbmigration.DbOffline;
import io.ebeaninternal.server.core.bootup.BootupClasses;
import io.ebeanservice.docstore.api.mapping.DocPropertyType;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.joda.time.LocalDateTime;
@@ -25,6 +25,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.persistence.AttributeConverter;
+import javax.persistence.EnumType;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
@@ -337,12 +338,18 @@ public final class DefaultTypeManager implements TypeManager {
Type valueType = getValueType(genericType);
if (type.equals(List.class)) {
if (arrayTypeListFactory != null) {
+ if(isEnumType(valueType)) {
+ return arrayTypeListFactory.typeForEnum(createEnumScalarType(asEnumClass(valueType), EnumType.STRING));
+ }
return arrayTypeListFactory.typeFor(valueType);
}
// fallback to JSON storage in VARCHAR column
return new ScalarTypeJsonList.Varchar(getDocType(valueType));
} else if (type.equals(Set.class)) {
if (arrayTypeSetFactory != null) {
+ if(isEnumType(valueType)) {
+ return arrayTypeSetFactory.typeForEnum(createEnumScalarType(asEnumClass(valueType), EnumType.STRING));
+ }
return arrayTypeSetFactory.typeFor(valueType);
}
// fallback to JSON storage in VARCHAR column
@@ -351,6 +358,15 @@ public final class DefaultTypeManager implements TypeManager {
throw new IllegalStateException("Type [" + type + "] not supported for @DbArray");
}
+ @SuppressWarnings("unchecked")
+ private Class extends Enum>> asEnumClass(Type valueType) {
+ return (Class extends Enum>>)valueType;
+ }
+
+ private boolean isEnumType(Type valueType) {
+ return valueType instanceof Class && ((Class>)valueType).isEnum();
+ }
+
@Override
public ScalarType> getJsonScalarType(Class> type, int dbType, int dbLength, Type genericType) {
@@ -571,7 +587,36 @@ public final class DefaultTypeManager implements TypeManager {
*
*/
@Override
- public ScalarType> createEnumScalarType(Class extends Enum>> enumType) {
+ public ScalarType> createEnumScalarType(Class extends Enum>> enumType, EnumType type) {
+
+ ScalarType> scalarType = getScalarType(enumType);
+ if (scalarType != null) {
+ return scalarType;
+ }
+
+ scalarType = createEnumScalarTypePerExtentions(enumType);
+ if (scalarType == null) {
+ // use JPA normal Enum type (without mapping)
+ scalarType = createEnumScalarTypePerSpec(enumType, type);
+ }
+ addEnumType(scalarType, enumType);
+ return scalarType;
+ }
+
+ private ScalarType> createEnumScalarTypePerSpec(Class> enumType, EnumType type) {
+ if (type == null) {
+ // default as per spec is ORDINAL
+ return new ScalarTypeEnumStandard.OrdinalEnum(enumType);
+
+ } else if (type == EnumType.ORDINAL) {
+ return new ScalarTypeEnumStandard.OrdinalEnum(enumType);
+
+ } else {
+ return new ScalarTypeEnumStandard.StringEnum(enumType);
+ }
+ }
+
+ private ScalarType> createEnumScalarTypePerExtentions(Class extends Enum>> enumType) {
Method[] methods = enumType.getMethods();
for (Method method : methods) {
diff --git a/src/main/java/io/ebeaninternal/server/type/PlatformArrayTypeFactory.java b/src/main/java/io/ebeaninternal/server/type/PlatformArrayTypeFactory.java
index 90251fae7..11bcf8613 100644
--- a/src/main/java/io/ebeaninternal/server/type/PlatformArrayTypeFactory.java
+++ b/src/main/java/io/ebeaninternal/server/type/PlatformArrayTypeFactory.java
@@ -12,4 +12,8 @@ public interface PlatformArrayTypeFactory {
*/
ScalarType> typeFor(Type valueType);
+ /**
+ * Return the ScalarType to handle DB ARRAY for the given enum element type.
+ */
+ ScalarType> typeForEnum(ScalarType> scalarType);
}
diff --git a/src/main/java/io/ebeaninternal/server/type/ScalarTypeArrayList.java b/src/main/java/io/ebeaninternal/server/type/ScalarTypeArrayList.java
index 9673c39c1..424f8da8b 100644
--- a/src/main/java/io/ebeaninternal/server/type/ScalarTypeArrayList.java
+++ b/src/main/java/io/ebeaninternal/server/type/ScalarTypeArrayList.java
@@ -1,11 +1,11 @@
package io.ebeaninternal.server.type;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonParser;
import io.ebean.text.json.EJson;
import io.ebeaninternal.json.ModifyAwareList;
import io.ebeanservice.docstore.api.mapping.DocPropertyType;
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.core.JsonParser;
import javax.persistence.PersistenceException;
import java.io.IOException;
@@ -57,6 +57,12 @@ public class ScalarTypeArrayList extends ScalarTypeJsonCollection implemen
}
throw new IllegalArgumentException("Type [" + valueType + "] not supported for @DbArray mapping");
}
+
+ @Override
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public ScalarTypeArrayList typeForEnum(ScalarType> scalarType) {
+ return new ScalarTypeArrayList("varchar", DocPropertyType.TEXT, new ArrayElementConverter.EnumConverter(scalarType));
+ }
}
private final String arrayType;
@@ -92,7 +98,7 @@ public class ScalarTypeArrayList extends ScalarTypeJsonCollection implemen
}
protected Object[] toArray(List value) {
- return value.toArray();
+ return converter.toDbArray(value.toArray());
}
@Override
diff --git a/src/main/java/io/ebeaninternal/server/type/ScalarTypeArrayListH2.java b/src/main/java/io/ebeaninternal/server/type/ScalarTypeArrayListH2.java
index f41dd0418..e793a86f2 100644
--- a/src/main/java/io/ebeaninternal/server/type/ScalarTypeArrayListH2.java
+++ b/src/main/java/io/ebeaninternal/server/type/ScalarTypeArrayListH2.java
@@ -46,6 +46,11 @@ class ScalarTypeArrayListH2 extends ScalarTypeArrayList {
}
throw new IllegalArgumentException("Type [" + valueType + "] not supported for @DbArray mapping");
}
+
+ @Override
+ public ScalarType> typeForEnum(ScalarType> scalarType) {
+ return new ScalarTypeArrayListH2("varchar", DocPropertyType.TEXT, new ArrayElementConverter.EnumConverter(scalarType));
+ }
}
@SuppressWarnings("rawtypes")
diff --git a/src/main/java/io/ebeaninternal/server/type/ScalarTypeArraySet.java b/src/main/java/io/ebeaninternal/server/type/ScalarTypeArraySet.java
index d12cea509..29fc9d0f8 100644
--- a/src/main/java/io/ebeaninternal/server/type/ScalarTypeArraySet.java
+++ b/src/main/java/io/ebeaninternal/server/type/ScalarTypeArraySet.java
@@ -56,6 +56,12 @@ public class ScalarTypeArraySet extends ScalarTypeJsonCollection> impl
}
throw new IllegalArgumentException("Type [" + valueType + "] not supported for @DbArray mapping on set");
}
+
+ @Override
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public ScalarTypeArraySet typeForEnum(ScalarType> scalarType) {
+ return new ScalarTypeArraySet("varchar", DocPropertyType.TEXT, new ArrayElementConverter.EnumConverter(scalarType));
+ }
}
private final String arrayType;
@@ -91,7 +97,7 @@ public class ScalarTypeArraySet extends ScalarTypeJsonCollection> impl
}
protected Object[] toArray(Set value) {
- return value.toArray();
+ return converter.toDbArray(value.toArray());
}
@Override
diff --git a/src/main/java/io/ebeaninternal/server/type/ScalarTypeArraySetH2.java b/src/main/java/io/ebeaninternal/server/type/ScalarTypeArraySetH2.java
index 03aa65a6c..2c7ac0123 100644
--- a/src/main/java/io/ebeaninternal/server/type/ScalarTypeArraySetH2.java
+++ b/src/main/java/io/ebeaninternal/server/type/ScalarTypeArraySetH2.java
@@ -28,6 +28,7 @@ class ScalarTypeArraySetH2 extends ScalarTypeArraySet {
* Return the ScalarType to use based on the List's generic parameter type.
*/
@Override
+ @SuppressWarnings("unchecked")
public ScalarTypeArraySetH2> typeFor(Type valueType) {
if (valueType.equals(java.util.UUID.class)) {
return UUID;
@@ -46,9 +47,15 @@ class ScalarTypeArraySetH2 extends ScalarTypeArraySet {
}
throw new IllegalArgumentException("Type [" + valueType + "] not supported for @DbArray mapping");
}
+
+ @Override
+ public ScalarTypeArraySetH2 typeForEnum(ScalarType> scalarType) {
+ return new ScalarTypeArraySetH2("varchar", DocPropertyType.TEXT, new ArrayElementConverter.EnumConverter(scalarType));
+ }
}
- private ScalarTypeArraySetH2(String arrayType, DocPropertyType docPropertyType, ArrayElementConverter converter) {
+ @SuppressWarnings("unchecked")
+ private ScalarTypeArraySetH2(String arrayType, DocPropertyType docPropertyType, ArrayElementConverter converter) {
super(arrayType, docPropertyType, converter);
}
diff --git a/src/main/java/io/ebeaninternal/server/type/TypeManager.java b/src/main/java/io/ebeaninternal/server/type/TypeManager.java
index 9e5e39aec..15827cfbe 100644
--- a/src/main/java/io/ebeaninternal/server/type/TypeManager.java
+++ b/src/main/java/io/ebeaninternal/server/type/TypeManager.java
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.type;
import io.ebean.annotation.DbArray;
+import javax.persistence.EnumType;
import java.lang.reflect.Type;
/**
@@ -43,7 +44,7 @@ public interface TypeManager {
* Create a ScalarType for an Enum using a mapping (rather than JPA Ordinal
* or String which has limitations).
*/
- ScalarType> createEnumScalarType(Class extends Enum>> enumType);
+ ScalarType> createEnumScalarType(Class extends Enum>> enumType, EnumType enumerated);
/**
* Return the ScalarType used to handle JSON content.
diff --git a/src/test/java/io/ebean/server/type/TestTypeManager.java b/src/test/java/io/ebean/server/type/TestTypeManager.java
index cace36412..4e552b69f 100644
--- a/src/test/java/io/ebean/server/type/TestTypeManager.java
+++ b/src/test/java/io/ebean/server/type/TestTypeManager.java
@@ -7,10 +7,10 @@ import io.ebeaninternal.server.core.bootup.BootupClasses;
import io.ebeaninternal.server.type.DefaultTypeManager;
import io.ebeaninternal.server.type.RsetDataReader;
import io.ebeaninternal.server.type.ScalarType;
-import org.tests.model.ivo.Money;
-import org.tests.model.ivo.converter.MoneyTypeConverter;
import org.junit.Assert;
import org.junit.Test;
+import org.tests.model.ivo.Money;
+import org.tests.model.ivo.converter.MoneyTypeConverter;
import java.sql.SQLException;
import java.sql.Types;
@@ -24,7 +24,7 @@ public class TestTypeManager extends BaseTestCase {
DefaultTypeManager typeManager = createTypeManager();
- ScalarType> type = typeManager.createEnumScalarType(MyEnum.class);
+ ScalarType> type = typeManager.createEnumScalarType(MyEnum.class, null);
typeManager.addEnumType(type, MyEnum.class);
Object val = type.read(new DummyDataReader("A"));
@@ -49,7 +49,7 @@ public class TestTypeManager extends BaseTestCase {
DefaultTypeManager typeManager = createTypeManager();
- ScalarType> dayOfWeekType = typeManager.createEnumScalarType(MyDayOfWeek.class);
+ ScalarType> dayOfWeekType = typeManager.createEnumScalarType(MyDayOfWeek.class, null);
Object val = dayOfWeekType.read(new DummyDataReader("MONDAY "));
assertThat(val).isEqualTo(MyDayOfWeek.MONDAY);
diff --git a/src/test/java/org/tests/model/array/EArrayBean.java b/src/test/java/org/tests/model/array/EArrayBean.java
index 417b9345a..853fe9976 100644
--- a/src/test/java/org/tests/model/array/EArrayBean.java
+++ b/src/test/java/org/tests/model/array/EArrayBean.java
@@ -8,11 +8,16 @@ import javax.persistence.Id;
import javax.persistence.Version;
import java.util.ArrayList;
import java.util.List;
+import java.util.Set;
import java.util.UUID;
@Entity
public class EArrayBean {
+ enum Status {
+ ONE, TWO, THREE
+ }
+
@Id
Long id;
@@ -30,6 +35,12 @@ public class EArrayBean {
@DbArray
List doubs;
+ @DbArray
+ List statuses;
+
+ @DbArray
+ Set status2;
+
@Version
Long version;
@@ -81,6 +92,23 @@ public class EArrayBean {
this.doubs = doubs;
}
+ public List getStatuses() {
+ return statuses;
+ }
+
+ public void setStatuses(List statuses) {
+ this.statuses = statuses;
+ }
+
+
+ public Set getStatus2() {
+ return status2;
+ }
+
+ public void setStatus2(Set status2) {
+ this.status2 = status2;
+ }
+
public Long getVersion() {
return version;
}
diff --git a/src/test/java/org/tests/model/array/TestDbArray_basic.java b/src/test/java/org/tests/model/array/TestDbArray_basic.java
index 92c4f0bdc..e816edc86 100644
--- a/src/test/java/org/tests/model/array/TestDbArray_basic.java
+++ b/src/test/java/org/tests/model/array/TestDbArray_basic.java
@@ -7,7 +7,9 @@ import org.ebeantest.LoggedSqlCollector;
import org.junit.Test;
import java.util.ArrayList;
+import java.util.LinkedHashSet;
import java.util.List;
+import java.util.Set;
import java.util.UUID;
import static org.assertj.core.api.Assertions.assertThat;
@@ -39,6 +41,13 @@ public class TestDbArray_basic extends BaseTestCase {
bean.getOtherIds().add(96L);
bean.getOtherIds().add(97L);
bean.setDoubs(doubles);
+ bean.setStatuses(new ArrayList<>());
+ bean.getStatuses().add(EArrayBean.Status.ONE);
+ bean.getStatuses().add(EArrayBean.Status.THREE);
+
+ bean.setStatus2(new LinkedHashSet<>());
+ bean.getStatus2().add(EArrayBean.Status.TWO);
+ bean.getStatus2().add(EArrayBean.Status.ONE);
Ebean.save(bean);
@@ -53,10 +62,18 @@ public class TestDbArray_basic extends BaseTestCase {
.arrayContains("uids", bean.getUids().get(0))
.arrayContains("phoneNumbers", "9823")
.arrayIsNotEmpty("phoneNumbers")
+ .arrayContains("statuses", EArrayBean.Status.ONE)
+ .arrayContains("status2", EArrayBean.Status.TWO)
.query();
List list = query.findList();
+ List statuses = list.get(0).getStatuses();
+ Set status2 = list.get(0).getStatus2();
+
+ assertThat(statuses).contains(EArrayBean.Status.ONE, EArrayBean.Status.THREE);
+ assertThat(status2).contains(EArrayBean.Status.ONE, EArrayBean.Status.TWO);
+
assertThat(query.getGeneratedSql()).contains(" t0.other_ids @> array[?,?]::bigint[] ");
assertThat(query.getGeneratedSql()).contains(" t0.uids @> array[?] ");
assertThat(query.getGeneratedSql()).contains(" t0.phone_numbers @> array[?] ");