27

I try to use Firebase Firestore in a Kotlin project. Everything is going fine except when I want to instantiate an object with DocumentSnapshot.toObject(Class valueType).

Here is the code :

FirebaseFirestore
    .getInstance()
    .collection("myObjects")
    .addSnapshotListener(this,
    { querySnapshot: QuerySnapshot?, e: FirebaseFirestoreException? ->

        for (document in querySnapshot.documents) {

            val myObject = document.toObject(MyObject::class.java)

            Log.e(TAG,document.data.get("foo")) // Print : "foo"
            Log.e(TAG, myObject.foo) // Print : ""
        }
    }
})

As you can see, when I use documentChange.document.toObject(MyObject::class.java), my object is instantiated but the inner fields are not set. I know that Firestore needs the model to have an empty constructor. So here is the model :

class MyObject {

    var foo: String = ""

    constructor(){}

}

Can somebody tell me what I'm doing wrong?

Thank you

3 Answers 3

33

You forgot to include the public constructor with arguments, or you can also just use a data class with default values, it should be enough:

data class MyObject(var foo: String = "")
Sign up to request clarification or add additional context in comments.

4 Comments

Using a data class is likely the best option since it creates publicly named getters/setters for each field. The Firestore data mapper looks for these (so to instantiate foo it needs a public setFoo())
And the failure mode for not having a default constructor is almost useless - you'll get "java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object java.lang.reflect.Constructor.newInstance(java.lang.Object[])' on a null object reference.
All Kotlin classes generate publicly named getters and setters for each public var field and publicly named getters for each public val field. Not only data classes.
To avoid the error, just create a data class and call the primary constructor in the empty constructor like constructor() : this("", null, 0)
11

In my case I was getting a NullPointerException because there wasn't a default constructor. Using a data class with default values fixed the error.

data class Message(
        val messageId : String = "",
        val userId : String = "",
        val userName : String = "",
        val text : String = "",
        val imageUrl : String? = null,
        val date : String = ""
)

2 Comments

What would be the difference if we omit the default values? Also what will happen when the property of non-nullable data class does not exist in document? Thanks
A default empty constructor will NOT be generated if you specify all the default values as shown above. Just set the properties to something that makes sense, in my case it was empty string for String type for example.
0
class MyObject {

    lateinit var foo: String

    constructor(foo:String) {
        this.foo = foo
    }

    constructor()

}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.