首页 > 解决方案 > 如何在 Dart 中使用带有 json 序列化的泛型和泛型列表?

问题描述

我正在开发一个使用 Flutter 制作的移动项目。该项目需要连接到一些服务器以进行 REST 消费服务(GET、POST、PUT、DELETE,...),并检索数据以及向它们发送数据。数据需要以 JSON 格式格式化,因此我决定将 Json 序列化库 2.0.3 用于 Dart,并带有 Json 注释 2.0.0 和 build_runner 1.2.8;它确实适用于 int、String 和 bool 等基本数据类型以及自定义对象。但它似乎根本不适用于泛型,例如<T> item;字段或List<T> list;字段。

我的目的是添加一些通用字段,以便它们可用于返回所有类型的 json 类型和结构。我设法为第一种情况找到了解决方案,通过使用“@JsonKey”覆盖 fromJson 和 toJson,并<T>与我想在方法中将其转换为的所需类型进行比较。但是,我找不到List<T>键入字段的解决方案。如果我尝试为它们使用注释,我得到的只是一个List<dynamic>类型,它对于比较类进行强制转换是无用的。我该如何解决我的困境?我应该坚持使用 json_serialization 还是改用 build_value ?非常感谢您对此事的任何帮助。

我的代码:

import 'package:json_annotation/json_annotation.dart';

part 'json_generic.g.dart';

@JsonSerializable()
class JsonGeneric<T> {
  final int id;
  final String uri;
  final bool active;
  @JsonKey(fromJson: _fromGenericJson, toJson: _toGenericJson)
  final T item;
  @JsonKey(fromJson: _fromGenericJsonList, toJson: _toGenericJsonList)
  final List<T> list;

  static const String _exceptionMessage = "Incompatible type used in JsonEnvelop";

  JsonGeneric({this.id, this.uri, this.active, this.item, this.list});

  factory JsonGeneric.fromJson(Map<String, dynamic> json) =>
      _$JsonGenericFromJson(json);

  Map<String, dynamic> toJson() => _$JsonGenericToJson(this);

  static T _fromGenericJson<T>(Map<String, dynamic> json) {
    if (T == User) {
      return json == null ? null : User.fromJson(json) as T;
    } else if (T == Company) {
      return json == null ? null : Company.fromJson(json) as T;
    } else if (T == Data) {
      return json == null ? null : Data.fromJson(json) as T;
    } else {
      throw Exception(_exceptionMessage);
    }
  }

  static Map<String, dynamic> _toGenericJson<T>(T value) {
    if (T == User) {
      return (T as User).toJson();
    } else if(T == Company) {
      return (T as Company).toJson();
    } else if(T == Data) {
      return (T as Data).toJson();
    } else {
      throw Exception(_exceptionMessage);
    }
  }

  static dynamic _fromGenericJsonList<T>(List<dynamic> json) {
    if (T == User) {

    } else if(T == Company) {

    } else if(T == Data) {

    } else {
      throw Exception(_exceptionMessage);
    }
  }

  static List<Map<String, dynamic>> _toGenericJsonList<T>(dynamic value) {
    if (T == User) {

    } else if(T == Company) {

    } else if(T == Data) {

    } else {
      throw Exception(_exceptionMessage);
    }
  }
}

我希望能够序列化/反序列化“最终列表”;使用“@JsonKey”或不使用它,但到目前为止,我未能找到将其转换为正确 json 格式的方法。

当我尝试为此类生成代码时(使用命令“flutter packages pub run build_runner build”),我最终收到以下错误:

运行 JsonSerializableGenerator 时出错由于类型无法生成fromJson代码。提供的实例都不支持定义的类型。包:json_generic.dart:11:17listTTypeHelper

   ╷
11 │   final List<T> list;
   │                 ^^^^
   ╵

标签: jsongenericsserializationdartflutter

解决方案


这是我的正确解决方案,非常适合我。

class Paginate<T> {
  int from;
  int index;
  int size;
  int count;
  int pages;
  List<T> items;
  bool hasPrevious;
  bool hasNext;

  Paginate(
      {this.index,
      this.size,
      this.count,
      this.from,
      this.hasNext,
      this.hasPrevious,
      this.items,
      this.pages});


  factory  Paginate.fromJson(Map<String,dynamic> json,Function fromJsonModel){
    final items = json['items'].cast<Map<String, dynamic>>();
    return Paginate<T>(
      from: json['from'],
      index: json['index'],
      size: json['size'],
      count: json['count'],
      pages: json['pages'],
      hasPrevious: json['hasPrevious'],
      hasNext: json['hasNext'],
      items: new List<T>.from(items.map((itemsJson) => fromJsonModel(itemsJson)))
    );
  }
}

假设我们将使用飞行模型分页模型。在这里您必须配置航班列表。

class Flight {
  String flightScheduleId;
  String flightId;
  String flightNo;
  String flightDate;
  String flightTime;

  Flight(
      {this.flightScheduleId,
      this.flightId,
      this.flightNo,
      this.flightDate,
      this.flightTime});

  factory Flight.fromJson(Map<String, dynamic> parsedJson) {
    var dateFormatter = new DateFormat(Constants.COMMON_DATE_FORMAT);
    var timeFormatter = new DateFormat(Constants.COMMON_TIME_FORMAT);
    var parsedDate = DateTime.parse(parsedJson['flightDepartureTime']);
    String formattedDate = dateFormatter.format(parsedDate);
    String formattedTime = timeFormatter.format(parsedDate);
    return Flight(
        flightScheduleId: parsedJson['id'],
        flightId: parsedJson['flightLayoutId'],
        flightNo: parsedJson['outboundFlightName'],
        flightDate: formattedDate,
        flightTime: formattedTime,
  }
  // Magic goes here. you can use this function to from json method.
  static Flight fromJsonModel(Map<String, dynamic> json) => Flight.fromJson(json);
}

-> 在这里你可以使用,

 Paginate<Flight>.fromJson(responses, Flight.fromJsonModel);

推荐阅读