Java中JSON对象表达式求值实现方案咨询
Java中JSON对象内表达式求值的实现方案
需求说明
源JSON包含三类需要求值的表达式:
- 纯算术表达式(如
${a}*${b}) - 字符串拼接(如
${model}-${variant}) - 拼接与算术组合(如
${model}-${variant}-${stage*10})
源JSON:
{"model":"abc","variant":"m1","stage":2,"a":100,"b":200,"display name":"${model}-${variant}","c":"${a}*${b}","description":"${model}-${variant}-${stage*10}"}
求值后目标JSON:
{"model":"abc","variant":"m1","stage":2,"a":100,"b":200,"display name":"abc-m1","c":"300","description":"abc-m1-20"}
可行实现方案
方案一:模板引擎+表达式求值库组合
用模板引擎处理字符串拼接逻辑,搭配表达式库完成算术运算,步骤如下:
- 选Apache Velocity或Freemarker做模板引擎,解析带变量占位符的字符串;
- 用Apache Commons JEXL或MVEL做表达式求值库,处理算术计算;
- 遍历JSON字段,先提取并计算算术子表达式,再用模板引擎渲染完整字符串;
- 将渲染结果替换回JSON,生成目标结构。
示例代码片段(JEXL+Velocity):
// 初始化JEXL引擎 JexlEngine jexl = new JexlEngine(); // 初始化Velocity引擎 Velocity.init(); VelocityContext velocityContext = new VelocityContext(); // 解析源JSON为Map(依赖Jackson) Map<String, Object> sourceMap = new ObjectMapper().readValue(sourceJson, Map.class); sourceMap.forEach(velocityContext::put); // 遍历处理每个字段 sourceMap.forEach((key, value) -> { if (value instanceof String strValue) { Pattern pattern = Pattern.compile("\\$\\{(.*?)\\}"); Matcher matcher = pattern.matcher(strValue); StringBuffer result = new StringBuffer(); while (matcher.find()) { String expr = matcher.group(1); if (expr.matches(".*[+\\-*/].*")) { // 计算算术表达式 JexlExpression jexlExpr = jexl.createExpression(expr); Object evalResult = jexlExpr.evaluate(new MapContext(sourceMap)); matcher.appendReplacement(result, evalResult.toString()); } else { // 保留变量占位符给Velocity处理 matcher.appendReplacement(result, matcher.group(0)); } } // 用Velocity渲染最终字符串 String processedExpr = matcher.appendTail(result).toString(); StringWriter writer = new StringWriter(); Velocity.evaluate(velocityContext, writer, "", processedExpr); sourceMap.put(key, writer.toString()); } }); // 转换回JSON字符串 String targetJson = new ObjectMapper().writeValueAsString(sourceMap);
方案二:自定义解析+JS引擎计算
不想引入过多第三方库时,可借助Java内置的ScriptEngine实现:
- 用正则提取
${}内的表达式内容; - 尝试用JS引擎计算表达式,失败则视为变量引用直接取值;
- 替换所有表达式后更新JSON字段。
示例代码片段:
ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript"); Map<String, Object> sourceMap = new ObjectMapper().readValue(sourceJson, Map.class); sourceMap.forEach((key, value) -> { if (value instanceof String strValue) { Pattern pattern = Pattern.compile("\\$\\{(.*?)\\}"); Matcher matcher = pattern.matcher(strValue); StringBuffer result = new StringBuffer(); while (matcher.find()) { String expr = matcher.group(1); Object evalResult; try { // 尝试计算表达式 evalResult = engine.eval(expr, new SimpleBindings(sourceMap)); } catch (ScriptException e) { // 计算失败则直接取变量值 evalResult = sourceMap.get(expr); } matcher.appendReplacement(result, evalResult.toString()); } sourceMap.put(key, matcher.appendTail(result).toString()); } }); String targetJson = new ObjectMapper().writeValueAsString(sourceMap);
方案三:使用支持表达式的JSON库
部分JSON库内置表达式求值能力,比如Jsonata的Java实现,可直接解析源JSON中的表达式并生成目标结构,无需拆分处理步骤。
内容的提问来源于stack exchange,提问作者Pranav
相关产品推荐
相关产品推荐

