Mutual conversion between Java objects and JSON using Moshi

Overview

To implement the process of converting a Java object to JSON and saving it in a file, or converting the saved JSON to a Java object, use the standard Android SDK org.json, not to mention Jackson. I was a little bit hard, and when I searched for a good library, I found Moshi in Square, Inc.. I found out that there is a library called /), so I tried it easily.


Moshi Moshi is a JSON library developed by Square Inc. It seems that it was introduced as one of the Ok series at Droidcon Montreal 2015.

A Few 'Ok' Libraries (Droidcon MTL 2015)

I won't touch on this time, but in the Ok series, there are other HTTP client OkHttp and I / O library Okio. / square / ooki /) etc. have been released.

version

As of August 12, 2017, when this article was written, the latest release is 1.5.0 (2017/05) / 15).

file size

The file size is as small as 64KB. This can be an advantage in Android app development. Considering that Jackson is close to 1MB and Gson is 144KB, the latest 2.8.1 is quite small.

According to the 1.4.0 API documentation, the classes included in the body are:

  1. FromJson
  2. Json
  3. JsonAdapter
  4. JsonAdapter.Factory
  5. JsonDataException
  6. JsonEncodingException
  7. JsonQualifier
  8. JsonReader
  9. JsonReader.Options
  10. JsonReader.Token
  11. JsonWriter
  12. Moshi
  13. Moshi.Builder
  14. ToJson
  15. Types

Dependence

If you take a quick look at the source code of GitHub Library, test will find android.util.Pair. (reference / android / util / Pair.html) is used, and it seems that the Android SDK dependency is not included in the library implementation. Therefore, it can be used with other than Android apps like other Ok series.

Note that Okio is included as a dependency. This is also an I / O library that does not depend on the Android SDK.

license

In 1.5.0 it was Apache 2.0 like the other Ok series.


Introduction

Addition of dependence

You can use it just by adding one line.

app/build.gradle


