package br.com.caelum.iogi.conversion;
import br.com.caelum.iogi.exceptions.ConversionException;
import br.com.caelum.iogi.reflection.Target;
public class EnumConverter extends TypeConverter<Object> {
public boolean isAbleToInstantiate(final Target<?> target) {
return Enum.class.isAssignableFrom(target.getClassType());
}
@Override
protected Object convert(final String stringValue, final Target<?> to) {
ensureTargetIsAnEnum(to);
final Class<?> enumClass = to.getClassType();
if (isNumber(stringValue))
return instantiateFromOrdinal(enumClass, stringValue, to);
else
return instantiateFromName(enumClass, stringValue, to);
}
private void ensureTargetIsAnEnum(final Target<?> to) {
if (!Enum.class.isAssignableFrom(to.getClassType()))
throw new ConversionException("Target %s does not represent a Java enum.", to);
}
private boolean isNumber(final String stringValue) {
for (int i = 0; i < stringValue.length(); i++)
if (!Character.isDigit(stringValue.charAt(i)))
return false;
return true;
}
private Object instantiateFromOrdinal(final Class<?> enumClass, final String ordinalAsString, final Target<?> to) {
try {
final Object[] enumConstants = enumClass.getEnumConstants();
final int ordinal = Integer.parseInt(ordinalAsString);
return enumConstants[ordinal];
} catch (final Exception e) {
throw new ConversionException("Failed to interpret '%s' as an ordinal index into enum '%s' " +
"(when trying to fulfill target %s)",
ordinalAsString, enumClass.getName(), to);
}
}
@SuppressWarnings({ "unchecked", "rawtypes" }) //SupressWarnings ok because at this point we know type is an Enum
private Object instantiateFromName(final Class<?> type, final String name, final Target<?> to) {
try {
final Class<? extends Enum> enumClass = (Class<? extends Enum>) type;
return Enum.valueOf(enumClass, name);
} catch (final IllegalArgumentException iae) {
throw new ConversionException("Attempted to convert '%s' to an enum value of type '%s' " +
"(when trying to fulfill target %s)",
name, type.getName(), to);
}
}
}