Java 8中如何从数据库表记录生成动态JSON?
问题
我有如下数据库表记录,表中每行包含各类字符串记录,格式如下。其中domainVal、idVal、versionVal为常量,其余键均为动态(可为任意字符串);payment[]对应JSON中的数组结构。我需要从这类记录生成动态JSON。
尝试过创建POJO,但由于字段不固定,无法生成精确的POJO;也尝试用Java集合存储记录并生成JSON,但不知道如何解析记录存入集合。
数据库表
| domain | id | version |
|---|---|---|
| identifier.domainKey | identifier.idKey | identifier.versionKey |
| payload.account.domain | payload.account.id | payload.order.version.version |
| payload.order.domain | payload.order.id | payload.order.version.dealVersion |
| payload.customer.customerType.domain | payload.customer.customerType.id | payload.customer.customerType.version |
| payload.payment[].deal.domain | payload.payment[].deal.id | payload.payment[].deal.version |
| payload.payment[].dealType.domain | payload.payment[].dealType.id | payload.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
相关产品推荐
相关产品推荐

