Hi I have a Kotlin data class as follows
data class User (
@get:Exclude val gUser: Boolean,
@get:Exclude val uid: String,
@get:PropertyName("display_name") val displayName: String,
@get:PropertyName("email") val email: String,
@get:PropertyName("account_picture_url") val accountPicUrl: String,
@get:PropertyName("provider") val provider: String
)
I am able to serialize the object without an issues. But i'm having trouble deserializing the object when doing a firebase query. Currently this is what i'm doing to get the data
_firebaseReference.child(getString(R.string.firebase_users_key)).child(user.uid)
.setValue(user).addOnCompleteListener{
_firebaseReference.child("users").child(user.uid)
.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onCancelled(p0: DatabaseError) {
}
override fun onDataChange(p0: DataSnapshot) {
if (p0.exists()) {
val userHash = p0.value as HashMap<*, *>
var currentUser: User
if (userHash[getString(R.string.provider_key)]
!= getString(R.string.provider_google)) {
currentUser = User(false, p0.key!!,
userHash["display_name"].toString(),
userHash["email"].toString(),
userHash["account_picture_url"].toString(),
userHash["provider"].toString())
} else {
currentUser = User(true, p0.key!!,
userHash["display_name"].toString(),
userHash["email"].toString(),
userHash["account_picture_url"].toString(),
userHash["provider"].toString())
}
}
}
})
}
This is only a test project that i'm working on to practice my Kotlin, but this is something I would like to figure out.
If i'm doing it completely wrong please let me know, any advise would be greatly appreciated
Thanks
A DataSnapshot is passed to the event callbacks you attach with on() or once() . You can extract the contents of the snapshot as a JavaScript object by calling the val() method. Alternatively, you can traverse into the snapshot by calling child() to return child snapshots (which you could then call val() on).
Calling the getKey() method on this reference will return the auto-generated key which may then be used to store a corresponding value. Using Firebase to generate unique keys in this way is also of particular use when an app has multiple users creating child nodes at the same path in the tree.
A DataSnapshot is an efficiently-generated immutable copy of the data at a Firebase Location.
Firebase data is retrieved by either a one time call to GetValueAsync() or attaching to an event on a FirebaseDatabase reference. The event listener is called once for the initial state of the data and again anytime the data changes.
Firebase needs an empty constructor to be able to deserialize the objects:
data class User(
@Exclude val gUser: Boolean,
@Exclude val uid: String,
@PropertyName("display_name") val displayName: String,
@PropertyName("email") val email: String,
@PropertyName("account_picture_url") val accountPicUrl: String,
@PropertyName("provider") val provider: String
) {
constructor() : this(false, "", "", "", "", "")
}
You can either declare it like so and provide some default values to be able to call the primary constructor or you can declare default values for all your parameters:
data class User (
@Exclude val gUser: Boolean = false,
@Exclude val uid: String = "",
@PropertyName("display_name") val displayName: String = "",
@PropertyName("email") val email: String = "",
@PropertyName("account_picture_url") val accountPicUrl: String = "",
@PropertyName("provider") val provider: String = ""
)
Then various constructors will be created for you, including an empty constructor.
If there's a problem with serialization there might be because of the getters and setters generated by the ide, try reinforcing them with @get and @set annotations:
data class User (
@Exclude val gUser: Boolean = false,
@Exclude val uid: String = "",
@set:PropertyName("display_name")
@get:PropertyName("display_name")
var displayName: String = "",
@PropertyName("email") val email: String = "",
@set:PropertyName("account_picture_url")
@get:PropertyName("account_picture_url")
var accountPicUrl: String = "",
@PropertyName("provider") val provider: String = ""
)
What I actually wanted is a Kotlin data class which is derived from a domain model interface like so
data class Dto(@PropertyName("serialized_title") val override title: String) : DomainModel
In this case DomainModel is defined this way
interface DomainModel { val title: String }
My goal was to fetch data from Firestore and get deserialized Dto objects which are provided to clients which receive objects of type DomainModel. So this solution above unfortunately didn't work. I saw the workarounds using @get: and @set: Annotations but I wanted my data class properties to be immutable. Simply using vars is a bad design decision in my use case. And also this solution looks quite ugly...
After inspecting the decompiled Java-Code I came up with this solution
data class Dto(
@field:[JvmField PropertyName("serialized_title")]
override val title: String = "") : DomainModel
The decompiled Java-Code simply uses title as public final field having the PropertyName annotation.
I prefer this solution since it doesn't violate certain design decisions I made...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With