web-dev-qa-db-ja.com

Flutter-ジェネリックを持つクラスにネストされたjsonを解析する方法は?

ネストされた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"という名前のコンストラクタがないため、明らかに最後の行でエラーがスローされます。タイプにいくつかの制限を追加してみましたが、解決策は見つかりませんでした。これをどのようにやってのけるかについて何か考えがありますか?

10
Sebastian

あなたはそのようなことはできません。少なくとも羽ばたきはできません。なので Dart:mirrorは無効であり、クラスコンストラクターのインターフェイスはありません。

別のルートを取る必要があります。

代わりにPOOを使用することをお勧めします。ここでは、responseObjectからBaseResponseをデシリアライズすることをあきらめます。そして、BaseResponseのサブクラスがこの逆シリアル化を処理します

通常、タイプごとに1つのサブクラスがあります。

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"});
8
Rémi Rousselet

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)])
);

世話をする必要がある定型文がもう1つあります。 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

3