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

Gson反序列化多态类型Map<String,List<? extends Mother>>报错求助

问题分析

你遇到的问题本质是Gson处理多态类型反序列化时的局限性:序列化后的JSON中没有保存Java对象的类型元数据,反序列化时Gson只能根据List<? extends Mother>的泛型上限创建Mother类的实例,而非Son或Daughter子类,因此强制类型转换时抛出ClassCastException。

解决方案1:自定义TypeAdapter+类型标识字段

通过在父类中添加类型标识字段让JSON保留子类信息,再自定义TypeAdapter根据标识字段创建对应子类实例。

步骤1:修改POJO类,添加类型标识

import lombok.AllArgsConstructor;
import lombok.Data;

class Mother {
    private String type;

    public String getType() {
        return type;
    }

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

@Data
@AllArgsConstructor
class Son extends Mother {
    private int age;

    public Son(int age) {
        this.age = age;
        setType("son");
    }
}

@Data
@AllArgsConstructor
class Daughter extends Mother {
    private int age;

    public Daughter(int age) {
        this.age = age;
        setType("daughter");
    }
}

步骤2:自定义Mother的TypeAdapter

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

public class MotherTypeAdapter extends TypeAdapter<Mother> {
    @Override
    public void write(JsonWriter out, Mother value) throws IOException {
        out.beginObject();
        out.name("type").value(value.getType());
        if (value instanceof Son) {
            out.name("age").value(((Son) value).getAge());
        } else if (value instanceof Daughter) {
            out.name("age").value(((Daughter) value).getAge());
        }
        out.endObject();
    }

    @Override
    public Mother read(JsonReader in) throws IOException {
        in.beginObject();
        String type = null;
        int age = 0;
        while (in.hasNext()) {
            switch (in.nextName()) {
                case "type":
                    type = in.nextString();
                    break;
                case "age":
                    age = in.nextInt();
                    break;
            }
        }
        in.endObject();
        if ("son".equals(type)) {
            return new Son(age);
        } else if ("daughter".equals(type)) {
            return new Daughter(age);
        }
        return null;
    }
}

步骤3:修改测试代码,使用自定义TypeAdapter

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

public class Test {
    public static void main(String[] args) {
        List<Son> sons = new ArrayList<>();
        sons.add(new Son(12));
        sons.add(new Son(13));

        List<Daughter> daughters = new ArrayList<>();
        daughters.add(new Daughter(5));
        daughters.add(new Daughter(6));

        Map<String, List<? extends Mother>> map = new HashMap<>();
        map.put("ex-husband", sons);
        map.put("husband", daughters);

        Gson gson = new GsonBuilder()
                .registerTypeAdapter(Mother.class, new MotherTypeAdapter())
                .create();
        String json = gson.toJson(map);
        System.out.println(json);

        Type type = new TypeToken<Map<String, List<? extends Mother>>>() {}.getType();
        Map<String, List<? extends Mother>> map1 = gson.fromJson(json, type);

        List<Son> sons1 = (List<Son>) map1.get("ex-husband");
        System.out.println(sons1.get(0).getAge()); // 正常输出12
    }
}

解决方案2:使用Gson的RuntimeTypeAdapterFactory(推荐)

Gson扩展库gson-extras提供的RuntimeTypeAdapterFactory可简洁处理多态类型序列化/反序列化,无需手动添加类型字段。

步骤1:引入依赖(Maven示例)

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson-extras</artifactId>
    <version>2.10.1</version> <!-- 使用最新稳定版本 -->
</dependency>

步骤2:修改测试代码,使用RuntimeTypeAdapterFactory

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import com.google.gson.typeadapters.RuntimeTypeAdapterFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Test {
    public static void main(String[] args) {
        RuntimeTypeAdapterFactory<Mother> typeFactory = RuntimeTypeAdapterFactory.of(Mother.class, "type")
                .registerSubtype(Son.class, "son")
                .registerSubtype(Daughter.class, "daughter");

        List<Son> sons = new ArrayList<>();
        sons.add(new Son(12));
        sons.add(new Son(13));

        List<Daughter> daughters = new ArrayList<>();
        daughters.add(new Daughter(5));
        daughters.add(new Daughter(6));

        Map<String, List<? extends Mother>> map = new HashMap<>();
        map.put("ex-husband", sons);
        map.put("husband", daughters);

        Gson gson = new GsonBuilder()
                .registerTypeAdapterFactory(typeFactory)
                .create();
        String json = gson.toJson(map);
        System.out.println(json);

        Type type = new TypeToken<Map<String, List<? extends Mother>>>() {}.getType();
        Map<String, List<? extends Mother>> map1 = gson.fromJson(json, type);

        List<Son> sons1 = (List<Son>) map1.get("ex-husband");
        System.out.println(sons1.get(0).getAge()); // 正常输出12
    }
}

说明

RuntimeTypeAdapterFactory会自动在JSON中添加指定的类型字段,序列化时写入子类标识,反序列化时根据标识创建对应子类实例,无需手动处理JSON读写逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 06:00:18