Flutter中json_serializable包Double类型转换问题及优雅解法问询
解决Dart json_annotation反序列化时字符串转数字的类型错误
问题场景
定义AccountFilter实体类并使用json_annotation生成序列化代码后,反序列化时抛出错误:type 'String' is not a subtype of type 'num' in type cast。原因是接口返回的latitude和longitude字段为字符串类型,但实体类中定义为double,生成的代码直接尝试将字符串强转为num导致失败。
原实体类代码:
import 'package:json_annotation/json_annotation.dart'; part 'account_filter.g.dart'; @JsonSerializable() class AccountFilter { double latitude = 0; double longitude = 0; String city = ""; String country = ""; int minAge = 18; int maxAge = 99; int gender = 1; AccountFilter( this.latitude, this.longitude, this.city, this.country, this.minAge, this.maxAge, this.gender, ); factory AccountFilter.fromJson(Map<String, dynamic> json) => _$AccountFilterFromJson(json); Map<String, dynamic> toJson() => _$AccountFilterToJson(this); }
生成的反序列化代码中报错行:
(json['latitude'] as num).toDouble() // 尝试将字符串强转为num失败
优雅解决方案
无需额外定义字符串字段和getter,直接通过json_annotation的扩展能力处理类型转换:
方法一:自定义JsonConverter(复用性高)
创建通用的字符串转double转换器,可在多个字段/类中复用:
class StringToDoubleConverter implements JsonConverter<double, dynamic> { const StringToDoubleConverter(); @override double fromJson(dynamic json) { if (json is String) { return double.parse(json); } else if (json is num) { return json.toDouble(); } throw FormatException('无法将${json.runtimeType}转换为double'); } @override dynamic toJson(double object) => object; }
在实体类字段上标注转换器:
@JsonSerializable() class AccountFilter { @JsonKey(converter: StringToDoubleConverter()) double latitude = 0; @JsonKey(converter: StringToDoubleConverter()) double longitude = 0; // 其他字段保持不变 // 构造函数和序列化方法不变 }
方法二:直接在@JsonKey中定义转换逻辑(简洁快速)
如果仅在当前类使用,可直接在@JsonKey参数中写匿名转换函数:
@JsonSerializable() class AccountFilter { @JsonKey( fromJson: _stringToDouble, toJson: _doubleToString, ) double latitude = 0; @JsonKey( fromJson: _stringToDouble, toJson: _doubleToString, ) double longitude = 0; // 其他字段保持不变 // 构造函数和序列化方法不变 // 定义转换函数 static double _stringToDouble(dynamic value) { if (value is String) { return double.parse(value); } else if (value is num) { return value.toDouble(); } return 0.0; // 也可根据业务需求抛出异常 } static dynamic _doubleToString(double value) => value; }
效果
重新执行dart run build_runner build --delete-conflicting-outputs生成代码后,反序列化时会自动兼容字符串/数字类型的latitude和longitude,无需修改业务逻辑,保持实体类字段的类型纯净。
内容的提问来源于stack exchange,提问作者Draško
相关产品推荐
相关产品推荐

