package org.nutz.mapl.impl.convert; import java.lang.reflect.Array; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Stack; import org.nutz.castor.Castors; import org.nutz.el.El; import org.nutz.json.Json; import org.nutz.json.entity.JsonEntity; import org.nutz.json.entity.JsonEntityField; import org.nutz.lang.Lang; import org.nutz.lang.Mirror; import org.nutz.lang.util.Context; import org.nutz.mapl.Mapl; import org.nutz.mapl.MaplConvert; /** * 对象转换 将MapList结构转换成对应的对象 TODO 具有循环引用的对象应该会出问题 * * @author juqkai(juqkai@gmail.com) */ public class ObjConvertImpl implements MaplConvert { // 路径 Stack<String> path = new Stack<String>(); // 对象缓存 Context context = Lang.context(); private Type type; public ObjConvertImpl(Type type) { this.type = type; } /** * 这个实现, 主要将 List, Map 的对象结构转换成真实的对象. * <p> * 规则: * <ul> * <li>对象以Map存储, key为属性名, value为属性值 * <li>数组以List存储 * <li>Map直接存储为Map * <li>List直接存储为List * <li>只要不是List, Map 存储的, 都认为是可以直接写入对象的. TODO 这点可以调整一下. * </ul> */ public Object convert(Object model) { if (model == null) return null; if (type == null) return model; // obj是基本数据类型或String if (!(model instanceof Map) && !(model instanceof List)) { return Castors.me().castTo(model, Lang.getTypeClass(type)); } return inject(model, type); } Object inject(Object model, Type type) { if (model == null) { return null; } Mirror<?> me = Mirror.me(type); Object obj = null; if (Collection.class.isAssignableFrom(me.getType())) { obj = injectCollection(model, me); } else if (Map.class.isAssignableFrom(me.getType())) { obj = injectMap(model, me); } else if (me.getType().isArray()) { obj = injectArray(model, me); } else { obj = injectObj(model, me); } if (path.size() > 0) path.pop(); return obj; } @SuppressWarnings({"unchecked", "rawtypes"}) private Object injectArray(Object model, Mirror<?> me) { Class<?> clazz = me.getType().getComponentType(); List list = (List) model; List vals = new ArrayList(); int j = 0; for (Object obj : list) { if (isLeaf(obj)) { vals.add(Castors.me().castTo(obj, clazz)); continue; } path.push("a" + (j++)); vals.add(inject(obj, clazz)); } Object obj = Array.newInstance(clazz, vals.size()); for (int i = 0; i < vals.size(); i++) { Array.set(obj, i, vals.get(i)); } return obj; } @SuppressWarnings({"unchecked", "rawtypes"}) private Object injectMap(Object model, Mirror<?> me) { Map re = null; if (me.isInterface()) { re = new HashMap(); } else { re = (Map) me.born(); } Map map = (Map) model; if (me.getGenericsTypes() == null) { re.putAll(map); return re; } Type type = me.getGenericsType(1); for (Object key : map.keySet()) { Object val = map.get(key); // 转换Key if (!isLeaf(key)) { key = inject(key, me.getGenericsType(0)); } // 转换val并填充 if (isLeaf(val)) { re.put(key, Castors.me().castTo(val, Lang.getTypeClass(type))); continue; } path.push(key.toString()); re.put(key, inject(val, type)); } return re; } @SuppressWarnings({"rawtypes", "unchecked"}) private Object injectCollection(Object model, Mirror<?> me) { if (! (model instanceof Collection)) { throw Lang.makeThrow("Not a Collection --> " + model.getClass()); } Collection re = null; if (!me.isInterface()) { re = (Collection) me.born(); } else { re = makeCollection(me); } if (me.getGenericsTypes() == null) { re.addAll((Collection) model); return re; } Type type = me.getGenericsType(0); int j = 0; for (Object obj : (Collection) model) { if (isLeaf(obj)) { re.add(Castors.me().castTo(obj, Lang.getTypeClass(type))); continue; } path.push("a" + (j++)); re.add(inject(obj, type)); } return re; } @SuppressWarnings("rawtypes") private Collection makeCollection(Mirror<?> me) { if (List.class.isAssignableFrom(me.getType())) { return new ArrayList(); } if (Set.class.isAssignableFrom(me.getType())) { return new HashSet(); } throw new RuntimeException("不支持的类型!"); } @SuppressWarnings("unchecked") private Object injectObj(Object model, Mirror<?> mirror) { // zzh: 如果是 Object,那么就不要转换了 if (mirror.getType() == Object.class) return model; Object obj = mirror.born(); context.set(fetchPath(), obj); Map<String, ?> map = (Map<String, ?>) model; JsonEntity jen = Json.getEntity(mirror); for (String key : map.keySet()) { JsonEntityField jef = jen.getField(key); if (jef == null) { continue; } Object val = map.get(jef.getName()); if (val == null) { continue; } if (isLeaf(val)) { if (val instanceof El) { val = ((El) val).eval(context); } // zzh@2012-09-14: 暂时去掉 createBy 吧 // jef.setValue(obj, Castors.me().castTo(jef.createValue(obj, // val, null), Lang.getTypeClass(jef.getGenericType()))); // jef.setValue(obj, jef.createValue(obj, val, null)); jef.setValue(obj, Mapl.maplistToObj(val, jef.getGenericType())); continue; } else { path.push(key); // jef.setValue(obj, Mapl.maplistToObj(val, // me.getGenericsType(0))); jef.setValue(obj, Mapl.maplistToObj(val, jef.getGenericType())); // zzh@2012-09-14: 暂时去掉 createBy 吧 // jef.setValue(obj, jef.createValue(obj, val, // me.getGenericsType(0))); } } return obj; } private boolean isLeaf(Object obj) { if (obj instanceof Map) { return false; } if (obj instanceof List) { return false; } return true; } private String fetchPath() { StringBuffer sb = new StringBuffer(); sb.append("root"); for (String item : path) { if (item.charAt(0) != 'a') { sb.append("m"); } sb.append(item); } return sb.toString(); } }