Moshi: Exclude property without backing field from deserialization

Created on 1 Aug 2018  路  8Comments  路  Source: square/moshi

To remove a property from deserialization with Moshi, I need to use the Kotlin's @Transient annotation. However, I use a property without a backing field (with custom getter and setter), and therefore doesn't have any backing field and can't use @Transient.

One solution I thought about is doing a custom JsonAdapter that would skip the deserialization of this property. It is easy to skip serialization using skipValue(), but the fromJson function needs to return something, which will set the property.

How can I correct that?

Should properties without backing fields be skipped when serializing/deserializing the class?

enhancement

Most helpful comment

Gson has basically zero understanding of kotlin, anything "working" there is coincidental

All 8 comments

What happens if you define the property as an extension? Like so?
https://github.com/square/moshi/pull/612

I didn't think about doing this at first! It works well! However, I think it is cleaner to define a val property along with a custom setter function, like so:

val vegetable: String get() = "Potato"
fun setVegetable(vegetable: String) {
    this.vegetable = vegetable
}

The 4 issues that I found with using an extension property are:

  1. With the extension property, you can't set private or protected class variables or call protected and private functions in the class.
  2. No way to declare the extension property in the class. You can declare it in the same file, before or after declaring the class but not in it.
  3. Need to add a new import where the property is used.
  4. Interoperability with Java is not that great, because you don't see the getter/setter functions directly at the class level, you need to call the static function getting or setting the field. In the project I work on, Java interop is important as not all code was migrated to Kotlin yet.

I still think it would be great to be able to exclude properties without backing field from serialization/deserialization. If not automatically, maybe with a custom annotation.

Yeah, you're right. Need to find the right API.

Is there a plan to fix this? We couldn't migrate to Moshi because of this.

I'm running into this as well. Cannot apply @Transient to getters without backing fields.

Gson seems to ignore the non-backed kotlin fields without issue. Maybe there's a clue there on how to detect and ignore these?

Gson has basically zero understanding of kotlin, anything "working" there is coincidental

This is a huge issue for our team as well. A class-wide option for the codegen to ignore properties without backing fields would be life-saving for now.

So, until this enhancement has been implemented, here's an ugly hack you could use:

You can just reference the backing field in either the getter or the setter, without actually using it.
That way Kotlin will allow you to use @Transient and Moshi will ignore your computed property.

Please note that even though your property will be used as a computed property, it will still have to be initialized if you reference its backing field.

Example:

@Transient
val myComputedProperty: String = "" // Initialization is required.
get() { 
    field // Backing field reference so that @Transient may be allowed.
    return "I am computed"
}
Was this page helpful?
0 / 5 - 0 ratings