Java中如何计算JSON对象内的表达式?
在Java中计算JSON对象内的表达式
我们需要解析JSON对象,将其中形如calc(表达式)的字符串替换为对应表达式的计算结果——比如把"calc(a+c)"换成400(当a=100、c=300时)。之前尝试的工具不满足需求,这里可以用**Jackson(JSON解析)+ Apache Commons JEXL(表达式计算)**组合实现。
一、依赖准备
如果用Maven,在pom.xml中添加以下依赖:
<!-- Jackson 用于JSON解析与修改 --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.15.2</version> </dependency> <!-- Apache Commons JEXL 用于解析计算表达式 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-jexl3</artifactId> <version>3.3</version> </dependency>
二、核心实现逻辑
- 用Jackson将源JSON解析为可修改的
ObjectNode; - 递归遍历所有JSON节点:
- 识别字符串节点中符合
calc(...)格式的内容; - 提取括号内的表达式,收集当前节点层级的所有数值型键值对作为计算上下文;
- 用JEXL计算表达式结果,将原字符串节点替换为数值节点;
- 识别字符串节点中符合
- 将修改后的
ObjectNode转回格式化的JSON字符串。
三、完整代码示例
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import org.apache.commons.jexl3.JexlBuilder; import org.apache.commons.jexl3.JexlContext; import org.apache.commons.jexl3.JexlEngine; import org.apache.commons.jexl3.MapContext; import java.util.regex.Matcher; import java.util.regex.Pattern; public class JsonExpressionEvaluator { // 匹配calc(...)格式的正则表达式 private static final Pattern CALC_PATTERN = Pattern.compile("^calc\\((.*)\\)$"); // 初始化JEXL表达式引擎 private static final JexlEngine JEXL_ENGINE = new JexlBuilder().create(); public static void main(String[] args) throws Exception { // 源JSON字符串 String sourceJson = """ { "a": 100, "b": 200, "c": 300, "d": "calc(a+c)", "f": { "g": 100, "h": 200, "i": "calc(g+h)" } } """; ObjectMapper mapper = new ObjectMapper(); // 解析为可修改的ObjectNode ObjectNode rootNode = (ObjectNode) mapper.readTree(sourceJson); // 递归处理所有节点 processNode(rootNode); // 输出格式化后的结果JSON String resultJson = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(rootNode); System.out.println(resultJson); } private static void processNode(ObjectNode node) { // 遍历当前节点的所有字段 node.fields().forEachRemaining(entry -> { JsonNode valueNode = entry.getValue(); if (valueNode.isObject()) { // 子节点是对象,递归处理 processNode((ObjectNode) valueNode); } else if (valueNode.isTextual()) { String text = valueNode.asText(); Matcher matcher = CALC_PATTERN.matcher(text); if (matcher.find()) { // 提取括号内的表达式内容 String exprStr = matcher.group(1); // 构建当前节点的计算上下文(仅包含数值类型的键值对) JexlContext context = new MapContext(); node.fields().forEachRemaining(field -> { JsonNode fieldValue = field.getValue(); if (fieldValue.isNumber()) { context.set(field.getKey(), fieldValue.asDouble()); } }); // 计算表达式结果 Object result = JEXL_ENGINE.createExpression(exprStr).evaluate(context); // 将原字符串节点替换为数值节点 if (result instanceof Number) { node.put(entry.getKey(), ((Number) result).intValue()); } } } }); } }
四、运行结果
执行代码后,输出的JSON与预期完全一致:
{ "a" : 100, "b" : 200, "c" : 300, "d" : 400, "f" : { "g" : 100, "h" : 200, "i" : 300 } }
内容的提问来源于stack exchange,提问作者dattam katore
相关产品推荐
相关产品推荐

