如何结合泛型最佳使用json_serializable?支持嵌套泛型场景
我完全理解你的需求——想要一个通用的Response<T>类,既能用json_serializable快速序列化,又能完美支持T从原生类型到多层嵌套泛型自定义类的所有场景。之前用自定义类型转换器搞不定深层嵌套的问题,其实是因为普通转换器没法递归处理泛型参数的嵌套逻辑,不过我们可以通过json_serializable的泛型参数工厂特性来解决这个问题,哪怕需要写一些上层封装代码也完全能实现完美支持。
第一步:配置泛型Response类,开启genericArgumentFactories
首先修改你的Response类,开启genericArgumentFactories参数,这个参数会让生成的序列化方法接收一个处理T类型的转换函数,从而支持递归处理嵌套类型:
import 'package:json_annotation/json_annotation.dart'; part 'response.g.dart'; @JsonSerializable(genericArgumentFactories: true) class Response<T> { final int code; final T data; Response({required this.code, required this.data}); // 新增泛型转换函数参数fromJsonT,用来处理T的反序列化 factory Response.fromJson( Map<String, dynamic> json, T Function(Object? json) fromJsonT, ) => _$ResponseFromJson(json, fromJsonT); // 新增泛型转换函数参数toJsonT,用来处理T的序列化 Map<String, dynamic> toJson( Object? Function(T value) toJsonT, ) => _$ResponseToJson(this, toJsonT); }
第二步:针对具体的T类型,传入对应的转换逻辑
不管T是原生类型、自定义类还是深层嵌套的泛型类,只需要在调用fromJson/toJson时传入对应的转换函数即可。
举几个常见场景的例子:
场景1:T是自定义普通类(比如User)
先定义你的自定义类并配置序列化:
import 'package:json_annotation/json_annotation.dart'; part 'user.g.dart'; @JsonSerializable() class User { final String name; final int age; User({required this.name, required this.age}); factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json); Map<String, dynamic> toJson() => _$UserToJson(this); }
然后反序列化Response<User>:
final jsonMap = {'code': 200, 'data': {'name': 'Alice', 'age': 30}}; final userResponse = Response.fromJson( jsonMap, (json) => User.fromJson(json as Map<String, dynamic>), );
场景2:T是嵌套的泛型集合(比如List)
final listJson = {'code': 200, 'data': [ {'name': 'Alice', 'age': 30}, {'name': 'Bob', 'age': 25} ]}; final userListResponse = Response.fromJson( listJson, (json) => (json as List).map((item) => User.fromJson(item as Map<String, dynamic>)).toList(), );
场景3:T是多层嵌套的泛型类(比如Result)
先定义嵌套的泛型类同样开启genericArgumentFactories:
import 'package:json_annotation/json_annotation.dart'; part 'result.g.dart'; @JsonSerializable(genericArgumentFactories: true) class Result<U> { final U value; final String message; Result({required this.value, required this.message}); factory Result.fromJson( Map<String, dynamic> json, U Function(Object? json) fromJsonU, ) => _$ResultFromJson(json, fromJsonU); Map<String, dynamic> toJson( Object? Function(U value) toJsonU, ) => _$ResultToJson(this, toJsonU); }
然后反序列化Response<Result<User>>:
final nestedJson = {'code': 200, 'data': { 'value': {'name': 'Alice', 'age': 30}, 'message': '请求成功' }}; final nestedResponse = Response.fromJson( nestedJson, (json) => Result.fromJson( json as Map<String, dynamic>, (userJson) => User.fromJson(userJson as Map<String, dynamic>), ), );
第三步:封装上层代码简化调用(可选)
如果觉得每次都写转换函数太繁琐,可以封装扩展方法或者工厂类来简化调用:
extension ResponseHelpers on Response { // 封装User类型的Response反序列化 static Response<User> fromUserJson(Map<String, dynamic> json) { return Response.fromJson(json, (json) => User.fromJson(json as Map<String, dynamic>)); } // 封装List<User>类型的Response反序列化 static Response<List<User>> fromUserListJson(Map<String, dynamic> json) { return Response.fromJson( json, (json) => (json as List).map((item) => User.fromJson(item as Map<String, dynamic>)).toList(), ); } // 封装Result<User>类型的Response反序列化 static Response<Result<User>> fromNestedUserResultJson(Map<String, dynamic> json) { return Response.fromJson( json, (json) => Result.fromJson( json as Map<String, dynamic>, (userJson) => User.fromJson(userJson as Map<String, dynamic>), ), ); } }
调用时就可以直接用:
final userResponse = ResponseHelpers.fromUserJson(jsonMap);
为什么之前的自定义转换器不行?
普通的JsonConverter是针对单一固定类型设计的,没法动态处理泛型参数的深层嵌套逻辑。而开启genericArgumentFactories后,生成的序列化代码会把T的转换逻辑完全委托给你传入的函数,这个函数可以递归处理任意层级的嵌套泛型,完美解决你的问题。
最后别忘了运行build_runner生成序列化代码:
# Flutter项目 flutter pub run build_runner build # 纯Dart项目 dart run build_runner build
内容的提问来源于stack exchange,提问作者user7720975

