0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Flutter】freezedを使った複数型対応のJSON自動変換

Last updated at Posted at 2024-10-21

はじめに

freezedを用いたモデルクラスの自動生成の際に、APIのレスポンスのうちのあるフィールドがStringまたはintという複数の型で落ちてきて型キャストがうまくいかなったときの対処法です。

freezedの自動生成のfromJsonを使わずに自前で書けば問題ないのですが、フィールドが多かったり、ネストが深かったりする場合面倒なのでなるべく自動生成を使いたかったという背景もあります。

起こっていた問題

freezedで作ったモデルクラス

@freezed
class Model with _$Model {
  const factory Model({
    required int id, // intかStringで落ちてくる
    required String name,
  }) = _Model;
  factory Model.fromJson(Map<String, dynamic> json) =>
      _$ModelFromJson(json);
}

APIレスポンス

idの型がintかString(なぜ。。。)

{
  data:[
    {
      "id":1,
      "name":"hoge"
    },
    {
      "id":"2",
      "name":"fuga",
  ]
}

このように自動生成のfromjsonでは型キャストエラーが起きてしまいます。

解決方法

カスタムJsonConverterを作る
intにキャストするコンバーターを作ることで解決できます。
本来は自作クラスに変換したりなどに使いますが、このように複数の型に無理やり対応させるような使い方をします。

class IntOrStringConverter implements JsonConverter<int, dynamic> {
  const IntOrStringConverter();

  @override
  int fromJson(dynamic json) {
   if (json is int) {
      return json;
    } else if (json is String) {
      return int.tryParse(json) ?? 0;
    } else {
      throw Exception('intでもstringでもありません');
    }
  }

  @override
  dynamic toJson(int object) => object;
}

これをidのフィールドに適用させる

@freezed
class Model with _$Model {
  const factory Model({
    @IntOrStringConverter() required int id,
    required String name,
  }) = _Model;
  factory Model.fromJson(Map<String, dynamic> json) =>
      _$ModelFromJson(json);
}

おわりに

自動生成は便利ですが、柔軟さが微妙ですね。。。
tsのunion型みたいなのがdartでも使えるといいんですが

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?