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

如何使用Java数据结构结合Gson序列化不含children属性的嵌套JSON结构?

解决Gson序列化动态嵌套子节点的Java数据结构方案

针对你需要生成的这种直接将子节点作为Person对象的顶级属性(而非通过children数组/字段嵌套)的JSON结构,这里有两个实用的方案,结合Gson就能完美实现需求:

方案一:让Person继承HashMap<String, Object>(快速实现)

这个方案利用Gson会同时序列化类的字段和Map条目的特性,让Person既保留固定的Type和age属性,又能动态添加子节点(键为孩子名字,值为Child对象)。

代码示例

首先定义实体类:

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

class Person extends HashMap<String, Object> {
    @SerializedName("Type")
    private final String type = "Person"; // 固定为Person类型
    private int age;

    // 构造器和age的getter/setter
    public Person(int age) {
        this.age = age;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    // 添加子节点的方法,避免键名和固定属性冲突
    public void addChild(String childName, Child child) {
        if ("Type".equals(childName) || "age".equals(childName)) {
            throw new IllegalArgumentException("Child name cannot conflict with fixed fields: Type/age");
        }
        put(childName, child);
    }
}

class Child {
    @SerializedName("Type")
    private final String type = "child"; // 固定为child类型
    private int age;

    public Child(int age) {
        this.age = age;
    }

    // 可选:age的getter/setter
}

然后使用Gson序列化:

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.util.HashMap;
import java.util.Map;

public class Main {
    public static void main(String[] args) {
        // 构建John的节点
        Person john = new Person(30);
        john.addChild("Sean", new Child(3));
        john.addChild("Julian", new Child(4));

        // 构建Paul的节点
        Person paul = new Person(64);
        paul.addChild("Stella", new Child(10));
        paul.addChild("James", new Child(12));

        // 外层用Map<String, Person>处理John、Paul顶级节点
        Map<String, Person> peopleMap = new HashMap<>();
        peopleMap.put("John", john);
        peopleMap.put("Paul", paul);

        // 生成格式化后的JSON
        Gson gson = new GsonBuilder().setPrettyPrinting().create();
        String jsonOutput = gson.toJson(peopleMap);
        System.out.println(jsonOutput);
    }
}

方案优缺点

  • ✅ 优点:实现简单,代码量少,无需额外配置Gson
  • ❌ 缺点:需要注意避免子节点名字和固定字段(Type、age)冲突;反序列化时需要注意区分固定字段和子节点

方案二:自定义TypeAdapter(精确控制序列化/反序列化)

如果你希望更严谨地控制序列化逻辑,不想让Person继承Map,可以用Gson的自定义TypeAdapter,手动处理固定字段和动态子节点的序列化/反序列化。

代码示例

首先定义常规的实体类(无需继承Map):

import com.google.gson.annotations.SerializedName;
import java.util.HashMap;
import java.util.Map;

class Person {
    @SerializedName("Type")
    private String type = "Person";
    private int age;
    // 用Map存储子节点,键为孩子名字
    private Map<String, Child> childrenByName = new HashMap<>();

    // 构造器、getter/setter
    public Person(int age) {
        this.age = age;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Map<String, Child> getChildrenByName() {
        return childrenByName;
    }

    public void addChild(String childName, Child child) {
        childrenByName.put(childName, child);
    }
}

class Child {
    @SerializedName("Type")
    private String type = "child";
    private int age;

    public Child(int age) {
        this.age = age;
    }

    // getter/setter
    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

然后编写自定义的TypeAdapter:

import com.google.gson.TypeAdapter;
import com.google.gson.Gson;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;
import java.util.Map;

class PersonTypeAdapter extends TypeAdapter<Person> {
    private final Gson gson = new Gson();

    @Override
    public void write(JsonWriter out, Person person) throws IOException {
        out.beginObject();
        // 写入固定字段Type和age
        out.name("Type").value(person.getType());
        out.name("age").value(person.getAge());
        // 遍历子节点Map,将每个键值对作为Person的顶级属性写入
        for (Map.Entry<String, Child> entry : person.getChildrenByName().entrySet()) {
            out.name(entry.getKey());
            gson.toJson(entry.getValue(), Child.class, out);
        }
        out.endObject();
    }

    @Override
    public Person read(JsonReader in) throws IOException {
        Person person = new Person(0);
        Map<String, Child> children = new HashMap<>();

        in.beginObject();
        while (in.hasNext()) {
            String fieldName = in.nextName();
            switch (fieldName) {
                case "Type":
                    person.setType(in.nextString());
                    break;
                case "age":
                    person.setAge(in.nextInt());
                    break;
                default:
                    // 其他字段都作为子节点处理
                    Child child = gson.fromJson(in, Child.class);
                    children.put(fieldName, child);
                    break;
            }
        }
        in.endObject();
        person.getChildrenByName().putAll(children);
        return person;
    }
}

最后注册TypeAdapter并序列化:

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.util.HashMap;
import java.util.Map;

public class Main {
    public static void main(String[] args) {
        Person john = new Person(30);
        john.addChild("Sean", new Child(3));
        john.addChild("Julian", new Child(4));

        Person paul = new Person(64);
        paul.addChild("Stella", new Child(10));
        paul.addChild("James", new Child(12));

        Map<String, Person> peopleMap = new HashMap<>();
        peopleMap.put("John", john);
        peopleMap.put("Paul", paul);

        // 注册自定义TypeAdapter
        Gson gson = new GsonBuilder()
                .registerTypeAdapter(Person.class, new PersonTypeAdapter())
                .setPrettyPrinting()
                .create();

        String jsonOutput = gson.toJson(peopleMap);
        System.out.println(jsonOutput);
    }
}

方案优缺点

  • ✅ 优点:逻辑清晰,完全控制序列化/反序列化过程,避免键名冲突问题,反序列化更安全
  • ❌ 缺点:需要编写额外的TypeAdapter代码,相对繁琐一些

两种方案都能生成你需要的JSON结构,根据你的项目复杂度选择即可。

内容的提问来源于stack exchange,提问作者Erez Ben Harush

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 21:57:43