使用Gson反序列化含动态数字键的嵌套JSON对象报错问询
问题根因
你遇到的报错核心原因是JSON结构和实体类定义不匹配:
java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1
你将People字段声明为数组类型,但实际JSON返回的People是对象类型,Gson解析时预期匹配数组起始符[,实际匹配到了对象起始符{,因此抛出异常。同时你的实体类层级也和JSON不匹配:AddressData是People节点的子属性,不是General节点的子属性。
正确实现方案
由于People节点下同时包含动态数字键的用户对象、固定的AddressData对象,我们需要自定义Gson反序列化器处理混合结构,具体步骤如下:
1. 修正实体类定义
import com.google.gson.annotations.Expose; import com.google.gson.annotations.SerializedName; import java.util.List; // 最外层JSON根节点 public class Root { @SerializedName("General") @Expose private General general; public General getGeneral() { return general; } } public class General { @SerializedName("Code") @Expose private String code; @SerializedName("People") @Expose private PeopleContainer peopleContainer; // 对应数字键的用户对象 public static class PeopleItem { @SerializedName("Name") @Expose private String name; public String getName() { return name; } } // 对应地址对象 public static class AddressData { @SerializedName("Street") @Expose private Integer street; @SerializedName("ZIP") @Expose private Integer zip; public Integer getStreet() { return street; } public Integer getZip() { return zip; } } // 对应整个People节点的容器 public static class PeopleContainer { private List<PeopleItem> peopleList; private AddressData addressData; public List<PeopleItem> getPeopleList() { return peopleList; } public AddressData getAddressData() { return addressData; } public void setPeopleList(List<PeopleItem> peopleList) { this.peopleList = peopleList; } public void setAddressData(AddressData addressData) { this.addressData = addressData; } } public String getCode() { return code; } public PeopleContainer getPeopleContainer() { return peopleContainer; } }
注意:所有内部POJO类需要加static修饰,否则Gson无法实例化非静态内部类。
2. 实现自定义反序列化器
import com.google.gson.Gson; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Map; public class PeopleContainerDeserializer implements JsonDeserializer<General.PeopleContainer> { @Override public General.PeopleContainer deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { JsonObject peopleObject = json.getAsJsonObject(); General.PeopleContainer container = new General.PeopleContainer(); ArrayList<General.PeopleItem> peopleList = new ArrayList<>(); Gson gson = new Gson(); // 遍历People节点的所有键值对 for (Map.Entry<String, JsonElement> entry : peopleObject.entrySet()) { String key = entry.getKey(); if (key.equals("AddressData")) { // 匹配固定地址字段 General.AddressData addressData = gson.fromJson(entry.getValue(), General.AddressData.class); container.setAddressData(addressData); } else if (key.matches("\\d+")) { // 匹配动态数字键的用户对象 General.PeopleItem item = gson.fromJson(entry.getValue(), General.PeopleItem.class); peopleList.add(item); } } container.setPeopleList(peopleList); return container; } }
3. 注册反序列化器并执行解析
import com.google.gson.Gson; import com.google.gson.GsonBuilder; public class JsonParseDemo { public static void main(String[] args) { String jsonStr = "你的完整JSON字符串"; // 注册自定义反序列化器 Gson gson = new GsonBuilder() .registerTypeAdapter(General.PeopleContainer.class, new PeopleContainerDeserializer()) .create(); // 直接解析JSON Root root = gson.fromJson(jsonStr, Root.class); // 可通过get方法获取对应属性 General general = root.getGeneral(); List<General.PeopleItem> people = general.getPeopleContainer().getPeopleList(); General.AddressData address = general.getPeopleContainer().getAddressData(); } }
该方案兼容动态变化的数字键数量,无需修改代码即可适配不同拉取时机返回的用户数量。
内容的提问来源于stack exchange,提问作者Someone_plz_help
相关产品推荐
相关产品推荐

