はじめに
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でも使えるといいんですが