I've stumbled upon the same problem recently. I needed to resend some of the data from one endpoint to another with adding some new stuff to it.
The response from the server looks like this:
{
"someProperty": "value",
"someOtherProperty": "otherValue",
"someDynamicProperty": {
// There may be anything including nested structures, not known beforehand
}
}
Normally Moshi doesn't have built-in support for something like this, but it allows you to build your own adapters and handle the parsing logic.
What you need is define the type that you want to receive as a result:
@JsonClass(generateAdapter = true)
data class CustomResponse(
val someProperty: String,
val someOtherProperty: String,
val someDynamicProperty: JSONObject?
)
Then, you need to create a custom adapter to handle the parsing:
internal object JSONObjectAdapter {
@FromJson
fun fromJson(reader: JsonReader): JSONObject? {
// Here we're expecting the JSON object, it is processed as Map<String, Any> by Moshi
return (reader.readJsonValue() as? Map<String, Any>)?.let { data ->
try {
JSONObject(data)
} catch (e: JSONException) {
// Handle error if arises
}
}
}
@ToJson
fun toJson(writer: JsonWriter, value: JSONObject?) {
value?.let { writer.value(Buffer().writeUtf8(value.toString())) }
}
}
Then, just add this adapter to Moshi builder on creation:
Moshi.Builder().add(JSONObjectAdapter).build()
or use Moshi annotations if you want to apply it only to some particular properties.