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

使用Gson fromJson()解析含动态键的JSON时,动态@SerializedName值的处理方案咨询

Gson fromJson()解析含动态键的JSON时,动态@SerializedName值的处理方案咨询

看起来你遇到的是Gson解析动态键JSON的典型问题——因为transactions里的键是从API返回的found_detail字段动态生成的,没法提前写死@SerializedName的值,对吧?我来给你拆解几个可行的方案,比反射修改注解要靠谱得多:

方案一:修正Map类型的使用方式(最简便)

你之前尝试用Map但没成功,大概率是字段定义或者Gson配置的问题。正确的做法是直接用Map<String, EFDTransaction>接收动态键的内容,同时对应好JSON的层级结构:

修正后的类结构

// 对应JSON里的transactions对象
public class EFDTransactions {
    @Expose
    private Map<String, EFDTransaction> transactionMap; // 用Map接收动态键的内容

    public EFDTransactions() {}

    public Map<String, EFDTransaction> getTransactionMap() {
        return transactionMap;
    }

    public void setTransactionMap(Map<String, EFDTransaction> transactionMap) {
        this.transactionMap = transactionMap;
    }
}

解析代码

要确保Gson配置保留@Expose注解的字段,然后直接解析transactions节点:

// 从已有的responsejobj中提取transactions节点
JsonObject transactionsObj = responsejobj.getAsJsonObject("transactions");

Gson rspgson = new GsonBuilder()
        .excludeFieldsWithoutExposeAnnotation()
        .create();

// 解析成EFDTransactions对象
EFDTransactions trans = rspgson.fromJson(transactionsObj, EFDTransactions.class);

// 之后可以通过Map获取动态键对应的内容,比如结合found_detail提取的键
String dynamicKey = "Request ID 000002"; // 实际从found_detail中提取
EFDTransaction targetTrans = trans.getTransactionMap().get(dynamicKey);

方案二:自定义JsonDeserializer(更灵活)

如果需要自动从found_detail提取动态键并直接返回目标对象,可以写一个自定义反序列化器,完全掌控解析逻辑:

自定义反序列化器实现

public class EFDTransactionsDeserializer implements JsonDeserializer<EFDTransactions> {
    // 可以传入提前从found_detail提取的动态键,也可以在内部解析
    private final String dynamicKey;

    public EFDTransactionsDeserializer(String dynamicKey) {
        this.dynamicKey = dynamicKey;
    }

    @Override
    public EFDTransactions deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        JsonObject transactionsObj = json.getAsJsonObject();
        EFDTransactions transactions = new EFDTransactions();
        
        // 直接根据动态键提取并解析目标对象
        JsonElement transElement = transactionsObj.get(dynamicKey);
        EFDTransaction transaction = context.deserialize(transElement, EFDTransaction.class);
        
        // 封装到EFDTransactions中(如果需要单个对象而非Map)
        Map<String, EFDTransaction> transMap = new HashMap<>();
        transMap.put(dynamicKey, transaction);
        transactions.setTransactionMap(transMap);
        
        return transactions;
    }
}

注册并使用反序列化器

// 先从found_detail提取动态键
String foundDetail = responsejobj.get("found_detail").getAsString();
Pattern pattern = Pattern.compile("\\[(.*?)\\]");
Matcher matcher = pattern.matcher(foundDetail);
String dynamicKey = matcher.find() ? matcher.group(1) : "";

// 注册自定义反序列化器并解析
Gson rspgson = new GsonBuilder()
        .excludeFieldsWithoutExposeAnnotation()
        .registerTypeAdapter(EFDTransactions.class, new EFDTransactionsDeserializer(dynamicKey))
        .create();

EFDTransactions trans = rspgson.fromJson(responsejobj.getAsJsonObject("transactions"), EFDTransactions.class);

方案三:手动提取动态键后解析(场景简单时最直接)

如果你的场景里transactions下永远只有一个动态键,完全可以跳过复杂的类结构,直接提取键后解析目标对象:

// 1. 从found_detail提取动态键
String foundDetail = responsejobj.get("found_detail").getAsString();
String dynamicKey = Pattern.compile("\\[(.*?)\\]").matcher(foundDetail).group(1);

// 2. 直接解析目标EFDTransaction
JsonObject transactionsObj = responsejobj.getAsJsonObject("transactions");
EFDTransaction transaction = rspgson.fromJson(transactionsObj.get(dynamicKey), EFDTransaction.class);

// 3. 如需封装到EFDTransactions类,手动创建对象即可
EFDTransactions trans = new EFDTransactions();
Map<String, EFDTransaction> transMap = new HashMap<>();
transMap.put(dynamicKey, transaction);
trans.setTransactionMap(transMap);

为什么不推荐反射修改@SerializedName?

反射修改注解不仅实现复杂,而且Gson初始化时会缓存注解信息,运行时修改大概率不生效,还会引入性能开销和兼容性风险,完全没必要用这种绕远路的方式。

总结下来,方案一最适合大多数场景,改改类定义就能用;如果需要定制解析逻辑选方案二;场景简单的话方案三最直接。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 08:39:50