Step #3: Defining Our Response
Our “Web service” is going to send us JSON that looks like:
[
{
"id": "bce0dde0-5eee-0137-c042-38ca3ad2633d",
"description": "Write a JSON file containing to-do items",
"completed": true,
"notes": "Technically, this work was not completed when I wrote this, though it is completed now",
"created_on": "2019-05-22"
},
{
"id": "f42d74e8-6fd8-4eb1-a4fe-af1c1314573b",
"description": "Add a third object to this JSON file",
"completed": false,
"notes": "",
"created_on": "2019-05-22"
}
]
This resembles our model objects, but it is not quite identical. Moreover, many times the maintainers of the Web service are not the same developers as those who maintain the Android app (let alone the iOS app, the Web app, etc.). The Web service API might change from time to time.
The recommended way of handling this is to treat the Web service data model as being distinct from the app’s data model, with conversions between them as needed. This is similar to how we have our Room entities defined separately from our models, so any changes in Room do not affect our core app logic. As it turns out, we are going to funnel our server responses into the database, so we will be focusing more on converting Web service responses into entities that we can attempt to insert into the database.
With that in mind, right-click over the com.commonsware.todo.repo
package in the java/
directory and choose “New” > “Kotlin File/Class” from the context menu. For the name, fill in ToDoServerItem
, and choose “Class” for the kind. Press Enter or Return to create the class. Then, replace the class declaration with:
@JsonClass(generateAdapter = true)
data class ToDoServerItem(
val description: String,
val id: String,
val completed: Boolean,
val notes: String,
@Json(name = "created_on") val createdOn: Instant
)
The properties of ToDoServerItem
match that of the JSON that we will receive from the Web service, with one exception: the JSON has our creation date in a created_on
property, and we would like to use lowerCamelCase
formatting for our Kotlin property. The @Json
annotation applied to the createdOn
property tells Moshi that the created_on
value in the JSON goes into this createdOn
property on our class.
The @JsonClass
annotation applied to ToDoServerItem
overall indicates that we want Moshi to code-generate the code that can fill in a ToDoServerItem
from a matching JSON object.
This will work, with one exception: Moshi knows only about standard Java/Kotlin primitive types and strings. In particular, Moshi knows nothing about Instant
and knows nothing about how to take a value like "2019-05-22"
and convert it into a Instant
. For that, we need to create an adapter class.
So, below ToDoServerItem
in the same file, add this code:
private val FORMATTER = DateTimeFormatter.ISO_INSTANT
class MoshiInstantAdapter {
@ToJson
fun toJson(date: Instant) = FORMATTER.format(date)
@FromJson
fun fromJson(dateString: String): Instant =
FORMATTER.parse(dateString, Instant::from)
}
A Moshi type adapter is simply a class with two functions:
- One with the
@ToJson
annotation that takes a data type and returns a string representation suitable for use in a JSON property - One with the
@FromJson
annotation that takes the string representation and returns the corresponding object in that data type
In this case, we are using DateTimeFormatter
to convert a Instant
to and from a string representation, specifically using the representation found in the Web service’s JSON file.
Prev Table of Contents Next
This book is licensed under the Creative Commons Attribution-ShareAlike 4.0 International license.