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

如何使用Java与Google Gson将嵌套JSON数组UNNEST为类SQL关联查询结果

Java + Gson: 动态展开嵌套JSON数组为SQL JOIN风格的扁平结构

需求背景

你有一个包含多层嵌套数组(items、tags、actions)的JSON结构,需要将其转换为类似SQL关联查询的扁平输出——每个嵌套数组的元素单独成为一条记录,未关联的字段填充为null,同时保留顶层的公共字段(比如number)。

实现方案

我们可以通过定义数据模型 + 手动遍历转换的方式实现,Gson负责JSON的序列化和反序列化工作。以下是具体步骤:


1. 定义数据模型类

首先创建对应原始JSON结构的模型类,以及对应输出扁平结构的模型类:

import com.google.gson.annotations.SerializedName;
import java.util.List;

// 原始JSON对应的模型类
class Order {
    private int number;
    private List<Item> items;
    private List<String> tags;
    private Customer customer; // 该字段输出未用到,可按需扩展处理
    private List<Action> actions;

    // Getters & Setters (可使用Lombok简化代码)
    public int getNumber() { return number; }
    public void setNumber(int number) { this.number = number; }
    public List<Item> getItems() { return items; }
    public void setItems(List<Item> items) { this.items = items; }
    public List<String> getTags() { return tags; }
    public void setTags(List<String> tags) { this.tags = tags; }
    public List<Action> getActions() { return actions; }
    public void setActions(List<Action> actions) { this.actions = actions; }
}

class Item {
    private String product;
    private double cost;

    public String getProduct() { return product; }
    public void setProduct(String product) { this.product = product; }
    public double getCost() { return cost; }
    public void setCost(double cost) { this.cost = cost; }
}

class Action {
    @SerializedName("moment")
    private String actionMoment;
    private String description;

    public String getActionMoment() { return actionMoment; }
    public void setActionMoment(String actionMoment) { this.actionMoment = actionMoment; }
    public String getDescription() { return description; }
    public void setDescription(String description) { this.description = description; }
}

class Customer {
    private String name;
    private String shortName;
    // Getters & Setters 省略
}

// 输出扁平结构对应的模型类
class FlatOrder {
    private int number;
    @SerializedName("items_product")
    private String itemsProduct;
    @SerializedName("items_cost")
    private Double itemsCost; // 用包装类型允许字段为null
    private String tags;
    @SerializedName("actions_moment")
    private String actionsMoment;
    @SerializedName("actions_description")
    private String actionsDescription;

    // 构造方法:初始化公共字段number,其他字段默认null
    public FlatOrder(int number) {
        this.number = number;
    }

    // Getters & Setters 省略
    public void setItemsProduct(String itemsProduct) { this.itemsProduct = itemsProduct; }
    public void setItemsCost(Double itemsCost) { this.itemsCost = itemsCost; }
    public void setTags(String tags) { this.tags = tags; }
    public void setActionsMoment(String actionsMoment) { this.actionsMoment = actionsMoment; }
    public void setActionsDescription(String actionsDescription) { this.actionsDescription = actionsDescription; }
}

2. 编写转换逻辑

创建工具方法遍历原始Order对象,分别处理每个嵌套数组,生成对应的扁平记录:

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.util.ArrayList;
import java.util.List;

public class JsonFlattener {
    private static final Gson gson = new Gson();

    public static void main(String[] args) {
        // 原始JSON字符串
        String originalJson = "[ \n" +
                "{ \n" +
                "\"number\": 123, \n" +
                "\"items\" : [ {\"product\": \"P1\",\"cost\":10.5}, {\"product\": \"P2\",\"cost\":5.25} ], \n" +
                "\"tags\":[\"a\",\"b\",\"c\"], \n" +
                "\"customer\": { \"name\": \"Roberto\", \"shortName\": \"Beto\" }, \n" +
                "\"actions\":[{ \"moment\": \"2021-01-01 11:22:22.222\", \"description\": \"action 1\" },{ \"moment\": \"2021-01-23 11:22:22.222\", \"description\": \"action 2\" }] \n" +
                "} \n" +
                "]";

        // 反序列化原始JSON为Order列表
        List<Order> orders = gson.fromJson(originalJson, new TypeToken<List<Order>>() {}.getType());

        // 转换为扁平结构
        List<FlatOrder> flatOrders = convertToFlatOrders(orders);

        // 序列化输出结果
        String outputJson = gson.toJson(flatOrders);
        System.out.println(outputJson);
    }

    public static List<FlatOrder> convertToFlatOrders(List<Order> orders) {
        List<FlatOrder> result = new ArrayList<>();

        for (Order order : orders) {
            int orderNumber = order.getNumber();

            // 处理items数组:每个Item生成一条扁平记录
            if (order.getItems() != null && !order.getItems().isEmpty()) {
                for (Item item : order.getItems()) {
                    FlatOrder flat = new FlatOrder(orderNumber);
                    flat.setItemsProduct(item.getProduct());
                    flat.setItemsCost(item.getCost());
                    result.add(flat);
                }
            }

            // 处理tags数组:每个tag生成一条扁平记录
            if (order.getTags() != null && !order.getTags().isEmpty()) {
                for (String tag : order.getTags()) {
                    FlatOrder flat = new FlatOrder(orderNumber);
                    flat.setTags(tag);
                    result.add(flat);
                }
            }

            // 处理actions数组:每个Action生成一条扁平记录
            if (order.getActions() != null && !order.getActions().isEmpty()) {
                for (Action action : order.getActions()) {
                    FlatOrder flat = new FlatOrder(orderNumber);
                    flat.setActionsMoment(action.getActionMoment());
                    flat.setActionsDescription(action.getDescription());
                    result.add(flat);
                }
            }
        }

        return result;
    }
}

3. 关键细节说明

  • 字段映射:通过@SerializedName注解确保输出JSON的字段名与需求完全匹配(比如items_product对应模型类的itemsProduct)。
  • Null兼容:扁平模型类使用包装类型(如Double)替代基本类型,避免基本类型无法为null的问题;未赋值的字段Gson会自动序列化为null。
  • 扩展性:如果后续需要新增嵌套数组的处理,只需在转换方法中添加对应数组的遍历逻辑即可。

运行上述代码后,就能得到你需要的类似SQL JOIN风格的扁平JSON输出。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 19:32:32