How to skip JSON properties in Moshi?

3.1k views Asked by At

I'm trying to implement JSON parsing in my Android application written in Kotlin using com.squareup.moshi (v1.10.0).

Within the JSON file there are some properties that are not interesting in my case. Let's say, I only need the position to be able to mark the place on a map and the JSON looks like this:

    "location":{
         "address":{
            "country":"..."
         },
         "position":{
            "lat":47.469866,
            "lon":19.062435
         }
     }

If I'm right, the data class in Kotlin should look like this if I'd like to parse that JSON:

   @Parcelize
   data class Location(
       val address: Address,
       val position: Position
   ): Parcelable

   @Parcelize
   data class Address(
       val country: String
   ): Parcelable

   @Parcelize
   data class Position(
       val lat: Double,
       val lon: Double
   ): Parcelable

In Moshi's documentation I could find the transient keyword to skip values which in Kotlin works as an annotation (@Transient). As the documentation says:

Transient fields are omitted when writing JSON. When reading JSON, the field is skipped even if the JSON contains a value for the field. Instead it will get a default value.

Does it mean that if I don't want to have the address object, I should use the following code?

   @Parcelize
   data class Location(
       @Transient val address: Address? = null,
       val position: Position
   ): Parcelable

Also, what about in general terms? What if I have huge list of properties within a JSON object but I know I only need the 'position' object? Do I still have to create null values to parse the JSON file field-by-field?

2

There are 2 answers

2
Michael Lundie On BEST ANSWER

I think you are looking for something similar to GSON's @Expose annotations, wherein all model fields are excluded from parsing except those annotated.

This functionality is currently not available in Moshi, so your current implementation using the @Transient annotation seems to be the most optimal solution. (See Moshi issues conversation here.)

Extra food for thought:

You may also wish to use @IgnoredOnParcel on your transient fields since you are implementing the parcelable interface. (Have a look here for some implementation pointers.)

Alternatively you could separate your data model into 2 models - one for use in your app and one which reflects the server (JSON) schema (just as you have done above). The main data model for your app (which could implement parcelable) would contain only the fields you use (for example, the position field). When you parse your data, you then convert that data to your primary data model using some simple adapter. (This is often good practice anyhow, since server-side schemas are inherent to change. This way, any changes in the JSON schema wouldn't end having any ripple effect throughout your code.)

0
Rahul Patel On

https://github.com/square/moshi#omit-fields-with-transient

Omit fields with transient Some models declare fields that shouldn’t be included in JSON. For example, suppose our blackjack hand has a total field with the sum of the cards:

public final class BlackjackHand {
  private int total;

  ...
}

By default, all fields are emitted when encoding JSON, and all fields are accepted when decoding JSON. Prevent a field from being included by adding Java’s transient keyword:

public final class BlackjackHand {
  private transient int total;

  ...
}

Transient fields are omitted when writing JSON. When reading JSON, the field is skipped even if the JSON contains a value for the field. Instead it will get a default value.