文档章节

Java内嵌Groovy脚本引擎进行业务规则剥离(三)--多层Map对象简化

O龙猫O
 O龙猫O
发布于 2017/02/08 10:13
字数 2032
阅读 1634
收藏 13

java操作json对象不像js那样方便,实际开发过程中,我们需要他像js那样方便进行存取。json对象在java中可借助map进行实现, 我们需要对这个map进行增强。

例如我们需要的json对象实际上是这个样子

{
         '基础信息':
                    {
                            '是否90后': null,
                            '性别'   : 0,
                            '注册天数':0,
                            '地区':null,
                    },

            '评级'  : {
                    '学费档次' : null,
                    '收入档次':null
            },
            '学习情况': {
                    '总学时':0,
                    '迟到次数':0,
                    '出勤次数':0,
                    '单门课程最长学时':0,
            }
}

为了方便java程序调用,自然会使用到map来实现。

如果直接使用map进行组装,代码将会是这样(属性少,层次只有一层是没问题的,如果层次深一些,属性多一些,这里就会非常麻烦。

	public void test00(){
		Map<String,Object> rootObject = new LinkedHashMap<String, Object>();
		Map<String,Object> ruleSet = new LinkedHashMap<String, Object>();
		
		Map<String,Object> baseMap = new LinkedHashMap<String, Object>();
		baseMap.put("是否90后", "是");
		baseMap.put("性别", "女");
		baseMap.put("注册天数", 180);
		baseMap.put("地区", "江浙沪");
		Map<String,Object> ratingMap = new LinkedHashMap<String, Object>();
		ratingMap.put("学费档次", "A");
		ratingMap.put("收入档次", "B");
		
		//按层级组装
		rootObject.put("规则集", ruleSet);
		ruleSet.put("基础信息", baseMap);
		ruleSet.put("评级", ratingMap);
		
	}

其实我想偷懒想它的写法是这个样子,而最终生成的map存储结构是具备层次结构的。

dataObject.xput("规则集.基础信息.是否90后", "是");
dataObject.xput("规则集.基础信息.性别", "女");
dataObject.xput("规则集.基础信息.注册天数", 180);
dataObject.xput("规则集.基础信息.地区", "江浙沪");
dataObject.xput("规则集.评级.学费档次", "A");
dataObject.xput("规则集.评级.收入档次", "B");

因此,我们需要继承map对象,并且借助xpah的思路,进行一些扩展增强。

DataObject类就是用来解决这个问题(代码有点多,不想仔细阅读的,可以跳过,看后面的使用案例)。

package com.amarsoft.rax.lang;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.MessageFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONPath;
import com.alibaba.fastjson.JSONPathException;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.serializer.SerializeConfig;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.serializer.SimpleDateFormatSerializer;

/**
 * 定义通用数据对象,实际上是对Map的直接包装,方便取数据以及对数据的直接操作<br/>
 * 支持xpath取层次较深的数据
 * @date 2016/12/09
 */
public class DataObject extends LinkedHashMap<String,Object>{

    private static final long serialVersionUID = 5317763763625001921L;
    private static DecimalFormat decimalFormat = new DecimalFormat("#");
    private static DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
    private Set<String> xPathKeyCache = new LinkedHashSet<String>();
    
    public enum DataType{Object,String,Double,BigDecimal,Integer,Date,Boolean,UnKnow}

    public DataObject() {
        super();
    }
    
    @SuppressWarnings("unchecked")
    public DataObject(Object bean){
        if(bean instanceof Map){
            this.putAll((Map<String,Object>)bean);
        }else{
            Map<String,Object> map = bean2Map(bean);
            this.putAll((Map<String,Object>)map);
        }
    }
    
	public static final Map<String, Object> bean2Map(Object bean) {  
        Map<String, Object> returnMap = new HashMap<String, Object>();  
        BeanInfo beanInfo;
        try {
            beanInfo = Introspector.getBeanInfo(bean.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();  
            for (int i = 0; i< propertyDescriptors.length; i++) {  
                PropertyDescriptor descriptor = propertyDescriptors[i];  
                String propertyName = descriptor.getName();  
                if (!propertyName.equals("class")) {  
                    Method readMethod = descriptor.getReadMethod();  
                    Object result = readMethod.invoke(bean, new Object[0]);  
                    if (result != null) {  
                        returnMap.put(propertyName, result);  
                    } else {  
                        returnMap.put(propertyName, "");  
                    }  
                }  
            }  
        } catch (IntrospectionException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (IllegalArgumentException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        }  
        return returnMap;  
    }  
	
	public static <T> T map2Bean(Map<String, Object> map, Class<T> clazz) {  
        T bean = null;  
        try {  
            bean = clazz.newInstance();  
            org.apache.commons.beanutils.BeanUtils.populate(bean, map);  
        } catch (InstantiationException e) {  
            e.printStackTrace();  
        } catch (IllegalAccessException e) {  
            e.printStackTrace();  
        } catch (InvocationTargetException e) {  
            e.printStackTrace();  
        }  
        return bean;  
    }
    
    public <T> T castToBean(Class<T> clazz) {  
        return map2Bean(this, clazz);
    }
    
    /**
     * 名称是否为XPath表达式
     * @param name
     * @return
     */
    protected boolean isXPath(String name){
        return false;
    }
    
    public DataType getDataType(Object object){
        DataType dataType = DataType.UnKnow;
        if(object instanceof Double){
            dataType = DataType.Double;
        }else if(object instanceof Float){
            dataType = DataType.Double;
        }else if(object instanceof Integer){
            dataType = DataType.Integer;
        }else if(object instanceof BigDecimal){
            dataType = DataType.BigDecimal;
        }else if(object instanceof Number){
            dataType = DataType.Double;
        }else if(object instanceof Date){
            dataType = DataType.Date;
        }else if(object instanceof Boolean){
            dataType = DataType.Boolean;
        }else if(object instanceof String){
            dataType = DataType.String;
        }else if(object instanceof Object){
            dataType = DataType.Object;
        }
        return dataType;
    }
    public DataType getDataType(String name){
        Object object = getObject(name);
        if(object == null) return null;
        return getDataType(object);
    }
    
    @SuppressWarnings("unchecked")
    public Object getObject(String name){
        Object object = null;
        if(name.indexOf(".")>0){    //说明是xpath格式
            
            JSONPath xpath = new JSONPath(name);
            try{
                object = xpath.eval(this);
            }catch(NullPointerException e){
                object = null;
            }catch(JSONPathException e){
            	//fastjson的xpath不太靠谱,有时候解不天,如果解不开,则硬解
                String[] names = name.split("\\.");
                Map<String,Object> curObject = this;
                String nPath = "";
                for(String n : names){
                    nPath += n+".";
                    if(curObject == null || !curObject.containsKey(n)){
                        throw new NullPointerException(MessageFormat.format("attribute [{0}] not exists in DataObject",nPath.substring(0, nPath.length()-1)));
                    }
                    object = curObject.get(n);
                    if(object instanceof Map){
                        curObject = (Map<String, Object>)object;
                        continue;
                    }
                    return object;
                }
            }
        }else{
            if(!containsKey(name)){
                throw new NullPointerException(MessageFormat.format("attribute [{0}] not exists in DataObject",name));
            }
            object = get(name);
        }
        return object;
    }
    
    public boolean attributeExists(String name){
        if(name.indexOf(".")>0){    //说明是xpath格式
            JSONPath xpath = new JSONPath(name);
            Object object = null;
            try{
                object = xpath.eval(this);
            }catch(NullPointerException e){
                object = null;
            }
            return object != null;
        }else{
            return this.containsKey(name);
        }
    }
    
    @SuppressWarnings("unchecked")
    public <T> T getObject(String name,Class<T> requiredType) {
        Object object = getObject(name);
        return (T)object;
    }
    @SuppressWarnings("unchecked")
    public <T> List<T> getObjectList(String name,Class<T> requiredType) {
        Object object = getObject(name);
        return (List<T>)object;
    }
    
    
    
    public void putAll(Map<? extends String, ? extends Object> m) {
        super.putAll(m);
    }
    
    @SuppressWarnings("unchecked")
    public Object put(String key, Object value) {
        if(value instanceof Map){
            return super.put(key,cascadeConvertMap((Map<Object, Object>)value));
        }else if(value instanceof List){
            List<Object> listValue = (List<Object>)value;
            for(int i=0;i<listValue.size();i++){
                Object v = listValue.get(i);
                if(v instanceof Map){
                    listValue.set(i, cascadeConvertMap((Map<Object,Object>)v));
                }
            }
            return super.put(key, listValue);
        }else{
            return super.put(key, value);
        }
    }
    
    /**
     * 递归转换所有的Map为ElasticDataObject
     * @param key
     * @param mapValue
     * @return
     */
    @SuppressWarnings("unchecked")
    protected DataObject cascadeConvertMap(Map<Object,Object> mapValue){
        Iterator<?> iterator = mapValue.keySet().iterator();
        while(iterator.hasNext()){
            Object k = iterator.next();
            Object v = mapValue.get(k);
            if(v instanceof Map){
                mapValue.put(k, cascadeConvertMap((Map<Object,Object>)v));
            }
        }
        return new DataObject(mapValue);
    }

    public Integer getInteger(String name){
        Object object = getObject(name);
        if(object == null) return null;
        DataType dataType = getDataType(object);
        if(dataType == DataType.Integer){
            return (Integer)object;
        }else if(dataType == DataType.Double){
            return ((Double)object).intValue();
        }else if(dataType == DataType.BigDecimal){
            return ((BigDecimal)object).intValue();
        }else if(dataType == DataType.String){
            return Integer.parseInt((String)object);
        }else{
            return null;
        }
    }
    public Double getDouble(String name){
        Object object = getObject(name);
        if(object == null) return null;
        DataType dataType = getDataType(object);
        if(dataType == DataType.Integer){
            return ((Integer)object).doubleValue();
        }else if(dataType == DataType.Double){
            return ((Double)object);
        }else if(dataType == DataType.BigDecimal){
            return ((BigDecimal)object).doubleValue();
        }else if(dataType == DataType.String){
            return Double.parseDouble((String)object);
        }else{
            return null;
        }
    }
    
    /**
     * 取出数据,直接转为String
     * @param name
     * @return
     */
    public String getString(String name){
        Object object = getObject(name);
        if(object == null) return null;
        DataType dataType = getDataType(object);
        if(dataType == DataType.Integer){
            return decimalFormat.format((Integer)object);
        }else if(dataType == DataType.Double){
            return decimalFormat.format((Double)object);
        }else if(dataType == DataType.String){
            return (String)object;
        }else if(dataType == DataType.Boolean){
            return ((Boolean)object).toString();
        }else if(dataType == DataType.Date){
            return dateFormat.format((Date)object);
        }else{
            return object.toString();
        }
    }
    
    public Boolean getBoolean(String name){
        Object object = getObject(name);
        if(object == null) return null;
        DataType dataType = getDataType(object);
        if(dataType == DataType.Boolean){
            return ((Boolean)object);
        }else if(dataType == DataType.String){
            return Boolean.parseBoolean((String)object);
        }else{
            return null;
        }
    }
    
    public String getJSONString() {
        SerializeConfig slizeCfg = new SerializeConfig();
        slizeCfg.put(Date.class, new SimpleDateFormatSerializer("yyyy/MM/dd HH:mm:ss.SSS")); 
    	return JSON.toJSONString(this,
        		slizeCfg,
        		SerializerFeature.WriteMapNullValue,
				SerializerFeature.PrettyFormat,
				SerializerFeature.WriteNonStringKeyAsString,
				SerializerFeature.SortField);
    }

    /**
     * 取出数据,如果是日期类型或日期字串,都可以直接转成日期类型
     * @param name
     * @return
     */
    public Date getDate(String name){
        Object object = getObject(name);
        if(object == null) return null;
        DataType dataType = getDataType(object);
        if(dataType == DataType.Date){
            return (Date)object;
        }else if(dataType == DataType.String){
            return toDate((String)object);
        }else{
            return null;
        }
    }
    
    
    private Date toDate(String _date){
    	Date date = new Date();
    	
    	DateFormat df = dateFormat;
    	try {
			date = df.parse(_date);
		} catch (ParseException e) {
			df = new SimpleDateFormat("yyyy/MM/dd");
			try {
				date = df.parse(_date);
			} catch (ParseException e1) {
				throw new RuntimeException("",e);
			}
		}
    	
    	return date;
    }
    
    /**
     * 支持xpath形式的设置值
     * @param name
     * @param value
     */
    public void xput(String name,Object value){
        if(name.indexOf(".")<0)put(name,value);
        String[] names = name.split("\\.");
        DataObject cursor = this;
        for(int i=0;i<names.length;i++){
            String n = names[i];
            boolean isLast = (i == names.length -1);
            if(!isLast){
                //根据xpath路径,不存在,则创建一个相应的对象
                if(!cursor.containsKey(n)){
                    cursor.put(n, new DataObject());
                }
                cursor = cursor.getObject(n, DataObject.class);
            }else{
                cursor.put(n, value);
            }
        }
        xPathKeyCache.add(name);
    }
    
    public Iterator<String> xpathKeyIterator(){
    	return xPathKeyCache.iterator();
    }
    
    /**
     * 把层次结构深的对象使用xpath方式拉平
     * @return
     */
    public Map<String,Object> flatMap(){
    	Map<String,Object> mapResult = new LinkedHashMap<String, Object>();
    	Iterator<String> iterator = xpathKeyIterator();
    	while(iterator.hasNext()){
    		String xpath = iterator.next();
    		mapResult.put(xpath, this.getObject(xpath));
    	}
    	return mapResult;
    }
    
    public void set(String text){
        this.putAll(JSON.parseObject(text, new TypeReference<Map<String,Object>>(){}));
    }
    public static DataObject createNew(String text){
        DataObject edo = new DataObject();
        edo.set(text);
        return edo;
    }
}

用fastjson来解决xpath的解析问题。

代码有400多行,阅读起来有点累。不过没关系,请看下面,知道怎么用就好了。

最终的使用案例是这样:

	@Test
	public void test01(){
		DataObject dataObject = new DataObject();
		
		//形成有层次结构的map
		dataObject.xput("规则集.基础信息.是否90后", "是");
		dataObject.xput("规则集.基础信息.性别", "女");
		dataObject.xput("规则集.基础信息.注册天数", 180);
		dataObject.xput("规则集.基础信息.地区", "江浙沪");
		dataObject.xput("规则集.评级.学费档次", "A");
		dataObject.xput("规则集.评级.收入档次", "B");
		
		System.out.println(dataObject.getJSONString());
		
		//使用xpath取数据或对象
		Assert.assertTrue(dataObject.getObject("规则集") instanceof Map);
		Assert.assertTrue(dataObject.getObject("规则集") instanceof DataObject);
		Assert.assertTrue(dataObject.getObject("规则集.基础信息") instanceof Map);
		Assert.assertTrue(dataObject.getObject("规则集.基础信息") instanceof DataObject);
		Assert.assertTrue(dataObject.getObject("规则集.基础信息.注册天数") instanceof Integer);
		Assert.assertTrue(dataObject.getInteger("规则集.基础信息.注册天数") == 180);
		Assert.assertEquals(dataObject.getString("规则集.基础信息.注册天数"),"180");
	}

 

© 著作权归作者所有

O龙猫O

O龙猫O

粉丝 124
博文 39
码字总数 21143
作品 1
苏州
部门经理
私信 提问
加载中

评论(2)

O龙猫O
O龙猫O 博主

引用来自“aires-sky”的评论

String str="{
'基础信息':
{
'是否90后': null,
'性别' : 0,
'注册天数':0,
'地区':null,
},

'评级' : {
'学费档次' : null,
'收入档次':null
},
'学习情况': {
'总学时':0,
'迟到次数':0,
'出勤次数':0,
'单门课程最长学时':0,
}
}";
JSONObject jasonObject = JSONObject.fromObject(str);
Map map = (Map)jasonObject;
这样转换不可以吗?

至于读取,我觉得你这种思路还可以.
可以的。如果一次性到位,你这种做法也是OK的。如果这个json对象我需要进行动态存取一个指定层级指定位置的属性,会比较麻烦一点。我这种方式,无非就是简化编码开发,根据情况选择一个适合于自己的需求就可以。
烨儿
烨儿
String str="{
'基础信息':
{
'是否90后': null,
'性别' : 0,
'注册天数':0,
'地区':null,
},

'评级' : {
'学费档次' : null,
'收入档次':null
},
'学习情况': {
'总学时':0,
'迟到次数':0,
'出勤次数':0,
'单门课程最长学时':0,
}
}";
JSONObject jasonObject = JSONObject.fromObject(str);
Map map = (Map)jasonObject;
这样转换不可以吗?

至于读取,我觉得你这种思路还可以.
java脚本引擎的设计原理浅析

本人在阿里巴巴长期担任和负责规则引擎、流程引擎相关的技术开发,另外还负责开发和维护开源项目: https://github.com/alibaba/QLExpress QLExpress是一个脚本引擎工具,类似Groovy,JRuby...

baobao_pandora
2018/08/01
0
0
《Groovy极简教程》第1章 Groovy简介

《Groovy极简教程》第1章 Groovy简介 Groovy: 绝妙的; 流行的; 最佳状态的。 A multi-faceted language for the Java platform. (JVM平台上的多面体语言。) 官网文档:http://www.groovy-lan...

程序员诗人
2017/04/16
0
0
Gradle入门(一)--Groovy常用语法

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 https://blog.csdn.net/zly921112/article/details/90479841 概述 Groovy是一种可以用于构建...

zhuliyuan丶
05/23
0
0
Android Gradle(三)Groovy快速入门指南

本文首发于微信公众号「刘望舒」 原文链接:Groovy快速入门看这篇就够了 前言 在前面我们学习了为什么现在要用Gradle?和Gradle入门前奏两篇文章,对Gradle也有了大概的了解,这篇文章我们接...

刘望舒
2018/10/10
0
0
Groovy入门 | 基础语法

Java的东西Groovy都能用,包括语法和类库 Groovy继承了Java的所有东西,就是你突然忘了Groovy的语法可以写成Java代码,也就是Groovy和Java混在一起也能执行。 Groovy和Java一样运行在JVM,源...

水天云黑白
2018/10/28
0
0

没有更多内容

加载失败,请刷新页面

加载更多

使用zabbix自带的模板监控MySQL自带

一、安装zabbix server 略 二、安装zabbix agent 略 三、给主机套自带的模板 略 四、创建授权用户 mysql> grant all on *.* to 'zabbix'@'localhost' identified by 'musingtec2019';Quer......

雁南飞丶
8分钟前
4
0
notepad++快捷键

notepad++也情有独钟,最近发现了一个快捷键,就是选中单词,ctrl+shift+enter。不过现在想知道一个快捷键,假设有三行代码,选中后一般按TAB就可以三行全部缩进. Notepad++绝对是windows下进...

zhengzhixiang
30分钟前
5
0
区块链背景是什么?区块链的意义是什么?

一、前言 区块链技术的首次也是最著名的应用是比特币,一个在2009年1月初正式上线运行的去中心化数字货币应用,他的创始人叫中本聪,但目前大家并不知道此人的真实身份。 比特币不同于现代国...

daxiongdi
35分钟前
4
0
在Bash中循环浏览文件内容

如何使用Bash遍历文本文件的每一行? 使用此脚本: echo "Start!"for p in (peptides.txt)do echo "${p}"done 我在屏幕上得到以下输出: Start!./runPep.sh: line 3: syntax error......

技术盛宴
38分钟前
8
0
史上最强IP正则表达式

port ([0-9]|[1-9]\\d{1,3}|[1-5]\\d{4}|6[0-4]\\d{4}|65[0-4]\\d{2}|655[0-2]\\d|6553[0-5]) ipv4 ^((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)$ ipv4+mask......

蜗牛伊
41分钟前
10
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部