1
1

More than 1 year has passed since last update.

【Android】Firebaseを使っていて、Could not deserialize object...エラーが発生した時の解決方法

Posted at

エラーが発生した当時の環境

Firestoreに保存されているドキュメントを取得する際に、toObject()を呼び出してドキュメントをデータクラスのインスタンスに変換しようとしました。

その時に使用したのが、以下の内容のMemberデータクラスです。プロパティとして、String型やDocumentReference型にTimestamp型など、Firebaseを使う方にはお馴染みの内容かと思われます。

data class Member(
    val id: String = "",
    val name: String = "",
    val groupRef: DocumentReference,
    val imageRef: DocumentReference? = null,
    val createdAt: Timestamp = Timestamp(Date()),
)

そして、いつものように取得したDocumentSnapshotインスタンスの値に対してtoObject()を呼び出して、定義したデータクラスのインスタンスにデシリアライズを行おうとしました。

val documentReference = firestore.collection("members").document("member-id-1")
val snapshot = documentReference.get().await()

val data = snapshot.toObject<Member>()?.copy(
    id = snapshot.id
)

Could not deserialize object...エラーの発生

上記の処理を実行したら、次のようなエラーが発生しました。

E  java.lang.RuntimeException: Could not deserialize object. Class com.takagimeow.xxx.core.service.model.Member does not define a no-argument constructor. If you are using ProGuard, make sure these constructors are not stripped

Could not deserialize object...エラーの発生箇所

Log.d()などを配置して、順を追って調べていくと、なんとエラーの原因がsnapshot.toObject<Member>()の呼び出しであることが判明しました。

return snapshot.toObject<Member>()?.copy(
    id = snapshot.id
)

ただ、問題の原因はこのtoObject<Member>()の呼び出し事態ではありませんでした。

実は、このMemberデータクラスのコンストラクタの定義自体に問題があったのです。

toObject()に渡すデータクラスを定義する際の注意点

コンストラクタの部分をよく見ると、groupRefプロパティにだけ、初期値が設定されていないことがわかると思います。

data class Member(
    ...
    val groupRef: DocumentReference,
    ...
)

Kotlinのデータクラスを定義した場合、引数のないコンストラクタは自動的に作成されません。

前提知識として、Android用のFirebase SDKでは、DocumentSnapshotインスタンスの値に対してtoObject<T>()を呼び出すことで自動的にデシリアライゼーションが行われます。

そのため、toObject()に使用するデータクラスの定義時には、引数なしでコンストラクタを呼び出しても大丈夫なように各プロパティに対して初期値を指定してあげる必要があるのです。

このとき、データクラスのすべてのプロパティには、nullもしくは型に対応した適切な値を初期値として渡します。

もし初期値を設定しない場合は、デシリアライゼーションの機能が使えなくなってしまうため、toObject()呼び出しが失敗します。そして、その失敗の原因としてCould not deserialize object...エラーが発生することになります。

データクラスのすべてのプロパティに初期値を設定する

修正したMemberデータクラスは次のようになります。

data class Member(
    val id: String = "",
    val name: String = "",
    val groupRef: DocumentReference? = null,
    val imageRef: DocumentReference? = null,
    val createdAt: Timestamp = Timestamp(Date()),
)

この修正のおかげで、無事エラーの発生は解消されました。

まとめ

Android用Firebase SDKを使う際は、データクラスの定義時に必ず初期値を渡すことをこころがけながら開発することを強くおすすめします。さもないと、自分のように解決までに無駄な時間を費やしてしまうことになるかもしれません・・・

参考にした記事

1
1
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
1
1