EnumTypeHandler.java
package nz.co.gregs.dbvolution.internal.properties;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.WildcardType;
import nz.co.gregs.dbvolution.datatypes.DBEnum;
import nz.co.gregs.dbvolution.datatypes.DBEnumValue;
import nz.co.gregs.dbvolution.exceptions.InvalidDeclaredTypeException;
/**
* Handles reflection of generics on field/properties of type {@link DBEnum}.
* Identifies the exact enum type from the field or property declaration.
*
* <p>
* A generic parameter to the {@link DBEnum} field type is mandatory if the QDT
* type is {@code DBEnum}.
*
* <p style="color: #F90;">Support DBvolution at
* <a href="http://patreon.com/dbvolution" target=new>Patreon</a></p>
*
* @author Malcolm Lett
*/
class EnumTypeHandler<BASETYPE> implements Serializable{
private static final long serialVersionUID = 1l;
private final Class<? extends Enum<?>> enumType; // null if not present on property
private final Class<?> enumLiteralValueType; // null if not present or not able to be inferred
@SuppressWarnings("unchecked")
EnumTypeHandler(JavaProperty<BASETYPE> javaProperty, ColumnHandler<?> columnHandler) {
Type type = javaProperty.genericType();
Class<?> propertyClass = classOf(type);
Class<? extends Enum<?>> identifiedEnumType = null;
Class<?> identifiedEnumLiteralValueType = null;
if (columnHandler.isColumn() && propertyClass != null && DBEnum.class.isAssignableFrom(propertyClass)) {
if (type instanceof ParameterizedType) {
Type[] parameterTypes = ((ParameterizedType) type).getActualTypeArguments();
if (parameterTypes.length >= 1) {
identifiedEnumType = (Class<? extends Enum<?>>) classOf(parameterTypes[0]);
}
} else if (type instanceof WildcardType) {
throw new InvalidDeclaredTypeException(
"Wildcard generics must not be used on " + propertyClass.getSimpleName()
+ " declaration for " + javaProperty);
}
if (identifiedEnumType == null) {
throw new InvalidDeclaredTypeException(
"Use of " + propertyClass.getSimpleName() + " declaration requires concrete generic parameter"
+ " on " + javaProperty);
} else {
identifiedEnumLiteralValueType = enumLiteralValueTypeOf(identifiedEnumType);
}
}
this.enumType = identifiedEnumType;
this.enumLiteralValueType = identifiedEnumLiteralValueType;
}
/**
* Gets the enum type, or null if not appropriate. Null if not a column.
*
* <p style="color: #F90;">Support DBvolution at
* <a href="http://patreon.com/dbvolution" target=new>Patreon</a></p>
*
* @return the enum type, which will also implement {@link DBEnumValue}
*/
public Class<? extends Enum<?>> getEnumType() {
return enumType;
}
/**
* Gets the type of the code supplied by enum values. This is derived from the
* {@link DBEnumValue} implementation in the enum. Null if not a column.
*
* <p style="color: #F90;">Support DBvolution at
* <a href="http://patreon.com/dbvolution" target=new>Patreon</a></p>
*
* @return null if not appropriate, or not able to be inferred
*/
public Class<?> getEnumLiteralValueType() {
return enumLiteralValueType;
}
// reflection helper method
private static Class<?> classOf(Type type) {
if (type instanceof Class) {
return (Class<?>) type;
} else if (type instanceof ParameterizedType) {
return classOf(((ParameterizedType) type).getRawType());
} else {
return null;
}
}
/**
* Determines the type of literal code values for the given enum type.
*
* <p style="color: #F90;">Support DBvolution at
* <a href="http://patreon.com/dbvolution" target=new>Patreon</a></p>
*
* @return Ummm...
*/
private static Class<?> enumLiteralValueTypeOf(Class<? extends Enum<?>> enumType) {
Enum<?>[] enumValues = enumType.getEnumConstants();
if (enumValues != null) {
for (Enum<?> enumValue : enumValues) {
if (enumValue instanceof DBEnumValue) {
Object code = ((DBEnumValue<?>) enumValue).getCode();
if (code != null) {
return code.getClass();
}
}
}
}
return null;
}
}