You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中未知结构JSON的通用表达式求值方案(支持calc/concat)

在Java中实现未知结构JSON的表达式求值通用方案

需求说明

需要处理任意层级的JSON结构,自动识别并求值其中的calc()、concat()这类表达式,同时严格保留原JSON的层级结构。已知固定JSON结构时可实现,但需要一套通用的递归遍历处理方案。

实现思路

核心是递归遍历JSON节点,针对不同类型节点做差异化处理:

  • 对于JSON对象:遍历所有键值对,递归处理每个值,再构建新的对象节点
  • 对于JSON数组:遍历所有元素,递归处理每个元素,再构建新的数组节点
  • 对于字符串值:判断是否为目标表达式(如calc(...)),解析表达式后从当前上下文(当前层级的JSON对象)提取变量值,执行计算并替换原字符串

代码实现(基于Jackson库)

首先引入Jackson依赖:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.15.2</version>
</dependency>

通用处理工具类:

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class JsonExpressionEvaluator {
    private static final ObjectMapper mapper = new ObjectMapper();
    private static final ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
    private static final Pattern CALC_PATTERN = Pattern.compile("^calc\\((.*)\\)$");
    private static final Pattern CONCAT_PATTERN = Pattern.compile("^concat\\((.*)\\)$");

    // 对外暴露的处理入口
    public static JsonNode evaluate(JsonNode root) {
        return processNode(root, null);
    }

    // 递归处理节点,parentNode传递当前层级的变量上下文
    private static JsonNode processNode(JsonNode node, JsonNode parentNode) {
        if (node.isObject()) {
            ObjectNode newObject = mapper.createObjectNode();
            node.fields().forEachRemaining(entry -> {
                String key = entry.getKey();
                JsonNode value = entry.getValue();
                newObject.set(key, processNode(value, node));
            });
            return newObject;
        } else if (node.isArray()) {
            ArrayNode newArray = mapper.createArrayNode();
            node.elements().forEachRemaining(element -> {
                newArray.add(processNode(element, parentNode));
            });
            return newArray;
        } else if (node.isTextual()) {
            String text = node.asText();
            // 处理calc算术表达式
            Matcher calcMatcher = CALC_PATTERN.matcher(text);
            if (calcMatcher.matches() && parentNode != null) {
                String expr = calcMatcher.group(1);
                String replacedExpr = replaceVariables(expr, parentNode);
                try {
                    Object result = engine.eval(replacedExpr);
                    return mapper.valueToTree(result);
                } catch (Exception e) {
                    // 表达式解析失败则保留原字符串
                    return node;
                }
            }
            // 处理concat字符串拼接表达式
            Matcher concatMatcher = CONCAT_PATTERN.matcher(text);
            if (concatMatcher.matches() && parentNode != null) {
                String parts = concatMatcher.group(1);
                String[] partArr = parts.split(",");
                StringBuilder sb = new StringBuilder();
                for (String part : partArr) {
                    String trimmedPart = part.trim();
                    if (parentNode.has(trimmedPart)) {
                        sb.append(parentNode.get(trimmedPart).asText());
                    } else {
                        sb.append(trimmedPart.replace("'", "").replace("\"", ""));
                    }
                }
                return mapper.valueToTree(sb.toString());
            }
            // 非表达式字符串直接返回
            return node;
        } else {
            // 数值、布尔等非字符串类型直接返回
            return node;
        }
    }

    // 替换表达式中的变量为当前上下文的实际值
    private static String replaceVariables(String expr, JsonNode parentNode) {
        Pattern varPattern = Pattern.compile("([a-zA-Z_][a-zA-Z0-9_]*)");
        Matcher varMatcher = varPattern.matcher(expr);
        StringBuffer sb = new StringBuffer();
        while (varMatcher.find()) {
            String varName = varMatcher.group(1);
            if (parentNode.has(varName)) {
                JsonNode varValue = parentNode.get(varName);
                if (varValue.isNumber()) {
                    varMatcher.appendReplacement(sb, varValue.asText());
                } else if (varValue.isTextual()) {
                    varMatcher.appendReplacement(sb, "'" + varValue.asText() + "'");
                } else {
                    varMatcher.appendReplacement(sb, varName);
                }
            } else {
                varMatcher.appendReplacement(sb, varName);
            }
        }
        varMatcher.appendTail(sb);
        return sb.toString();
    }

    // 测试示例
    public static void main(String[] args) throws Exception {
        String sourceJson = """
                {
                  "a": 100,
                  "b": 200,
                  "c": 300,
                  "d": "calc(a+c)",
                  "f": {
                    "g": 100,
                    "h": 200,
                    "i": "calc(g+h)",
                    "k": {
                      "m": 50,
                      "n": 70,
                      "p": "calc(m+n)"
                    }
                  }
                }
                """;
        JsonNode root = mapper.readTree(sourceJson);
        JsonNode result = evaluate(root);
        System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(result));
    }
}

关键说明

  1. 递归遍历:通过processNode方法递归处理所有类型的JSON节点,确保任意嵌套层级都能被覆盖
  2. 表达式识别:用正则匹配目标表达式格式,后续扩展新表达式类型只需添加对应正则和处理逻辑
  3. 上下文变量替换:从当前层级的JSON对象中提取变量值,替换表达式中的变量后执行计算
  4. ScriptEngine:借助Java内置的JavaScript引擎执行表达式,支持常见算术运算,无需手动实现复杂的表达式解析
  5. 容错处理:表达式解析失败时保留原字符串,避免破坏JSON原有结构

扩展方向

  • 支持跨层级变量引用:修改上下文传递逻辑,实现f.g这类层级变量的引用
  • 增加聚合表达式:比如sum()、average(),扩展对应的处理逻辑即可
  • 安全增强:若处理不可信来源的JSON,需限制ScriptEngine权限,或使用更安全的表达式解析库(如JEXL)

内容的提问来源于stack exchange,提问作者dattam katore

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 10:45:33