Kotlin’s a great language for JSON

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",
"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.

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.