package jef.tools.reflect;
import java.lang.reflect.Array;
import java.lang.reflect.Type;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.management.ReflectionException;
import jef.common.Entry;
import jef.common.Node;
import jef.common.log.LogUtil;
import jef.http.client.support.CommentEntry;
import jef.tools.ArrayUtils;
import jef.tools.DateUtils;
import jef.tools.StringUtils;
import jef.tools.collection.CollectionUtils;
import jef.tools.reflect.convert.Converter;
import org.apache.commons.lang.ObjectUtils;
/**
* 数据类型转换工具类
* @author jiyi
*
*/
public final class ConvertUtils {
private static final Converter<Long> N2J = new Converter<Long>() {
public Long apply(Object input) {
return ((Number) input).longValue();
}
public boolean accept(Object v) {
return v instanceof Number;
}
};
private static final Converter<Integer> N2I = new Converter<Integer>() {
public Integer apply(Object input) {
return ((Number) input).intValue();
}
public boolean accept(Object v) {
return v instanceof Number;
}
};
private static final Converter<Short> N2S = new Converter<Short>() {
public Short apply(Object input) {
return ((Number) input).shortValue();
}
public boolean accept(Object v) {
return v instanceof Number;
}
};
private static final Converter<Float> N2F = new Converter<Float>() {
public Float apply(Object input) {
return ((Number) input).floatValue();
}
public boolean accept(Object v) {
return v instanceof Number;
}
};
private static final Converter<Double> N2D = new Converter<Double>() {
public Double apply(Object input) {
return ((Number) input).doubleValue();
}
public boolean accept(Object v) {
return v instanceof Number;
}
};
private static final Converter<Character> N2C = new Converter<Character>() {
public Character apply(Object input) {
return (char) ((Number) input).intValue();
}
public boolean accept(Object v) {
return v instanceof Number;
}
};
private static final Converter<Byte> N2B = new Converter<Byte>() {
public Byte apply(Object input) {
return (byte) ((Number) input).intValue();
}
public boolean accept(Object v) {
return v instanceof Number;
}
};
private static final Converter<Boolean> N2Z = new Converter<Boolean>() {
public Boolean apply(Object input) {
return ((Number) input).intValue() != 0;
}
public boolean accept(Object v) {
return v instanceof Number;
}
};
private static final Converter<String> O2String = new Converter<String>() {
public String apply(Object input) {
return String.valueOf(input);
}
public boolean accept(Object v) {
return v instanceof Object;
}
};
private static final Converter<Integer> O2I = new Converter<Integer>() {
public Integer apply(Object input) {
String s = String.valueOf(input);
if (StringUtils.isEmpty(s)) {
return 0;
}
return Integer.valueOf(s);
}
public boolean accept(Object v) {
return v instanceof Object;
}
};
private static final Converter<Long> O2J = new Converter<Long>() {
public Long apply(Object input) {
String s = String.valueOf(input);
if (StringUtils.isEmpty(s)) {
return 0L;
}
return Long.valueOf(s);
}
public boolean accept(Object v) {
return v instanceof Object;
}
};
private static final Converter<Short> O2S = new Converter<Short>() {
public Short apply(Object input) {
String s = String.valueOf(input);
if (StringUtils.isEmpty(s)) {
return 0;
}
return Short.valueOf(s);
}
public boolean accept(Object v) {
return v instanceof Object;
}
};
private static final Converter<Float> O2F = new Converter<Float>() {
public Float apply(Object input) {
String s = String.valueOf(input);
if (StringUtils.isEmpty(s)) {
return 0F;
}
return Float.valueOf(s);
}
public boolean accept(Object v) {
return v instanceof Object;
}
};
private static final Converter<Double> O2D = new Converter<Double>() {
public Double apply(Object input) {
String s = String.valueOf(input);
if (StringUtils.isEmpty(s)) {
return 0D;
}
return Double.valueOf(s);
}
public boolean accept(Object v) {
return v instanceof Object;
}
};
private static final Converter<Character> O2C = new Converter<Character>() {
public Character apply(Object input) {
String s = String.valueOf(input);
if (StringUtils.isEmpty(s)) {
return 0;
}
return s.charAt(0);
}
public boolean accept(Object v) {
return v instanceof Object;
}
};
private static final Converter<Byte> O2B = new Converter<Byte>() {
public Byte apply(Object input) {
String s = String.valueOf(input);
if (StringUtils.isEmpty(s)) {
return 0;
}
return Byte.valueOf(s);
}
public boolean accept(Object v) {
return v instanceof Object;
}
};
private static final Converter<Boolean> O2Z = new Converter<Boolean>() {
public Boolean apply(Object input) {
String s = String.valueOf(input);
if (StringUtils.isEmpty(s)) {
return false;
}
return StringUtils.toBoolean(s, false);
}
public boolean accept(Object v) {
return v instanceof Object;
}
};
private static final Converter<java.util.Date> String2Date = new Converter<java.util.Date>() {
@Override
public Date apply(Object input) {
String value = String.valueOf(input);
Date date = DateUtils.autoParse(value);
return date;
}
@Override
public boolean accept(Object v) {
return true;
}
};
private static final Converter<java.sql.Date> String2SqlDate = new Converter<java.sql.Date>() {
@Override
public java.sql.Date apply(Object input) {
String value = String.valueOf(input);
Date date = DateUtils.autoParse(value);
return new java.sql.Date(date.getTime());
}
@Override
public boolean accept(Object v) {
return true;
}
};
private static final Converter<java.sql.Timestamp> String2TimeStamp = new Converter<java.sql.Timestamp>() {
@Override
public Timestamp apply(Object input) {
String value = String.valueOf(input);
Date date = DateUtils.autoParse(value);
return new java.sql.Timestamp(date.getTime());
}
@Override
public boolean accept(Object v) {
return true;
}
};
private static final Converter<java.sql.Time> String2Time = new Converter<java.sql.Time>() {
@Override
public Time apply(Object input) {
String value = String.valueOf(input);
Date date = DateUtils.autoParse(value);
return new java.sql.Time(date.getTime());
}
@Override
public boolean accept(Object v) {
return true;
}
};
private static final Converter<Object> RAW = new Converter<Object>() {
@Override
public Object apply(Object input) {
return input;
}
@Override
public boolean accept(Object v) {
return true;
}
};
private static final Converter<Number> ToNumber = new Converter<Number>() {
@Override
public Number apply(Object input) {
String value = String.valueOf(input);
if (value.indexOf('.') > -1) {
double d = Double.valueOf(value);
return d;
} else {
long l = Long.valueOf(value);
if (l <= Integer.MAX_VALUE) {
return (int) l;
} else {
return l;
}
}
}
@Override
public boolean accept(Object v) {
return true;
}
};
private static class EnumConverter<T extends Enum<T>> extends Converter<T> {
private Class<T> clz;
EnumConverter(Class<T> clz) {
this.clz = clz;
}
@Override
public T apply(Object input) {
if (input instanceof Integer) {
int i = ((Integer) input).intValue();
T[] ts = clz.getEnumConstants();
if (i >= 0 && i < ts.length) {
return ts[i];
} else {
return null;
}
} else {
String s = String.valueOf(input);
return Enums.valueOf(clz, s, null);
}
}
@Override
public boolean accept(Object v) {
return true;
}
};
private static class StringArrayConverter extends Converter< Object> {
private Class<?> clz;
private ClassEx cex;
// StringArrayConverter(Class<?> clz) {
// this.clz = clz;
// this.cex=new ClassEx(clz);
// }
StringArrayConverter(Type clz) {
this.cex=new ClassEx(clz);
this.clz =cex.getWrappered();
}
@Override
public Object apply(Object input) {
String text=String.valueOf(input);
String[] values = StringUtils.split(text,',');
Object array = Array.newInstance(clz, values.length);// 创建数组容器
int i = 0;
for (Object o : values) {
Array.set(array, i, toProperType(StringUtils.toString(o), cex, null));
i++;
}
return array;
}
@Override
public boolean accept(Object v) {
return v instanceof CharSequence;
}
}
private static final Map<Class<?>, Node<Converter<?>>> CACHE = new ConcurrentHashMap<Class<?>, Node<Converter<?>>>();
static {
Node<Converter<?>> toInt = new Node<Converter<?>>(N2I).append(O2I);
CACHE.put(int.class, toInt);
CACHE.put(Integer.class, toInt);
Node<Converter<?>> toLong = new Node<Converter<?>>(N2J).append(O2J);
CACHE.put(long.class, toLong);
CACHE.put(Long.class, toLong);
Node<Converter<?>> toShort = new Node<Converter<?>>(N2S).append(O2S);
CACHE.put(short.class, toShort);
CACHE.put(Short.class, toShort);
Node<Converter<?>> toFloat = new Node<Converter<?>>(N2F).append(O2F);
CACHE.put(float.class, toFloat);
CACHE.put(Float.class, toFloat);
Node<Converter<?>> toDouble = new Node<Converter<?>>(N2D).append(O2D);
CACHE.put(double.class, toDouble);
CACHE.put(Double.class, toDouble);
Node<Converter<?>> toCharacter = new Node<Converter<?>>(N2C).append(O2C);
CACHE.put(char.class, toCharacter);
CACHE.put(Character.class, toCharacter);
Node<Converter<?>> toByte = new Node<Converter<?>>(N2B).append(O2B);
CACHE.put(byte.class, toByte);
CACHE.put(Byte.class, toByte);
Node<Converter<?>> toBoolean = new Node<Converter<?>>(N2Z).append(O2Z);
CACHE.put(boolean.class, toBoolean);
CACHE.put(Boolean.class, toBoolean);
CACHE.put(String.class, new Node<Converter<?>>(O2String));
CACHE.put(java.util.Date.class, new Node<Converter<?>>(String2Date));
CACHE.put(java.sql.Date.class, new Node<Converter<?>>(String2SqlDate));
CACHE.put(java.sql.Timestamp.class, new Node<Converter<?>>(String2TimeStamp));
CACHE.put(java.sql.Time.class, new Node<Converter<?>>(String2Time));
CACHE.put(Object.class, new Node<Converter<?>>(RAW));
CACHE.put(Number.class, new Node<Converter<?>>(ToNumber));
}
private ConvertUtils() {
}
/**
* 尝试将String转换为合适的类型,以设置到某个Bean或容器中。<br>
* 目前能支持各种基本类型、数组、Map等复杂类型
*
* @param value
* 要转换的String
* @param clz
* 容器类型
* @param oldValue
* 容器中原来的旧值,或可参照的对象实例。(可为null)
* @throws UnsupportedOperationException
* 如果无法转换,将抛出此异常
*
*/
public static Object toProperType(String value, ClassEx clz, Object oldValue) {
if (value == null) {
if (clz.isPrimitive()) {
return defaultValueOfPrimitive(clz.getWrappered());
} else {
return null;
}
}
// 容器所允许的最宽松类型
ClassEx container = clz;
if (oldValue != null)
clz = new ClassEx(oldValue.getClass());
if (clz.isAssignableFrom(String.class)) {
return value;
}
if (StringUtils.isEmpty(value)) {
return defaultValueForBasicType(clz.getWrappered());
}
// 凡是在转换器池里的都是必定支持的转换
Node<Converter<?>> c = CACHE.get(container.getWrappered());
if (c != null) {
return process(c, value);
}
if (clz.isEnum()) {
@SuppressWarnings({ "rawtypes", "unchecked" })
EnumConverter ec = new EnumConverter(clz.getWrappered().asSubclass(Enum.class));
CACHE.put(clz.getWrappered(), new Node<Converter<?>>(ec));
return ec.apply(value);
} else if (clz.isArray()) {
StringArrayConverter ec=new StringArrayConverter(clz.getComponentType());
CACHE.put(clz.getWrappered(), new Node<Converter<?>>(ec));
return ec.apply(value);
} else if (clz.isCollection()) {
String[] values = value.split(",");
return toProperCollectionType(Arrays.asList(values), clz, oldValue);
} else if (Map.class.isAssignableFrom(clz.getWrappered())) {
return stringToMap(value, clz, oldValue);
} else if (oldValue != null) {// 采用旧值类型转换不成功,尝试采用容器类型转换
return toProperType(value, container, null);
} else if (StringUtils.isEmpty(value)) {// 没东西,转啥呀
return null;
} else {
StringBuilder sb = new StringBuilder("Can not convert [");
sb.append(StringUtils.truncate(value, 200));
sb.append("] to proper javatype:" + clz.getName());
throw new UnsupportedOperationException(sb.toString());
}
}
/**
* 转换为合适的值
*
* @param value
* @param container
* @return
*/
public static Object toProperType(Object value, Type container) {
return toProperType(value, new ClassEx(container), null);
}
/**
* 根据容器类型,转换数值
*
* @param value
* @param container
* @param oldValue
* @return
*/
@SuppressWarnings("rawtypes")
public static Object toProperType(Object value, ClassEx container, Object oldValue) {
if (value == null) {
if (container.isPrimitive()) {
return defaultValueOfPrimitive(container.getWrappered());
} else {
return null;
}
}
Class<?> clz = value.getClass();
if (container.isAssignableFrom(clz)) {
if (container.isCollection()) {
return checkAndConvertCollection((Collection) value, container);
} else if (container.isMap()) {
return checkAndConvertMap((Map) value, container);
} else {
return value;
}
} else if (CollectionUtils.isArrayOrCollection(clz)) {
Collection<Object> accessor = CollectionUtils.toCollection(value, Object.class);
if (container.isArray()) {
return toProperArrayType(accessor, container, oldValue);
} else if (container.isCollection()) {
return toProperCollectionType(accessor, container, oldValue);
} else {
toProperType(accessor.toString(), container, oldValue);
}
}
Node<Converter<?>> c = CACHE.get(container.getWrappered());
if (c != null) {
Object result = process(c, value);
if (result != ObjectUtils.NULL)
return result;
}
return toProperType(StringUtils.toString(value), container, oldValue);
}
private static Object process(Node<Converter<?>> cs, Object value) {
for (Converter<?> c : cs) {
if (c.accept(value)) {
return c.apply(value);
}
}
return ObjectUtils.NULL;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private static Object checkAndConvertMap(Map rawValue, ClassEx container) {
Entry<Type, Type> types = GenericUtils.getMapTypes(container.genericType);
boolean checkKey = types.getKey() != Object.class;
boolean checkValue = types.getValue() != Object.class;
if (!checkKey && !checkValue)
return rawValue;
ClassEx tk = new ClassEx(types.getKey());
ClassEx tv = new ClassEx(types.getValue());
Set<Map.Entry> es = rawValue.entrySet();
Map result;
try {
result = rawValue.getClass().newInstance();
} catch (InstantiationException e1) {
throw new IllegalArgumentException(e1);
} catch (IllegalAccessException e1) {
throw new IllegalArgumentException(e1);
}
for (Map.Entry e : es) {
Object key = e.getKey();
Object value = e.getValue();
if (key != null && checkKey)
key = toProperType(key, tk, null);
if (value != null && checkValue)
value = toProperType(value, tv, null);
result.put(key, value);
}
return result;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private static Object checkAndConvertCollection(Collection rawValue, ClassEx container) {
Type type = GenericUtils.getCollectionType(container.genericType);
if (type == Object.class)
return rawValue;
ClassEx t = new ClassEx(type);
Collection result;
try {
result = rawValue.getClass().newInstance();
} catch (InstantiationException e1) {
throw new IllegalArgumentException(e1);
} catch (IllegalAccessException e1) {
throw new IllegalArgumentException(e1);
}
for (Object e : rawValue) {
e = toProperType(e, t, null);
result.add(e);
}
return result;
}
/**
* 转换为合适的数组类型
*
* @param values
* @param c
* @param oldValue
* @return
*/
static Object toProperArrayType(Collection<?> values, ClassEx c, Object oldValue) {
ClassEx arrType = new ClassEx(c.getComponentType());
Object array = Array.newInstance(arrType.getWrappered(), values.size());// 创建数组容器
int i = 0;
for (Object o : values) {
ArrayUtils.set(array, i, toProperType(StringUtils.toString(o), arrType, null));
i++;
}
return array;
}
/**
* 返回八个原生类型的默认数值(的装箱类型)
*
* @param javaClass
* 数据类型
* @return 返回该种技术类型的默认数值
* @throws IllegalArgumentException
* 如果传入的javaClass不是八种基础类型之一抛出。
*/
public static Object defaultValueOfPrimitive(Class<?> javaClass) {
// int 226
// short 215
// long 221
// boolean 222
// float 219
// double 228
// char 201
// byte 237
if (javaClass.isPrimitive()) {
String s = javaClass.getName();
switch (s.charAt(1) + s.charAt(2)) {
case 226:
return 0;
case 215:
return Short.valueOf((short) 0);
case 221:
return 0L;
case 222:
return Boolean.FALSE;
case 219:
return 0f;
case 228:
return 0d;
case 201:
return (char) 0;
case 237:
return Byte.valueOf((byte) 0);
}
}
throw new IllegalArgumentException(javaClass + " is not Primitive Type.");
}
/**
* 得到原生对象和String的缺省值。
*
* @param cls
* 类型
*
* @return 指定类型数据的缺省值。如果传入类型是primitive和String之外的类型返回null。
*/
public static Object defaultValueForBasicType(Class<?> cls) {
if (cls == String.class) {
return "";
} else if (cls.isPrimitive()) {
return defaultValueOfPrimitive(cls);
}
return null;
}
/**
* 转换为合适的集合类型
*
* @param values
* @param c
* @param oldValue
* @return
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
private static Object toProperCollectionType(Collection<?> values, ClassEx c, Object oldValue) {
ClassEx cType = new ClassEx(c.getComponentType());
try {
Collection l = (Collection) CollectionUtils.createContainerInstance(c, 0);
for (Object o : values) {
l.add(ConvertUtils.toProperType(StringUtils.toString(o), cType, findElementInstance(oldValue)));
}
return l;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 将输入对象视为集合、数组对象,查找其中的非空元素,返回第一个 注意:Map不是Collection
*
* @param 参数
*/
public static Object findElementInstance(Object collection) {
if (collection == null)
return null;
if (collection.getClass().isArray()) {
for (int i = 0; i < Array.getLength(collection); i++) {
Object o = Array.get(collection, i);
if (o != null) {
return o;
}
}
} else if (collection instanceof Collection) {
for (Object o : ((Collection<?>) collection)) {
if (o != null) {
return o;
}
}
}
return null;
}
/**
* 将输入对象视为集合、数组对象,根据其中的元素类型,返回新的元素实例
*
* @throws
*/
public static Object createElementByElement(Object collection) {
Object o = findElementInstance(collection);
try {
if (o != null) {
return BeanUtils.newInstanceAnyway(o.getClass());
}
} catch (ReflectionException e) {
LogUtil.exception(e);
}
return null;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private static Object stringToMap(String value, ClassEx c, Object oldValue) {
String[] values = StringUtils.split(value, ',');
Entry<Type, Type> types = GenericUtils.getMapTypes(c.getGenericType());
try {
Map l = (Map) CollectionUtils.createContainerInstance(c, 0);
Object hintKey = null;
Object hintValue = null;
if (oldValue != null) {
Map old = (Map) oldValue;
Set ks = old.keySet();
Collection vs = old.values();
if (ks.size() > 0) {
hintKey = ks.iterator().next();
}
if (vs.size() > 0) {
hintValue = vs.iterator().next();
}
}
for (int i = 0; i < values.length; i++) {
CommentEntry e = CommentEntry.createFromString(values[i], ':', '=');
l.put(ConvertUtils.toProperType(e.getKey(), new ClassEx(types.getKey()), hintKey), ConvertUtils.toProperType(e.getValue(), new ClassEx(types.getValue()), hintValue));
}
return l;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}