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

Java 8中如何从数据库表记录生成动态JSON?

问题

我有如下数据库表记录,表中每行包含各类字符串记录,格式如下。其中domainVal、idVal、versionVal为常量,其余键均为动态(可为任意字符串);payment[]对应JSON中的数组结构。我需要从这类记录生成动态JSON。

尝试过创建POJO,但由于字段不固定,无法生成精确的POJO;也尝试用Java集合存储记录并生成JSON,但不知道如何解析记录存入集合。

数据库表

domainidversion
identifier.domainKeyidentifier.idKeyidentifier.versionKey
payload.account.domainpayload.account.idpayload.order.version.version
payload.order.domainpayload.order.idpayload.order.version.dealVersion
payload.customer.customerType.domainpayload.customer.customerType.idpayload.customer.customerType.version
payload.payment[].deal.domainpayload.payment[].deal.idpayload.payment[].deal.version
payload.payment[].dealType.domainpayload.payment[].dealType.idpayload.payment[].dealType.version

期望生成的JSON

{
"identifier": {
    "domainKey": "domainVal",
    "idKey": "idVal",
    "versionKey": "versionVal"
},
"payload": {
    "account": {
        "domain": "domainVal",
        "id": "idVal",
        "version": "versionVal"
    },
    "order": {
        "domainKey": "domainVal",
        "idKey": "idVal",
        "version": {
            "dealVersion": "versionVal"
        }
    },
    "customer": {
        "customerType": {
            "domain": "domainVal",
            "id": "idVal",
            "version": "versionVal"
        }
    },
    "payment": [
        {
            "deal": {
                "domain": "domainVal",
                "id": "idVal",
                "version": "versionVal"
            }
        },
        {
            "dealType": {
                "domain": "domainVal",
                "id": "idVal",
                "version": "versionVal"
            }
        }
    ]
}
解决方案

可以用Jackson库动态构建JSON结构,它提供的ObjectNode、ArrayNode等API能灵活处理动态字段,无需固定POJO。核心思路是解析每条记录的路径字符串,将常量值插入到JSON树的对应位置,遇到[]标记时创建数组节点并添加元素。

依赖引入(Maven)

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

Java代码实现

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 java.util.ArrayList;
import java.util.List;

public class DynamicJsonGenerator {
    // 定义常量值
    private static final String DOMAIN_VAL = "domainVal";
    private static final String ID_VAL = "idVal";
    private static final String VERSION_VAL = "versionVal";

    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        ObjectNode root = mapper.createObjectNode();

        // 模拟数据库查询得到的记录
        List<Record> records = new ArrayList<>();
        records.add(new Record("identifier.domainKey", "identifier.idKey", "identifier.versionKey"));
        records.add(new Record("payload.account.domain", "payload.account.id", "payload.order.version.version"));
        records.add(new Record("payload.order.domain", "payload.order.id", "payload.order.version.dealVersion"));
        records.add(new Record("payload.customer.customerType.domain", "payload.customer.customerType.id", "payload.customer.customerType.version"));
        records.add(new Record("payload.payment[].deal.domain", "payload.payment[].deal.id", "payload.payment[].deal.version"));
        records.add(new Record("payload.payment[].dealType.domain", "payload.payment[].dealType.id", "payload.payment[].dealType.version"));

        // 逐条处理记录,构建JSON树
        for (Record record : records) {
            setValueToPath(root, record.domain, DOMAIN_VAL);
            setValueToPath(root, record.id, ID_VAL);
            setValueToPath(root, record.version, VERSION_VAL);
        }

        // 输出格式化后的JSON
        System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(root));
    }

    /**
     * 根据路径将值插入到JSON节点的对应位置
     */
    private static void setValueToPath(ObjectNode root, String path, String value) {
        String[] pathSegments = path.split("\\.");
        JsonNode currentNode = root;

        for (int i = 0; i < pathSegments.length; i++) {
            String segment = pathSegments[i];
            boolean isArrayNode = segment.endsWith("[]");
            String nodeName = isArrayNode ? segment.substring(0, segment.length() - 2) : segment;

            // 到达路径最后一段,设置值
            if (i == pathSegments.length - 1) {
                if (currentNode instanceof ObjectNode) {
                    ((ObjectNode) currentNode).put(nodeName, value);
                }
                return;
            }

            // 处理中间节点
            if (isArrayNode) {
                // 创建或获取数组节点
                ArrayNode arrayNode;
                if (currentNode.has(nodeName) && currentNode.get(nodeName).isArray()) {
                    arrayNode = (ArrayNode) currentNode.get(nodeName);
                } else {
                    arrayNode = ((ObjectNode) currentNode).putArray(nodeName);
                }
                // 为数组添加新的对象元素
                ObjectNode newArrayElement = ((ObjectNode) currentNode).objectNode();
                arrayNode.add(newArrayElement);
                currentNode = newArrayElement;
            } else {
                // 创建或获取普通对象节点
                if (!currentNode.has(nodeName) || !currentNode.get(nodeName).isObject()) {
                    ((ObjectNode) currentNode).putObject(nodeName);
                }
                currentNode = currentNode.get(nodeName);
            }
        }
    }

    // 模拟数据库记录的实体类
    static class Record {
        String domain;
        String id;
        String version;

        public Record(String domain, String id, String version) {
            this.domain = domain;
            this.id = id;
            this.version = version;
        }
    }
}

代码说明

  • setValueToPath是核心方法:将路径分割为节点段,逐个处理每个节点,遇到[]标记时创建数组并添加新对象元素,普通节点则创建对象节点。
  • 每条payment[]开头的记录会对应数组中的一个独立元素,确保deal和dealType分别在数组的不同对象中。
  • 利用Jackson的节点API可以完全动态构建JSON结构,适配任意变化的字段路径。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 14:36:19