我是使用json_serializable
这个插件进行json序列化的。
因为服务器返回的json结构都是统一如下结构:
{
"code": 200,
"message": "SUCCESS",
"data": {
"countdown": 3,
"createDate": 1625647940000,
"modifiedDate": 1625647940000
}
}
自然就会想通过一个泛型的方式,进行封装,进而不用每个json序列化model都包含code、message的通用部分。
当我直接把data通过泛型抽取出来时,执行如下命令生成代码时,出现如下错误:
import 'package:json_annotation/json_annotation.dart';
part 'response_model.g.dart';
@JsonSerializable(explicitToJson: true)
class ResponseModel<T> {
T? data;
int? code;
String? message;
ResponseModel({
this.data,
this.code,
this.message
});
factory ResponseModel.fromJson(Map<String, dynamic> json) => _$ResponseModelFromJson<T>(json);
Map<String, dynamic> toJson() => _$ResponseModelToJson(this);
}
错误:
flutter packages pub run build_runner build
[INFO] Generating build script...
[INFO] Generating build script completed, took 515ms
[INFO] Initializing inputs
[INFO] Reading cached asset graph...
[INFO] Reading cached asset graph completed, took 61ms
[INFO] Checking for updates since last build...
[INFO] Checking for updates since last build completed, took 511ms
[INFO] Running build...
[INFO] 1.3s elapsed, 10/14 actions completed.
[SEVERE] json_serializable:json_serializable on lib/model/response_model.dart:
Could not generate `fromJson` code for `data` because of type `T` (type parameter).
To support type parameters (generic types) you can:
* Use `JsonConverter`
https://pub.dev/documentation/json_annotation/latest/json_annotation/JsonConverter-class.html
* Use `JsonKey` fields `fromJson` and `toJson`
https://pub.dev/documentation/json_annotation/latest/json_annotation/JsonKey/fromJson.html
https://pub.dev/documentation/json_annotation/latest/json_annotation/JsonKey/toJson.html
* Set `JsonSerializable.genericArgumentFactories` to `true`
https://pub.dev/documentation/json_annotation/latest/json_annotation/JsonSerializable/genericArgumentFactories.html
package:doucan_flutter/model/response_model.dart:6:6
╷
6 │ T? data;
│ ^^^^
╵
[INFO] Running build completed, took 1.6s
[INFO] Caching finalized dependency graph...
[INFO] Caching finalized dependency graph completed, took 61ms
[SEVERE] Failed after 1.6s
pub finished with exit code 1
主要问题就是这里:
Could not generate `fromJson` code for `data` because of type `T` (type parameter).
在GitHub的issue中找到如下答案:
https://github.com/google/json_serializable.dart/issues/252
依葫芦画瓢改了一下,木有成功,可能我理解不到位。
于是继续Google…
发现了这篇文章:
https://wamae.medium.com/generics-and-json-serialization-in-flutter-a8d335840d7b
按照里面的写法成功了一大半,但还是有些错误,可能和flutter版本有关,我使用的是Flutter 2.2.3 Dart 2.13.4
。
做些调整后就成功了!!~
因为具体Data类的fromJson接收的参数类型为Map
,而原文中的是Object
,导致调用时失败。以下为修改内容:
//原文:
factory BaseResponse.fromJson(
Map json,
T Function(Object json) fromJsonT,
) =>
_$BaseResponseFromJson(json, fromJsonT);
// 改为:
factory BaseResponse.fromJson(
Map json,
T Function(Map json) fromJsonT
) =>
_$BaseResponseFromJson(json, fromJsonT);
//相对应的,base_response.g.dart文件也需要修改FromJson方法中的参数变量类型
以下是最终的代码:
## file : response_model.dart
import 'package:json_annotation/json_annotation.dart';
part 'response_model.g.dart';
@JsonSerializable(
genericArgumentFactories: true, fieldRename: FieldRename.snake)
class ResponseModel<T> {
@JsonKey(name: 'code')
final int code;
@JsonKey(name: 'message')
final String message;
@JsonKey(name: 'data')
final T data;
ResponseModel(this.data, this.code, this.message);
factory ResponseModel.fromJson(
Map<String, dynamic> json, T Function(Map<String, dynamic> json) fromJsonT) =>
_$ResponseModelFromJson(json, fromJsonT);
Map<String, dynamic> toJson(Object Function(T value) toJsonT) =>
_$ResponseModelToJson(this, toJsonT);
}
## file : response_model.g.dart
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'response_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
ResponseModel<T> _$ResponseModelFromJson<T>(
Map<String, dynamic> json,
T Function(Map<String, dynamic> json) fromJsonT,
) {
return ResponseModel<T>(
fromJsonT(json['data']),
json['code'] as int,
json['message'] as String,
);
}
Map<String, dynamic> _$ResponseModelToJson<T>(
ResponseModel<T> instance,
Object? Function(T value) toJsonT,
) =>
<String, dynamic>{
'code': instance.code,
'message': instance.message,
'data': toJsonT(instance.data),
};
开始食用:
data具体类:
import 'package:json_annotation/json_annotation.dart';
part 'splash_model.g.dart';
@JsonSerializable(explicitToJson: true)
class SplashmodelData {
int countdown;
int createDate;
int modifiedDate;
SplashmodelData(
this.countdown,
this.createDate,
this.modifiedDate,
);
factory SplashmodelData.fromJson(Map<String, dynamic> json) =>
_$SplashmodelDataFromJson(json);
Map<String, dynamic> toJson() => _$SplashmodelDataToJson(this);
}
import 'dart:convert';
import 'package:doucan_flutter/config/network_config.dart';
import 'package:doucan_flutter/model/response_model.dart';
import 'package:doucan_flutter/model/splash_model.dart';
import 'package:http/http.dart' as http;
class SplashDao {
static Future<SplashmodelData?> fetch() async {
Uri url = Uri.parse(NetworkConfig.url('app_launcher/patient/splash'));
final respones = await http.get(url);
print(respones.statusCode);
print(respones.body);
if (respones.statusCode == 200) {
var jsonResult = json.decode(Utf8Decoder().convert(respones.bodyBytes));
return ResponseModel<SplashmodelData>.fromJson(
jsonResult, (data) => SplashmodelData.fromJson(data)).data;
} else {
throw Exception(
'request app_launcher/patient/splash failed ');
}
}
}