Map list深层嵌套访问增强工具,可以像js 对象一样访问
背景:
当在基于配置时写软件时,在java世界很不方便。 配置内容特别多很复杂, 在js里,直接定义一个普通对象即可。
但是在java世界 ,常见的是xml、properties、 YML这类,他们的读写访问都不便,常常要针对配置文件写Bean类,当在写软件初期,配置格式经常改动,这种方式工作量相当大。这时很羡慕js或python之类的,他们有良好的数据结构解决。java 尽管map与list的深度嵌套 能与js对象 或与json 进行一一映射,理论上也是万能数据结构,但是map与list的嵌套,那类型转换、null处理烦得不要不要的,嵌套一层两层解析还好,当嵌套5层以上,直接晕死。在这种情况,就很希望能有一个工具,能像js一样对对象进行灵活的读写访问。 这是背景
开发说明1:
js 中 :
var obj={ id:1 name:"aa", items:[{ sid:1, sname:"saa"} ] }
我们可以这样使用:
obj.items[0].sid
为了简化开发难度,所有的数组访问必须有 一个小圆点,即这种形式访问:
obj.items.[0].sid
如果不考虑那么点性能话,可以在这上面一层直接 用正则改造,把 obj.items[0].sid 改成 obj.items.[0].sid。 当然,你也可以用字符串手工解析的(效率比正则高)。
开发说明2:
注意:本文是原创文章,也还没经过实际生产项目验证过,成熟度还有待提高,尽管有较多的测试,但是由于逻辑复杂,没有全覆盖测试,故不要冒然用于生产上。
开发说明3:
非线程安全,用在线程环境中时,注意不要对全局状态变量使用,否则哪怕用锁 也不能100%保障性程安全。
背景交待完毕,直接上代码:
Mapt.java
import java.util.*; import static com.alibaba.druid.sql.ast.SQLPartitionValue.Operator.List; public class Mapt { /* * Map与list相互深层嵌套处理工具。在投放与获取数据时非常快捷方便。 * 获取或投放数据,必须有k。k 是一个字符串,由小数点分隔成多部份, * 每部份对应着一个嵌套层。任意部份如果首尾由中括号括着,对应着List, * 否则非最底层部份对应着Map.访问形式类似Js中的对象访问,但是也仅类似, * 对于数组(即list)的访问,必须有小数点,比如js中aa[0]是可以的,但 * 这个工具必须是 aa.[0]的形式访问。 * Mapt.put(map,"aa.[3].x",2); * Object obj = Mapt.get(map,"aa.[3].x"); * 这是obj是2. * Object obj1 = Mapt.get(map,"aa.[3]"); * 这是obj1是个Map,他只有一个元素。key为x,value为2 * ============================= * 注意,put时,如果不存在则创建,如果存在则覆盖。父路径与子路径的数据格式不一致, * 且最近操作的key又对应的是父路径时,会以当前操作为准,子路径将被删除。 * 如: put(aa.bb.[0].dd ,34), 当前执行put("aa.bb",55),那么前一个put会被覆盖即被删除 * */ /** * 注意,在并发环境中,只能在配置阶段进行全局设置,在并发工作状态 禁止设置 */ private static String separator = "\\."; /** * 注意,在并发环境中,只能在配置阶段进行全局设置,在并发工作状态 禁止设置 */ private static boolean friendsKeyBL = false; public static boolean isExist(Object target, String k){ return isExist(target,k,separator); } public static boolean isExist(Object target, String k, String separator){ if (k == null || target == null) return false; if (friendsKeyBL) { k = k.replaceAll("(?<=[A-Z|a-z|0-9|\\]])(\\[)", ".["); } String[] strs = k.split(separator); Object rst = target; for (int i = 0; i < strs.length; i++) { String nextKey = null; if (i < strs.length - 1) { nextKey = strs[i + 1]; } rst = doingGet(rst, strs[i]); if(rst==null) return false; } return rst==null?false:true; } public static boolean isChildType(Object target, String k,Class typeClass) { return isChildType(target, k, typeClass,separator); } public static boolean isChildType(Object target, String k,Class typeClass, String separator) { if (k == null || target == null) return false; if (friendsKeyBL) { k = k.replaceAll("(?<=[A-Z|a-z|0-9|\\]])(\\[)", ".["); } String[] strs = k.split(separator); Object rst = target; for (int i = 0; i < strs.length; i++) { String nextKey = null; if (i < strs.length - 1) { nextKey = strs[i + 1]; } rst = doingGet(rst, strs[i]); if (rst==null) return false; } if (rst==null) return false; return typeClass.isAssignableFrom(rst.getClass()); } public static Object get(Object target, String k) { return get(target, k, separator); } public static Object get(Object target, String k, String separator) { if (k == null || target == null) return null; if (friendsKeyBL) { k = k.replaceAll("(?<=[A-Z|a-z|0-9|\\]])(\\[)", ".["); } String[] strs = k.split(separator); Object rst = target; for (int i = 0; i < strs.length; i++) { String nextKey = null; if (i < strs.length - 1) { nextKey = strs[i + 1]; } rst = doingGet(rst, strs[i]); if (rst ==null) return null; } return rst; } private static Object doingGet(Object target, String key) { if (key == null || target == null) return target; key = key.trim(); if (List.class.isAssignableFrom(target.getClass())) { key = key.substring(1, key.length() - 1); int pos = Integer.parseInt(key); List list = (List) target; return list.get(pos); } else if (Map.class.isAssignableFrom(target.getClass())) { if (key.substring(0, 1).equals("[")) return null; Map map = (Map) target; Object son = map.get(key); return son; } return null; } public static Object put(Object target, String k, Object v) { return put(target, k, v, separator); } public static Object put(Object target, String k, Object v, String separator) { if (k == null) return target; if (friendsKeyBL) { k = k.replaceAll("(?<=[A-Z|a-z|0-9|\\]])(\\[)", ".["); } String[] strs = k.split(separator); if (target == null) target = createObj(k); Object rst = target; for (int i = 0; i < strs.length; i++) { String nextKey = null; if (i < strs.length - 1) { nextKey = strs[i + 1]; } rst = doingPut(rst, strs[i], nextKey, v); } return target; } private static Object doingPut(Object target, String key, String nextKey, Object v) { if (key == null || target == null) return target; key = key.trim(); nextKey = nextKey == null ? null : nextKey.trim(); if (target == null) target = createObj(key); if (nextKey == null) { return setVal(target, key, v); } else { return getNext(target, key, nextKey); } } private static Object getNext(Object target, String key, String nextKey) { if (List.class.isAssignableFrom(target.getClass())) { key = key.substring(1, key.length() - 1); int pos = Integer.parseInt(key); List list = (List) target; int count = list.size(); for (int i = 0; count + i <= pos; i++) { list.add(null); } Object obj = list.get(pos); if (obj == null) { obj = createObj(nextKey); list.set(pos, obj); } else if (nextKey != null && !isSameType(obj,nextKey)) { obj = createObj(nextKey); list.set(pos, obj); } return obj; } else if (Map.class.isAssignableFrom(target.getClass())) { if (key.substring(0, 1).equals("[")) return null; Map map = (Map) target; Object son = map.get(key); if (son == null) { son = createObj(nextKey); map.put(key, son); } if (nextKey != null && !isSameType(son,nextKey)) { son = createObj(nextKey); map.put(key,son); } return son; } return null; } private static boolean isSameType(Object obj,String key){ String tmp="o"; if (List.class.isAssignableFrom(obj.getClass())){ tmp="l"; } else if (Map.class.isAssignableFrom(obj.getClass())){ tmp="m"; } String r=""; if(key.substring(0,1).equals("[")){ r="l"; } else { r="m"; } return tmp.equals(r); } private static Object createObj(String key) { if (key != null && key.indexOf("[") == 0) { return new ArrayList<>(); } else if (key != null && key.indexOf("[") != 0) { return new LinkedHashMap<>(); } return null; } private static Object setVal(Object target, String key, Object v) { if (target == null || key == null) return null; if (List.class.isAssignableFrom(target.getClass())) { key = key.substring(1, key.length() - 1); int pos = Integer.parseInt(key); List list = (List) target; int count = list.size(); for (int i = 0; count + i <= pos; i++) { list.add(null); } list.set(pos, v); return target; } else if (Map.class.isAssignableFrom(target.getClass())) { if (key.substring(0, 1).equals("[")) return null; Map map = (Map) target; map.put(key, v); return target; } return null; } public static String getString(Object target, String k) { Object obj = get(target, k); if (obj == null) return null; return obj.toString(); } public static Integer getInteger(Object target, String k) { Object obj = get(target, k); if (obj == null) return null; return (Integer) obj; } public static Long getLong(Object target, String k) { Object obj = get(target, k); if (obj == null) return null; return (Long) obj; } public static Boolean getBoolean(Object target, String k) { Object obj = get(target, k); if (obj == null) return null; return (Boolean) obj; } public static Date getDate(Object target, String k) { Object obj = get(target, k); if (obj == null) return null; return (Date) obj; } public static Double getDouble(Object target, String k) { Object obj = get(target, k); if (obj == null) return null; return (Double) obj; } public static Float getFloat(Object target, String k) { Object obj = get(target, k); if (obj == null) return null; return (Float) obj; } public static <T> Map<String, T> getMap(Object target, String k) { Object obj = get(target, k); if (obj == null) return null; return (Map<String, T>) obj; } public static <T> List<T> getList(Object target, String k) { Object obj = get(target, k); if (obj == null) return null; return (List<T>) obj; } public static <T> T getBean(Object target, String k) { Object obj = get(target, k); if (obj == null) return null; return (T) obj; } public static String getSeparator() { return separator; } public static void setSeparator(String separator) { Mapt.separator = separator; } public static boolean isFriendsKeyBL() { return friendsKeyBL; } public static void setFriendsKeyBL(boolean friendsKeyBL) { Mapt.friendsKeyBL = friendsKeyBL; } }
测试与使用示例:
1 import com.alibaba.fastjson.JSON; 2 import com.fyh.mybatisplusdemo.JackJsonUtils; 3 import com.fyh.mybatisplusdemo.entiy.Man; 4 import com.fyh.mybatisplusdemo.entiy.ManDetail; 5 import org.junit.Test; 6 import org.springframework.cglib.beans.BeanMap; 7 8 import java.util.ArrayList; 9 import java.util.LinkedHashMap; 10 import java.util.List; 11 import java.util.Map; 12 13 public class MaptTest { 14 // @Test 15 public void put(){ 16 17 boolean tmpbl; 18 Map<String,Object> map =new LinkedHashMap<>(); 19 Mapt.setFriendsKeyBL(true); 20 Mapt.put(map,"aa.[0]",5); 21 Mapt.put(map,"aa.[3].x",2); 22 Mapt.put(map,"aa.[0].cc.xx","aaaaa"); 23 tmpbl=Mapt.isExist(map,"aa.[0].cc"); 24 tmpbl=Mapt.isChildType(map,"aa",List.class); 25 Mapt.put(map,"aa.[0].cc.yy","bb"); 26 Mapt.put(map,"aa.yy","bb"); 27 String xx=JSON.toJSONString(map); 28 System.out.println(xx); 29 Object obj = Mapt.get(map,"aa.[3].x"); 30 Object obj1 = Mapt.get(map,"aa.[3]"); 31 Map<String,Integer> tmp = Mapt.getMap(map,"aa.[3]"); 32 33 List list =new ArrayList<>(); 34 Mapt.put(list,"[1].x.[0].yy.[0].[0].dd",5); 35 Object obj2 =Mapt.get(list,"[1].x.[0].yy.[0].[0]"); 36 37 Object obj3 =Mapt.put(null,"aa.[0]",5); 38 Mapt.put(obj3,"bb.[0]",66); 39 Mapt.put(obj3,"aa.[3].x",2); 40 Object tmpObj = Mapt.get(obj3,"aa.[3].x"); 41 System.out.println(); 42 } 43 44 // @Test 45 public void jsonTest(){ 46 boolean tmpbl; 47 Map<String,Object> map =new LinkedHashMap<>(); 48 Mapt.setFriendsKeyBL(true); 49 Mapt.put(map,"aa.[0]",5); 50 Mapt.put(map,"aa.[3].x",2); 51 Mapt.put(map,"aa.[0].cc.xx","aaaaa"); 52 tmpbl=Mapt.isExist(map,"aa.[0].cc"); 53 tmpbl=Mapt.isChildType(map,"aa",List.class); 54 Mapt.put(map,"aa.[0].cc.yy","bb"); 55 String jsonstr = JackJsonUtils.toJson(map); 56 System.out.println(jsonstr); 57 58 } 59 60 @Test 61 public void beanMapTest(){ 62 Man man =new Man(); 63 man.setId(1L); 64 man.setName("zhang1"); 65 man.setType1("student"); 66 List<ManDetail> list = new ArrayList<>(); 67 man.setItems(list); 68 ManDetail detail=new ManDetail(); 69 detail.setId(1L); 70 detail.setpId(1L); 71 detail.setTel("1111"); 72 73 list.add(detail); 74 detail=new ManDetail(); 75 detail.setId(2L); 76 detail.setpId(1L); 77 detail.setTel("222"); 78 list.add(detail); 79 80 String str=JackJsonUtils.toJson(man); 81 Map<String,Object> map =JackJsonUtils.fromJson(str,Map.class ); 82 String manDetailStr = Mapt.getJsonString(map,"items.[0]"); 83 ManDetail manDetail = JackJsonUtils.fromJson(manDetailStr,ManDetail.class); 84 85 //展示通过js对象转标准JSON字符串,再转成Map实例 86 String str1=JackJsonUtils.getStdJsonStr("{no:1,name:'张三'}"); 87 Map<String,Object> map1 =JackJsonUtils.fromJson(str1,Map.class ); 88 89 str1=JackJsonUtils.getStdJsonStr("aa.js","man"); 90 map1 =JackJsonUtils.fromJson(str1,Map.class ); 91 92 //兼容spring的 BeanMap所得map的读写 93 map =BeanMap.create(man); 94 str1=Mapt.getString(map,"items.[0].man.name"); 95 96 System.out.println(str); 97 } 98 }
测试用到辅助类
1 public class Man implements Serializable { 2 private Long id; 3 private String name; 4 private String type1; 5 6 7 @TableField(exist = false) 8 private String nameDesc; 9 10 @TableField(exist = false) 11 private List<ManDetail> items; 12 //省略 getter and setter 13 }
1 import java.io.Serializable; 2 3 public class ManDetail implements Serializable { 4 private Long id; 5 private Long pId; 6 private String tel; 7 //省略 getter and setter 8 9 }