【问题标题】:Flutter - How to parsed nested json to a class with generics?Flutter - 如何将嵌套的 json 解析为具有泛型的类?
【发布时间】:2019-01-05 14:33:20
【问题描述】:

我想知道如何将嵌套的 json 解析为具有泛型类型的类。我的意图是用代码和消息包装来自后端的响应(例如包含令牌的 loginRespose)

我有

class BaseResponse<T>{
  int code;
  String message;
  T responseObject;

  BaseResponse.fromJson(Map<String, dynamic> parsedJson)
    : code = parsedJson['Code'],
      message = parsedJson['Message'],
      responseObject = T.fromJson(parsedJson['ResponseObject']); //This is what I'd like to do
}

显然最后一行会抛出一个错误,因为 T 没有命名构造函数“fromJson”。 我尝试向 Type 添加一些限制,但没有找到任何解决方案。您对如何实现这一点有任何想法吗?

【问题讨论】:

  • 我认为这是不可能的。没有构造函数接口,并且已禁用颤振dart:mirror。也许直接存储在responseObject json 对象中。并单独解析。或者您可以将自定义反序列化器传递给fromJson ctor
  • @RémiRousselet 谢谢你的回答。您介意举例说明其中一些解决方案吗?非常感谢
  • 找到了更好的解决方案。这是:)
  • 你可能想看看 built_value 包。它承诺“您可以设计的任何对象模型都可以序列化,包括充分利用泛型和接口。其他一些库需要具体类型或不完全支持泛型。”
  • @CarsonH​​olzheimer 这里最大的问题不是序列化,而是反序列化。

标签: json parsing generics dart flutter


【解决方案1】:

你不能做这样的事情,至少不能颤抖。由于dart:mirror 被禁用并且类构造函数没有接口。

您将不得不采取不同的路线。

我建议改用 POO。您将在这里放弃从您的BaseResponse 反序列化responseObject。然后让BaseResponse 的子类处理这个反序列化

通常每个类型都有一个子类:

class IntResponse extends BaseResponse<int> {
  IntResponse.fromJson(Map<String, dynamic> json) : super._fromJson(json) {
    this.responseObject = int.parse(json["Hello"]);
  }
}

然后,您可以通过在 BaseResponse 上添加自定义工厂构造函数来隐藏这些混乱,以使其更方便使用。

class BaseResponse<T> {
  int code;
  String message;
  T responseObject;

  BaseResponse._fromJson(Map<String, dynamic> parsedJson)
      : code = parsedJson['Code'],
        message = parsedJson['Message'];

  factory BaseResponse.fromJson(Map<String, dynamic> json) {
    if (T == int) {
      return IntResponse.fromJson(json) as BaseResponse<T>;
    }
    throw UnimplementedError();
  }
}

然后要么直接实例化想要的类型,要么使用工厂构造函数:

final BaseResponse foo = BaseResponse.fromJson<int>({"Hello": "42", "Code": 42, "Message": "World"});

【讨论】:

  • 如果TList&lt;int&gt; 一样嵌套呢?
  • 这行得通。谢谢老板
  • @Frenco 请检查我的回答
【解决方案2】:

您可以使用built_value 包来实现这一点(您还需要built_value_generatorbuild_runner)。您的课程将如下所示:

part 'base_response.g.dart';

abstract class BaseResponse<T> implements Built<BaseResponse<T>, BaseResponseBuilder<T>> {
  int code;
  String message;
  T responseObject;

  factory BaseResponse([updates(BaseResponseBuilder<T> b)]) = _$BaseResponse<T>;

  static Serializer<BaseResponse> get serializer => _$baseResponseSerializer;
}

您必须运行flutter packages pub run build_runner build 来生成生成的文件。然后你像这样使用它:

BaseResponse baseResponse = serializers.deserialize(
  json.decode(response.body),
  specifiedType: const FullType(BaseResponse, const [FullType(ConcreteTypeGoesHere)])
);

您还需要处理更多样板文件。您需要另一个名为 serializers.dart 的文件。您需要在此处手动添加要反序列化的所有类,还需要为每个接受类型参数的类以及要使用的每个具体类型添加一个 addBuilderFactory 函数。

part 'serializers.g.dart';

@SerializersFor(const [
  BaseResponse,
  ConcreteTypeGoesHere,
])
final Serializers serializers = (_$serializers.toBuilder()
      ..addBuilderFactory(
        FullType(BaseResponse, const [const FullType(ConcreteTypeGoesHere)]),
        () => new BaseResponseBuilder<ConcreteTypeGoesHere>()
      )
      ..addPlugin(StandardJsonPlugin()))
    .build();

然后重新运行flutter packages pub run build_runner build

让我希望 Gson... :S

【讨论】:

  • "Gjson" 在这里有点无关紧要。这个样板主要是由于 dart:mirror 被禁用。 gjson 会有同样的问题
  • 是的,我希望 dart:mirrors 可用,这样我们就可以有一个简单的 json 反序列化解决方案
【解决方案3】:

这是我的方法:

class Wrapper<T, K> {
  bool? isSuccess;
  T? data;

  Wrapper({
    this.isSuccess,
    this.data,
  });

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

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

Wrapper<T, K> _$WrapperFromJson<T, K>(Map<String, dynamic> json) {
  return Wrapper<T, K>(
    isSuccess: json['isSuccess'] as bool?,
    data: json['data'] == null ? null : Generic.fromJson<T, K>(json['data']),
  );
}

class Generic {
  /// If T is a List, K is the subtype of the list.
  static T fromJson<T, K>(dynamic json) {
    if (json is Iterable) {
      return _fromJsonList<K>(json) as T;
    } else if (T == LoginDetails) {
      return LoginDetails.fromJson(json) as T;
    } else if (T == UserDetails) {
      return UserDetails.fromJson(json) as T;
    } else if (T == Message) {
      return Message.fromJson(json) as T;
    } else if (T == bool || T == String || T == int || T == double) { // primitives
      return json;
  } else {
      throw Exception("Unknown class");
    }
  }

  static List<K> _fromJsonList<K>(List<dynamic> jsonList) {
    return jsonList?.map<K>((dynamic json) => fromJson<K, void>(json))?.toList();
  }
}

为了添加对新数据模型的支持,只需将其添加到 Generic.fromJson:

else if (T == NewDataModel) {
  return NewDataModel.fromJson(json) as T;
}

这适用于任一通用对象:

Wrapper<Message, void>.fromJson(someJson)

或通用对象列表:

Wrapper<List<Message>, Message>.fromJson(someJson)

【讨论】:

    猜你喜欢
    • 2021-02-25
    • 1970-01-01
    • 2019-01-24
    • 2020-12-26
    • 2020-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-06
    相关资源
    最近更新 更多