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

基于Gson的嵌套JSON自定义反序列化实现思路确认

问题描述

我有一个嵌套JSON结构,想把它转换成Java类实例,觉得需要用自定义反序列化器。目前已经能把顶层的response_object JSON字符串转成JsonObject,还能遍历获取files数组的数据,代码如下:

JsonObject robj = value.getAsJsonObject("response_object");
JsonArray uarray = robj.getAsJsonArray("updates");
for(int i1 = 0; i1 < uarray.size(); i1++) {
    JsonElement jel = uarray.get(i1);
    JsonObject jobj = jel.getAsJsonObject();
    String v = jobj.get("upgrades_to_version").getAsString();
    JsonArray files = jobj.getAsJsonArray("files");
    for (int ij = 0; ij < files.size(); ij++ ) {
        JsonElement fel = files.get(ij);
        JsonObject fobj = fel.getAsJsonObject();
        url = fobj.get("url").getAsString();
    }
}

我的疑问是:能不能写一个从顶层开始的自定义反序列化器,接收response_object的JsonObject,直接返回对应的Java实例?

另外我查资料了解到,可以创建ResponseObject类,实现接收JsonObject的反序列化器,遍历JSON设置属性并创建嵌套类实例(需要定义嵌套类且各自实现反序列化器),这个思路对吗?

对应的JSON结构如下:

"response_object" : {
   "asset_type" : "software",
   "asset_virtual_id" : "Instance_Cluster-0001",
   "category" : "Software",
   "connect_transaction_id" : "11223344_1714400505026_Event-000001",
   "efd_transaction_id" : "H17246155",
   "event_time" : "2024-09-25 21:43:42",
   "event_time_ms" : 1727300622750,
   "event_type" : "software_update",
   "group" : "foo",
   "instance" : "0123456789abcdef",
   "response_code" : 200,
   "response_size" : 997,
   "software_update_request" : {
      "asset_event_detail" : {
         "body" : {
            "action" : "Order SW",
            "component" : "compid_xx",
            "description" : "Orderfix",
            "efd_product" : "Log Collector",
            "operation" : "order_software",
            "request_type" : "specific_fix",
            "update_ids" : [
               "1.0.1.0-fix001"
            ]
         },
         "header" : {
            "event_id" : "11223344_1714400505026_SWupdate-000002",
            "event_time" : "2024-04-29 09:00:00",
            "event_time_ms" : 1714400505026,
            "event_type" : "software_update"
         }
      }
   },
   "times" : {
      "efd_delta" : "1.5 seconds",
      "efd_recv" : 1727300622749,
      "efd_send" : 1727300621292
   },
   "type" : "11223344",
   "updates" : [
      {
         "applies_to_version" : "v1.0.1.0",
         "description" : "This is the initial release",
         "files" : [
            {
               "description" : "Runnable Jar File",
               "descriptor" : "data/installable-unit.fix",
               "hash" : "AHcK2tBVoETIZcINUefJcLrZmNxFFMyFnjEj4dCcc+8=",
               "hashAlgorithm" : "SHA-256",
               "size" : 14787032,
               "url" : "https://example.com/runnable1.jar",
               "url_type" : "edge"
            },
            {
               "description" : "Runnable",
               "descriptor" : "some_description",
               "hash" : "foo",
               "hashAlgorithm" : "SHA-256",
               "size" : 14787032,
               "url" : "https://example.com/runnable2.jar",
               "url_type" : "edge"
            }

         ],
         "id" : "1.0.1.0-fix001",
         "name" : "Initial Release 001",
         "release_date" : "2024-04-25T18:42:00.382Z",
         "status" : "available",
         "type" : "fix pack",
         "upgrades_to_version" : "v1.0.1.0"
      }
   ]
}
解决方案

1. 思路正确性确认

你的思路完全正确。创建顶层ResponseObject类,配合自定义反序列化器,同时为嵌套结构定义对应的Java类(嵌套类或独立类都可以),并按需实现各自的反序列化逻辑,是处理这种复杂嵌套JSON的常规方案。

2. 具体实现步骤

第一步:定义所有对应Java类

按照JSON结构逐层定义实体类,每个类的字段和JSON键一一对应,可通过@JsonProperty注解处理命名差异(比如JSON的下划线命名转Java驼峰命名)。示例部分关键类:

