FreezedでInvalid argumentを解決する

 ・ 1 min

photo by Jasper Gribble on Unsplash

Flutterでdomainオブジェクトを作る際にfreezedjson_serializableパッケージを使っています。ところが、あるクラスが別のクラスに依存しており、そのオブジェクトをtoJson関数でMapに変換した後、FirebaseのFirestoreに保存しようとすると以下のようなエラーが発生しました。

[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Invalid argument: Instance of '_$TimeSlotImpl'

エラーが発生したWhenToMeetオブジェクトは以下の通りです。TimeSlotオブジェクトが問題になっていた状況でした。

@freezed
class WhenToMeet with _$WhenToMeet {
  const factory WhenToMeet({
    required WhenToMeetID id,
    required String title,
    required UserID creator,
    required List<User> invitees,
    required List<User> attendees,
    required Map<DateTime, Set<TimeSlot>> availableTimes,
    required Map<UserID, Map<DateTime, TimeSlot>> selectedTimes,
  }) = _WhenToMeet;

このエラーをデバッグするのは簡単ではありませんでした。_$TimeSlotImplはbuild_runnerで生成されたfreezed.dartファイルで作られ、g.dartファイルで参照されているオブジェクトでした。自分で作ったものではないため、なぜエラーが発生するのか不思議でした。そこでprint関数を使ってtoJsonの結果を確認してみました。

image

JSONであればオブジェクトの情報がないはずなのに、まるでtoStringを出力したかのようにTimeSlotオブジェクトとTimeOfDayオブジェクトの情報が表示されていて、おかしいと思いました。

そこで調べてみると、似たような問題をfreezedのGitHubリポジトリで見つけました。実はこれはfreezedの問題というよりもjson_serializableの設定の問題でした。

build_runnerを使っているので、この問題を解決するためにFlutterプロジェクトにbuild.yamlファイルを作成しました。その後、以下の内容を記述してください。

targets:
  $default:
    builders:
      json_serializable:
        options:
          explicit_to_json: true

すると、build_runnerのwatchモードを有効にしている場合、自動的にgeneratedファイルが削除されて再生成されます。再度toJsonを試すと、先ほどとは違い、内部で使用されるオブジェクトもJSON形式にきちんと変換されていることが確認できます!

image

この問題とは直接関係ないかもしれませんが、TimeSlot内でFlutterに組み込みのTimeOfDayオブジェクトを使っており、これがtoJsonでうまくいかなかったため、JsonConverterを実装した_TimeOfDayConverterを以下のように使用しています。

@freezed
class TimeSlot with _$TimeSlot {
  @Assert('start.compareTo(end) != 0', 'startはendより早くなければなりません。')
  factory TimeSlot({
    @_TimeOfDayConverter() required TimeOfDay start,
    @_TimeOfDayConverter() required TimeOfDay end,
  }) = _TimeSlot;

A room without books is like a body without a soul.

— Marcus Tullius Cicero


他の投稿
Flutterで仮想キーボードによるRenderFlex overflowを解決する 커버 이미지
 ・ 2 min

Flutterで仮想キーボードによるRenderFlex overflowを解決する

強大国の興亡 커버 이미지
 ・ 3 min

強大国の興亡

キーチェーンパスワードポップアップエラーの解決方法 커버 이미지
 ・ 1 min

キーチェーンパスワードポップアップエラーの解決方法