com.gitee.qdbp.staticize.utils.OgnlUtils Maven / Gradle / Ivy
package com.gitee.qdbp.staticize.utils;
import java.util.HashMap;
import java.util.Map;
import com.gitee.qdbp.able.model.reusable.ExpressionExecutor;
import com.gitee.qdbp.able.model.reusable.ExpressionMap;
import com.gitee.qdbp.staticize.exception.TagException;
import com.gitee.qdbp.tools.utils.JsonTools;
import com.gitee.qdbp.tools.utils.StringTools;
import ognl.ExpressionSyntaxException;
import ognl.InappropriateExpressionException;
import ognl.MethodFailedException;
import ognl.NoSuchPropertyException;
import ognl.Ognl;
import ognl.OgnlContext;
import ognl.OgnlException;
/**
* OGNL工具类, copy from qdbp-tools.jar OgnlTools
*
* @author zhaohuihua
* @version 20200531
*/
public class OgnlUtils {
/** 静态工具类私有构造方法 **/
private OgnlUtils() {
}
/**
* 计算Ognl表达式的值
*
* @param expression 表达式
* @return 计算结果
* @throws TagException 表达式语法错误, 表达式取值错误
*/
public static Object evaluate(String expression) throws TagException {
return doEvaluate(expression, RESULT_SCALE, CALC_SCALE, null);
}
/**
* 计算Ognl表达式的值
*
* @param expression 表达式
* @param root 变量根容器
* @return 计算结果
* @throws TagException 表达式语法错误, 表达式取值错误
*/
public static Object evaluate(String expression, Object root) throws TagException {
return doEvaluate(expression, RESULT_SCALE, CALC_SCALE, root);
}
/**
* 计算Ognl表达式的值
*
* @param expression 表达式
* @param scale 结果保留几位小数 (只在结果是数字时生效)
* @param root 变量根容器
* @return 计算结果
* @throws TagException 表达式语法错误, 表达式取值错误
*/
public static Object evaluate(String expression, int scale, Object root) throws TagException {
return doEvaluate(expression, scale, CALC_SCALE, root);
}
/**
* 计算Ognl表达式的值
*
* @param expression 表达式
* @param resultScale 结果保留几位小数 (只在结果是数字时生效)
* @param calcScale 计算过程中的数字保留几位小数
* @param root 变量根容器
* @return 计算结果
* @throws TagException 表达式语法错误, 表达式取值错误
*/
public static Object evaluate(String expression, int resultScale, int calcScale, Object root)
throws TagException {
return doEvaluate(expression, resultScale, calcScale, root);
}
/**
* 计算Ognl表达式的值
*
* @param expression 表达式
* @param useBigDecimal 是否转换为BigDecimal以解决浮点数计算精度的问题
* @param root 变量根容器
* @return 计算结果
* @throws TagException 表达式语法错误, 表达式取值错误
*/
public static Object evaluate(String expression, boolean useBigDecimal, Object root) throws TagException {
return doEvaluate(expression, null, useBigDecimal ? CALC_SCALE : null, root);
}
static final Integer RESULT_SCALE = null;
static final Integer CALC_SCALE = 18;
/**
* 计算Ognl表达式的值
*
* @param expression 表达式
* @param resultScale 结果保留几位小数 (只在结果是数字时生效)
* @param calcScale 计算过程中的数字保留几位小数
* @param root 变量根容器
* @return 计算结果
* @throws TagException 表达式语法错误, 表达式取值错误
*/
static Object doEvaluate(String expression, Integer resultScale, Integer calcScale, Object root)
throws TagException {
if (expression == null || expression.trim().length() == 0) {
throw new TagException("ExpressionCanNotBeEmpty");
}
Object vars = root;
if (root != null && calcScale != null && !(root instanceof ExpressionMap)) {
Map json = JsonTools.beanToMap(root);
ExpressionMap map = new ExpressionMap();
map.setDecimalCalcScale(calcScale);
map.putAll(json);
vars = map;
}
OgnlContext context = new OgnlContext(null, null, OgnlMemberAccess.ALLOW_ALL_ACCESS);
try {
Object result = Ognl.getValue(expression, context, vars);
return ExpressionExecutor.trySetDecimalScale(result, resultScale);
} catch (ExpressionSyntaxException e) {
throw new TagException("ExpressionSyntaxException: " + expression, e);
} catch (MethodFailedException e) {
throw new TagException("MethodFailedException: " + expression, e);
} catch (InappropriateExpressionException e) {
// 不以属性引用结尾的表达式传递给setValue时将触发该异常
throw new TagException("InappropriateExpressionException: " + expression, e);
} catch (NoSuchPropertyException e) {
// 表达式指定的属性不存在, 不需要报错, 以方便页面取值, 不需要空值判断
return null;
} catch (OgnlException e) {
// source is null for getProperty(null, "fieldName")
// 取Ognl表达式出错, 不需要报错, 以方便页面取值, 不需要空值判断
return null;
} catch (Exception e) {
throw new TagException("UnknownException: " + expression, e);
}
}
/**
* 从容器中获取Ognl表达式的值
*
* @param root 根容器
* @param fields 字段名
* @return 字段值
* @throws TagException 表达式语法错误, 表达式取值错误
*/
public static Object getValue(Object root, String fields) throws TagException {
return evaluate(fields, false, root);
}
/**
* 根据Ognl表达式向容器中设置值
*
* @param root 变量根容器
* @param fields 字段名
* @param value 字段值
* @throws TagException 表达式语法错误, 表达式指定的属性不存在
*/
public static void setValue(Object root, String fields, Object value) throws TagException {
if (fields == null || fields.trim().length() == 0) {
throw new TagException("ExpressionCanNotBeEmpty");
}
// 检查需要设置的key的上级是否存在, 如果不存在则设置为空map
checkParentFieldInMap(root, fields);
OgnlContext context = new OgnlContext(null, null, OgnlMemberAccess.ALLOW_ALL_ACCESS);
try {
Ognl.setValue(fields, context, root, value);
} catch (ExpressionSyntaxException e) {
throw new TagException("ExpressionSyntaxException: " + fields, e);
} catch (MethodFailedException e) {
throw new TagException("MethodFailedException: " + fields, e);
} catch (NoSuchPropertyException e) {
throw new TagException("NoSuchPropertyException: " + fields, e);
} catch (InappropriateExpressionException e) {
// 不以属性引用结尾的表达式传递给setValue时将触发该异常
throw new TagException("InappropriateExpressionException: " + fields, e);
} catch (OgnlException e) {
throw new TagException("UnknownException: " + fields, e);
} catch (Exception e) {
throw new TagException("UnknownException: " + fields, e);
}
}
// 为了能直接在map中通过多级key设置value
// 先检查需要设置的key的上级是否存在, 如果不存在则设置为空map
// 如setValue(map, "userBean.address.details", "Beijing China")
// 如果userBean和address不存在就会报错
private static void checkParentFieldInMap(Object root, String fields) {
if (root instanceof Map && fields.indexOf('.') > 0) {
String[] fieldNames = StringTools.split(fields, '.');
@SuppressWarnings("unchecked")
Map parent = (Map) root;
for (int i = 0; i < fieldNames.length - 1; i++) {
String fieldName = fieldNames[i];
if (!StringTools.isWordString(fieldName)) {
break; // 如果不是字段名, 则退出, 如: address[0], getAddress()
}
Object fieldValue = parent.get(fieldName);
if (fieldValue == null) {
Map map = new HashMap<>();
parent.put(fieldName, map);
parent = map;
} else if (fieldValue instanceof Map) {
@SuppressWarnings("unchecked")
Map map = (Map) fieldValue;
parent = map;
} else {
break;
}
}
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy