如何在Dart中通过JSON序列化使用泛型和泛型列表?

Mar*_*lho 6 generics serialization json dart flutter

我正在开发使用Flutter开发的移动项目。该项目需要连接到一些用于REST消费服务的服务器(GET,POST,PUT,DELETE等),并检索数据以及向它们发送数据。数据需要使用JSON格式化,因此我决定将Dson的Json序列化库2.0.3与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);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

我希望能够序列化/反序列化“最终列表列表”;要么带有“ @JsonKey”,要么不带有它,但是到目前为止,我找不到一种将其转换为正确的json格式的方法。

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

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

   ?
11 ?   final List<T> list;
   ?                 ^^^^
   ?
Run Code Online (Sandbox Code Playgroud)

Bak*_*ker 25

json_serialized

\n

json_serialized有几种策略1将泛型类型作为单个对象处理TList<T>(从 v. 5.0.2+ 开始):

\n
    \n
  1. 助手类:JsonConverter
  2. \n
  3. 辅助方法:@JsonKey(fromJson:, toJson:)
  4. \n
  5. 通用参数工厂@JsonSerializable(genericArgumentFactories: true)
  6. \n
\n

1 据我所知。可能还有其他方法可以做到这一点。

\n

助手类:JsonConverter

\n

基本思想:编写一个带有方法的自定义JsonConverter类来识别和处理我们的类型fromJsontoJsonT字段反/序列化。

\n

该策略的好处JsonCoverter在于它将模型的所有反/序列化逻辑封装到一个类中,该类可在任何需要序列化相同模型类型的类中重用。并且您的toJson,fromJson调用不会改变,这与通用参数工厂策略相反,在通用参数工厂策略中,每个toJson,fromJson调用都需要我们提供一个处理函数。

\n

我们可以JsonConverter通过注释与我们的对象一起使用来进行反/序列化:

\n
    \n
  • 需要自定义处理的个人T/List<T>字段,或
  • \n
  • 整个类(它将用于任何/所有类型的字段T)。
  • \n
\n

OperationResult<T>下面是包含泛型类型字段的 json_serialized 类的示例T

\n

上课注意事项OperationResult

\n
    \n
  • 有一个通用类型字段T t
  • \n
  • t可以是单个类型的对象T 对象的集合List<T>
  • \n
  • 无论类型T是什么,它都必须有toJson()/fromJson()方法(即可反/可序列化)。
  • \n
  • 有一个JsonConverter名为ModelConverter注释T t字段的类。
  • \n
  • 生成存根_$OperationResultFromJson<T>(json)&_$OperationResultToJson<T>()现在采用一个T变量
  • \n
\n
/// This method of json_serializable handles generic type arguments / fields by\n/// specifying a converter helper class on the generic type field or on the entire class.\n/// If the converter is specified on the class itself vs. just a field, any field with\n/// type T will be de/serialized using the converter.\n/// This strategy also requires us determine the JSON type during deserialization manually,\n/// by peeking at the JSON and making assumptions about its class.\n@JsonSerializable(explicitToJson: true)\nclass OperationResult<T> {\n  final bool ok;\n  final Operation op;\n  @ModelConverter()\n  final T t;\n  final String title;\n  final String msg;\n  final String error;\n\n  OperationResult({\n    this.ok = false,\n    this.op = Operation.update,\n    required this.t,\n    this.title = \'Operation Error\',\n    this.msg = \'Operation failed to complete\',\n    this.error= \'Operation could not be decoded for processing\'});\n\n  factory OperationResult.fromJson(Map<String,dynamic> json) =>\n      _$OperationResultFromJson<T>(json);\n  Map<String,dynamic> toJson() => _$OperationResultToJson<T>(this);\n}\n
Run Code Online (Sandbox Code Playgroud)\n

这是上面的JsonConverter类:ModelConverter

\n
/// This JsonConverter class holds the toJson/fromJson logic for generic type\n/// fields in our Object that will be de/serialized.\n/// This keeps our Object class clean, separating out the converter logic.\n///\n/// JsonConverter takes two type variables: <T,S>.\n///\n/// Inside our JsonConverter, T and S are used like so:\n///\n/// T fromJson(S)\n/// S toJson(T)\n///\n/// T is the concrete class type we\'re expecting out of fromJson() calls.\n/// It\'s also the concrete type we\'re inputting for serialization in toJson() calls.\n///\n/// Most commonly, T will just be T: a variable type passed to JsonConverter in our\n/// Object being serialized, e.g. the "T" from OperationResult<T> above.\n///\n/// S is the JSON type.  Most commonly this would Map<String,dynamic>\n/// if we\'re only de/serializing single objects.  But, if we want to de/serialize\n/// Lists, we need to use "Object" instead to handle both a single object OR a List of objects.\nclass ModelConverter<T> implements JsonConverter<T, Object> {\n  const ModelConverter();\n\n  /// fromJson takes Object instead of Map<String,dynamic> so as to handle both\n  /// a JSON map or a List of JSON maps.  If List is not used, you could specify\n  /// Map<String,dynamic> as the S type variable and use it as\n  /// the json argument type for fromJson() & return type of toJson(). \n  /// S can be any Dart supported JSON type\n  /// https://pub.dev/packages/json_serializable/versions/6.0.0#supported-types\n  /// In this example we only care about Object and List<Object> serialization\n  @override\n  T fromJson(Object json) {\n    /// start by checking if json is just a single JSON map, not a List\n    if (json is Map<String,dynamic>) {\n      /// now do our custom "inspection" of the JSON map, looking at key names\n      /// to figure out the type of T t. The keys in our JSON will\n      /// correspond to fields of the object that was serialized.\n      if (json.containsKey(\'items\') && json.containsKey(\'customer\')) {\n        /// In this case, our JSON contains both an \'items\' key/value pair\n        /// and a \'customer\' key/value pair, which I know only our Order model class\n        /// has as fields.  So, this JSON map is an Order object that was serialized\n        /// via toJson().  Now I\'ll deserialize it using Order\'s fromJson():\n        return Order.fromJson(json) as T;\n        /// We must cast this "as T" because the return type of the enclosing\n        /// fromJson(Object? json) call is "T" and at compile time, we don\'t know\n        /// this is an Order.  Without this seemingly useless cast, a compile time\n        /// error will be thrown: we can\'t return an Order for a method that\n        /// returns "T".\n      }\n      /// Handle all the potential T types with as many if/then checks as needed.\n      if (json.containsKey(\'status\') && json.containsKey(\'menuItem\')) {\n        return OrderItem.fromJson(json) as T;\n      }\n      if (json.containsKey(\'name\') && json.containsKey(\'restaurantId\')) {\n        return Menu.fromJson(json) as T;\n      }\n      if (json.containsKey(\'menuId\') && json.containsKey(\'restaurantId\')) {\n        return MenuItem.fromJson(json) as T;\n      }\n    } else if (json is List) { /// here we handle Lists of JSON maps\n      if (json.isEmpty) return [] as T;\n\n      /// Inspect the first element of the List of JSON to determine its Type\n      Map<String,dynamic> _first = json.first as Map<String,dynamic>;\n      bool _isOrderItem = _first.containsKey(\'status\') && _first.containsKey(\'menuItem\');\n\n      if (_isOrderItem) {\n        return json.map((_json) => OrderItem.fromJson(_json)).toList() as T;\n      }\n\n      bool _isMenuItem = _first.containsKey(\'menuId\') && _first.containsKey(\'restaurantId\');\n\n      if (_isMenuItem) {\n        return json.map((_json) => MenuItem.fromJson(_json)).toList() as T;\n      }\n\n    }\n    /// We didn\'t recognize this JSON map as one of our model classes, throw an error\n    /// so we can add the missing case\n    throw ArgumentError.value(json, \'json\', \'OperationResult._fromJson cannot handle\'\n        \' this JSON payload. Please add a handler to _fromJson.\');\n  }\n\n  /// Since we want to handle both JSON and List of JSON in our toJson(),\n  /// our output Type will be Object.\n  /// Otherwise, Map<String,dynamic> would be OK as our S type / return type.\n  ///\n  /// Below, "Serializable" is an abstract class / interface we created to allow\n  /// us to check if a concrete class of type T has a "toJson()" method. See\n  /// next section further below for the definition of Serializable.\n  /// Maybe there\'s a better way to do this?\n  ///\n  /// Our JsonConverter uses a type variable of T, rather than "T extends Serializable",\n  /// since if T is a List, it won\'t have a toJson() method and it\'s not a class\n  /// under our control.\n  /// Thus, we impose no narrower scope so as to handle both cases: an object that\n  /// has a toJson() method, or a List of such objects.\n  @override\n  Object toJson(T object) {\n    /// First we\'ll check if object is Serializable.\n    /// Testing for Serializable type (our custom interface of a class signature\n    /// that has a toJson() method) allows us to call toJson() directly on it.\n    if (object is Serializable){\n      return object.toJson();\n    } /// otherwise, check if it\'s a List & not empty & elements are Serializable\n    else if (object is List) {\n      if (object.isEmpty) return [];\n\n      if (object.first is Serializable) {\n        return object.map((t) => t.toJson()).toList();\n      }\n    }\n    /// It\'s not a List & it\'s not Serializable, this is a design issue\n    throw ArgumentError.value(object, \'Cannot serialize to JSON\',\n        \'OperationResult._toJson this object or List either is not \'\n            \'Serializable or is unrecognized.\');\n  }\n\n}\n
Run Code Online (Sandbox Code Playgroud)\n

下面是Serializable我们的模型类使用的接口,例如OrderMenuItem来实现(请参阅上面toJson()的代码ModelConverter以了解如何/为什么使用它):

\n
/// Interface for classes to implement and be "is" test-able and "as" cast-able\nabstract class Serializable {\n  Map<String,dynamic> toJson();\n}\n
Run Code Online (Sandbox Code Playgroud)\n

辅助方法:@JsonKey(fromJson:, toJson:)

\n

此注释用于使用 json_serialized 为类中任何类型的字段指定自定义反/序列化处理程序,而不仅仅是泛型类型。

\n

因此,我们可以T t使用与上面 JsonConverter 示例中使用的相同的“查看键”逻辑,为泛型类型字段指定自定义处理程序。

\n

下面,我们在类中添加了两个静态方法OperationResultJsonKey<T>(这样命名只是为了在 Stackoverflow 示例中显而易见):

\n
    \n
  • _fromJson
  • \n
  • _toJson
  • \n
\n

(这些也可以作为顶级函数存在于类之外。)

\n

然后我们向 JsonKey 提供这两个方法:

\n

@JsonKey(fromJson: _fromJson, toJson: _toJson)

\n

flutter pub run build_runner build然后,在为 flutter 或 dart (或)重新运行 build_runner 后dart run build_runner build,这两个静态方法将由 json_serialized 提供的生成的反/序列化方法使用。

\n
/// This method of json_serializable handles generic type arguments / fields by\n/// specifying a static or top-level helper method on the field itself.\n/// json_serializable will call these hand-typed helpers when de/serializing that particular\n/// field.\n/// During de/serialization we\'ll again determine the type manually, by peeking at the\n/// JSON keys and making assumptions about its class.\n@JsonSerializable(explicitToJson: true)\nclass OperationResultJsonKey<T> {\n  final bool ok;\n  final Operation op;\n  @JsonKey(fromJson: _fromJson, toJson: _toJson)\n  final T t;\n  final String title;\n  final String msg;\n  final String error;\n\n\n  OperationResultJsonKey({\n    this.ok = false,\n    this.op = Operation.update,\n    required this.t,\n    this.title = \'Operation Error\',\n    this.msg = \'Operation failed to complete\',\n    this.error = \'Operation could not be decoded for processing\'});\n\n  static T _fromJson<T>(Object json) {\n    // same logic as JsonConverter example\n  }\n\n  static Object _toJson<T>(T object) {\n    // same logic as JsonConverter example\n  }\n\n  /// These two _$ methods will be created by json_serializable and will call the above\n  /// static methods `_fromJson` and `_toJson`.\n  factory OperationResultJsonKey.fromJson(Map<String, dynamic> json) =>\n      _$OperationResultJsonKeyFromJson(json);\n\n  Map<String, dynamic> toJson() => _$OperationResultJsonKeyToJson(this);\n\n}\n
Run Code Online (Sandbox Code Playgroud)\n