import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;

public class ResponseObject {
    @JsonProperty("asset_type")
    private String assetType;
    @JsonProperty("asset_virtual_id")
    private String assetVirtualId;
    @JsonProperty("response_code")
    private Integer responseCode;
    @JsonProperty("software_update_request")
    private SoftwareUpdateRequest softwareUpdateRequest;
    @JsonProperty("times")
    private Times times;
    @JsonProperty("updates")
    private List<Update> updates;

    // 省略getter、setter、构造方法
}

public class Update {
    @JsonProperty("applies_to_version")
    private String appliesToVersion;
    @JsonProperty("upgrades_to_version")
    private String upgradesToVersion;
    @JsonProperty("files")
    private List<File> files;

    // 省略其他字段、getter、setter
}

public class File {
    @JsonProperty("url")
    private String url;
    @JsonProperty("hash")
    private String hash;

    // 省略其他字段、getter、setter
}

// 其他嵌套类如SoftwareUpdateRequest、Times等同理定义

第二步:实现顶层自定义反序列化器

如果需要完全手动控制反序列化逻辑(比如特殊字段转换、自定义校验),可以实现Jackson的JsonDeserializer<ResponseObject>接口,在deserialize方法中遍历JsonObject并构建实例:

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class ResponseObjectDeserializer extends JsonDeserializer<ResponseObject> {
    @Override
    public ResponseObject deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        JsonNode rootNode = p.getCodec().readTree(p);
        ResponseObject responseObject = new ResponseObject();

        // 赋值简单字段
        responseObject.setAssetType(rootNode.get("asset_type").asText());
        responseObject.setAssetVirtualId(rootNode.get("asset_virtual_id").asText());
        responseObject.setResponseCode(rootNode.get("response_code").asInt());

        // 处理嵌套对象times
        JsonNode timesNode = rootNode.get("times");
        Times times = new Times();
        times.setEfdDelta(timesNode.get("efd_delta").asText());
        times.setEfdRecv(timesNode.get("efd_recv").asLong());
        responseObject.setTimes(times);

        // 处理updates数组
        ArrayNode updatesArray = (ArrayNode) rootNode.get("updates");
        List<Update> updates = new ArrayList<>();
        for (JsonNode updateNode : updatesArray) {
            Update update = new Update();
            update.setAppliesToVersion(updateNode.get("applies_to_version").asText());
            update.setUpgradesToVersion(updateNode.get("upgrades_to_version").asText());

            // 处理files子数组
            ArrayNode filesArray = (ArrayNode) updateNode.get("files");
            List<File> files = new ArrayList<>();
            for (JsonNode fileNode : filesArray) {
                File file = new File();
                file.setUrl(fileNode.get("url").asText());
                file.setHash(fileNode.get("hash").asText());
                files.add(file);
            }
            update.setFiles(files);
            updates.add(update);
        }
        responseObject.setUpdates(updates);

        // 其他嵌套对象(如software_update_request)按相同逻辑处理
        return responseObject;
    }
}

第三步:注册反序列化器并使用

在ResponseObject类上添加注解指定反序列化器,之后用Jackson的ObjectMapper完成转换:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.JsonNode;

// 给ResponseObject类加注解
@JsonDeserialize(using = ResponseObjectDeserializer.class)
public class ResponseObject {
    // ... 类内容不变
}

// 使用示例
public class Main {
    public static void main(String[] args) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        // 假设已拿到包含response_object的JSON字符串
        String jsonStr = "...";
        JsonNode rootNode = mapper.readTree(jsonStr);
        JsonNode responseObjectNode = rootNode.get("response_object");
        // 转换为Java实例
        ResponseObject responseObject = mapper.treeToValue(responseObjectNode, ResponseObject.class);
    }
}

3. 可选优化:利用框架自动反序列化

如果没有特殊反序列化需求,Jackson等框架可以自动完成转换,无需手动遍历。只需确保实体类字段和JSON键通过@JsonProperty正确映射,直接调用ObjectMapper即可:

ObjectMapper mapper = new ObjectMapper();
// 忽略未知字段(避免JSON有额外字段时报错)
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// 直接转换response_object节点
ResponseObject responseObject = mapper.treeToValue(responseObjectNode, ResponseObject.class);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 09:42:10