package org.nutz.dao; import java.lang.reflect.Field; import java.util.LinkedHashMap; import java.util.Map; import org.nutz.dao.entity.Entity; import org.nutz.dao.entity.MappingField; import org.nutz.dao.jdbc.ValueAdaptor; import org.nutz.json.Json; import org.nutz.lang.Mirror; /** * 名值链。 * <p> * 通过 add 方法,建立一条名值对的链表 * * @author zozoh(zozohtnt@gmail.com) * @author Wendal(wendal1985@gmail.com) * @author lzxz1234 */ public abstract class Chain { /** * 建立一条名值链开始的一环 * * @param name * 名称 * @param value * 值 * @return 链头 */ public static Chain make(String name, Object value) { DefaultChain chain = new DefaultChain(name, value); return chain; } /** * @return 链的长度 */ public abstract int size(); /** * 改变当前节点的名称 * * @param name * 新名称 * @return 当前节点 */ public abstract Chain name(String name); /** * 改变当前节点的值 * * @param value * 新值 * @return 当前节点 */ public abstract Chain value(Object value); /** * 设置节点的参考适配器 * * @param adaptor * 适配器 * @return 当前节点 */ public abstract Chain adaptor(ValueAdaptor adaptor); /** * @return 当前节点的参考适配器 */ public abstract ValueAdaptor adaptor(); /** * 将一个名值对,添加为本链节点的下一环 * * @param name * 名 * @param value * 值 * @return 新增加的节点 */ public abstract Chain add(String name, Object value); /** * @return 当前节点的名称 */ public abstract String name(); /** * @return 当前节点的值 */ public abstract Object value(); /** * @return 往后移动一个结点,到达末尾返回空,否则返回当前对象 */ public abstract Chain next(); /** * @return 整个链的第一环(头节点) */ public abstract Chain head(); /** * 根据 Entity 里的设定,更新整个链所有节点的名称。 * <p> * 如果节点的名称是 Entity 的一个字段,则采用数据库字段的名称 * * @param entity * 实体 * @return 链头节点 */ public abstract Chain updateBy(Entity<?> entity); /** * 由当前的名值链,生成一个对象 * * @param classOfT * 对象类型 * @return 对象实例 */ public abstract <T> T toObject(Class<T> classOfT); /** * 由当前名值链,生成一个 Map * * @return Map */ public abstract Map<String, Object> toMap(); /** * 整个Chain是否为特殊Chain,只要有一个特殊结点,就是特殊Chain * @see org.nutz.dao.Chain#addSpecial(String, Object) * @since 1.b.44 */ public abstract boolean isSpecial(); /** * 当前结点是不是特殊结点 * @return */ public abstract boolean special(); /** * 由当前的值链生成一个可被实体化的 Map。 即有 '.table' 属性 * * @param tableName * 表名 * @return 可被实体化的 Map */ public Map<String, Object> toEntityMap(String tableName) { Map<String, Object> map = toMap(); map.put(".table", tableName); return map; } /** * 生成一个 JSON 字符串 */ public String toString() { return Json.toJson(toMap()); } /** * 根据一个对象的字段 生成一个 Chain 对象 * <p> * 这个对象可以是一个 POJO 或者是一个 Map。 * <p> * 支持 FieldMatcher,即你可以通过 FieldMatcher 来指定你需要哪些字段加入 Chain * * @param obj * 对象,可以是一个 POJO 或者是一个 Map * @param fm * 指明可用字段,null 表示全部字段可用 * @return Chain 对象,null 表示对象中没有可用字段 * * @see org.nutz.dao.FieldMatcher */ public static Chain from(Object obj, FieldMatcher fm) { if (null == obj) return null; Chain c = null; /* * Is Map */ if (obj instanceof Map<?, ?>) { for (Map.Entry<?, ?> en : ((Map<?, ?>) obj).entrySet()) { Object key = en.getKey(); if (null == key) continue; String name = key.toString(); if (null != fm && !fm.match(name)) continue; Object v = en.getValue(); if (null != fm && null == v && fm.isIgnoreNull()) continue; if (c == null) { c = Chain.make(name, v); } else { c = c.add(name, v); } } } /* * Is POJO */ else { Mirror<?> mirror = Mirror.me(obj.getClass()); for (Field f : mirror.getFields()) { if (null != fm && !fm.match(f.getName())) continue; Object v = mirror.getValue(obj, f.getName()); if (null != fm && null == v && fm.isIgnoreNull()) continue; if (c == null) { c = Chain.make(f.getName(), v); } else { c = c.add(f.getName(), v); } } } return c; } /** * 根据一个 POJO 对象的字段 生成一个 Chain 对象 * <p> * 相当于 Chain.from(obj,null) * * @param obj * POJO 对象 * @return Chain 对象 */ public static Chain from(Object obj) { return from(obj, null); } //============================================================= //===========update语句使用特定的值,例如+1 -1 toDate()等======== //============================================================= /** * 添加一个特殊节点, 如果value非空,则有3个情况:<p> * <li>+1 效果如age=age+1</li> * <li>-1 效果如count=count-1</li> * <li>支持的运算符有 + - *\/ % & ^ | * <li>其他值, 则对value.toString(),效果如 time=todate("XXXXX")</li> * * @since 1.b.44 */ public abstract Chain addSpecial(String name, Object value); /** * @see org.nutz.dao.Chain#addSpecial(String, Object) * @since 1.b.44 */ public static Chain makeSpecial(String name, Object value) { DefaultChain chain = new DefaultChain(name, value); chain.head.special = true; return chain; } private static class DefaultChain extends Chain { private Entry head; private Entry current; private Entry tail; private int size; public DefaultChain(String name, Object value) { this.head = new Entry(name, value); this.current = head; this.tail = head; this.size = 1; } public int size() { return size; } public Chain name(String name) { current.name = name; return this; } public Chain value(Object value) { current.value = value; return this; } public Chain adaptor(ValueAdaptor adaptor) { current.adaptor = adaptor; return this; } public ValueAdaptor adaptor() { return current.adaptor; } public Chain add(String name, Object value) { tail.next = new Entry(name, value); tail = tail.next; size ++; return this; } public String name() { return current.name; } public Object value() { return current.value; } public Chain next() { current = current.next; return current == null ? null : this; } public Chain head() { current = head; return this; } public Chain addSpecial(String name, Object value) { add(name, value); tail.special = true; return this; } public boolean special() { return current.special; } public boolean isSpecial() { Entry entry = head; do { if(entry.special) return true; } while ((entry = entry.next) != null); return false; } public Map<String, Object> toMap() { Map<String, Object> map = new LinkedHashMap<String, Object>(); Entry current = head; while (current != null) { map.put(current.name, current.value); current = current.next; } return map; } public Chain updateBy(Entity<?> entity) { if (null != entity) { Entry current = head; while (current != null) { MappingField ef = entity.getField(current.name); if (null != ef) { current.name = ef.getColumnName(); } current = current.next; } } return head(); } public <T> T toObject(Class<T> classOfT) { Mirror<T> mirror = Mirror.me(classOfT); T re = mirror.born(); Entry current = head; while (current != null) { mirror.setValue(re, current.name, current.value); current = current.next; } return re; } private static class Entry { protected String name; Object value; ValueAdaptor adaptor; boolean special; Entry next; public Entry(String name, Object value) { this.name = name; this.value = value; } } } }