skip to Main Content

I am developing an Android application using Firebase Realtime Database.

According to Firebase document,

Pass a custom Java object, if the class that defines it has a default constructor that takes no arguments and has public getters for the properties to be assigned.

So I made a custom Kotlin data class with Instant field as below :

import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import kotlinx.serialization.Serializable

@Serializable
data class UserStatus(
// ...
   val updatedAt: Instant = Clock.System.now(),
// ...
}

It has default constructor and only public getters.

val newUserStatus = UserStatus()
Firebase.database.reference.child(REFERENCE_USER_STATUS_NAME).child(createdUser.uid).setValue(newUserStatus).await()

But, because of Instant field of the class, the error occurs as below :

com.google.firebase.database.DatabaseException: Invalid key: value$kotlinx_datetime. Keys must not contain '/', '.', '#', '$', '[', or ']'
at com.google.firebase.database.core.utilities.Validation.validateWritableKey(Validation.java:123)
at com.google.firebase.database.core.utilities.Validation.validateWritableObject(Validation.java:106)
at com.google.firebase.database.core.utilities.Validation.validateWritableObject(Validation.java:107)
at com.google.firebase.database.DatabaseReference.setValueInternal(DatabaseReference.java:283)
at com.google.firebase.database.DatabaseReference.setValue(DatabaseReference.java:159)
//...

When I comment that Instant field and build, It works well.
What am I missing?

Instant has a default serializer.

I figured out that Firebase uses an internal property of kotlinx.datetime.Instant so the key includes $.

When I asked the same question on kotlinx.datetime repository, the maintainer answered me he thinks this problem is related to the Firebase, not Instant.link

2

Answers


  1. The question is, why? You have to understand that you are trying to save a complex Instant object which is obviously not compatible with the RealTimeDatabase saving standard. According to the documentation, you should simplify the database structure as much as possible.

    val updatedAt: String = Clock.System.now().toString()
    

    or

    val updatedAt: Long = System.currentTimeMillis()
    

    Wouldn’t it be less expensive?

    -Hugs

    Login or Signup to reply.
  2. As you already noticed, the error that you get is because of the following line of code:

    val updatedAt: Instant = Clock.System.now()
    

    And this is because now() returns an object of type Instant. Even if such a field has a default serializer and also exists in a class that is Serializable, it will always produce an error because such an object is not a supported data type.

    While kllysmman’s solution might work, as it will save a long value in the database, it will more elegant to save the date and time in the Realtime Database as a timestamp. To achieve that, please check my answer in the following post:

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search