通用参数工厂@JsonSerializable(genericArgumentFactories: true)

\n

在这种专门处理反/序列化的最后一种方式中,我们希望直接为我们的调用提供自定义的反/序列toJson()fromJson()方法OperationResult

\n

这种策略可能是最灵活的(允许您准确指定如何为每个泛型类型处理序列化),但它也非常冗长,要求您为每个/每个/提供一个序列化处理程序toJson函数fromJson。这真的很快就会变老。

\n

托森

\n

例如,在序列化时OperationResult<Order>.toJson()调用采用一个函数,该函数告诉 json_serialized在序列化时如何序列化字段。OrderOperationResult<Order>

\n

该辅助函数的签名为:\nObject Function(T) toJsonT

\n

因此,在OperationResult我们的toJson()存根方法中(json_serialized 为我们完成)来自:

\n

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

\n

到:

\n

Map<String,dynamic> toJson(Object Function(T) toJsonT) => _$OperationResultToJson<T>(this, toJsonT);

\n
    \n
  • toJson()从采用参数到采用函数作为参数
  • \n
  • 序列化时该函数将由 json_serialized 调用Order
  • \n
  • 函数返回Object而不是返回,以便Map<String,dynamic>它还可以处理T诸如ListList<OrderItem>
  • \n
\n

来自Json

\n

对于我们类上使用的fromJson()一面,期望我们提供一个签名函数:\ngenericArgumentFactoriesOperationResult<Order>T Function(Object?) fromJsonT

\n

因此,如果我们要反/序列化的具有泛型类型的对象是OperationResult<Order>,那么我们的辅助函数fromJson()将是:\nstatic Order fromJsonModel(Object? json) => Order.fromJson(json as Map<String,dynamic>);

\n

这是一个名为OperationResultGAFusing 的示例类genericArgumentFactories

