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

在Flutter中使用JsonSerializable时如何在泛型数据模型中传递自定义参数名?

在Flutter中使用JsonSerializable时如何在泛型数据模型中传递自定义参数名?

嘿,我完全懂你的需求——你不想把param字段对应的JSON键名硬写成固定的"statistics",而是希望能根据不同场景自定义这个键名,同时还要保留JsonSerializable的泛型支持对吧?其实这个问题很好解决,咱们只需要给fromJson和toJson方法加个可选参数来传递自定义键名就行,下面一步步来给你演示:

首先,咱们修改你的DataModel类,给fromJson工厂方法新增一个paramKey参数(默认值设为你原来的"statistics",这样不传入的时候也能正常用),同时在toJson方法里也做对应的修改:

import 'package:json_annotation/json_annotation.dart';

part 'data_model.g.dart';

@JsonSerializable(genericArgumentFactories: true)
class DataModel<T, P> {
  final int? total;
  final List<T> items;
  final P? param;

  DataModel({
    this.total,
    required this.items,
    this.param,
  });

  // 新增paramKey参数,支持自定义JSON键名
  factory DataModel.fromJson(
    Map<String, dynamic> json,
    T Function(Object?) fromJsonT,
    P Function(Object?) fromJsonP, {
    String paramKey = "statistics", // 默认使用原来的键名
  }) {
    final List<dynamic> itemsJson = json['items'] as List<dynamic>;
    final List<T> items = itemsJson
        .map<T>((item) => fromJsonT(item as Map<String, dynamic>))
        .toList();

    // 根据传入的paramKey获取对应JSON值
    final dynamic paramJson = json[paramKey];
    final P? param = paramJson != null ? fromJsonP(paramJson) : null;

    return DataModel(
      total: json['total'] as int?,
      items: items,
      param: param,
    );
  }

  // 同样给toJson添加paramKey参数,支持自定义序列化键名
  Map<String, dynamic> toJson(
    Object Function(T) toJsonT,
    Object Function(P) toJsonP, {
    String paramKey = "statistics",
  }) {
    return {
      'total': total,
      'items': items.map(toJsonT).toList(),
      // 只有param不为空时才添加这个键值对
      if (param != null) paramKey: toJsonP(param),
    };
  }
}

接下来,咱们看看怎么用这个修改后的模型。假设你有两个子模型User和Statistics:

@JsonSerializable()
class User {
  final String name;
  User(this.name);
  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
  Map<String, dynamic> toJson() => _$UserToJson(this);
}

@JsonSerializable()
class Statistics {
  final int count;
  Statistics(this.count);
  factory Statistics.fromJson(Map<String, dynamic> json) => _$StatisticsFromJson(json);
  Map<String, dynamic> toJson() => _$StatisticsToJson(this);
}

现在你既可以用默认的"statistics"键名解析,也可以自定义键名,比如"metadata":

// 使用默认键名"statistics"解析JSON
final defaultJson = {
  'total': 2,
  'items': [{'name': 'Alice'}, {'name': 'Bob'}],
  'statistics': {'count': 10}
};
final defaultDataModel = DataModel.fromJson(
  defaultJson,
  (json) => User.fromJson(json as Map<String, dynamic>),
  (json) => Statistics.fromJson(json as Map<String, dynamic>),
);

// 使用自定义键名"metadata"解析JSON
final customJson = {
  'total': 3,
  'items': [{'name': 'Charlie'}, {'name': 'Dave'}, {'name': 'Eve'}],
  'metadata': {'count': 15}
};
final customDataModel = DataModel.fromJson(
  customJson,
  (json) => User.fromJson(json as Map<String, dynamic>),
  (json) => Statistics.fromJson(json as Map<String, dynamic>),
  paramKey: "metadata", // 这里传入自定义键名
);

序列化的时候也是一样的逻辑,想输出哪个键名就传哪个:

// 序列化为带"statistics"键的JSON
final defaultOutput = defaultDataModel.toJson(
  (user) => user.toJson(),
  (stats) => stats.toJson(),
);

// 序列化为带"metadata"键的JSON
final customOutput = customDataModel.toJson(
  (user) => user.toJson(),
  (stats) => stats.toJson(),
  paramKey: "metadata",
);

最后提醒一下:每次修改完模型代码后,记得运行flutter pub run build_runner build命令重新生成对应的.g.dart文件,确保代码生成正确哦~

备注:内容来源于stack exchange,提问作者Oleksii Shtanko

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.16 07:35:34