#1259 - Throw explicit mapping error when an Enum is mapped to both ORDINAL and STRING

This commit is contained in:
Rob Bygrave
2018-02-14 12:39:35 +13:00
parent b2967dec1e
commit 7c477827fe
9 changed files with 176 additions and 38 deletions
@@ -112,30 +112,16 @@ public class DeployUtil {
if (!enumType.isEnum()) {
throw new IllegalArgumentException("Class [" + enumType + "] is Not a Enum?");
}
ScalarType<?> scalarType = typeManager.getScalarType(enumType);
if (enumOverrideDefaultMapping(enumerated, scalarType)) {
logger.debug("override default enum mapping for type {}", enumType);
scalarType = null;
}
if (scalarType == null) {
// look for @DbEnumValue or @EnumValue annotations etc
Class<? extends Enum<?>> enumClass = (Class<? extends Enum<?>>) enumType;
EnumType type = enumerated != null ? enumerated.value() : null;
scalarType = typeManager.createEnumScalarType(enumClass, type);
}
prop.setScalarType(scalarType);
prop.setDbType(scalarType.getJdbcType());
}
try {
Class<? extends Enum<?>> enumClass = (Class<? extends Enum<?>>) enumType;
EnumType type = enumerated != null ? enumerated.value() : null;
ScalarType<?> scalarType = typeManager.createEnumScalarType(enumClass, type);
prop.setScalarType(scalarType);
prop.setDbType(scalarType.getJdbcType());
/**
* Return true if there is an existing default mapping for the enum that needs
* to be overridden (for example, DayOfWeek defaults to Integer mapping 1 to 7
* and some might want this mapped to 'MONDAY' etc).
*/
private boolean enumOverrideDefaultMapping(Enumerated enumerated, ScalarType<?> scalarType) {
return enumerated != null && scalarType != null
&& enumerated.value() == EnumType.STRING
&& scalarType.getJdbcType() != Types.VARCHAR;
} catch (IllegalStateException e) {
throw new PersistenceException("Error mapping property " + prop.getFullBeanName() + " - " + e.getMessage());
}
}
/**
@@ -304,7 +290,7 @@ public class DeployUtil {
prop.setScalarType(scalarType);
}
public boolean isClobType(Class<?> type) {
private boolean isClobType(Class<?> type) {
return type.equals(String.class);
}
@@ -271,6 +271,7 @@ public final class DefaultTypeManager implements TypeManager {
public void addEnumType(ScalarType<?> scalarType, Class<? extends Enum> enumClass) {
Set<Class<?>> mappedClasses = new HashSet<>();
mappedClasses.add(enumClass);
for (Object value : EnumSet.allOf(enumClass).toArray()) {
mappedClasses.add(value.getClass());
}
@@ -552,7 +553,7 @@ public final class DefaultTypeManager implements TypeManager {
* Return null if the EnumValue annotations are not present/used.
* </p>
*/
private ScalarType<?> createEnumScalarType2(Class<?> enumType) {
private ScalarTypeEnum<?> createEnumScalarType2(Class<?> enumType) {
boolean integerType = true;
@@ -589,8 +590,11 @@ public final class DefaultTypeManager implements TypeManager {
@Override
public ScalarType<?> createEnumScalarType(Class<? extends Enum<?>> enumType, EnumType type) {
ScalarType<?> scalarType = getScalarType(enumType);
if (scalarType != null) {
ScalarTypeEnum<?> scalarType = (ScalarTypeEnum<?>) getScalarType(enumType);
if (scalarType != null && !scalarType.isOverrideBy(type)) {
if (type != null && !scalarType.isCompatible(type)) {
throw new IllegalStateException("Error mapping Enum type:"+enumType+" It is mapped using 2 different modes when only one is supported (ORDINAL, STRING or an Ebean mapping)");
}
return scalarType;
}
@@ -603,7 +607,7 @@ public final class DefaultTypeManager implements TypeManager {
return scalarType;
}
private ScalarType<?> createEnumScalarTypePerSpec(Class<?> enumType, EnumType type) {
private ScalarTypeEnum<?> createEnumScalarTypePerSpec(Class<?> enumType, EnumType type) {
if (type == null) {
// default as per spec is ORDINAL
return new ScalarTypeEnumStandard.OrdinalEnum(enumType);
@@ -616,7 +620,7 @@ public final class DefaultTypeManager implements TypeManager {
}
}
private ScalarType<?> createEnumScalarTypePerExtentions(Class<? extends Enum<?>> enumType) {
private ScalarTypeEnum<?> createEnumScalarTypePerExtentions(Class<? extends Enum<?>> enumType) {
Method[] methods = enumType.getMethods();
for (Method method : methods) {
@@ -638,7 +642,7 @@ public final class DefaultTypeManager implements TypeManager {
* Return null if the EnumValue annotations are not present/used.
* </p>
*/
private ScalarType<?> createEnumScalarTypeDbValue(Class<? extends Enum<?>> enumType, Method method, boolean integerType) {
private ScalarTypeEnum<?> createEnumScalarTypeDbValue(Class<? extends Enum<?>> enumType, Method method, boolean integerType) {
Map<String, String> nameValueMap = new HashMap<>();
@@ -664,7 +668,7 @@ public final class DefaultTypeManager implements TypeManager {
* length create the ScalarType for the Enum.
*/
@SuppressWarnings({"unchecked", "rawtypes"})
private ScalarType<?> createEnumScalarType(Class enumType, Map<String, String> nameValueMap, boolean integerType, int dbColumnLength) {
private ScalarTypeEnum<?> createEnumScalarType(Class enumType, Map<String, String> nameValueMap, boolean integerType, int dbColumnLength) {
EnumToDbValueMap<?> beanDbMap = EnumToDbValueMap.create(integerType);
@@ -1,5 +1,6 @@
package io.ebeaninternal.server.type;
import javax.persistence.EnumType;
import java.sql.SQLException;
import java.sql.Types;
import java.time.DayOfWeek;
@@ -22,6 +23,14 @@ public class ScalarTypeDayOfWeek extends ScalarTypeEnumWithMapping {
super(beanDbMap, DayOfWeek.class, 1);
}
/**
* We allow this to be overridden by a JPA EnumType.
*/
@Override
public boolean isOverrideBy(EnumType type) {
return type != null;
}
/**
* Bind DayOfWeek enum using getValue().
*/
@@ -1,15 +1,29 @@
package io.ebeaninternal.server.type;
import javax.persistence.EnumType;
import java.util.Set;
/**
* Marker interface for the Enum scalar types.
*/
public interface ScalarTypeEnum {
public interface ScalarTypeEnum<T> extends ScalarType<T> {
/**
* Return the IN values for DB constraint construction.
*/
Set<String> getDbCheckConstraintValues();
/**
* Return true if we allow this scalar enum type to be overridden.
* Ability to override the built-in support for java time DayOfWeek and Month.
*/
default boolean isOverrideBy(EnumType type) {
return false;
}
/**
* Return true if the scalar type is compatible with the specified enum type.
*/
boolean isCompatible(EnumType enumType);
}
@@ -5,6 +5,7 @@ import com.fasterxml.jackson.core.JsonParser;
import io.ebean.text.TextException;
import io.ebeanservice.docstore.api.mapping.DocPropertyType;
import javax.persistence.EnumType;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
@@ -40,6 +41,11 @@ public class ScalarTypeEnumStandard {
this.length = maxValueLength(enumType);
}
@Override
public boolean isCompatible(EnumType enumType) {
return EnumType.STRING == enumType;
}
/**
* Return the IN values for DB constraint construction.
*/
@@ -128,6 +134,11 @@ public class ScalarTypeEnumStandard {
this.enumArray = EnumSet.allOf(enumType).toArray();
}
@Override
public boolean isCompatible(EnumType enumType) {
return EnumType.ORDINAL == enumType;
}
/**
* Return the IN values for DB constraint construction.
*/
@@ -1,5 +1,6 @@
package io.ebeaninternal.server.type;
import javax.persistence.EnumType;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.LinkedHashSet;
@@ -24,6 +25,11 @@ public class ScalarTypeEnumWithMapping extends ScalarTypeEnumStandard.EnumBase i
this.length = length;
}
@Override
public boolean isCompatible(EnumType enumType) {
return enumType == null;
}
@Override
public long asVersion(Object value) {
throw new RuntimeException("not supported");
@@ -1,5 +1,6 @@
package io.ebeaninternal.server.type;
import javax.persistence.EnumType;
import java.sql.SQLException;
import java.sql.Types;
import java.time.Month;
@@ -22,6 +23,14 @@ public class ScalarTypeMonth extends ScalarTypeEnumWithMapping {
super(beanDbMap, Month.class, 1);
}
/**
* We allow this to be overridden by a JPA EnumType.
*/
@Override
public boolean isOverrideBy(EnumType type) {
return type != null;
}
/**
* Bind Month enum value.
*/