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

如何利用框架将带JSONPath的Map转换为嵌套JSON字符串?

扁平化Map转嵌套JSON的框架方案

问题场景

我有如下键值对形式的Map:

{
  "key1": "value1",
  "list[0].key1": "listkeyvalue1",
  "list[0].key2": "listkeyvalue2",
  "list[1].key1": "listkeyvalue1",
  "list[1].key2": "listkeyvalue3"
}

使用Jackson的ObjectMapper执行以下代码:

new ObjectMapper().writeValueAsString(map);

得到的是扁平化JSON:

{
  "key1": "value1",
  "list[0].key1": "listkeyvalue1",
  "list[0].key2": "listkeyvalue2",
  "list[1].key1": "listkeyvalue1",
  "list[1].key2": "listkeyvalue3"
}

但期望生成嵌套结构的JSON:

{
  "key1": "value1",
  "list": [
    {
      "key1": "listkeyvalue1",
      "key2": "listkeyvalue2"
    },
    {
      "key1": "listkeyvalue1",
      "key2": "listkeyvalue3"
    }
  ]
}

想知道有没有现成框架可以实现这个转换,不用自己编写逻辑。


可用框架方案

不用自己写路径解析逻辑,有几个现成工具可以直接实现这个转换:

1. Apache Commons Configuration

这个库原生支持解析带点分隔和数组索引的键,把扁平化Map转成嵌套结构。步骤很简单:

  • 用MapConfiguration包装你的扁平化Map
  • 借助NodeModel将配置转为树形节点结构
  • 把树形节点转成普通Map后,再用Jackson序列化即可

示例代码:

import org.apache.commons.configuration2.MapConfiguration;
import org.apache.commons.configuration2.tree.ImmutableNode;
import org.apache.commons.configuration2.tree.NodeModel;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.HashMap;
import java.util.Map;

public class FlatToNested {
    public static void main(String[] args) throws Exception {
        // 初始化扁平化Map
        Map<String, String> flatMap = new HashMap<>();
        flatMap.put("key1", "value1");
        flatMap.put("list[0].key1", "listkeyvalue1");
        flatMap.put("list[0].key2", "listkeyvalue2");
        flatMap.put("list[1].key1", "listkeyvalue1");
        flatMap.put("list[1].key2", "listkeyvalue3");

        // 转换为嵌套结构
        MapConfiguration config = new MapConfiguration(flatMap);
        NodeModel model = NodeModel.createModel(config);
        ImmutableNode root = model.getRootNode();

        // 将ImmutableNode转为可序列化的Map
        Map<String, Object> nestedMap = nodeToMap(root);

        // 生成嵌套JSON
        ObjectMapper mapper = new ObjectMapper();
        System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(nestedMap));
    }

    private static Map<String, Object> nodeToMap(ImmutableNode node) {
        Map<String, Object> map = new HashMap<>();
        for (ImmutableNode child : node.getChildren()) {
            if (child.getChildren().isEmpty()) {
                map.put(child.getNodeName(), child.getValue());
            } else {
                // 处理数组(节点名称相同的情况)
                if (map.containsKey(child.getNodeName())) {
                    Object existing = map.get(child.getNodeName());
                    if (!(existing instanceof java.util.List)) {
                        java.util.List<Object> list = new java.util.ArrayList<>();
                        list.add(existing);
                        list.add(nodeToMap(child));
                        map.put(child.getNodeName(), list);
                    } else {
                        ((java.util.List<Object>) existing).add(nodeToMap(child));
                    }
                } else {
                    map.put(child.getNodeName(), nodeToMap(child));
                }
            }
        }
        return map;
    }
}

2. Spring Binder(Spring生态下首选)

如果你的项目基于Spring或Spring Boot,直接用Binder类就能把扁平化键值对绑定到对应的实体类,序列化实体类就得到嵌套JSON,完全不用自己处理路径:

首先定义对应实体类:

public class DataModel {
    private String key1;
    private List<Item> list;

    // getter、setter
    public static class Item {
        private String key1;
        private String key2;
        // getter、setter
    }
}

然后用Binder绑定并序列化:

import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.MutablePropertySources;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.HashMap;
import java.util.Map;

public class SpringBinderExample {
    public static void main(String[] args) throws Exception {
        Map<String, String> flatMap = new HashMap<>();
        flatMap.put("key1", "value1");
        flatMap.put("list[0].key1", "listkeyvalue1");
        flatMap.put("list[0].key2", "listkeyvalue2");
        flatMap.put("list[1].key1", "listkeyvalue1");
        flatMap.put("list[1].key2", "listkeyvalue3");

        MutablePropertySources sources = new MutablePropertySources();
        sources.addFirst(new MapPropertySource("flatMap", flatMap));

        DataModel dataModel = Binder.get(sources).bind("", DataModel.class).get();

        ObjectMapper mapper = new ObjectMapper();
        System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(dataModel));
    }
}

3. Jackson JsonPointer(轻量实现)

Jackson的JsonPointer可以定位JSON节点,你可以遍历扁平化Map的键,用JsonPointer在空的JsonNode上逐个设置值,最后序列化这个JsonNode。虽然需要写一点遍历代码,但不需要自己解析路径语法:

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.util.HashMap;
import java.util.Map;

public class JacksonJsonPointerExample {
    public static void main(String[] args) throws Exception {
        Map<String, String> flatMap = new HashMap<>();
        flatMap.put("key1", "value1");
        flatMap.put("list[0].key1", "listkeyvalue1");
        flatMap.put("list[0].key2", "listkeyvalue2");
        flatMap.put("list[1].key1", "listkeyvalue1");
        flatMap.put("list[1].key2", "listkeyvalue3");

        ObjectNode rootNode = JsonNodeFactory.instance.objectNode();
        ObjectMapper mapper = new ObjectMapper();

        for (Map.Entry<String, String> entry : flatMap.entrySet()) {
            // 将"list[0].key1"转为JSONPointer格式"/list/0/key1"
            String pointerStr = "/" + entry.getKey().replace("[", "/").replace("]", "").replace(".", "/");
            rootNode.at(pointerStr).set(mapper.convertValue(entry.getValue(), JsonNode.class));
        }

        System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(rootNode));
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 01:45:30