package org.nutz.castor; import java.lang.reflect.Array; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import org.nutz.castor.castor.Object2Object; import org.nutz.lang.Lang; import org.nutz.lang.Mirror; import org.nutz.lang.TypeExtractor; import org.nutz.log.Log; import org.nutz.log.Logs; /** * 一个创建 Castor 的工厂类。它的使用方式是: * * <pre> * Castors.me().cast(obj, fromType, toType); * </pre> * * * @author zozoh(zozohtnt@gmail.com) * @author Wendal(wendal1985@gmail.com) */ public class Castors { private static final Log log = Logs.get(); /** * @return 单例 */ public static Castors me() { return one; } /** * @return 一个新的 Castors 实例 */ public static Castors create() { return new Castors(); } /** * 如何抽取对象的类型级别 */ private TypeExtractor extractor; /** * Castor 的配置 */ private Object setting; private HashMap<Class<?>, Method> settingMap; /** * 设置转换的配置 * <p> * 配置对象所有的共有方法都会被遍历。只要这个方法有一个且只有一个参数,并且该参数 是一个 org.nutz.castor.Castor * 接口的实现类。那么就会被认为是对该种 Castor 的一个 配置。 * <p> * 当初始化这个 Castor 之前,会用这个方法来设置一下你的 Castor (如果你的 Castor 需要配置的话) * * @param obj * 配置对象。可以是任意的 Java 对象。 */ public synchronized Castors setSetting(Object obj) { if (obj != null) { setting = obj; this.reload(); } return this; } /** * 设置自定义的对象类型提取器逻辑 * * @param te * 类型提取器 */ public synchronized Castors setTypeExtractor(TypeExtractor te) { extractor = te; return this; } private Castors() { setting = new DefaultCastorSetting(); reload(); } private void reload() { buildSettingMap(); //this.map = ArrayList<Class<?>> classes = new ArrayList<Class<?>>(); classes.addAll(defaultCastorList); for (Class<?> klass : classes) { try { if (Modifier.isAbstract(klass.getModifiers())) continue; if (!Castor.class.isAssignableFrom(klass)) continue; fillMap(klass, settingMap,false); } catch (Throwable e) { if (log.isWarnEnabled()) log.warnf("Fail to create castor [%s] because: %s", klass, e.getMessage()); } } if (log.isDebugEnabled()) log.debugf("Using %s castor for Castors", map.size()); } private void buildSettingMap() throws SecurityException { settingMap = new HashMap<Class<?>, Method>(); for (Method m1 : setting.getClass().getMethods()) { Class<?>[] pts = m1.getParameterTypes(); if (pts.length == 1 && Castor.class.isAssignableFrom(pts[0])){ settingMap.put(pts[0], m1); } } } public void addCastor(Class<?> klass) { try { fillMap(klass, settingMap,true); } catch (Throwable e) { throw Lang.wrapThrow(Lang.unwrapThrow(e)); } } /** * 填充 map .<br> * 在map中使用hash值来做为key来进行存储 * * @param klass * @param settingMap * @param replace * @throws InstantiationException * @throws IllegalAccessException * @throws IllegalArgumentException * @throws InvocationTargetException */ private void fillMap(Class<?> klass, HashMap<Class<?>, Method> settingMap,boolean replace) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { Castor<?, ?> castor = (Castor<?, ?>) klass.newInstance(); if (!map.containsKey(castor.toString()) || replace) { map.put(castor.toString(), castor); }else{ castor = map.get(castor.toString()); } Method m = settingMap.get(castor.getClass()); if (null == m) { for (Entry<Class<?>, Method> entry : settingMap.entrySet()) { Class<?> cc = entry.getKey(); if (cc.isAssignableFrom(klass)) { m = settingMap.get(cc); break; } } } if (null != m) m.invoke(setting, castor); } /** * First index is "from" (source) The second index is "to" (target) */ // private Map<String, Map<String, Castor<?, ?>>> map; // private Map<Integer, Castor<?,?>> map; private Map<String, Castor<?, ?>> map = new ConcurrentHashMap<String, Castor<?, ?>>();; /** * 转换一个 POJO 从一个指定的类型到另外的类型 * * @param src * 源对象 * @param fromType * 源对象类型 * @param toType * 目标类型 * @param args * 转换时参数。有些 Castor 可能需要这个参数,比如 Array2Map * @return 目标对象 * @throws FailToCastObjectException * 如果没有找到转换器,或者转换失败 */ @SuppressWarnings({"unchecked", "rawtypes"}) public <F, T> T cast(Object src, Class<F> fromType, Class<T> toType, String... args) throws FailToCastObjectException { if (null == src) { // 原生数据的默认值 if (toType.isPrimitive()) { if (toType == int.class) return (T) Integer.valueOf(0); else if (toType == long.class) return (T) Long.valueOf(0L); else if (toType == byte.class) return (T) Byte.valueOf((byte) 0); else if (toType == short.class) return (T) Short.valueOf((short) 0); else if (toType == float.class) return (T) Float.valueOf(.0f); else if (toType == double.class) return (T) Double.valueOf(.0); else if (toType == boolean.class) return (T) Boolean.FALSE; else if (toType == char.class) return (T) Character.valueOf(' '); throw Lang.impossible(); } // 是对象,直接返回 null return null; } if (fromType == toType || toType == null || fromType == null) return (T) src; Class<?> componentType = toType.getComponentType(); if (null != componentType && fromType != String.class && componentType.isAssignableFrom(fromType)) { Object array = Array.newInstance(componentType, 1); Array.set(array, 0, src); return (T) array; } if (fromType.getName().equals(toType.getName())) return (T) src; if (toType.isAssignableFrom(fromType)) return (T) src; Mirror<?> from = Mirror.me(fromType, extractor); Castor c = find(from, toType); if (null == c) throw new FailToCastObjectException(String.format("Can not find castor for '%s'=>'%s' in (%d) because:\n%s", fromType.getName(), toType.getName(), map.size(), "Fail to find matched castor")); if (Object2Object.class.getName().equals(c.getClass().getName()) && from.canCastToDirectly(toType)) { // Use language built-in cases return (T) src; } try { return (T) c.cast(src, toType, args); } catch (FailToCastObjectException e) { throw e; } catch (Exception e) { throw new FailToCastObjectException(String.format("Fail to cast from <%s> to <%s> for {%s} because:\n%s:%s", fromType.getName(), toType.getName(), src, e.getClass() .getSimpleName(), e.getMessage()), Lang.unwrapThrow(e)); } } /** * 获取一个转换器 * * @param from * 源类型 * @param to * 目标类型 * @return 转换器 */ public <F, T> Castor<F, T> find(Class<F> from, Class<T> to) { return find(Mirror.me(from), to); } @SuppressWarnings("unchecked") private <F, T> Castor<F, T> find(Mirror<F> from, Class<T> toType) { String key = Castor.key(from.getType(), toType); // 哈,这种类型以前转过,直接返回转换器就行了 if (map.containsKey(key)) { return (Castor<F, T>) map.get(key); } Mirror<T> to = Mirror.me(toType, extractor); Class<?>[] fets = from.extractTypes(); Class<?>[] tets = to.extractTypes(); for (Class<?> ft : fets) { for (Class<?> tt : tets) { if (map.containsKey(Castor.key(ft, tt))) { Castor<F, T> castor = (Castor<F, T>) map.get(Castor.key(ft, tt)); // 缓存转换器,加速下回转换速度 map.put(key, castor); return castor; } } } return null; } /** * 转换一个 POJO 到另外的类型 * * @param src * 源对象 * @param toType * 目标类型 * @return 目标对象 * @throws FailToCastObjectException * 如果没有找到转换器,或者转换失败 */ public <T> T castTo(Object src, Class<T> toType) throws FailToCastObjectException { return cast(src, null == src ? null : src.getClass(), toType); } /** * 判断一个类型是否可以被转换成另外一个类型 * <p> * 判断的依据就是看是否可以直接被转型,以及能不能找到一个专有的转换器 * * @param fromType * 起始类型 * @param toType * 目标类型 * @return 是否可以转换 */ public boolean canCast(Class<?> fromType, Class<?> toType) { if (Mirror.me(fromType).canCastToDirectly(toType)) return true; if (toType.isArray() && toType.getComponentType().isAssignableFrom(fromType)) { return true; } Castor<?, ?> castor = this.find(fromType, toType); return !(castor instanceof Object2Object); } /** * 将一个 POJO 转换成字符串 * * @param src * 源对象 * @return 字符串 */ public String castToString(Object src) { try { return castTo(src, String.class); } catch (FailToCastObjectException e) { return String.valueOf(src); } } private static List<Class<?>> defaultCastorList = new ArrayList<Class<?>>(120); static { defaultCastorList.add(org.nutz.castor.castor.Array2Array.class); defaultCastorList.add(org.nutz.castor.castor.Array2Collection.class); defaultCastorList.add(org.nutz.castor.castor.Array2Map.class); defaultCastorList.add(org.nutz.castor.castor.Array2Object.class); defaultCastorList.add(org.nutz.castor.castor.Array2String.class); defaultCastorList.add(org.nutz.castor.castor.Boolean2Number.class); defaultCastorList.add(org.nutz.castor.castor.Boolean2String.class); defaultCastorList.add(org.nutz.castor.castor.Calendar2Datetime.class); defaultCastorList.add(org.nutz.castor.castor.Calendar2Long.class); defaultCastorList.add(org.nutz.castor.castor.Calendar2String.class); defaultCastorList.add(org.nutz.castor.castor.Calendar2Timestamp.class); defaultCastorList.add(org.nutz.castor.castor.Character2Number.class); defaultCastorList.add(org.nutz.castor.castor.Class2Mirror.class); defaultCastorList.add(org.nutz.castor.castor.Class2String.class); defaultCastorList.add(org.nutz.castor.castor.Collection2Array.class); defaultCastorList.add(org.nutz.castor.castor.Collection2Collection.class); defaultCastorList.add(org.nutz.castor.castor.Collection2Map.class); defaultCastorList.add(org.nutz.castor.castor.Collection2Object.class); defaultCastorList.add(org.nutz.castor.castor.Collection2String.class); defaultCastorList.add(org.nutz.castor.castor.DateTimeCastor.class); defaultCastorList.add(org.nutz.castor.castor.Datetime2Calendar.class); defaultCastorList.add(org.nutz.castor.castor.Datetime2Long.class); defaultCastorList.add(org.nutz.castor.castor.Datetime2SqlDate.class); defaultCastorList.add(org.nutz.castor.castor.Datetime2SqlTime.class); defaultCastorList.add(org.nutz.castor.castor.Datetime2String.class); defaultCastorList.add(org.nutz.castor.castor.Datetime2Timpestamp.class); defaultCastorList.add(org.nutz.castor.castor.Enum2Number.class); defaultCastorList.add(org.nutz.castor.castor.Enum2String.class); defaultCastorList.add(org.nutz.castor.castor.File2String.class); defaultCastorList.add(org.nutz.castor.castor.Map2Array.class); defaultCastorList.add(org.nutz.castor.castor.Map2Collection.class); defaultCastorList.add(org.nutz.castor.castor.Map2Enum.class); defaultCastorList.add(org.nutz.castor.castor.Map2Object.class); defaultCastorList.add(org.nutz.castor.castor.Map2String.class); defaultCastorList.add(org.nutz.castor.castor.Mirror2Class.class); defaultCastorList.add(org.nutz.castor.castor.Mirror2String.class); defaultCastorList.add(org.nutz.castor.castor.Number2Boolean.class); defaultCastorList.add(org.nutz.castor.castor.Number2Byte.class); defaultCastorList.add(org.nutz.castor.castor.Number2Calendar.class); defaultCastorList.add(org.nutz.castor.castor.Number2Char.class); defaultCastorList.add(org.nutz.castor.castor.Number2Character.class); defaultCastorList.add(org.nutz.castor.castor.Number2Datetime.class); defaultCastorList.add(org.nutz.castor.castor.Number2Double.class); defaultCastorList.add(org.nutz.castor.castor.Number2Enum.class); defaultCastorList.add(org.nutz.castor.castor.Number2Float.class); defaultCastorList.add(org.nutz.castor.castor.Number2Integer.class); defaultCastorList.add(org.nutz.castor.castor.Number2Long.class); defaultCastorList.add(org.nutz.castor.castor.Number2Short.class); defaultCastorList.add(org.nutz.castor.castor.Number2String.class); defaultCastorList.add(org.nutz.castor.castor.Number2Timestamp.class); defaultCastorList.add(org.nutz.castor.castor.Object2Class.class); defaultCastorList.add(org.nutz.castor.castor.Object2List.class); defaultCastorList.add(org.nutz.castor.castor.Object2Map.class); defaultCastorList.add(org.nutz.castor.castor.Object2Mirror.class); defaultCastorList.add(org.nutz.castor.castor.Object2Object.class); defaultCastorList.add(org.nutz.castor.castor.Object2String.class); defaultCastorList.add(org.nutz.castor.castor.SqlDate2String.class); defaultCastorList.add(org.nutz.castor.castor.SqlDate2Timestamp.class); defaultCastorList.add(org.nutz.castor.castor.SqlTime2String.class); defaultCastorList.add(org.nutz.castor.castor.SqlTime2Timestamp.class); defaultCastorList.add(org.nutz.castor.castor.String2Array.class); defaultCastorList.add(org.nutz.castor.castor.String2BigDecimal.class); defaultCastorList.add(org.nutz.castor.castor.String2Boolean.class); defaultCastorList.add(org.nutz.castor.castor.String2Byte.class); defaultCastorList.add(org.nutz.castor.castor.String2Calendar.class); defaultCastorList.add(org.nutz.castor.castor.String2Character.class); defaultCastorList.add(org.nutz.castor.castor.String2Class.class); defaultCastorList.add(org.nutz.castor.castor.String2Collection.class); defaultCastorList.add(org.nutz.castor.castor.String2Datetime.class); defaultCastorList.add(org.nutz.castor.castor.String2Double.class); defaultCastorList.add(org.nutz.castor.castor.String2Email.class); defaultCastorList.add(org.nutz.castor.castor.String2Enum.class); defaultCastorList.add(org.nutz.castor.castor.String2File.class); defaultCastorList.add(org.nutz.castor.castor.String2Float.class); defaultCastorList.add(org.nutz.castor.castor.String2Integer.class); defaultCastorList.add(org.nutz.castor.castor.String2Long.class); defaultCastorList.add(org.nutz.castor.castor.String2Map.class); defaultCastorList.add(org.nutz.castor.castor.String2Mirror.class); defaultCastorList.add(org.nutz.castor.castor.String2Number.class); defaultCastorList.add(org.nutz.castor.castor.String2Object.class); defaultCastorList.add(org.nutz.castor.castor.String2Pattern.class); defaultCastorList.add(org.nutz.castor.castor.String2Set.class); defaultCastorList.add(org.nutz.castor.castor.String2Short.class); defaultCastorList.add(org.nutz.castor.castor.String2SqlDate.class); defaultCastorList.add(org.nutz.castor.castor.String2SqlTime.class); defaultCastorList.add(org.nutz.castor.castor.String2TimeZone.class); defaultCastorList.add(org.nutz.castor.castor.String2Timestamp.class); defaultCastorList.add(org.nutz.castor.castor.TimeZone2String.class); defaultCastorList.add(org.nutz.castor.castor.Timestamp2Calendar.class); defaultCastorList.add(org.nutz.castor.castor.Timestamp2Datetime.class); defaultCastorList.add(org.nutz.castor.castor.Timestamp2Long.class); defaultCastorList.add(org.nutz.castor.castor.Timestamp2SqlDate.class); defaultCastorList.add(org.nutz.castor.castor.Timestamp2SqlTime.class); defaultCastorList.add(org.nutz.castor.castor.Timestamp2String.class); } private static Castors one = new Castors(); }