如何在Freezed中通过一个字段获取两个不同的JSON值?
在Freezed中处理多JSON字段映射到同一模型属性的问题
问题背景
现有基于Freezed的Dto模型类:
@freezed abstract class Dto implements _$Dto { const factory Dto({ String? name, String? url, }) = _Dto; factory Dto.fromJson(Map<String, dynamic> json) => _$DtoFromJson(json); }
需要兼容两种JSON响应格式:
- 包含
display_picture_url字段的JSON:
{ "name": "superuser root", "display_picture_url": "/media_server/user.jpg" }
- 包含
picture_url字段的JSON:
{ "name": "superuser root", "picture_url": "/media_server/user.jpg" }
非Freezed环境下可以直接在fromJson中判断字段存在性来赋值,但Freezed生成的序列化逻辑需要特殊处理。
解决方案
方法一:自定义fromJson预处理JSON
直接在自定义的fromJson方法中预处理原始JSON,将两个可能的字段统一映射为模型中的url字段,再交给Freezed生成的解析方法处理:
@freezed abstract class Dto implements _$Dto { const factory Dto({ String? name, String? url, }) = _Dto; factory Dto.fromJson(Map<String, dynamic> json) { // 复制原始JSON避免修改原对象 final processedJson = Map<String, dynamic>.from(json); // 优先取display_picture_url,不存在则取picture_url if (processedJson.containsKey('display_picture_url')) { processedJson['url'] = processedJson.remove('display_picture_url'); } else if (processedJson.containsKey('picture_url')) { processedJson['url'] = processedJson.remove('picture_url'); } // 调用Freezed生成的解析方法 return _$DtoFromJson(processedJson); } }
这种方法逻辑直观,和非Freezed环境下的写法思路一致,适合处理多字段映射的场景。
方法二:使用@JsonKey自定义字段解析逻辑
通过@JsonKey的fromJson参数,为url字段指定自定义解析函数,从整个JSON对象中匹配目标字段:
// 自定义解析函数 String? _resolveUrl(Map<String, dynamic> json) { if (json.containsKey('display_picture_url')) { return json['display_picture_url'] as String?; } else if (json.containsKey('picture_url')) { return json['picture_url'] as String?; } return null; } @freezed abstract class Dto implements _$Dto { const factory Dto({ String? name, // 为url字段指定自定义解析逻辑 @JsonKey(fromJson: _resolveUrl) String? url, }) = _Dto; factory Dto.fromJson(Map<String, dynamic> json) => _$DtoFromJson(json); }
这种方法更贴合注解式序列化的风格,适合单一字段的多来源解析场景。
内容的提问来源于stack exchange,提问作者Meshkat Shadik
相关产品推荐
相关产品推荐

