如何为顶层Freezed模型指定自定义JsonConverter解决反序列化报错?
问题原因
你当前使用的是Freezed的联合类型(Sealed Union) 特性,Freezed默认生成的顶层fromJson方法会强制读取JSON中的runtimeType字段,以此判断应该实例化哪一个子类构造器(Data/Loading/Error)。由于后端返回的JSON没有该字段,因此会抛出类型校验异常,哪怕传入空Map也会因为找不到runtimeType匹配项报错。
解决方案
方案1:直接调用对应构造器(最适配当前场景)
你当前的接口请求成功场景固定对应Data构造器,完全不需要走Freezed自动生成的联合类型判断逻辑,直接修改api_provider中的代码即可:
return result.when( // 成功场景直接构造Data实例,无参数时可以加const优化性能 (json) => const InitialDataModel.Data(), error: (e) => InitialDataModel.error(e), );
如果后续Data构造器需要添加字段,你可以为单构造器单独配置fromJson,调整后代码如下:
// 模型定义修改示例 @freezed class InitialDataModel with _$InitialDataModel { const factory InitialDataModel({ // 新增需要反序列化的字段 String? userToken, int? expireTime, }) = Data; const factory InitialDataModel.loading() = Loading; const factory InitialDataModel.error([String? message]) = Error; // 只给Data构造器加fromJson即可 factory Data.fromJson(Map<String, dynamic> json) => _$DataFromJson(json); } // api_provider调用示例 (json) => Data.fromJson(json),
方案2:自定义联合类型反序列化规则
如果你需要保留使用顶层InitialDataModel.fromJson的写法,可以通过Freezed注解自定义反序列化逻辑:
场景A:后端有状态区分字段
如果后端返回的JSON中有专门用来区分状态的字段(比如code、type),可以通过unionKey指定匹配字段,unionValue指定每个构造器对应的值:
@Freezed(unionKey: 'code') // 指定用code字段匹配构造器 class InitialDataModel with _$InitialDataModel { @JsonValue(200) // code为200时匹配Data构造 const factory InitialDataModel() = Data; @JsonValue(-1) // code为-1时匹配Error构造 const factory InitialDataModel.error([String? message]) = Error; const factory InitialDataModel.loading() = Loading; factory InitialDataModel.fromJson(Map<String, dynamic> json) => _$InitialDataModelFromJson(json); }
场景B:后端无状态区分字段,指定默认构造
如果后端没有状态区分字段,可指定默认构造器作为未知状态的 fallback:
@Freezed(unknownEnumValue: InitialDataModel.Data) // 未匹配到类型时默认返回Data class InitialDataModel with _$InitialDataModel { const factory InitialDataModel() = Data; const factory InitialDataModel.loading() = Loading; const factory InitialDataModel.error([String? message]) = Error; factory InitialDataModel.fromJson(Map<String, dynamic> json) => _$InitialDataModelFromJson(json); }
方案3:完全自定义fromJson逻辑
你也可以直接重写顶层fromJson方法,完全自己控制反序列化规则,完全不需要依赖Freezed的默认匹配逻辑:
@freezed class InitialDataModel with _$InitialDataModel { const factory InitialDataModel() = Data; const factory InitialDataModel.loading() = Loading; const factory InitialDataModel.error([String? message]) = Error; factory InitialDataModel.fromJson(Map<String, dynamic> json) { // 自定义判断逻辑,比如判断是否有报错字段 if (json.containsKey('error_msg')) { return InitialDataModel.error(json['error_msg']); } // 默认返回Data return const InitialDataModel(); } }
内容的提问来源于stack exchange,提问作者Nagual
相关产品推荐
相关产品推荐

