firebase db: models with Kotlin delegated properti

2019-05-21 06:18发布

问题:

I'm using Kotlin objects to work with my Firebase Database models, as described in the guide. I have many fields that are stored as strings, but really are enums, so to be type-safe I have enum fields in the models, plus a string delegated property that returns the firebase stored value (as suggested in a question I asked some time ago). Now, these fields work if I get/set the string delegate in code, but firebase libs seem to skip them when converting to/from database's json format.

A simple example:

abstract class BaseModel {
    @Exclude
    open var path: String? = null  // fails even if I delete this field!
}

class Weight() : BaseModel() {
    constructor(v: Double, u: WeightUnit) : this() {
        value = v
        unitEnum = u
    }

    var value: Double = 0.0
    @Exclude
    var unitEnum: WeightUnit = WeightUnit.KG
    var unit: String by EnumStringLowercaseConverter(WeightUnit::class.java).getDelegate(Weight::unitEnum)

}

[...]
val testWeight = Weight(7.0, "kg")
db.getReference("/valid/path/to/save/testWeight").setValue(testWeight)
            .addOnSuccessListener { r -> Log.d(LOG_TAG, "set successful") }
            .addOnFailureListener { e -> Log.e(LOG_TAG, "set error", e) }

The setValue always gives a Permission Denied error, but works, if I delete unitEnum field and make unit a normal String property.

It's similar for reading: Firebase gives no errors when getting a Weight object, but the weightUnit field is never set to anything else than the default. But, if I manually do weight.unit = "lb", the unitEnum field properly returns WeightUnit.LB.

I'm using firebase libs v10.0.1

Now, the questions:

  • What can I do to make the delegated properties work correctly with firebase? I can try a different approach to the delegated enum fields, as long as the points from my original question are satisfied (readable, concise and type-safe code).
  • is there any way to see how exactly do firebase libs convert objects to/from json? Or at least see the converted json? Maybe then I could tweak things myself. Unfortunately, everything firebase-related shows as /* compiled code */ in AndroidStudio.

UPDATE: I could of course add a toMap() method to each model, where I would construct a map containing all the properties needed in firebase, but it would be tiresome to do this for every model, and it solves the saving issue only, the enum fields still wouldn't be set when getting.

The delegated props are also skipped when serializing with GSON. So maybe is there a generic way to make the delegated properties look like regular fields?

回答1:

Try this code, it should work.

@get:Exclude @set:Exclude
var unitEnum: WeightUnit = WeightUnit.KG
var unit: String
    get() = unitEnum.name
    set(v) { unitEnum = WeightUnit.valueOf(v) }