\n
@JsonSerializable(explicitToJson: true, genericArgumentFactories: true)\nclass OperationResultGAF<T> {\n  final bool ok;\n  final Operation op;\n  final String title;\n  final String msg;\n  final T t;\n  final String error;\n\n\n  OperationResultGAF({\n    this.ok = false,\n    this.op = Operation.update,\n    this.title = \'Operation Error\',\n    this.msg = \'Operation failed to complete\',\n    required this.t,\n    this.error= \'Operation could not be decoded for processing\'});\n\n  // Interesting bits here \xe2\x86\x92 ----------------------------------- \xe2\x86\x93 \xe2\x86\x93\n  factory OperationResultGAF.fromJson(Map<String,dynamic> json, T Function(Object? json) fromJsonT) =>\n      _$OperationResultGAFFromJson<T>(json, fromJsonT);\n\n  // And here \xe2\x86\x92 ------------- \xe2\x86\x93 \xe2\x86\x93\n  Map<String,dynamic> toJson(Object Function(T) toJsonT) =>\n      _$OperationResultGAFToJson<T>(this, toJsonT);\n}\n
Run Code Online (Sandbox Code Playgroud)\n

如果T是一个名为 的类Order,则该类Order可以包含与 genericArgumentFactories 一起使用的静态辅助方法:

\n
@JsonSerializable(explicitToJson: true, includeIfNull: false)\nclass Order implements Serializable {\n\n  //<snip>\n\n  /// Helper methods for genericArgumentFactories\n  static Order fromJsonModel(Object? json) => Order.fromJson(json as Map<String,dynamic>);\n  static Map<String, dynamic> toJsonModel(Order order) => order.toJson();\n\n  /// Usual json_serializable stub methods\n  factory Order.fromJson(Map<String,dynamic> json) => _$OrderFromJson(json);\n  Map<String,dynamic> toJson() => _$OrderToJson(this);\n\n}\n
Run Code Online (Sandbox Code Playgroud)\n

请注意,上面的辅助方法只是调用由 json_serialized 生成的常用toJson()存根fromJson()方法。

\n

将此类静态方法添加到模型类的目的是使向 提供这些辅助方法变得OperationResultGAF.toJson()更加OperationResultGAF.fromJson()简洁:我们只提供它们的函数名称而不是实际函数。

\n

例如,而不是:

\n
OperationResultGAF<Order>.fromJson(_json, (Object? json) => Order.fromJson(json as Map<String,dynamic>));\n
Run Code Online (Sandbox Code Playgroud)\n

我们可以用:

\n
OperationResultGAF<Order>.fromJson(_json, Order.fromJsonModel);\n
Run Code Online (Sandbox Code Playgroud)\n

如果T是一个List对象,例如List<MenuItem>,那么我们需要处理列表的辅助方法。

\n

这是要添加到的静态辅助方法的示例MenuItem类以处理列表的静态辅助方法的示例:

\n
  static List<MenuItem> fromJsonModelList(Object? jsonList) {\n    if (jsonList == null) return [];\n    \n    if (jsonList is List) {\n      return jsonList.map((json) => MenuItem.fromJson(json)).toList();\n    }\n    \n    // We shouldn\'t be here\n    if (jsonList is Map<String,dynamic>) {\n      return [MenuItem.fromJson(jsonList)];\n    }\n\n    // We really shouldn\'t be here\n    throw ArgumentError.value(jsonList, \'jsonList\', \'fromJsonModelList cannot handle\'\n        \' this JSON payload. Please add a handler for this input or use the correct \'\n        \'helper method.\');\n  }\n\n  /// Not at all comprehensive, but you get the idea\n  static List<Map<String,dynamic>> toJsonModelList(Object list) {\n    if (list is List<MenuItem>) {\n      return list.map((item) => item.toJson()).toList();\n    }\n    return [];\n  }\n
Run Code Online (Sandbox Code Playgroud)\n

以及如何在单元测试中调用这些静态帮助器方法的示例:

\n
  List<MenuItem> _mListA = [MockData.menuItem1, MockData.menuItem2];\n\n  OperationResultGAF<List<MenuItem>> _orC = OperationResultGAF<List<MenuItem>>(\n      op: Operation.delete, t: _mListA);\n\n  /// Use toJsonModelList to produce a List<Map<String,dynamic>>\n  var _json = _orC.toJson(MenuItem.toJsonModelList);\n\n  /// Use fromJsonModelList to convert List<Map<String,dynamic>> to List<MenuItem>\n  OperationResultGAF<List<MenuItem>> _orD = OperationResultGAF<List<MenuItem>>.fromJson(\n      _json, MenuItem.fromJsonModelList);\n\n  expect(_orC.op, _orD.op);\n  expect(_orC.t.first.id, _orD.t.first.id);\n
Run Code Online (Sandbox Code Playgroud)\n


小智 12

这是一个例子

https://github.com/dart-lang/json_serializable/blob/master/example/lib/json_converter_example.dart

// json_converter_example.dart


// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:json_annotation/json_annotation.dart';

part 'json_converter_example.g.dart';

@JsonSerializable()
class GenericCollection<T> {
  @JsonKey(name: 'page')
  final int page;

  @JsonKey(name: 'total_results')
  final int totalResults;

  @JsonKey(name: 'total_pages')
  final int totalPages;

  @JsonKey(name: 'results')
  @_Converter()
  final List<T> results;

  GenericCollection(
      {this.page, this.totalResults, this.totalPages, this.results});

  factory GenericCollection.fromJson(Map<String, dynamic> json) =>
      _$GenericCollectionFromJson<T>(json);

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

class _Converter<T> implements JsonConverter<T, Object> {
  const _Converter();

  @override
  T fromJson(Object json) {
    if (json is Map<String, dynamic> &&
        json.containsKey('name') &&
        json.containsKey('size')) {
      return CustomResult.fromJson(json) as T;
    }
    if (json is Map<String, dynamic> &&
        json.containsKey('name') &&
        json.containsKey('lastname')) {
      return Person.fromJson(json) as T;
    }
    // This will only work if `json` is a native JSON type:
    //   num, String, bool, null, etc
    // *and* is assignable to `T`.
    return json as T;
  }

  @override
  Object toJson(T object) {
    // This will only work if `object` is a native JSON type:
    //   num, String, bool, null, etc
    // Or if it has a `toJson()` function`.
    return object;
  }
}

@JsonSerializable()
class CustomResult {
  final String name;
  final int size;

  CustomResult(this.name, this.size);

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

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

  @override
  bool operator ==(Object other) =>
      other is CustomResult && other.name == name && other.size == size;

  @override
  int get hashCode => name.hashCode * 31 ^ size.hashCode;
}

@JsonSerializable()
class Person {
  final String name;
  final String lastname;

  Person(this.name, this.lastname);

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

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

  @override
  bool operator ==(Object other) =>
      other is Person && other.name == name && other.lastname == lastname;
}


Run Code Online (Sandbox Code Playgroud)

// main.dart

import './json_converter_example.dart';
import 'dart:convert';

final jsonStringCustom =
    '''{"page":1,"total_results":10,"total_pages":200,"results":[{"name":"Something","size":80},{"name":"Something 2","size":200}]}''';
final jsonStringPerson =
    '''{"page":2,"total_results":2,"total_pages":300,"results":[{"name":"Arya","lastname":"Stark"},{"name":"Night","lastname":"King"}]}''';
void main() {
  // Encode CustomResult
  List<CustomResult> results;
  results = [CustomResult("Mark", 223), CustomResult("Albert", 200)];
  // var customResult = List<CustomResult> data;
  var jsonData = GenericCollection<CustomResult>(
      page: 1, totalPages: 200, totalResults: 10, results: results);
  print({'JsonString', json.encode(jsonData)});

  // Decode CustomResult
  final genericCollectionCustom =
      GenericCollection<CustomResult>.fromJson(json.decode(jsonStringCustom));
  print({'name', genericCollectionCustom.results[0].name});

  // Encode Person

  List<Person> person;
  person = [Person("Arya", "Stark"), Person("Night", "King")];

  var jsonDataPerson = GenericCollection<Person>(
      page: 2, totalPages: 300, totalResults: 2, results: person);
  print({'JsonStringPerson', json.encode(jsonDataPerson)});

  // Decode Person

  final genericCollectionPerson =
      GenericCollection<Person>.fromJson(json.decode(jsonStringPerson));

  print({'name', genericCollectionPerson.results[0].name});
}
Run Code Online (Sandbox Code Playgroud)

结果是

{JsonStringCustom, {"page":1,"total_results":10,"total_pages":200,"results":[{"name":"Mark","size":223},{"name":"Albert","size":200}]}}
{name, Something}
{JsonStringPerson, {"page":2,"total_results":2,"total_pages":300,"results":[{"name":"Arya","lastname":"Stark"},{"name":"Night","lastname":"King"}]}}
{name, Arya}
Run Code Online (Sandbox Code Playgroud)

  • 这不是最干净的方法..这违反了 generic&lt;T&gt; 的概念。任何具有序列化的数据类都应该是可接受的 (8认同)

Pra*_*ndo 8

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

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)))
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

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

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);
}
Run Code Online (Sandbox Code Playgroud)

-> 在这里你可以使用,

 Paginate<Flight>.fromJson(responses, Flight.fromJsonModel);
Run Code Online (Sandbox Code Playgroud)