dependencies {
  compile 'com.squareup.moshi:moshi:1.5.0'

Proguard settings for Android apps

According to the README of GitHub repository, the following settings are required when using Proguard. This setting is not required for use in Java applications.

-dontwarn okio.**
-dontwarn javax.annotation.Nullable
-dontwarn javax.annotation.ParametersAreNonnullByDefault
-keepclasseswithmembers class * {
    @com.squareup.moshi.* <methods>;
}
-keep @com.squareup.moshi.JsonQualifier interface *

Premise

Execution environment

item value
IDE Android Studio 2.3 & IntelliJ IDEA
Java 1.8.0_131
OS Windows 10

Below, the explanation of the sample class required for this operation verification will be continued, so [Click here if you do not need it](# java-% E3% 82% AA% E3% 83% 96% E3 % 82% B8% E3% 82% A7% E3% 82% AF% E3% 83% 88% E3% 81% A8-json-% E3% 82% 92% E7% 9B% B8% E4% BA% 92% E5% A4% 89% E6% 8F% 9B% E3% 81% 99% E3% 82% 8B).

Class to use this time

Let's work with a class that defines tabs in a web browser.

Tab.java


import java.util.ArrayList;
import java.util.List;

class Tab {

    private List<History> histories;

    private int index;

    private String thumbnailPath;

    private String lastTitle;

    Tab() {
        histories = new ArrayList<>();
        index = -1;
    }

    // Simple accessor methods...

    void addHistory(final History history) {
        histories.add(history);
        index++;
    }

    History getLatest() {
        return histories.get(index);
    }
}

The History class used in the Tab class is a simple class that has only two String type fields as shown below.

History.java


class History {

    private final String title;

    private final String url;

    private History(final String title, final String url) {
        this.title = title;
        this.url   = url;
    }

    public static History make(final String title, final String url) {
        return new History(title, url);
    }

    public String title() {
        return title;
    }

    public String url() {
        return url;
    }

}

Preparation

Initialize the Tab object prior to the following steps.

final Tab tab = new Tab();
tab.setThumbnailPath("file://~~");
tab.setLastTitle("Google");
tab.addHistory(History.make("Title", "URL"));

Convert between Java objects and JSON

Moshi uses a class called JsonAdapter to perform the conversion.

Get JsonAdapter

Create a Moshi object and use the adapter method to specify the type to be converted and get the JsonAdapter object.

final Moshi moshi = new Moshi.Builder().build();
final JsonAdapter<Tab> tabJsonAdapter = moshi.adapter(Tab.class);

Java object-> JSON conversion

Run with JsonAdapter.toJson.

final String json = tabJsonAdapter.toJson(tab);

output

The following JSON is output.

{"histories":[{"title":"Title","url":"URL"}],"index":0,"lastTitle":"Google","thumbnailPath":"file://~~"}

Pretty Printing If you want to output the JSON in a formatted state, it will take some time.

pretty_print


final Buffer buffer = new Buffer(); // 1.
final JsonWriter prettyPrintWriter = JsonWriter.of(buffer); // 2.
prettyPrintWriter.setIndent("  "); // 3.
try {
    tabJsonAdapter.toJson(prettyPrintWriter, tab); // 4.
} catch (final IOException e) {
    e.printStackTrace();
}

final String json = buffer.readUtf8(); // 5

procedure

  1. Prepare a Buffer object for Okio
  2. Get the JsonWriter object that targets the Buffer object in 1.
  3. Set any indentation for 2 JsonWriter
  4. Pass JsonWriter and Java object to JsonAdapter.toJson and execute Since a write is being performed to the Buffer object in 5.1, read it to retrieve the string.

It may be a little confusing as more classes are used, toJson no longer returns values directly, and toJson now raises exceptions.

Output result

As shown below, JSON was output with the specified indentation.

{
  "histories": [
    {
      "title": "Title",
      "url": "URL"
    }
  ],
  "index": 0,
  "lastTitle": "Google",
  "thumbnailPath": "file://~~"
}

Remarks

Although it is not practical at all, it seems that the character string passed as indent in step 3 above does not matter. For example, if * 2 is specified as indent, the following JSON will be output.

{
**"histories": [
****{
******"title": "Title",
******"url": "URL"
****}
**],
**"index": 0,
**"lastTitle": "Google",
**"thumbnailPath": "file://~~"
}

Of course, if you pass this JSON to JsonAdapter.fromJson, which will be described later, you will get an exception because it cannot be parsed as JSON.

JSON-> Java object conversion

Run with JsonAdapter.fromJson. This method can throw an IOException and needs to be taken care of.

try {
    final Tab fromJson = tabJsonAdapter.fromJson(json);
} catch (IOException e) {
    e.printStackTrace();
}

output

Let's display the contents of the obtained Tab object with standard output.

System.out.println(fromJson.getLastTitle());
System.out.println(fromJson.getThumbnailPath());
System.out.println(fromJson.getLatest().title());
System.out.println(fromJson.getLatest().url());
Google
file://~~
Title
URL

It seems that the History class defined by myself is also converted properly. I feel that it is good to be able to convert even a class that does not have a public constructor.

Source code

The code for this operation verification is put in gist. https://gist.github.com/toastkidjp/252bc2ac86de2c0a3625b9fed0b9fc62


Summary

Moshi is a lightweight and easy-to-use JSON library. Since the library itself does not include the Android SDK dependency, it can be used not only for Android but also for normal Java application development. I described a simple mutual conversion method using this Moshi.

reference

Recommended Posts

Mutual conversion between Java objects and JSON using Moshi
Mutual conversion between Function and Consumer
Moshi ~ Json conversion library ~
Convert JSON and YAML in Java (using Jackson and SnakeYAML)
[Java] Difference between == and equals
Differences between "beginner" Java and Kotlin
[JAVA] Difference between abstract and interface
[Java] Relationship between H2DB and JDBC
[Java] Difference between array and ArrayList
[Android] Convert Map to JSON using GSON in Kotlin and Java
Differences between Java and .NET Framework
[Java] Difference between Closeable and AutoCloseable
[Java] Difference between StringBuffer and StringBuilder
Java array / list / stream mutual conversion list
[Java] Difference between length, length () and size ()
[Java] Mutual conversion of notations such as camel case and snake case [Jackson]
Convert Java org.w3c.dom.Document objects and XML strings
Relationship between kotlin and java access modifiers
Difference between final and Immutable in Java
Java study # 3 (type conversion and instruction execution)
[For beginners] Difference between Java and Kotlin
Try using JSON format API in Java
[Java] Differences between instance variables and class variables
Java and Derby integration using JDBC (using NetBeans)
[Java] Difference between Intstream range and rangeClosed
[Java] Calculation mechanism, operators and type conversion
Difference between int and Integer in Java
HashMap # putAll () behaves differently between Java 7 and Java 8
Hex and UIColor mutual conversion in Swift
Summary of mutual conversion between Groovy's Default Groovy Methods and Java's Stream API
[Java] Understand the difference between List and Set
Create API using Retrofit2, Okhttp3 and Gson (Java)
Install java and android-sdk on Mac using homebrew
Difference between next () and nextLine () in Java Scanner
JSON with Java and Jackson Part 2 XSS measures
Kantai Collection Java # 1 Classes and Objects [For Beginners]
Summarize the differences between C # and Java writing
Distinguish between positive and negative numbers in Java
[Java] Difference between "final variable" and "immutable object"