Library / SDK
square/moshi avatar
square/moshi

Moshi's adapter lookup, the Kotlin reflection ban, and the extra class a reshaped JSON document costs

A modern JSON library for Kotlin and Java.

10,164 stars819 forksKotlinApache-2.0

At a glance

What is it?
Moshi is Square's JSON library for Android, Java and Kotlin, where every read and write goes through a JsonAdapter obtained from a Moshi instance. Kotlin classes need code generation or KotlinJsonAdapterFactory because plain Java reflection does not work on them, and the README's example of merging two JSON fields into one property uses an extra mirror class.
Who is it for?
Adopt Moshi when your payloads map onto classes you control and you want one place per field-shape decision. Expect to write a mirror class or adapter when the JSON shape differs from your classes, and a try block around fromJson, as the README's Event and card examples do.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Kotlin, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • square/moshi10,164 ★ · +1
Star history
Repository2026-09-222026-11-14
square/moshi10.2k10.2k

1 Stars in the last 53 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

Every read goes through an adapter you ask the Moshi instance for

There is one entry point worth memorising: you build a `Moshi`, ask it for a `JsonAdapter` for a concrete type, and call `fromJson` or `toJson` on that adapter. In the README's examples, the builder is where a custom adapter is registered.

Built-in support covers primitives such as int, float and char along with their boxed counterparts, arrays, collections, lists, sets and maps, strings, and enums. Model classes are read and written field by field, which is why a class holding a `hidden_card` and a `visible_cards` list maps onto the nested object and array in the sample document.

Serializing is the mirror image, and takes the same instance:

kotlin
val blackjackHand = BlackjackHand(
  Card('6', SPADES),
  listOf(Card('4', CLUBS), Card('A', HEARTS))
  )

val moshi: Moshi = Moshi.Builder().build()
val jsonAdapter: JsonAdapter<BlackjackHand> = moshi.adapter<BlackjackHand>()

val json: String = jsonAdapter.toJson(blackjackHand)
println(json)

Plain Java reflection does not work on Kotlin classes, and that decides your setup

The README opens with the constraint that should be read before any code: the Kotlin examples assume either Kotlin code generation or `KotlinJsonAdapterFactory`, and plain Java-based reflection is unsupported on Kotlin classes.

Without one of the two, Kotlin classes fall outside what the README supports, even though nothing in the JSON is at fault.

The repository layout answers where the two options live. `moshi-kotlin-codegen/` is the code generation module, `moshi-kotlin/` holds the Kotlin side, and `moshi/` is the core library, with `moshi-adapters/` and `moshi-kotlin-tests/` beside them. Java callers avoid the question, since plain Java classes are the reflection case that works.

Pick the module before you pick the adapter, because a data class with no generated adapter is a build configuration problem, not a library limitation.

Field names that do not line up cost you a second class and two annotated methods

The README's worked example shows one way to absorb a mismatch between the JSON and your classes. The worked example parses a document where the event date and time arrive as two separate strings, `begin_date` and `begin_time`, and produces a class with a single `beginDateAndTime` property.

The route is a mirror class whose fields match the document exactly, plus a pair of methods annotated `@FromJson` and `@ToJson` that move values between the mirror and the real class. Two details from that example widen the technique: the `@FromJson` method does not have to take a String, because Moshi parses into that declared type first and then calls the method, and the `@ToJson` method does not have to return a String.

The price is one translation class per awkward shape, hand-maintained in both directions.

Bad values surface as JsonDataException, not as an error return

The card adapter shows how a bad value is reported. Input whose length is not 2 throws `JsonDataException` with the message `Unknown card: `. A suit letter that matches none of the four cases falls into the else branch and throws `JsonDataException` with `unknown suit: `.

So the signal is an exception. A call site wraps `fromJson` in a try or catches that type, and a call site that forgets sees it propagate upward rather than receive a null, a default or a sealed failure value.

The README prints no dependency line, so the Gradle modules are the map

The project homepage is the Javadoc site for the 1.x line. What the repository gives you instead is a Gradle build with a wrapper, `settings.gradle.kts` and `build.gradle.kts`, split into modules for the core library, the adapters, the Kotlin reflective factory, the Kotlin code generator and its tests, plus an `examples/` project.

