MorphToNumber.java

package org.klojang.convert;

import static org.klojang.util.ArrayMethods.refIndexOf;
import static org.klojang.util.ClassMethods.box;
import static org.klojang.convert.Morph.stringify;

import org.klojang.util.ClassMethods;

/*
 * Used to morph objects into primitives and primitive wrapper types. Also used to
 * convert to {@code BigDecimal} and {@code BigInteger}. It's pointless to try and
 * use generics here. It will fight you. Too much dynamic stuff going on.
 */
@SuppressWarnings({"rawtypes", "unchecked"})
final class MorphToNumber {

  private MorphToNumber() {
    throw new UnsupportedOperationException();
  }

  static Object morph(Object obj, Class toType) {
    Class type = box(toType);
    if (type == Boolean.class) {
      return Bool.from(obj);
    } else if (type == Character.class) {
      return toChar(obj, toType);
    } else if (ClassMethods.isSubtype(type, Number.class)) {
      return toNumber(obj, type);
    }
    return null;
  }

  private static Number toNumber(Object obj, Class toType) {
    Class myType = obj.getClass();
    if (ClassMethods.isSubtype(myType, Number.class)) {
      return NumberMethods.convert((Number) obj, toType);
    } else if (myType.isEnum()) {
      return refIndexOf(myType.getEnumConstants(), obj);
    } else if (myType == Character.class) {
      return charToNumber(obj, box(toType));
    }
    return NumberMethods.parse(stringify(obj), toType);
  }

  private static Character toChar(Object obj, Class toType) {
    if (obj.getClass() == Boolean.class) {
      return (Boolean) obj ? '1' : '0';
    }
    String s = stringify(obj);
    if (s.length() == 1) {
      return s.charAt(0);
    }
    throw new TypeConversionException(obj,
        toType,
        "String length exceeds 1: %s",
        obj);
  }

  private static Number charToNumber(Object obj, Class targetType) {
    char c = (Character) obj;
    if (c >= '0' && c <= '9') {
      return NumberMethods.convert(c - 48, targetType);
    }
    throw new TypeConversionException(obj, targetType);
  }

}