3
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?

More than 3 years have passed since last update.

freezed (json_serializable) でカスタムマッピング

Last updated at Posted at 2022-02-18

やりたいこと

toJson, fromJson 時に、そのままの値でマッピングするのでなく特殊な処理を行い変換したい。

基本

@JsonKey 内に fromJson, toJson に変換用の関数を渡してあげればそれ使ってくれる。
static な関数しか渡せない。
以下は timestamp を datetime にマッピングする例

@JsonKey(
  fromJson: timestampToDatetimeNullable,
  toJson: datetimeTotimestampNullable,
)
    DateTime? createdAt,

// 以下は変換用の関数たち
/// TimestampをDateTimeに変換する(nullable)
DateTime? timestampToDatetimeNullable(Timestamp? timestamp) {
  return timestamp?.toDate();
}

/// DateTimeをTimestampに変換する(nullable)
Timestamp? datetimeTotimestampNullable(DateTime? dateTime) {
  if (dateTime == null) return null;
  return Timestamp.fromDate(dateTime);
}

使いまわす

JsonConverter を継承すればアノテーションとして使いまわせる

class TimestampField
    implements JsonConverter<DateTime?, Timestamp?> {
  const TimestampField();

  @override
  DateTime? fromJson(Timestamp? timestamp) {
    return timestamp?.toDate();
  }

  @override
  Timestamp? toJson(DateTime? dateTime) {
    if (dateTime == null) return null;
    return Timestamp.fromDate(dateTime);
  }
}
@TimestampField() DateTime? createdAt,

よくあるエラー

fromJson の変換用関数で List<特定の型> を引数にすると死ぬ。
特定の型があっていたとしても死ぬ。

例えば以下を読み込んで、userID のリストから User のリストにデコードしようとする。

{
  "id": 0,
  "name": "ほげチーム",
  "userIDs": [1, 2]
}
// 省略

@JsonKey(
  name: 'userIDs',
  fromJson: userDecode,
  toJson: userEncode,
)
    List<User> users,

// 省略

// デコード用
List<User> _userDecode(List<int> userIDs) {
	return userIDs.map((id) => User.fromID(id));
}

すると List<dynamic>List<int> に変換できないと言われて死ぬ。

さて、変換してる様子は g.dart に書いてある。変換してからデコード関数に渡すようだ。

users: _userDecode(json['userIDs'] as List<int>),

で、これはだめらしい。json.decode とか、firebase からのデータは dynamic であり、dynamicList<dynamic>, Map<String, dynamic> までしかダウンキャストできない。そして中身が正しくてもList<dynamic> -> List<int> とかはできない。ただし、dynamic -> int はできる。

なのでこうする。dynamicmap で一つずつ int に変換してあげる。

// 省略

@JsonKey(
  fromJson: userDecode,
  toJson: userEncode,
)
    List<User> users,

// 省略

// デコード用
List<User> _userDecode(List<dynamic> userIDs) {
	return userIDs.map((dynamic id) => id as int).map((id) => User.fromID(id));
}
3
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
3
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?