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

Flutter中使用JSONSerializable映射JSON列表失败求助

Flutter JSONSerializable 映射JSON列表失败排查与修复

问题现象

调用API返回200状态码,但触发默认错误提示,说明JSON到实体的映射存在异常。

API返回响应

接口返回的JSON结构如下:

{
    "code": 200,
    "message": "Countries Lists",
    "count": 250,
    "data": [
        {
            "id": 1,
            "name": "Afghanistan"
        },
        {
            "id": 2,
            "name": "Aland Islands"
        }
        // 其余国家数据省略
    ]
}

当前实体类代码

@JsonSerializable()
class BaseResponse {
  @JsonKey(name: "code")
  int? status;
  @JsonKey(name: "message")
  String? message;
}

@JsonSerializable(explicitToJson: true)
class AllCountryResponse extends BaseResponse {
  @JsonKey(name: "data")
  List<CountryResponse> data;  

  AllCountryResponse(this.data);  

  factory AllCountryResponse.fromJson(Map<String, dynamic> json) =>
      _$AllCountryResponseFromJson(json);  

  Map<String, dynamic> toJson() => _$AllCountryResponseToJson(this);
}

@JsonSerializable()
class CountryResponse {
  @JsonKey(name: "id")
  String? id;
  @JsonKey(name: "name")
  String? name;  

  CountryResponse(this.id, this.name);  
  factory CountryResponse.fromJson(Map<String, dynamic> json) =>
      _$CountryResponseFromJson(json);  

  Map<String, dynamic> toJson() => _$CountryResponseToJson(this);
}

当前映射器代码

class Countries {
  String id,name;
  Countries(this.id,this.name);
}

class AllCountries{
  List<Countries> countries;  

  AllCountries(this.countries);
}

extension CountryResponseMapper on CountryResponse? {
  Countries toDomain() {
    return Countries(
        this?.id.orEmpty() ?? EMPTY, this?.name.orEmpty() ?? EMPTY);
  }
}

extension AllCountriesResponseMapper on AllCountryResponse? {
  AllCountries toDomain() {
    return AllCountries(this?.data.map((e) => e.toDomain()).toList() ?? []);
  }
}

问题分析与修复方案

1. 数据类型不匹配

API返回的id是数字类型(int),但CountryResponse中定义的id为String?类型,JSONSerializable映射时会因类型不匹配抛出异常,直接导致映射失败。

修复:将CountryResponse的id类型改为int?,若业务需要String类型,在映射到领域模型时再转换:

@JsonSerializable()
class CountryResponse {
  @JsonKey(name: "id")
  int? id; // 改为int类型匹配API返回
  @JsonKey(name: "name")
  String? name;  

  CountryResponse({this.id, this.name}); // 改用命名构造函数,避免位置参数问题
  factory CountryResponse.fromJson(Map<String, dynamic> json) =>
      _$CountryResponseFromJson(json);  

  Map<String, dynamic> toJson() => _$CountryResponseToJson(this);
}

2. 父类序列化逻辑缺失

AllCountryResponse继承自BaseResponse,但BaseResponse未配置序列化方法,JSONSerializable无法正确解析父类的code和message字段,可能引发序列化异常。

修复:给BaseResponse添加序列化方法,并在子类中正确继承父类字段:

@JsonSerializable()
class BaseResponse {
  @JsonKey(name: "code")
  int? status;
  @JsonKey(name: "message")
  String? message;

  BaseResponse({this.status, this.message});

  // 添加父类序列化方法
  factory BaseResponse.fromJson(Map<String, dynamic> json) =>
      _$BaseResponseFromJson(json);

  Map<String, dynamic> toJson() => _$BaseResponseToJson(this);
}

@JsonSerializable(explicitToJson: true)
class AllCountryResponse extends BaseResponse {
  @JsonKey(name: "data")
  List<CountryResponse> data;  

  AllCountryResponse({required this.data, super.status, super.message});  

  factory AllCountryResponse.fromJson(Map<String, dynamic> json) =>
      _$AllCountryResponseFromJson(json);  

  Map<String, dynamic> toJson() => _$AllCountryResponseToJson(this);
}

3. 映射器空安全优化

映射器中this?.id.orEmpty() ?? EMPTY存在潜在风险:若orEmpty()未定义或EMPTY常量未声明,会触发错误。可直接替换为null判断逻辑:

extension CountryResponseMapper on CountryResponse? {
  Countries toDomain() {
    final response = this;
    return Countries(
      response?.id?.toString() ?? '', // 将int类型id转为String
      response?.name ?? '',
    );
  }
}

4. 处理未使用的count字段

API返回的count字段未在实体类中定义,若开启序列化严格模式会抛出异常。可在AllCountryResponse中添加忽略配置:

@JsonSerializable(explicitToJson: true)
class AllCountryResponse extends BaseResponse {
  @JsonKey(name: "data")
  List<CountryResponse> data;
  @JsonKey(ignore: true) // 忽略count字段
  int? count;

  AllCountryResponse({required this.data, super.status, super.message});  

  // ... 其余代码不变
}

最后操作

修改代码后,重新运行序列化代码生成命令:

flutter pub run build_runner build

重新测试API调用,确认映射正常,不再触发错误提示。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 00:54:33