First use in Java is six lines:

java
String json = ...;

Moshi moshi = new Moshi.Builder().build();
JsonAdapter<BlackjackHand> jsonAdapter = moshi.adapter(BlackjackHand.class);

BlackjackHand blackjackHand = jsonAdapter.fromJson(json);
System.out.println(blackjackHand);

The Kotlin form differs only in the generics:

kotlin
val moshi: Moshi = Moshi.Builder().build()
val jsonAdapter: JsonAdapter<BlackjackHand> = moshi.adapter<BlackjackHand>()

val blackjackHand = jsonAdapter.fromJson(json)
println(blackjackHand)

Whichever you take, the note at the top of the README applies to the Kotlin one only.

With no GitHub releases, CHANGELOG.md is the record of what changed

The repository has no GitHub releases, and the last push to `master` was on 2026-10-30. For a library that JVM and Android builds depend on, that changes how you follow versions. There is no release page to diff, so the version history lives in `CHANGELOG.md` at the repository root.

The tree also carries `releasing.md` and `CONTRIBUTING.md`.

Licensing is Apache-2.0, with `LICENSE.txt` at the root. Because there are no GitHub releases, the version number in your own build file is what pins you against a silent upgrade.

One registered adapter turns a verbose card object into a two-character string

The clearest argument for a type adapter is the playing card. Out of the box the encoding is verbose, with rank and suit in separate fields, `{"rank":"A","suit":"HEARTS"}`. A type adapter turns that into `"4H"` for the four of hearts or `"JD"` for the jack of diamonds, and the whole document becomes:

json
{
  "hidden_card": "6S",
  "visible_cards": [
    "4C",
    "AH"
  ]
}

Registration is the builder taking the adapter instance:

kotlin
val moshi = Moshi.Builder()
    .add(CardAdapter())
    .build()

and the Java form adds `new`:

java
Moshi moshi = new Moshi.Builder()
    .add(new CardAdapter())
    .build();

Editorial conclusion

Adopt Moshi when your payloads map onto classes you control and you want one place per field-shape decision. Expect to write a mirror class or adapter when the JSON shape differs from your classes, and a try block around fromJson, as the README's Event and card examples do. Verify one thing before you commit, namely whether your build wires `moshi-kotlin-codegen` or registers `KotlinJsonAdapterFactory`, since the README states plain Java-based reflection is unsupported on Kotlin classes.

Frequently asked questions

How does Moshi convert my Kotlin classes to JSON and back?

You ask a Moshi instance for a JsonAdapter of that type and call fromJson or toJson on it. Built-in support covers primitives and their boxed counterparts, arrays, collections, lists, sets and maps, strings and enums, while your own classes are read and written field by field. On Kotlin classes this assumes Kotlin code generation or KotlinJsonAdapterFactory, because plain Java-based reflection is unsupported on Kotlin classes.

How do I change the JSON shape Moshi produces for my own type?

Write a class with methods annotated @ToJson and @FromJson and register it on the builder with add before calling build. The @FromJson method does not have to take a String, since Moshi parses into the declared type first, and the @ToJson method does not have to return a String. The card example turns {"rank":"A","suit":"HEARTS"} into AH.

What happens when Moshi meets a value it cannot convert?

The card adapter in the README throws JsonDataException with the message Unknown card: when the input length is not 2, and JsonDataException with unknown suit: when the letter matches none of the four suits. Callers handle an exception.

Which types does Moshi handle without a custom adapter?

Primitives such as int, float and char and their boxed counterparts, arrays, collections, lists, sets and maps, strings, and enums. Everything else is either one of your own classes, which Moshi reads and writes field by field, or a type you cover with a generated or hand-written adapter.

How do I add Moshi to a Gradle project?

The repository is a Gradle build with a wrapper, split into modules for the core library, moshi-adapters, moshi-kotlin, moshi-kotlin-codegen and moshi-kotlin-tests, so the module coordinates are what you need to resolve before writing the dependency line.

Official sources

  1. Issues
  2. License: Apache-2.0
  3. Project website
  4. README
  5. square/moshi on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/square-moshi.svg)](https://hysenlabs.com/projects/square-moshi)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/square-moshi.svg)](https://hysenlabs.com/projects/square-moshi)

Was this useful?