Kotlin’s a great language for JSON
Why you should model your JSON documents with Kotlin
Though it has its wrinkles, I really like JSON. It’s easy to read, pretty fast to parse, and refreshingly simple. Here’s a sample message from GitHub’s exemplar API:
{
"url": "https://api.github.com/repos/square/okio/issues/156",
"id": 91393390,
"number": 156,
"title": "ByteString CharSequence idea",
"state": "open",
"created_at": "2015-06-27T00:49:40.000Z",
"body": "Let's make CharSequence that's backed by bytes.\n"
}
Kotlin’s concise immutable data classes make it easy to build a basic model for this JSON.
data class Issue(
val url: String,
val id: Long,
val number: Long,
val title: String,
val state: String,
val created_at: String,
val body: String)
That’s it. No equals()
, hashCode()
, or toString()
boilerplate. We don’t even need a builder! Let’s extend the model to take advantage of Kotlin’s default values and explicit nulls:
data class Issue(
val url: String,
val id: Long,
val number: Long,
val title: String,
**val comments: Long = 0L**,
val created_at: String,
**val closed_at: String?,**
**val body: String = ""**)
Default values fill in the gaps when decoding JSON from the network. I like that I can leave them out when creating sample data in my test cases. Explicit nullable types prevent data problems.
Today we’re releasing Moshi 1.5 with powerful Kotlin support via the moshi-kotlin
module. Moshi’s type adapters and annotations bind JSON to an idiomatic data model.
data class Issue(
val url: String,
val id: Long,
val number: Long,
val title: String,
**val state: IssueState**,
val comments: Long = 0L,
**@Json(name = "created_at") val createdAt: Date**,
**@Json(name = "closed_at") val closedAt: Date?**,
val body: String = "")
This class uses proper types instead of strings for the issue’s state and timestamps. The @Json
annotation maps snake_case
names in JSON to camelCase
property names in Kotlin.
To set this up I need a Moshi.Builder
and a JsonAdapter
. I can use Kotlin’s raw strings to embed a sample message right in the code.
val issueJson = """
{
"url": "[https://api.github.com/repos/square/okio/issues/156](https://api.github.com/repos/square/okio/issues/156)",
"id": 91393390,
"number": 156,
"title": "ByteString CharSequence idea",
"state": "open",
"created_at": "2015-06-27T00:49:40.000Z"
}
"""
val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.add(Date::class.java, Rfc3339DateJsonAdapter().nullSafe())
.build()
val issueAdapter = moshi.adapter(Issue::class.java)
val issue = issueAdapter.fromJson(issueJson)
If you’re using JSON, Moshi and Kotlin help you to build better models with less code. Note that moshi-kotlin
uses kotlin-reflect
for property binding. That dependency is large by Android standards (1.7 MiB / 11,500 methods). We’re thinking of creative ways to address that!
This post is part of Square’s “Square Open Source ♥s Kotlin” series.