Moshi Tutorial and Examples.

Moshi is a modern JSON library for Android and Java.

Moshi is able to read and write Java core’s data types

  1. Primitives (int, float, char…) and their boxed counterparts (Integer, Float, Character…).
  2. Arrays, Collections, Lists, Sets, and Maps
  3. Strings
  4. Enums

It’s very easy to customize how values are converted to and from JSON.

A type adapter is any class that has methods annotated @ToJson and @FromJson.

Morevover Moshi is designed to help you out when things go wrong.

It does this by always throwing a standard java.io.IOException if there is an error reading the JSON document, or if it is malformed. It throws a JsonDataException if the JSON document is well-formed, but doesn’t match the expected format.

Moshi also uses Okio for simple and powerful I/O. It’s a fine complement to OkHttp, which can share buffer segments for maximum efficiency.

Moshi is very similar to Gson. It uses the same streaming and binding mechanisms as Gson.

Basically it helps us easily parse JSON into Java objects:

String json = ...;

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

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

It also allows us easily serialize java objects into JSON:

BlackjackHand blackjackHand = new BlackjackHand(
    new Card('6', SPADES),
    Arrays.asList(new Card('4', CLUBS), new Card('A', HEARTS)));

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

String json = jsonAdapter.toJson(blackjackHand);
System.out.println(json);

Moshi Hello World

Let’s look at a hello world in moshi.

import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.Moshi;

import java.io.IOException;

/**
 *  Moshi Hello World
 *
  */
public class MoshiHelloWorld {
    public static void main(String[] args) throws IOException {
        // init class
        Destination destination = new Destination();
        destination.setName("Alpha Centauri");

        Starcraft starcraft = new Starcraft();
        starcraft.setName("Enterprise");
        starcraft.setDestination(destination);

        // convert to json
        Moshi moshi = new Moshi.Builder().build();
        JsonAdapter<Starcraft> jsonAdapter = moshi.adapter(Starcraft.class);

        String jsonString = jsonAdapter.toJson(starcraft);
        System.out.println("json " + jsonString); //print "json {"name":"Enterprise","destination":{"name":"Alpha Centauri"}}"

        // convert from json
        Starcraft newStarcraft = jsonAdapter.fromJson(jsonString);
        newStarcraft.show(); // print "Enterprise , Alpha Centauri!"
    }

    private static class Starcraft {
        private String name;
        private Destination destination;

        String getName() {
            return name;
        }

        void setName(String name) {
            this.name = name;
        }

        Destination getDestination() {
            return destination;
        }

        void setDestination(Destination destination) {
            this.destination = destination;
        }

        void show() {
            System.out.println();
            System.out.println(getName() + " , " + getDestination().getName() + "!");
        }
    }

    private static class Destination {
        private String name;

        String getName() {
            return name;
        }

        void setName(String name) {
            this.name = name;
        }
    }

}

More Examples

Here are more examples

1. Kotlin Android Convert To and From JSON using Moshi

This example will show you how to convert to and from JSON using Moshi.

The example is written in Kotlin and is easy to understand.

Step 1: Install Moshi

Start by installing Moshi by adding the following dependencies in your app/build.gradle:

    implementation "com.squareup.moshi:moshi:1.12.0"
    implementation "com.squareup.moshi:moshi-adapters:1.12.0"
    kapt "com.squareup.moshi:moshi-kotlin-codegen:1.12.0"

Step 2: Desigin Layout

The next step is two design a layout with two buttons: one to convert to JSON, the other from JSON:

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/button_to_json"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="TO JSON"
        app:layout_constraintBottom_toTopOf="@+id/button_from_json"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_chainStyle="packed" />

    <Button
        android:id="@+id/button_from_json"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="32dp"
        android:text="FROM JSON"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/button_to_json" />

</androidx.constraintlayout.widget.ConstraintLayout>

Step 3: Extend the JsonAdapter.Factory

Create our MoshiEnumAdapterFactory by extending the JsonAdapter.Factory as follows:

package com.star_zero.moshi.enumadapter

import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.Moshi
import com.squareup.moshi.adapters.EnumJsonAdapter
import com.squareup.moshi.rawType
import java.lang.reflect.Type

annotation class MoshiEnumFallback

/**
 * Annotating @MoshiEnumFallback will automatically add a fallback when an unknown value comes in the Enum.
 */
class MoshiEnumAdapterFactory : JsonAdapter.Factory {

    @Suppress("TYPE_MISMATCH_WARNING", "UNCHECKED_CAST")
    override fun create(
        type: Type,
        annotations: MutableSet<out Annotation>,
        moshi: Moshi
    ): JsonAdapter<*>? {
        val rawType = type.rawType
        if (!Enum::class.java.isAssignableFrom(rawType)) {
            return null
        }

        var fallbackEnum: Enum<*>? = null

        rawType.enumConstants.forEach {
            val enumElement = it as Enum<*>
            val fallback =
                rawType.getField(enumElement.name).getAnnotation(MoshiEnumFallback::class.java)
            if (fallback != null) {
                fallbackEnum = enumElement
                return@forEach
            }
        }

        return if (fallbackEnum == null) {
            EnumJsonAdapter.create(type as Class<Enum<*>>)
        } else {
            EnumJsonAdapter.create(type as Class<Enum<*>>).withUnknownFallback(fallbackEnum)
        }
    }
}

Step 4: Create Model class and MainActivity

Create them as follows:

MainActivity.kt

package com.star_zero.moshi.enumadapter

import android.os.Bundle
import android.util.Log
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import com.squareup.moshi.Moshi

@JsonClass(generateAdapter = true)
data class Sample(
    @Json(name = "id")
    val id: Int,
    @Json(name = "name")
    val name: String,
    @Json(name = "type")
    val type: Type,
    @Json(name = "kind")
    val kind: Kind,
)

@JsonClass(generateAdapter = false)
enum class Type {
    @Json(name = "a")
    A,

    @Json(name = "b")
    B,

    @MoshiEnumFallback
    @Json(name = "unknown")
    UNKNOWN
}

@JsonClass(generateAdapter = false)
enum class Kind {
    @MoshiEnumFallback
    @Json(name = "foo")
    Foo,

    @Json(name = "bar")
    Bar,
}

class MainActivity : AppCompatActivity() {

    private val moshi = Moshi.Builder()
        .add(MoshiEnumAdapterFactory())
        .build()

    private val moshiAdapter = moshi.adapter(Sample::class.java)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        findViewById<Button>(R.id.button_to_json).setOnClickListener {
            toJson()
        }

        findViewById<Button>(R.id.button_from_json).setOnClickListener {
            fromJson()
        }
    }

    private fun toJson() {
        val sample = Sample(1, "sample", Type.A, Kind.Bar)
        val json = moshiAdapter.toJson(sample)
        Log.d(TAG, "json = $json")
    }

    private fun fromJson() {
        val json1 = "{"id":1,"name":"sample","type":"a","kind":"bar"}"
        val sample1 = moshiAdapter.fromJson(json1)

        // unknown value
        val json2 = "{"id":1,"name":"sample","type":"c","kind":"piyo"}"
        val sample2 = moshiAdapter.fromJson(json2)

        Log.d(TAG, "sample1 = $sample1")
        Log.d(TAG, "sample2 = $sample2")
    }

    companion object {
        private val TAG = MainActivity::class.java.simpleName
    }
}

Reference

Download full code here.
Follow code author here.

[Read Individually.](https://android.camposha.info/en/example/moshi-enum-adapter-example/)