xref: /aosp_15_r20/external/moshi/README.md (revision 238ab3e782f339ab327592a602fa7df0a3f729ad)
1*238ab3e7SAndroid Build Coastguard WorkerMoshi
2*238ab3e7SAndroid Build Coastguard Worker=====
3*238ab3e7SAndroid Build Coastguard Worker
4*238ab3e7SAndroid Build Coastguard WorkerMoshi is a modern JSON library for Android, Java and Kotlin. It makes it easy to parse JSON into Java and Kotlin
5*238ab3e7SAndroid Build Coastguard Workerclasses:
6*238ab3e7SAndroid Build Coastguard Worker
7*238ab3e7SAndroid Build Coastguard Worker_Note: The Kotlin examples of this README assume use of either Kotlin code gen or `KotlinJsonAdapterFactory` for reflection. Plain Java-based reflection is unsupported on Kotlin classes._
8*238ab3e7SAndroid Build Coastguard Worker
9*238ab3e7SAndroid Build Coastguard Worker<details open>
10*238ab3e7SAndroid Build Coastguard Worker  <summary>Java</summary>
11*238ab3e7SAndroid Build Coastguard Worker
12*238ab3e7SAndroid Build Coastguard Worker```java
13*238ab3e7SAndroid Build Coastguard WorkerString json = ...;
14*238ab3e7SAndroid Build Coastguard Worker
15*238ab3e7SAndroid Build Coastguard WorkerMoshi moshi = new Moshi.Builder().build();
16*238ab3e7SAndroid Build Coastguard WorkerJsonAdapter<BlackjackHand> jsonAdapter = moshi.adapter(BlackjackHand.class);
17*238ab3e7SAndroid Build Coastguard Worker
18*238ab3e7SAndroid Build Coastguard WorkerBlackjackHand blackjackHand = jsonAdapter.fromJson(json);
19*238ab3e7SAndroid Build Coastguard WorkerSystem.out.println(blackjackHand);
20*238ab3e7SAndroid Build Coastguard Worker```
21*238ab3e7SAndroid Build Coastguard Worker</details>
22*238ab3e7SAndroid Build Coastguard Worker
23*238ab3e7SAndroid Build Coastguard Worker<details>
24*238ab3e7SAndroid Build Coastguard Worker  <summary>Kotlin</summary>
25*238ab3e7SAndroid Build Coastguard Worker
26*238ab3e7SAndroid Build Coastguard Worker```kotlin
27*238ab3e7SAndroid Build Coastguard Workerval json: String = ...
28*238ab3e7SAndroid Build Coastguard Worker
29*238ab3e7SAndroid Build Coastguard Workerval moshi: Moshi = Moshi.Builder().build()
30*238ab3e7SAndroid Build Coastguard Workerval jsonAdapter: JsonAdapter<BlackjackHand> = moshi.adapter<BlackjackHand>()
31*238ab3e7SAndroid Build Coastguard Worker
32*238ab3e7SAndroid Build Coastguard Workerval blackjackHand = jsonAdapter.fromJson(json)
33*238ab3e7SAndroid Build Coastguard Workerprintln(blackjackHand)
34*238ab3e7SAndroid Build Coastguard Worker```
35*238ab3e7SAndroid Build Coastguard Worker</details>
36*238ab3e7SAndroid Build Coastguard Worker
37*238ab3e7SAndroid Build Coastguard WorkerAnd it can just as easily serialize Java or Kotlin objects as JSON:
38*238ab3e7SAndroid Build Coastguard Worker
39*238ab3e7SAndroid Build Coastguard Worker<details open>
40*238ab3e7SAndroid Build Coastguard Worker    <summary>Java</summary>
41*238ab3e7SAndroid Build Coastguard Worker
42*238ab3e7SAndroid Build Coastguard Worker```java
43*238ab3e7SAndroid Build Coastguard WorkerBlackjackHand blackjackHand = new BlackjackHand(
44*238ab3e7SAndroid Build Coastguard Worker    new Card('6', SPADES),
45*238ab3e7SAndroid Build Coastguard Worker    Arrays.asList(new Card('4', CLUBS), new Card('A', HEARTS)));
46*238ab3e7SAndroid Build Coastguard Worker
47*238ab3e7SAndroid Build Coastguard WorkerMoshi moshi = new Moshi.Builder().build();
48*238ab3e7SAndroid Build Coastguard WorkerJsonAdapter<BlackjackHand> jsonAdapter = moshi.adapter(BlackjackHand.class);
49*238ab3e7SAndroid Build Coastguard Worker
50*238ab3e7SAndroid Build Coastguard WorkerString json = jsonAdapter.toJson(blackjackHand);
51*238ab3e7SAndroid Build Coastguard WorkerSystem.out.println(json);
52*238ab3e7SAndroid Build Coastguard Worker```
53*238ab3e7SAndroid Build Coastguard Worker</details>
54*238ab3e7SAndroid Build Coastguard Worker
55*238ab3e7SAndroid Build Coastguard Worker<details>
56*238ab3e7SAndroid Build Coastguard Worker    <summary>Kotlin</summary>
57*238ab3e7SAndroid Build Coastguard Worker
58*238ab3e7SAndroid Build Coastguard Worker```kotlin
59*238ab3e7SAndroid Build Coastguard Workerval blackjackHand = BlackjackHand(
60*238ab3e7SAndroid Build Coastguard Worker    Card('6', SPADES),
61*238ab3e7SAndroid Build Coastguard Worker    listOf(Card('4', CLUBS), Card('A', HEARTS))
62*238ab3e7SAndroid Build Coastguard Worker  )
63*238ab3e7SAndroid Build Coastguard Worker
64*238ab3e7SAndroid Build Coastguard Workerval moshi: Moshi = Moshi.Builder().build()
65*238ab3e7SAndroid Build Coastguard Workerval jsonAdapter: JsonAdapter<BlackjackHand> = moshi.adapter<BlackjackHand>()
66*238ab3e7SAndroid Build Coastguard Worker
67*238ab3e7SAndroid Build Coastguard Workerval json: String = jsonAdapter.toJson(blackjackHand)
68*238ab3e7SAndroid Build Coastguard Workerprintln(json)
69*238ab3e7SAndroid Build Coastguard Worker```
70*238ab3e7SAndroid Build Coastguard Worker</details>
71*238ab3e7SAndroid Build Coastguard Worker
72*238ab3e7SAndroid Build Coastguard Worker### Built-in Type Adapters
73*238ab3e7SAndroid Build Coastguard Worker
74*238ab3e7SAndroid Build Coastguard WorkerMoshi has built-in support for reading and writing Java’s core data types:
75*238ab3e7SAndroid Build Coastguard Worker
76*238ab3e7SAndroid Build Coastguard Worker * Primitives (int, float, char...) and their boxed counterparts (Integer, Float, Character...).
77*238ab3e7SAndroid Build Coastguard Worker * Arrays, Collections, Lists, Sets, and Maps
78*238ab3e7SAndroid Build Coastguard Worker * Strings
79*238ab3e7SAndroid Build Coastguard Worker * Enums
80*238ab3e7SAndroid Build Coastguard Worker
81*238ab3e7SAndroid Build Coastguard WorkerIt supports your model classes by writing them out field-by-field. In the example above Moshi uses
82*238ab3e7SAndroid Build Coastguard Workerthese classes:
83*238ab3e7SAndroid Build Coastguard Worker
84*238ab3e7SAndroid Build Coastguard Worker<details open>
85*238ab3e7SAndroid Build Coastguard Worker    <summary>Java</summary>
86*238ab3e7SAndroid Build Coastguard Worker
87*238ab3e7SAndroid Build Coastguard Worker```java
88*238ab3e7SAndroid Build Coastguard Workerclass BlackjackHand {
89*238ab3e7SAndroid Build Coastguard Worker  public final Card hidden_card;
90*238ab3e7SAndroid Build Coastguard Worker  public final List<Card> visible_cards;
91*238ab3e7SAndroid Build Coastguard Worker  ...
92*238ab3e7SAndroid Build Coastguard Worker}
93*238ab3e7SAndroid Build Coastguard Worker
94*238ab3e7SAndroid Build Coastguard Workerclass Card {
95*238ab3e7SAndroid Build Coastguard Worker  public final char rank;
96*238ab3e7SAndroid Build Coastguard Worker  public final Suit suit;
97*238ab3e7SAndroid Build Coastguard Worker  ...
98*238ab3e7SAndroid Build Coastguard Worker}
99*238ab3e7SAndroid Build Coastguard Worker
100*238ab3e7SAndroid Build Coastguard Workerenum Suit {
101*238ab3e7SAndroid Build Coastguard Worker  CLUBS, DIAMONDS, HEARTS, SPADES;
102*238ab3e7SAndroid Build Coastguard Worker}
103*238ab3e7SAndroid Build Coastguard Worker```
104*238ab3e7SAndroid Build Coastguard Worker</details>
105*238ab3e7SAndroid Build Coastguard Worker
106*238ab3e7SAndroid Build Coastguard Worker<details>
107*238ab3e7SAndroid Build Coastguard Worker    <summary>Kotlin</summary>
108*238ab3e7SAndroid Build Coastguard Worker
109*238ab3e7SAndroid Build Coastguard Worker```kotlin
110*238ab3e7SAndroid Build Coastguard Workerclass BlackjackHand(
111*238ab3e7SAndroid Build Coastguard Worker  val hidden_card: Card,
112*238ab3e7SAndroid Build Coastguard Worker  val visible_cards: List<Card>,
113*238ab3e7SAndroid Build Coastguard Worker  ...
114*238ab3e7SAndroid Build Coastguard Worker)
115*238ab3e7SAndroid Build Coastguard Worker
116*238ab3e7SAndroid Build Coastguard Workerclass Card(
117*238ab3e7SAndroid Build Coastguard Worker  val rank: Char,
118*238ab3e7SAndroid Build Coastguard Worker  val suit: Suit
119*238ab3e7SAndroid Build Coastguard Worker  ...
120*238ab3e7SAndroid Build Coastguard Worker)
121*238ab3e7SAndroid Build Coastguard Worker
122*238ab3e7SAndroid Build Coastguard Workerenum class Suit {
123*238ab3e7SAndroid Build Coastguard Worker  CLUBS, DIAMONDS, HEARTS, SPADES;
124*238ab3e7SAndroid Build Coastguard Worker}
125*238ab3e7SAndroid Build Coastguard Worker```
126*238ab3e7SAndroid Build Coastguard Worker</details>
127*238ab3e7SAndroid Build Coastguard Worker
128*238ab3e7SAndroid Build Coastguard Worker
129*238ab3e7SAndroid Build Coastguard Workerto read and write this JSON:
130*238ab3e7SAndroid Build Coastguard Worker
131*238ab3e7SAndroid Build Coastguard Worker```json
132*238ab3e7SAndroid Build Coastguard Worker{
133*238ab3e7SAndroid Build Coastguard Worker  "hidden_card": {
134*238ab3e7SAndroid Build Coastguard Worker    "rank": "6",
135*238ab3e7SAndroid Build Coastguard Worker    "suit": "SPADES"
136*238ab3e7SAndroid Build Coastguard Worker  },
137*238ab3e7SAndroid Build Coastguard Worker  "visible_cards": [
138*238ab3e7SAndroid Build Coastguard Worker    {
139*238ab3e7SAndroid Build Coastguard Worker      "rank": "4",
140*238ab3e7SAndroid Build Coastguard Worker      "suit": "CLUBS"
141*238ab3e7SAndroid Build Coastguard Worker    },
142*238ab3e7SAndroid Build Coastguard Worker    {
143*238ab3e7SAndroid Build Coastguard Worker      "rank": "A",
144*238ab3e7SAndroid Build Coastguard Worker      "suit": "HEARTS"
145*238ab3e7SAndroid Build Coastguard Worker    }
146*238ab3e7SAndroid Build Coastguard Worker  ]
147*238ab3e7SAndroid Build Coastguard Worker}
148*238ab3e7SAndroid Build Coastguard Worker```
149*238ab3e7SAndroid Build Coastguard Worker
150*238ab3e7SAndroid Build Coastguard WorkerThe [Javadoc][javadoc] catalogs the complete Moshi API, which we explore below.
151*238ab3e7SAndroid Build Coastguard Worker
152*238ab3e7SAndroid Build Coastguard Worker### Custom Type Adapters
153*238ab3e7SAndroid Build Coastguard Worker
154*238ab3e7SAndroid Build Coastguard WorkerWith Moshi, it’s particularly easy to customize how values are converted to and from JSON. A type
155*238ab3e7SAndroid Build Coastguard Workeradapter is any class that has methods annotated `@ToJson` and `@FromJson`.
156*238ab3e7SAndroid Build Coastguard Worker
157*238ab3e7SAndroid Build Coastguard WorkerFor example, Moshi’s default encoding of a playing card is verbose: the JSON defines the rank and
158*238ab3e7SAndroid Build Coastguard Workersuit in separate fields: `{"rank":"A","suit":"HEARTS"}`. With a type adapter, we can change the
159*238ab3e7SAndroid Build Coastguard Workerencoding to something more compact: `"4H"` for the four of hearts or `"JD"` for the jack of
160*238ab3e7SAndroid Build Coastguard Workerdiamonds:
161*238ab3e7SAndroid Build Coastguard Worker
162*238ab3e7SAndroid Build Coastguard Worker<details open>
163*238ab3e7SAndroid Build Coastguard Worker    <summary>Java</summary>
164*238ab3e7SAndroid Build Coastguard Worker
165*238ab3e7SAndroid Build Coastguard Worker```java
166*238ab3e7SAndroid Build Coastguard Workerclass CardAdapter {
167*238ab3e7SAndroid Build Coastguard Worker  @ToJson String toJson(Card card) {
168*238ab3e7SAndroid Build Coastguard Worker    return card.rank + card.suit.name().substring(0, 1);
169*238ab3e7SAndroid Build Coastguard Worker  }
170*238ab3e7SAndroid Build Coastguard Worker
171*238ab3e7SAndroid Build Coastguard Worker  @FromJson Card fromJson(String card) {
172*238ab3e7SAndroid Build Coastguard Worker    if (card.length() != 2) throw new JsonDataException("Unknown card: " + card);
173*238ab3e7SAndroid Build Coastguard Worker
174*238ab3e7SAndroid Build Coastguard Worker    char rank = card.charAt(0);
175*238ab3e7SAndroid Build Coastguard Worker    switch (card.charAt(1)) {
176*238ab3e7SAndroid Build Coastguard Worker      case 'C': return new Card(rank, Suit.CLUBS);
177*238ab3e7SAndroid Build Coastguard Worker      case 'D': return new Card(rank, Suit.DIAMONDS);
178*238ab3e7SAndroid Build Coastguard Worker      case 'H': return new Card(rank, Suit.HEARTS);
179*238ab3e7SAndroid Build Coastguard Worker      case 'S': return new Card(rank, Suit.SPADES);
180*238ab3e7SAndroid Build Coastguard Worker      default: throw new JsonDataException("unknown suit: " + card);
181*238ab3e7SAndroid Build Coastguard Worker    }
182*238ab3e7SAndroid Build Coastguard Worker  }
183*238ab3e7SAndroid Build Coastguard Worker}
184*238ab3e7SAndroid Build Coastguard Worker```
185*238ab3e7SAndroid Build Coastguard Worker</details>
186*238ab3e7SAndroid Build Coastguard Worker
187*238ab3e7SAndroid Build Coastguard Worker<details>
188*238ab3e7SAndroid Build Coastguard Worker    <summary>Kotlin</summary>
189*238ab3e7SAndroid Build Coastguard Worker
190*238ab3e7SAndroid Build Coastguard Worker```kotlin
191*238ab3e7SAndroid Build Coastguard Workerclass CardAdapter {
192*238ab3e7SAndroid Build Coastguard Worker  @ToJson fun toJson(card: Card): String {
193*238ab3e7SAndroid Build Coastguard Worker    return card.rank + card.suit.name.substring(0, 1)
194*238ab3e7SAndroid Build Coastguard Worker  }
195*238ab3e7SAndroid Build Coastguard Worker
196*238ab3e7SAndroid Build Coastguard Worker  @FromJson fun fromJson(card: String): Card {
197*238ab3e7SAndroid Build Coastguard Worker    if (card.length != 2) throw JsonDataException("Unknown card: $card")
198*238ab3e7SAndroid Build Coastguard Worker
199*238ab3e7SAndroid Build Coastguard Worker    val rank = card[0]
200*238ab3e7SAndroid Build Coastguard Worker    return when (card[1]) {
201*238ab3e7SAndroid Build Coastguard Worker      'C' -> Card(rank, Suit.CLUBS)
202*238ab3e7SAndroid Build Coastguard Worker      'D' -> Card(rank, Suit.DIAMONDS)
203*238ab3e7SAndroid Build Coastguard Worker      'H' -> Card(rank, Suit.HEARTS)
204*238ab3e7SAndroid Build Coastguard Worker      'S' -> Card(rank, Suit.SPADES)
205*238ab3e7SAndroid Build Coastguard Worker      else -> throw JsonDataException("unknown suit: $card")
206*238ab3e7SAndroid Build Coastguard Worker    }
207*238ab3e7SAndroid Build Coastguard Worker  }
208*238ab3e7SAndroid Build Coastguard Worker}
209*238ab3e7SAndroid Build Coastguard Worker```
210*238ab3e7SAndroid Build Coastguard Worker</details>
211*238ab3e7SAndroid Build Coastguard Worker
212*238ab3e7SAndroid Build Coastguard WorkerRegister the type adapter with the `Moshi.Builder` and we’re good to go.
213*238ab3e7SAndroid Build Coastguard Worker
214*238ab3e7SAndroid Build Coastguard Worker<details open>
215*238ab3e7SAndroid Build Coastguard Worker    <summary>Java</summary>
216*238ab3e7SAndroid Build Coastguard Worker
217*238ab3e7SAndroid Build Coastguard Worker```java
218*238ab3e7SAndroid Build Coastguard WorkerMoshi moshi = new Moshi.Builder()
219*238ab3e7SAndroid Build Coastguard Worker    .add(new CardAdapter())
220*238ab3e7SAndroid Build Coastguard Worker    .build();
221*238ab3e7SAndroid Build Coastguard Worker```
222*238ab3e7SAndroid Build Coastguard Worker</details>
223*238ab3e7SAndroid Build Coastguard Worker
224*238ab3e7SAndroid Build Coastguard Worker<details>
225*238ab3e7SAndroid Build Coastguard Worker    <summary>Kotlin</summary>
226*238ab3e7SAndroid Build Coastguard Worker
227*238ab3e7SAndroid Build Coastguard Worker```kotlin
228*238ab3e7SAndroid Build Coastguard Workerval moshi = Moshi.Builder()
229*238ab3e7SAndroid Build Coastguard Worker    .add(CardAdapter())
230*238ab3e7SAndroid Build Coastguard Worker    .build()
231*238ab3e7SAndroid Build Coastguard Worker```
232*238ab3e7SAndroid Build Coastguard Worker</details>
233*238ab3e7SAndroid Build Coastguard Worker
234*238ab3e7SAndroid Build Coastguard WorkerVoilà:
235*238ab3e7SAndroid Build Coastguard Worker
236*238ab3e7SAndroid Build Coastguard Worker```json
237*238ab3e7SAndroid Build Coastguard Worker{
238*238ab3e7SAndroid Build Coastguard Worker  "hidden_card": "6S",
239*238ab3e7SAndroid Build Coastguard Worker  "visible_cards": [
240*238ab3e7SAndroid Build Coastguard Worker    "4C",
241*238ab3e7SAndroid Build Coastguard Worker    "AH"
242*238ab3e7SAndroid Build Coastguard Worker  ]
243*238ab3e7SAndroid Build Coastguard Worker}
244*238ab3e7SAndroid Build Coastguard Worker```
245*238ab3e7SAndroid Build Coastguard Worker
246*238ab3e7SAndroid Build Coastguard Worker#### Another example
247*238ab3e7SAndroid Build Coastguard Worker
248*238ab3e7SAndroid Build Coastguard WorkerNote that the method annotated with `@FromJson` does not need to take a String as an argument.
249*238ab3e7SAndroid Build Coastguard WorkerRather it can take input of any type and Moshi will first parse the JSON to an object of that type
250*238ab3e7SAndroid Build Coastguard Workerand then use the `@FromJson` method to produce the desired final value. Conversely, the method
251*238ab3e7SAndroid Build Coastguard Workerannotated with `@ToJson` does not have to produce a String.
252*238ab3e7SAndroid Build Coastguard Worker
253*238ab3e7SAndroid Build Coastguard WorkerAssume, for example, that we have to parse a JSON in which the date and time of an event are
254*238ab3e7SAndroid Build Coastguard Workerrepresented as two separate strings.
255*238ab3e7SAndroid Build Coastguard Worker
256*238ab3e7SAndroid Build Coastguard Worker```json
257*238ab3e7SAndroid Build Coastguard Worker{
258*238ab3e7SAndroid Build Coastguard Worker  "title": "Blackjack tournament",
259*238ab3e7SAndroid Build Coastguard Worker  "begin_date": "20151010",
260*238ab3e7SAndroid Build Coastguard Worker  "begin_time": "17:04"
261*238ab3e7SAndroid Build Coastguard Worker}
262*238ab3e7SAndroid Build Coastguard Worker```
263*238ab3e7SAndroid Build Coastguard Worker
264*238ab3e7SAndroid Build Coastguard WorkerWe would like to combine these two fields into one string to facilitate the date parsing at a
265*238ab3e7SAndroid Build Coastguard Workerlater point. Also, we would like to have all variable names in CamelCase. Therefore, the `Event`
266*238ab3e7SAndroid Build Coastguard Workerclass we want Moshi to produce like this:
267*238ab3e7SAndroid Build Coastguard Worker
268*238ab3e7SAndroid Build Coastguard Worker<details open>
269*238ab3e7SAndroid Build Coastguard Worker    <summary>Java</summary>
270*238ab3e7SAndroid Build Coastguard Worker
271*238ab3e7SAndroid Build Coastguard Worker```java
272*238ab3e7SAndroid Build Coastguard Workerclass Event {
273*238ab3e7SAndroid Build Coastguard Worker  String title;
274*238ab3e7SAndroid Build Coastguard Worker  String beginDateAndTime;
275*238ab3e7SAndroid Build Coastguard Worker}
276*238ab3e7SAndroid Build Coastguard Worker```
277*238ab3e7SAndroid Build Coastguard Worker</details>
278*238ab3e7SAndroid Build Coastguard Worker
279*238ab3e7SAndroid Build Coastguard Worker<details>
280*238ab3e7SAndroid Build Coastguard Worker    <summary>Kotlin</summary>
281*238ab3e7SAndroid Build Coastguard Worker
282*238ab3e7SAndroid Build Coastguard Worker```kotlin
283*238ab3e7SAndroid Build Coastguard Workerclass Event(
284*238ab3e7SAndroid Build Coastguard Worker  val title: String,
285*238ab3e7SAndroid Build Coastguard Worker  val beginDateAndTime: String
286*238ab3e7SAndroid Build Coastguard Worker)
287*238ab3e7SAndroid Build Coastguard Worker```
288*238ab3e7SAndroid Build Coastguard Worker</details>
289*238ab3e7SAndroid Build Coastguard Worker
290*238ab3e7SAndroid Build Coastguard WorkerInstead of manually parsing the JSON line per line (which we could also do) we can have Moshi do the
291*238ab3e7SAndroid Build Coastguard Workertransformation automatically. We simply define another class `EventJson` that directly corresponds
292*238ab3e7SAndroid Build Coastguard Workerto the JSON structure:
293*238ab3e7SAndroid Build Coastguard Worker
294*238ab3e7SAndroid Build Coastguard Worker<details open>
295*238ab3e7SAndroid Build Coastguard Worker    <summary>Java</summary>
296*238ab3e7SAndroid Build Coastguard Worker
297*238ab3e7SAndroid Build Coastguard Worker```java
298*238ab3e7SAndroid Build Coastguard Workerclass EventJson {
299*238ab3e7SAndroid Build Coastguard Worker  String title;
300*238ab3e7SAndroid Build Coastguard Worker  String begin_date;
301*238ab3e7SAndroid Build Coastguard Worker  String begin_time;
302*238ab3e7SAndroid Build Coastguard Worker}
303*238ab3e7SAndroid Build Coastguard Worker```
304*238ab3e7SAndroid Build Coastguard Worker</details>
305*238ab3e7SAndroid Build Coastguard Worker
306*238ab3e7SAndroid Build Coastguard Worker<details>
307*238ab3e7SAndroid Build Coastguard Worker    <summary>Kotlin</summary>
308*238ab3e7SAndroid Build Coastguard Worker
309*238ab3e7SAndroid Build Coastguard Worker```kotlin
310*238ab3e7SAndroid Build Coastguard Workerclass EventJson(
311*238ab3e7SAndroid Build Coastguard Worker  val title: String,
312*238ab3e7SAndroid Build Coastguard Worker  val begin_date: String,
313*238ab3e7SAndroid Build Coastguard Worker  val begin_time: String
314*238ab3e7SAndroid Build Coastguard Worker)
315*238ab3e7SAndroid Build Coastguard Worker```
316*238ab3e7SAndroid Build Coastguard Worker</details>
317*238ab3e7SAndroid Build Coastguard Worker
318*238ab3e7SAndroid Build Coastguard WorkerAnd another class with the appropriate `@FromJson` and `@ToJson` methods that are telling Moshi how
319*238ab3e7SAndroid Build Coastguard Workerto convert an `EventJson` to an `Event` and back. Now, whenever we are asking Moshi to parse a JSON
320*238ab3e7SAndroid Build Coastguard Workerto an `Event` it will first parse it to an `EventJson` as an intermediate step. Conversely, to
321*238ab3e7SAndroid Build Coastguard Workerserialize an `Event` Moshi will first create an `EventJson` object and then serialize that object as
322*238ab3e7SAndroid Build Coastguard Workerusual.
323*238ab3e7SAndroid Build Coastguard Worker
324*238ab3e7SAndroid Build Coastguard Worker<details open>
325*238ab3e7SAndroid Build Coastguard Worker    <summary>Java</summary>
326*238ab3e7SAndroid Build Coastguard Worker
327*238ab3e7SAndroid Build Coastguard Worker```java
328*238ab3e7SAndroid Build Coastguard Workerclass EventJsonAdapter {
329*238ab3e7SAndroid Build Coastguard Worker  @FromJson Event eventFromJson(EventJson eventJson) {
330*238ab3e7SAndroid Build Coastguard Worker    Event event = new Event();
331*238ab3e7SAndroid Build Coastguard Worker    event.title = eventJson.title;
332*238ab3e7SAndroid Build Coastguard Worker    event.beginDateAndTime = eventJson.begin_date + " " + eventJson.begin_time;
333*238ab3e7SAndroid Build Coastguard Worker    return event;
334*238ab3e7SAndroid Build Coastguard Worker  }
335*238ab3e7SAndroid Build Coastguard Worker
336*238ab3e7SAndroid Build Coastguard Worker  @ToJson EventJson eventToJson(Event event) {
337*238ab3e7SAndroid Build Coastguard Worker    EventJson json = new EventJson();
338*238ab3e7SAndroid Build Coastguard Worker    json.title = event.title;
339*238ab3e7SAndroid Build Coastguard Worker    json.begin_date = event.beginDateAndTime.substring(0, 8);
340*238ab3e7SAndroid Build Coastguard Worker    json.begin_time = event.beginDateAndTime.substring(9, 14);
341*238ab3e7SAndroid Build Coastguard Worker    return json;
342*238ab3e7SAndroid Build Coastguard Worker  }
343*238ab3e7SAndroid Build Coastguard Worker}
344*238ab3e7SAndroid Build Coastguard Worker```
345*238ab3e7SAndroid Build Coastguard Worker</details>
346*238ab3e7SAndroid Build Coastguard Worker
347*238ab3e7SAndroid Build Coastguard Worker<details>
348*238ab3e7SAndroid Build Coastguard Worker    <summary>Kotlin</summary>
349*238ab3e7SAndroid Build Coastguard Worker
350*238ab3e7SAndroid Build Coastguard Worker```kotlin
351*238ab3e7SAndroid Build Coastguard Workerclass EventJsonAdapter {
352*238ab3e7SAndroid Build Coastguard Worker  @FromJson fun eventFromJson(eventJson: EventJson): Event {
353*238ab3e7SAndroid Build Coastguard Worker    val event = Event()
354*238ab3e7SAndroid Build Coastguard Worker    event.title = eventJson.title
355*238ab3e7SAndroid Build Coastguard Worker    event.beginDateAndTime = "${eventJson.begin_date} ${eventJson.begin_time}"
356*238ab3e7SAndroid Build Coastguard Worker    return event
357*238ab3e7SAndroid Build Coastguard Worker  }
358*238ab3e7SAndroid Build Coastguard Worker
359*238ab3e7SAndroid Build Coastguard Worker  @ToJson fun eventToJson(event: Event): EventJson {
360*238ab3e7SAndroid Build Coastguard Worker    val json = EventJson()
361*238ab3e7SAndroid Build Coastguard Worker    json.title = event.title
362*238ab3e7SAndroid Build Coastguard Worker    json.begin_date = event.beginDateAndTime.substring(0, 8)
363*238ab3e7SAndroid Build Coastguard Worker    json.begin_time = event.beginDateAndTime.substring(9, 14)
364*238ab3e7SAndroid Build Coastguard Worker    return json
365*238ab3e7SAndroid Build Coastguard Worker  }
366*238ab3e7SAndroid Build Coastguard Worker}
367*238ab3e7SAndroid Build Coastguard Worker```
368*238ab3e7SAndroid Build Coastguard Worker</details>
369*238ab3e7SAndroid Build Coastguard Worker
370*238ab3e7SAndroid Build Coastguard WorkerAgain we register the adapter with Moshi.
371*238ab3e7SAndroid Build Coastguard Worker
372*238ab3e7SAndroid Build Coastguard Worker<details open>
373*238ab3e7SAndroid Build Coastguard Worker    <summary>Java</summary>
374*238ab3e7SAndroid Build Coastguard Worker
375*238ab3e7SAndroid Build Coastguard Worker```java
376*238ab3e7SAndroid Build Coastguard WorkerMoshi moshi = new Moshi.Builder()
377*238ab3e7SAndroid Build Coastguard Worker    .add(new EventJsonAdapter())
378*238ab3e7SAndroid Build Coastguard Worker    .build();
379*238ab3e7SAndroid Build Coastguard Worker```
380*238ab3e7SAndroid Build Coastguard Worker</details>
381*238ab3e7SAndroid Build Coastguard Worker
382*238ab3e7SAndroid Build Coastguard Worker<details>
383*238ab3e7SAndroid Build Coastguard Worker    <summary>Kotlin</summary>
384*238ab3e7SAndroid Build Coastguard Worker
385*238ab3e7SAndroid Build Coastguard Worker```kotlin
386*238ab3e7SAndroid Build Coastguard Workerval moshi = Moshi.Builder()
387*238ab3e7SAndroid Build Coastguard Worker    .add(EventJsonAdapter())
388*238ab3e7SAndroid Build Coastguard Worker    .builder
389*238ab3e7SAndroid Build Coastguard Worker```
390*238ab3e7SAndroid Build Coastguard Worker</details>
391*238ab3e7SAndroid Build Coastguard Worker
392*238ab3e7SAndroid Build Coastguard WorkerWe can now use Moshi to parse the JSON directly to an `Event`.
393*238ab3e7SAndroid Build Coastguard Worker
394*238ab3e7SAndroid Build Coastguard Worker<details open>
395*238ab3e7SAndroid Build Coastguard Worker    <summary>Java</summary>
396*238ab3e7SAndroid Build Coastguard Worker
397*238ab3e7SAndroid Build Coastguard Worker```java
398*238ab3e7SAndroid Build Coastguard WorkerJsonAdapter<Event> jsonAdapter = moshi.adapter(Event.class);
399*238ab3e7SAndroid Build Coastguard WorkerEvent event = jsonAdapter.fromJson(json);
400*238ab3e7SAndroid Build Coastguard Worker```
401*238ab3e7SAndroid Build Coastguard Worker</details>
402*238ab3e7SAndroid Build Coastguard Worker
403*238ab3e7SAndroid Build Coastguard Worker<details>
404*238ab3e7SAndroid Build Coastguard Worker    <summary>Kotlin</summary>
405*238ab3e7SAndroid Build Coastguard Worker
406*238ab3e7SAndroid Build Coastguard Worker```kotlin
407*238ab3e7SAndroid Build Coastguard Workerval jsonAdapter = moshi.adapter<Event>()
408*238ab3e7SAndroid Build Coastguard Workerval event = jsonAdapter.fromJson(json)
409*238ab3e7SAndroid Build Coastguard Worker```
410*238ab3e7SAndroid Build Coastguard Worker</details>
411*238ab3e7SAndroid Build Coastguard Worker
412*238ab3e7SAndroid Build Coastguard Worker### Adapter convenience methods
413*238ab3e7SAndroid Build Coastguard Worker
414*238ab3e7SAndroid Build Coastguard WorkerMoshi provides a number of convenience methods for `JsonAdapter` objects:
415*238ab3e7SAndroid Build Coastguard Worker- `nullSafe()`
416*238ab3e7SAndroid Build Coastguard Worker- `nonNull()`
417*238ab3e7SAndroid Build Coastguard Worker- `lenient()`
418*238ab3e7SAndroid Build Coastguard Worker- `failOnUnknown()`
419*238ab3e7SAndroid Build Coastguard Worker- `indent()`
420*238ab3e7SAndroid Build Coastguard Worker- `serializeNulls()`
421*238ab3e7SAndroid Build Coastguard Worker
422*238ab3e7SAndroid Build Coastguard WorkerThese factory methods wrap an existing `JsonAdapter` into additional functionality.
423*238ab3e7SAndroid Build Coastguard WorkerFor example, if you have an adapter that doesn't support nullable values, you can use `nullSafe()` to make it null safe:
424*238ab3e7SAndroid Build Coastguard Worker
425*238ab3e7SAndroid Build Coastguard Worker<details open>
426*238ab3e7SAndroid Build Coastguard Worker    <summary>Java</summary>
427*238ab3e7SAndroid Build Coastguard Worker
428*238ab3e7SAndroid Build Coastguard Worker```java
429*238ab3e7SAndroid Build Coastguard WorkerString dateJson = "\"2018-11-26T11:04:19.342668Z\"";
430*238ab3e7SAndroid Build Coastguard WorkerString nullDateJson = "null";
431*238ab3e7SAndroid Build Coastguard Worker
432*238ab3e7SAndroid Build Coastguard Worker// Hypothetical IsoDateDapter, doesn't support null by default
433*238ab3e7SAndroid Build Coastguard WorkerJsonAdapter<Date> adapter = new IsoDateDapter();
434*238ab3e7SAndroid Build Coastguard Worker
435*238ab3e7SAndroid Build Coastguard WorkerDate date = adapter.fromJson(dateJson);
436*238ab3e7SAndroid Build Coastguard WorkerSystem.out.println(date); // Mon Nov 26 12:04:19 CET 2018
437*238ab3e7SAndroid Build Coastguard Worker
438*238ab3e7SAndroid Build Coastguard WorkerDate nullDate = adapter.fromJson(nullDateJson);
439*238ab3e7SAndroid Build Coastguard Worker// Exception, com.squareup.moshi.JsonDataException: Expected a string but was NULL at path $
440*238ab3e7SAndroid Build Coastguard Worker
441*238ab3e7SAndroid Build Coastguard WorkerDate nullDate = adapter.nullSafe().fromJson(nullDateJson);
442*238ab3e7SAndroid Build Coastguard WorkerSystem.out.println(nullDate); // null
443*238ab3e7SAndroid Build Coastguard Worker```
444*238ab3e7SAndroid Build Coastguard Worker</details>
445*238ab3e7SAndroid Build Coastguard Worker
446*238ab3e7SAndroid Build Coastguard Worker<details>
447*238ab3e7SAndroid Build Coastguard Worker    <summary>Kotlin</summary>
448*238ab3e7SAndroid Build Coastguard Worker
449*238ab3e7SAndroid Build Coastguard Worker```kotlin
450*238ab3e7SAndroid Build Coastguard Workerval dateJson = "\"2018-11-26T11:04:19.342668Z\""
451*238ab3e7SAndroid Build Coastguard Workerval nullDateJson = "null"
452*238ab3e7SAndroid Build Coastguard Worker
453*238ab3e7SAndroid Build Coastguard Worker// Hypothetical IsoDateDapter, doesn't support null by default
454*238ab3e7SAndroid Build Coastguard Workerval adapter: JsonAdapter<Date> = IsoDateDapter()
455*238ab3e7SAndroid Build Coastguard Worker
456*238ab3e7SAndroid Build Coastguard Workerval date = adapter.fromJson(dateJson)
457*238ab3e7SAndroid Build Coastguard Workerprintln(date) // Mon Nov 26 12:04:19 CET 2018
458*238ab3e7SAndroid Build Coastguard Worker
459*238ab3e7SAndroid Build Coastguard Workerval nullDate = adapter.fromJson(nullDateJson)
460*238ab3e7SAndroid Build Coastguard Worker// Exception, com.squareup.moshi.JsonDataException: Expected a string but was NULL at path $
461*238ab3e7SAndroid Build Coastguard Worker
462*238ab3e7SAndroid Build Coastguard Workerval nullDate = adapter.nullSafe().fromJson(nullDateJson)
463*238ab3e7SAndroid Build Coastguard Workerprintln(nullDate) // null
464*238ab3e7SAndroid Build Coastguard Worker```
465*238ab3e7SAndroid Build Coastguard Worker</details>
466*238ab3e7SAndroid Build Coastguard Worker
467*238ab3e7SAndroid Build Coastguard WorkerIn contrast to `nullSafe()` there is `nonNull()` to make an adapter refuse null values. Refer to the Moshi JavaDoc for details on the various methods.
468*238ab3e7SAndroid Build Coastguard Worker
469*238ab3e7SAndroid Build Coastguard Worker### Parse JSON Arrays
470*238ab3e7SAndroid Build Coastguard Worker
471*238ab3e7SAndroid Build Coastguard WorkerSay we have a JSON string of this structure:
472*238ab3e7SAndroid Build Coastguard Worker
473*238ab3e7SAndroid Build Coastguard Worker```json
474*238ab3e7SAndroid Build Coastguard Worker[
475*238ab3e7SAndroid Build Coastguard Worker  {
476*238ab3e7SAndroid Build Coastguard Worker    "rank": "4",
477*238ab3e7SAndroid Build Coastguard Worker    "suit": "CLUBS"
478*238ab3e7SAndroid Build Coastguard Worker  },
479*238ab3e7SAndroid Build Coastguard Worker  {
480*238ab3e7SAndroid Build Coastguard Worker    "rank": "A",
481*238ab3e7SAndroid Build Coastguard Worker    "suit": "HEARTS"
482*238ab3e7SAndroid Build Coastguard Worker  }
483*238ab3e7SAndroid Build Coastguard Worker]
484*238ab3e7SAndroid Build Coastguard Worker```
485*238ab3e7SAndroid Build Coastguard Worker
486*238ab3e7SAndroid Build Coastguard WorkerWe can now use Moshi to parse the JSON string into a `List<Card>`.
487*238ab3e7SAndroid Build Coastguard Worker
488*238ab3e7SAndroid Build Coastguard Worker<details open>
489*238ab3e7SAndroid Build Coastguard Worker    <summary>Java</summary>
490*238ab3e7SAndroid Build Coastguard Worker
491*238ab3e7SAndroid Build Coastguard Worker```java
492*238ab3e7SAndroid Build Coastguard WorkerString cardsJsonResponse = ...;
493*238ab3e7SAndroid Build Coastguard WorkerType type = Types.newParameterizedType(List.class, Card.class);
494*238ab3e7SAndroid Build Coastguard WorkerJsonAdapter<List<Card>> adapter = moshi.adapter(type);
495*238ab3e7SAndroid Build Coastguard WorkerList<Card> cards = adapter.fromJson(cardsJsonResponse);
496*238ab3e7SAndroid Build Coastguard Worker```
497*238ab3e7SAndroid Build Coastguard Worker</details>
498*238ab3e7SAndroid Build Coastguard Worker
499*238ab3e7SAndroid Build Coastguard Worker<details>
500*238ab3e7SAndroid Build Coastguard Worker    <summary>Kotlin</summary>
501*238ab3e7SAndroid Build Coastguard Worker
502*238ab3e7SAndroid Build Coastguard Worker```kotlin
503*238ab3e7SAndroid Build Coastguard Workerval cardsJsonResponse: String = ...
504*238ab3e7SAndroid Build Coastguard Worker// We can just use a reified extension!
505*238ab3e7SAndroid Build Coastguard Workerval adapter = moshi.adapter<List<Card>>()
506*238ab3e7SAndroid Build Coastguard Workerval cards: List<Card> = adapter.fromJson(cardsJsonResponse)
507*238ab3e7SAndroid Build Coastguard Worker```
508*238ab3e7SAndroid Build Coastguard Worker</details>
509*238ab3e7SAndroid Build Coastguard Worker
510*238ab3e7SAndroid Build Coastguard Worker### Fails Gracefully
511*238ab3e7SAndroid Build Coastguard Worker
512*238ab3e7SAndroid Build Coastguard WorkerAutomatic databinding almost feels like magic. But unlike the black magic that typically accompanies
513*238ab3e7SAndroid Build Coastguard Workerreflection, Moshi is designed to help you out when things go wrong.
514*238ab3e7SAndroid Build Coastguard Worker
515*238ab3e7SAndroid Build Coastguard Worker```
516*238ab3e7SAndroid Build Coastguard WorkerJsonDataException: Expected one of [CLUBS, DIAMONDS, HEARTS, SPADES] but was ANCHOR at path $.visible_cards[2].suit
517*238ab3e7SAndroid Build Coastguard Worker  at com.squareup.moshi.JsonAdapters$11.fromJson(JsonAdapters.java:188)
518*238ab3e7SAndroid Build Coastguard Worker  at com.squareup.moshi.JsonAdapters$11.fromJson(JsonAdapters.java:180)
519*238ab3e7SAndroid Build Coastguard Worker  ...
520*238ab3e7SAndroid Build Coastguard Worker```
521*238ab3e7SAndroid Build Coastguard Worker
522*238ab3e7SAndroid Build Coastguard WorkerMoshi always throws a standard `java.io.IOException` if there is an error reading the JSON document,
523*238ab3e7SAndroid Build Coastguard Workeror if it is malformed. It throws a `JsonDataException` if the JSON document is well-formed, but
524*238ab3e7SAndroid Build Coastguard Workerdoesn’t match the expected format.
525*238ab3e7SAndroid Build Coastguard Worker
526*238ab3e7SAndroid Build Coastguard Worker### Built on Okio
527*238ab3e7SAndroid Build Coastguard Worker
528*238ab3e7SAndroid Build Coastguard WorkerMoshi uses [Okio][okio] for simple and powerful I/O. It’s a fine complement to [OkHttp][okhttp],
529*238ab3e7SAndroid Build Coastguard Workerwhich can share buffer segments for maximum efficiency.
530*238ab3e7SAndroid Build Coastguard Worker
531*238ab3e7SAndroid Build Coastguard Worker### Borrows from Gson
532*238ab3e7SAndroid Build Coastguard Worker
533*238ab3e7SAndroid Build Coastguard WorkerMoshi uses the same streaming and binding mechanisms as [Gson][gson]. If you’re a Gson user you’ll
534*238ab3e7SAndroid Build Coastguard Workerfind Moshi works similarly. If you try Moshi and don’t love it, you can even migrate to Gson without
535*238ab3e7SAndroid Build Coastguard Workermuch violence!
536*238ab3e7SAndroid Build Coastguard Worker
537*238ab3e7SAndroid Build Coastguard WorkerBut the two libraries have a few important differences:
538*238ab3e7SAndroid Build Coastguard Worker
539*238ab3e7SAndroid Build Coastguard Worker * **Moshi has fewer built-in type adapters.** For example, you need to configure your own date
540*238ab3e7SAndroid Build Coastguard Worker   adapter. Most binding libraries will encode whatever you throw at them. Moshi refuses to
541*238ab3e7SAndroid Build Coastguard Worker   serialize platform types (`java.*`, `javax.*`, and `android.*`) without a user-provided type
542*238ab3e7SAndroid Build Coastguard Worker   adapter. This is intended to prevent you from accidentally locking yourself to a specific JDK or
543*238ab3e7SAndroid Build Coastguard Worker   Android release.
544*238ab3e7SAndroid Build Coastguard Worker * **Moshi is less configurable.** There’s no field naming strategy, versioning, instance creators,
545*238ab3e7SAndroid Build Coastguard Worker   or long serialization policy. Instead of naming a field `visibleCards` and using a policy class
546*238ab3e7SAndroid Build Coastguard Worker   to convert that to `visible_cards`, Moshi wants you to just name the field `visible_cards` as it
547*238ab3e7SAndroid Build Coastguard Worker   appears in the JSON.
548*238ab3e7SAndroid Build Coastguard Worker * **Moshi doesn’t have a `JsonElement` model.** Instead it just uses built-in types like `List` and
549*238ab3e7SAndroid Build Coastguard Worker   `Map`.
550*238ab3e7SAndroid Build Coastguard Worker * **No HTML-safe escaping.** Gson encodes `=` as `\u003d` by default so that it can be safely
551*238ab3e7SAndroid Build Coastguard Worker   encoded in HTML without additional escaping. Moshi encodes it naturally (as `=`) and assumes that
552*238ab3e7SAndroid Build Coastguard Worker   the HTML encoder – if there is one – will do its job.
553*238ab3e7SAndroid Build Coastguard Worker
554*238ab3e7SAndroid Build Coastguard Worker### Custom field names with @Json
555*238ab3e7SAndroid Build Coastguard Worker
556*238ab3e7SAndroid Build Coastguard WorkerMoshi works best when your JSON objects and Java or Kotlin classes have the same structure. But when they
557*238ab3e7SAndroid Build Coastguard Workerdon't, Moshi has annotations to customize data binding.
558*238ab3e7SAndroid Build Coastguard Worker
559*238ab3e7SAndroid Build Coastguard WorkerUse `@Json` to specify how Java fields or Kotlin properties map to JSON names. This is necessary when the JSON name
560*238ab3e7SAndroid Build Coastguard Workercontains spaces or other characters that aren’t permitted in Java field or Kotlin property names. For example, this
561*238ab3e7SAndroid Build Coastguard WorkerJSON has a field name containing a space:
562*238ab3e7SAndroid Build Coastguard Worker
563*238ab3e7SAndroid Build Coastguard Worker```json
564*238ab3e7SAndroid Build Coastguard Worker{
565*238ab3e7SAndroid Build Coastguard Worker  "username": "jesse",
566*238ab3e7SAndroid Build Coastguard Worker  "lucky number": 32
567*238ab3e7SAndroid Build Coastguard Worker}
568*238ab3e7SAndroid Build Coastguard Worker```
569*238ab3e7SAndroid Build Coastguard Worker
570*238ab3e7SAndroid Build Coastguard WorkerWith `@Json` its corresponding Java or Kotlin class is easy:
571*238ab3e7SAndroid Build Coastguard Worker
572*238ab3e7SAndroid Build Coastguard Worker<details open>
573*238ab3e7SAndroid Build Coastguard Worker    <summary>Java</summary>
574*238ab3e7SAndroid Build Coastguard Worker
575*238ab3e7SAndroid Build Coastguard Worker```java
576*238ab3e7SAndroid Build Coastguard Workerclass Player {
577*238ab3e7SAndroid Build Coastguard Worker  String username;
578*238ab3e7SAndroid Build Coastguard Worker  @Json(name = "lucky number") int luckyNumber;
579*238ab3e7SAndroid Build Coastguard Worker
580*238ab3e7SAndroid Build Coastguard Worker  ...
581*238ab3e7SAndroid Build Coastguard Worker}
582*238ab3e7SAndroid Build Coastguard Worker```
583*238ab3e7SAndroid Build Coastguard Worker</details>
584*238ab3e7SAndroid Build Coastguard Worker
585*238ab3e7SAndroid Build Coastguard Worker<details>
586*238ab3e7SAndroid Build Coastguard Worker    <summary>Kotlin</summary>
587*238ab3e7SAndroid Build Coastguard Worker
588*238ab3e7SAndroid Build Coastguard Worker```kotlin
589*238ab3e7SAndroid Build Coastguard Workerclass Player {
590*238ab3e7SAndroid Build Coastguard Worker  val username: String
591*238ab3e7SAndroid Build Coastguard Worker  @Json(name = "lucky number") val luckyNumber: Int
592*238ab3e7SAndroid Build Coastguard Worker
593*238ab3e7SAndroid Build Coastguard Worker  ...
594*238ab3e7SAndroid Build Coastguard Worker}
595*238ab3e7SAndroid Build Coastguard Worker```
596*238ab3e7SAndroid Build Coastguard Worker</details>
597*238ab3e7SAndroid Build Coastguard Worker
598*238ab3e7SAndroid Build Coastguard WorkerBecause JSON field names are always defined with their Java or Kotlin fields, Moshi makes it easy to find
599*238ab3e7SAndroid Build Coastguard Workerfields when navigating between Java or Koltin and JSON.
600*238ab3e7SAndroid Build Coastguard Worker
601*238ab3e7SAndroid Build Coastguard Worker### Alternate type adapters with @JsonQualifier
602*238ab3e7SAndroid Build Coastguard Worker
603*238ab3e7SAndroid Build Coastguard WorkerUse `@JsonQualifier` to customize how a type is encoded for some fields without changing its
604*238ab3e7SAndroid Build Coastguard Workerencoding everywhere. This works similarly to the qualifier annotations in dependency injection
605*238ab3e7SAndroid Build Coastguard Workertools like Dagger and Guice.
606*238ab3e7SAndroid Build Coastguard Worker
607*238ab3e7SAndroid Build Coastguard WorkerHere’s a JSON message with two integers and a color:
608*238ab3e7SAndroid Build Coastguard Worker
609*238ab3e7SAndroid Build Coastguard Worker```json
610*238ab3e7SAndroid Build Coastguard Worker{
611*238ab3e7SAndroid Build Coastguard Worker  "width": 1024,
612*238ab3e7SAndroid Build Coastguard Worker  "height": 768,
613*238ab3e7SAndroid Build Coastguard Worker  "color": "#ff0000"
614*238ab3e7SAndroid Build Coastguard Worker}
615*238ab3e7SAndroid Build Coastguard Worker```
616*238ab3e7SAndroid Build Coastguard Worker
617*238ab3e7SAndroid Build Coastguard WorkerBy convention, Android programs also use `int` for colors:
618*238ab3e7SAndroid Build Coastguard Worker
619*238ab3e7SAndroid Build Coastguard Worker<details open>
620*238ab3e7SAndroid Build Coastguard Worker    <summary>Java</summary>
621*238ab3e7SAndroid Build Coastguard Worker
622*238ab3e7SAndroid Build Coastguard Worker```java
623*238ab3e7SAndroid Build Coastguard Workerclass Rectangle {
624*238ab3e7SAndroid Build Coastguard Worker  int width;
625*238ab3e7SAndroid Build Coastguard Worker  int height;
626*238ab3e7SAndroid Build Coastguard Worker  int color;
627*238ab3e7SAndroid Build Coastguard Worker}
628*238ab3e7SAndroid Build Coastguard Worker```
629*238ab3e7SAndroid Build Coastguard Worker</details>
630*238ab3e7SAndroid Build Coastguard Worker
631*238ab3e7SAndroid Build Coastguard Worker<details>
632*238ab3e7SAndroid Build Coastguard Worker    <summary>Kotlin</summary>
633*238ab3e7SAndroid Build Coastguard Worker
634*238ab3e7SAndroid Build Coastguard Worker```kotlin
635*238ab3e7SAndroid Build Coastguard Workerclass Rectangle(
636*238ab3e7SAndroid Build Coastguard Worker  val width: Int,
637*238ab3e7SAndroid Build Coastguard Worker  val height: Int,
638*238ab3e7SAndroid Build Coastguard Worker  val color: Int
639*238ab3e7SAndroid Build Coastguard Worker)
640*238ab3e7SAndroid Build Coastguard Worker```
641*238ab3e7SAndroid Build Coastguard Worker</details>
642*238ab3e7SAndroid Build Coastguard Worker
643*238ab3e7SAndroid Build Coastguard WorkerBut if we encoded the above Java or Kotlin class as JSON, the color isn't encoded properly!
644*238ab3e7SAndroid Build Coastguard Worker
645*238ab3e7SAndroid Build Coastguard Worker```json
646*238ab3e7SAndroid Build Coastguard Worker{
647*238ab3e7SAndroid Build Coastguard Worker  "width": 1024,
648*238ab3e7SAndroid Build Coastguard Worker  "height": 768,
649*238ab3e7SAndroid Build Coastguard Worker  "color": 16711680
650*238ab3e7SAndroid Build Coastguard Worker}
651*238ab3e7SAndroid Build Coastguard Worker```
652*238ab3e7SAndroid Build Coastguard Worker
653*238ab3e7SAndroid Build Coastguard WorkerThe fix is to define a qualifier annotation, itself annotated `@JsonQualifier`:
654*238ab3e7SAndroid Build Coastguard Worker
655*238ab3e7SAndroid Build Coastguard Worker<details open>
656*238ab3e7SAndroid Build Coastguard Worker    <summary>Java</summary>
657*238ab3e7SAndroid Build Coastguard Worker
658*238ab3e7SAndroid Build Coastguard Worker```java
659*238ab3e7SAndroid Build Coastguard Worker@Retention(RUNTIME)
660*238ab3e7SAndroid Build Coastguard Worker@JsonQualifier
661*238ab3e7SAndroid Build Coastguard Workerpublic @interface HexColor {
662*238ab3e7SAndroid Build Coastguard Worker}
663*238ab3e7SAndroid Build Coastguard Worker```
664*238ab3e7SAndroid Build Coastguard Worker</details>
665*238ab3e7SAndroid Build Coastguard Worker
666*238ab3e7SAndroid Build Coastguard Worker<details>
667*238ab3e7SAndroid Build Coastguard Worker    <summary>Kotlin</summary>
668*238ab3e7SAndroid Build Coastguard Worker
669*238ab3e7SAndroid Build Coastguard Worker```kotlin
670*238ab3e7SAndroid Build Coastguard Worker@Retention(RUNTIME)
671*238ab3e7SAndroid Build Coastguard Worker@JsonQualifier
672*238ab3e7SAndroid Build Coastguard Workerannotation class HexColor
673*238ab3e7SAndroid Build Coastguard Worker```
674*238ab3e7SAndroid Build Coastguard Worker</details>
675*238ab3e7SAndroid Build Coastguard Worker
676*238ab3e7SAndroid Build Coastguard Worker
677*238ab3e7SAndroid Build Coastguard WorkerNext apply this `@HexColor` annotation to the appropriate field:
678*238ab3e7SAndroid Build Coastguard Worker
679*238ab3e7SAndroid Build Coastguard Worker<details open>
680*238ab3e7SAndroid Build Coastguard Worker    <summary>Java</summary>
681*238ab3e7SAndroid Build Coastguard Worker
682*238ab3e7SAndroid Build Coastguard Worker```java
683*238ab3e7SAndroid Build Coastguard Workerclass Rectangle {
684*238ab3e7SAndroid Build Coastguard Worker  int width;
685*238ab3e7SAndroid Build Coastguard Worker  int height;
686*238ab3e7SAndroid Build Coastguard Worker  @HexColor int color;
687*238ab3e7SAndroid Build Coastguard Worker}
688*238ab3e7SAndroid Build Coastguard Worker```
689*238ab3e7SAndroid Build Coastguard Worker</details>
690*238ab3e7SAndroid Build Coastguard Worker
691*238ab3e7SAndroid Build Coastguard Worker<details>
692*238ab3e7SAndroid Build Coastguard Worker    <summary>Kotlin</summary>
693*238ab3e7SAndroid Build Coastguard Worker
694*238ab3e7SAndroid Build Coastguard Worker```kotlin
695*238ab3e7SAndroid Build Coastguard Workerclass Rectangle(
696*238ab3e7SAndroid Build Coastguard Worker  val width: Int,
697*238ab3e7SAndroid Build Coastguard Worker  val height: Int,
698*238ab3e7SAndroid Build Coastguard Worker  @HexColor val color: Int
699*238ab3e7SAndroid Build Coastguard Worker)
700*238ab3e7SAndroid Build Coastguard Worker```
701*238ab3e7SAndroid Build Coastguard Worker</details>
702*238ab3e7SAndroid Build Coastguard Worker
703*238ab3e7SAndroid Build Coastguard WorkerAnd finally define a type adapter to handle it:
704*238ab3e7SAndroid Build Coastguard Worker
705*238ab3e7SAndroid Build Coastguard Worker<details open>
706*238ab3e7SAndroid Build Coastguard Worker    <summary>Java</summary>
707*238ab3e7SAndroid Build Coastguard Worker
708*238ab3e7SAndroid Build Coastguard Worker```java
709*238ab3e7SAndroid Build Coastguard Worker/** Converts strings like #ff0000 to the corresponding color ints. */
710*238ab3e7SAndroid Build Coastguard Workerclass ColorAdapter {
711*238ab3e7SAndroid Build Coastguard Worker  @ToJson String toJson(@HexColor int rgb) {
712*238ab3e7SAndroid Build Coastguard Worker    return String.format("#%06x", rgb);
713*238ab3e7SAndroid Build Coastguard Worker  }
714*238ab3e7SAndroid Build Coastguard Worker
715*238ab3e7SAndroid Build Coastguard Worker  @FromJson @HexColor int fromJson(String rgb) {
716*238ab3e7SAndroid Build Coastguard Worker    return Integer.parseInt(rgb.substring(1), 16);
717*238ab3e7SAndroid Build Coastguard Worker  }
718*238ab3e7SAndroid Build Coastguard Worker}
719*238ab3e7SAndroid Build Coastguard Worker```
720*238ab3e7SAndroid Build Coastguard Worker</details>
721*238ab3e7SAndroid Build Coastguard Worker
722*238ab3e7SAndroid Build Coastguard Worker<details>
723*238ab3e7SAndroid Build Coastguard Worker    <summary>Kotlin</summary>
724*238ab3e7SAndroid Build Coastguard Worker
725*238ab3e7SAndroid Build Coastguard Worker```kotlin
726*238ab3e7SAndroid Build Coastguard Worker/** Converts strings like #ff0000 to the corresponding color ints.  */
727*238ab3e7SAndroid Build Coastguard Workerclass ColorAdapter {
728*238ab3e7SAndroid Build Coastguard Worker  @ToJson fun toJson(@HexColor rgb: Int): String {
729*238ab3e7SAndroid Build Coastguard Worker    return "#%06x".format(rgb)
730*238ab3e7SAndroid Build Coastguard Worker  }
731*238ab3e7SAndroid Build Coastguard Worker
732*238ab3e7SAndroid Build Coastguard Worker  @FromJson @HexColor fun fromJson(rgb: String): Int {
733*238ab3e7SAndroid Build Coastguard Worker    return rgb.substring(1).toInt(16)
734*238ab3e7SAndroid Build Coastguard Worker  }
735*238ab3e7SAndroid Build Coastguard Worker}
736*238ab3e7SAndroid Build Coastguard Worker```
737*238ab3e7SAndroid Build Coastguard Worker</details>
738*238ab3e7SAndroid Build Coastguard Worker
739*238ab3e7SAndroid Build Coastguard WorkerUse `@JsonQualifier` when you need different JSON encodings for the same type. Most programs
740*238ab3e7SAndroid Build Coastguard Workershouldn’t need this `@JsonQualifier`, but it’s very handy for those that do.
741*238ab3e7SAndroid Build Coastguard Worker
742*238ab3e7SAndroid Build Coastguard Worker### Omit fields with `transient`
743*238ab3e7SAndroid Build Coastguard Worker
744*238ab3e7SAndroid Build Coastguard WorkerSome models declare fields that shouldn’t be included in JSON. For example, suppose our blackjack
745*238ab3e7SAndroid Build Coastguard Workerhand has a `total` field with the sum of the cards:
746*238ab3e7SAndroid Build Coastguard Worker
747*238ab3e7SAndroid Build Coastguard Worker<details open>
748*238ab3e7SAndroid Build Coastguard Worker    <summary>Java</summary>
749*238ab3e7SAndroid Build Coastguard Worker
750*238ab3e7SAndroid Build Coastguard Worker```java
751*238ab3e7SAndroid Build Coastguard Workerpublic final class BlackjackHand {
752*238ab3e7SAndroid Build Coastguard Worker  private int total;
753*238ab3e7SAndroid Build Coastguard Worker
754*238ab3e7SAndroid Build Coastguard Worker  ...
755*238ab3e7SAndroid Build Coastguard Worker}
756*238ab3e7SAndroid Build Coastguard Worker```
757*238ab3e7SAndroid Build Coastguard Worker</details>
758*238ab3e7SAndroid Build Coastguard Worker
759*238ab3e7SAndroid Build Coastguard Worker<details>
760*238ab3e7SAndroid Build Coastguard Worker    <summary>Kotlin</summary>
761*238ab3e7SAndroid Build Coastguard Worker
762*238ab3e7SAndroid Build Coastguard Worker```kotlin
763*238ab3e7SAndroid Build Coastguard Workerclass BlackjackHand(
764*238ab3e7SAndroid Build Coastguard Worker  private val total: Int,
765*238ab3e7SAndroid Build Coastguard Worker
766*238ab3e7SAndroid Build Coastguard Worker  ...
767*238ab3e7SAndroid Build Coastguard Worker)
768*238ab3e7SAndroid Build Coastguard Worker```
769*238ab3e7SAndroid Build Coastguard Worker</details>
770*238ab3e7SAndroid Build Coastguard Worker
771*238ab3e7SAndroid Build Coastguard WorkerBy default, all fields are emitted when encoding JSON, and all fields are accepted when decoding
772*238ab3e7SAndroid Build Coastguard WorkerJSON. Prevent a field from being included by adding Java’s `transient` keyword or Kotlin's `@Transient` annotation:
773*238ab3e7SAndroid Build Coastguard Worker
774*238ab3e7SAndroid Build Coastguard Worker<details open>
775*238ab3e7SAndroid Build Coastguard Worker    <summary>Java</summary>
776*238ab3e7SAndroid Build Coastguard Worker
777*238ab3e7SAndroid Build Coastguard Worker```java
778*238ab3e7SAndroid Build Coastguard Workerpublic final class BlackjackHand {
779*238ab3e7SAndroid Build Coastguard Worker  private transient int total;
780*238ab3e7SAndroid Build Coastguard Worker
781*238ab3e7SAndroid Build Coastguard Worker  ...
782*238ab3e7SAndroid Build Coastguard Worker}
783*238ab3e7SAndroid Build Coastguard Worker```
784*238ab3e7SAndroid Build Coastguard Worker</details>
785*238ab3e7SAndroid Build Coastguard Worker
786*238ab3e7SAndroid Build Coastguard Worker<details>
787*238ab3e7SAndroid Build Coastguard Worker    <summary>Kotlin</summary>
788*238ab3e7SAndroid Build Coastguard Worker
789*238ab3e7SAndroid Build Coastguard Worker```kotlin
790*238ab3e7SAndroid Build Coastguard Workerclass BlackjackHand(...) {
791*238ab3e7SAndroid Build Coastguard Worker  @Transient var total: Int
792*238ab3e7SAndroid Build Coastguard Worker
793*238ab3e7SAndroid Build Coastguard Worker  ...
794*238ab3e7SAndroid Build Coastguard Worker}
795*238ab3e7SAndroid Build Coastguard Worker```
796*238ab3e7SAndroid Build Coastguard Worker</details>
797*238ab3e7SAndroid Build Coastguard Worker
798*238ab3e7SAndroid Build Coastguard WorkerTransient fields are omitted when writing JSON. When reading JSON, the field is skipped even if the
799*238ab3e7SAndroid Build Coastguard WorkerJSON contains a value for the field. Instead, it will get a default value.
800*238ab3e7SAndroid Build Coastguard Worker
801*238ab3e7SAndroid Build Coastguard Worker
802*238ab3e7SAndroid Build Coastguard Worker### Default Values & Constructors
803*238ab3e7SAndroid Build Coastguard Worker
804*238ab3e7SAndroid Build Coastguard WorkerWhen reading JSON that is missing a field, Moshi relies on the Java or Kotlin or Android runtime to assign
805*238ab3e7SAndroid Build Coastguard Workerthe field’s value. Which value it uses depends on whether the class has a no-arguments constructor.
806*238ab3e7SAndroid Build Coastguard Worker
807*238ab3e7SAndroid Build Coastguard WorkerIf the class has a no-arguments constructor, Moshi will call that constructor and whatever value
808*238ab3e7SAndroid Build Coastguard Workerit assigns will be used. For example, because this class has a no-arguments constructor the `total`
809*238ab3e7SAndroid Build Coastguard Workerfield is initialized to `-1`.
810*238ab3e7SAndroid Build Coastguard Worker
811*238ab3e7SAndroid Build Coastguard WorkerNote: This section only applies to Java reflections.
812*238ab3e7SAndroid Build Coastguard Worker
813*238ab3e7SAndroid Build Coastguard Worker```java
814*238ab3e7SAndroid Build Coastguard Workerpublic final class BlackjackHand {
815*238ab3e7SAndroid Build Coastguard Worker  private int total = -1;
816*238ab3e7SAndroid Build Coastguard Worker  ...
817*238ab3e7SAndroid Build Coastguard Worker
818*238ab3e7SAndroid Build Coastguard Worker  private BlackjackHand() {
819*238ab3e7SAndroid Build Coastguard Worker  }
820*238ab3e7SAndroid Build Coastguard Worker
821*238ab3e7SAndroid Build Coastguard Worker  public BlackjackHand(Card hidden_card, List<Card> visible_cards) {
822*238ab3e7SAndroid Build Coastguard Worker    ...
823*238ab3e7SAndroid Build Coastguard Worker  }
824*238ab3e7SAndroid Build Coastguard Worker}
825*238ab3e7SAndroid Build Coastguard Worker```
826*238ab3e7SAndroid Build Coastguard Worker
827*238ab3e7SAndroid Build Coastguard WorkerIf the class doesn’t have a no-arguments constructor, Moshi can’t assign the field’s default value,
828*238ab3e7SAndroid Build Coastguard Worker**even if it’s specified in the field declaration**. Instead, the field’s default is always `0` for
829*238ab3e7SAndroid Build Coastguard Workernumbers, `false` for booleans, and `null` for references. In this example, the default value of
830*238ab3e7SAndroid Build Coastguard Worker`total` is `0`!
831*238ab3e7SAndroid Build Coastguard Worker
832*238ab3e7SAndroid Build Coastguard Worker
833*238ab3e7SAndroid Build Coastguard Worker```java
834*238ab3e7SAndroid Build Coastguard Workerpublic final class BlackjackHand {
835*238ab3e7SAndroid Build Coastguard Worker  private int total = -1;
836*238ab3e7SAndroid Build Coastguard Worker  ...
837*238ab3e7SAndroid Build Coastguard Worker
838*238ab3e7SAndroid Build Coastguard Worker  public BlackjackHand(Card hidden_card, List<Card> visible_cards) {
839*238ab3e7SAndroid Build Coastguard Worker    ...
840*238ab3e7SAndroid Build Coastguard Worker  }
841*238ab3e7SAndroid Build Coastguard Worker}
842*238ab3e7SAndroid Build Coastguard Worker```
843*238ab3e7SAndroid Build Coastguard Worker
844*238ab3e7SAndroid Build Coastguard WorkerThis is surprising and is a potential source of bugs! For this reason consider defining a
845*238ab3e7SAndroid Build Coastguard Workerno-arguments constructor in classes that you use with Moshi, using `@SuppressWarnings("unused")` to
846*238ab3e7SAndroid Build Coastguard Workerprevent it from being inadvertently deleted later:
847*238ab3e7SAndroid Build Coastguard Worker
848*238ab3e7SAndroid Build Coastguard Worker
849*238ab3e7SAndroid Build Coastguard Worker```java
850*238ab3e7SAndroid Build Coastguard Workerpublic final class BlackjackHand {
851*238ab3e7SAndroid Build Coastguard Worker  private int total = -1;
852*238ab3e7SAndroid Build Coastguard Worker  ...
853*238ab3e7SAndroid Build Coastguard Worker
854*238ab3e7SAndroid Build Coastguard Worker  @SuppressWarnings("unused") // Moshi uses this!
855*238ab3e7SAndroid Build Coastguard Worker  private BlackjackHand() {
856*238ab3e7SAndroid Build Coastguard Worker  }
857*238ab3e7SAndroid Build Coastguard Worker
858*238ab3e7SAndroid Build Coastguard Worker  public BlackjackHand(Card hidden_card, List<Card> visible_cards) {
859*238ab3e7SAndroid Build Coastguard Worker    ...
860*238ab3e7SAndroid Build Coastguard Worker  }
861*238ab3e7SAndroid Build Coastguard Worker}
862*238ab3e7SAndroid Build Coastguard Worker```
863*238ab3e7SAndroid Build Coastguard Worker
864*238ab3e7SAndroid Build Coastguard Worker### Composing Adapters
865*238ab3e7SAndroid Build Coastguard Worker
866*238ab3e7SAndroid Build Coastguard WorkerIn some situations Moshi's default Java-to-JSON conversion isn't sufficient. You can compose
867*238ab3e7SAndroid Build Coastguard Workeradapters to build upon the standard conversion.
868*238ab3e7SAndroid Build Coastguard Worker
869*238ab3e7SAndroid Build Coastguard WorkerIn this example, we turn serialize nulls, then delegate to the built-in adapter:
870*238ab3e7SAndroid Build Coastguard Worker
871*238ab3e7SAndroid Build Coastguard Worker<details open>
872*238ab3e7SAndroid Build Coastguard Worker    <summary>Java</summary>
873*238ab3e7SAndroid Build Coastguard Worker
874*238ab3e7SAndroid Build Coastguard Worker```java
875*238ab3e7SAndroid Build Coastguard Workerclass TournamentWithNullsAdapter {
876*238ab3e7SAndroid Build Coastguard Worker  @ToJson void toJson(JsonWriter writer, Tournament tournament,
877*238ab3e7SAndroid Build Coastguard Worker      JsonAdapter<Tournament> delegate) throws IOException {
878*238ab3e7SAndroid Build Coastguard Worker    boolean wasSerializeNulls = writer.getSerializeNulls();
879*238ab3e7SAndroid Build Coastguard Worker    writer.setSerializeNulls(true);
880*238ab3e7SAndroid Build Coastguard Worker    try {
881*238ab3e7SAndroid Build Coastguard Worker      delegate.toJson(writer, tournament);
882*238ab3e7SAndroid Build Coastguard Worker    } finally {
883*238ab3e7SAndroid Build Coastguard Worker      writer.setLenient(wasSerializeNulls);
884*238ab3e7SAndroid Build Coastguard Worker    }
885*238ab3e7SAndroid Build Coastguard Worker  }
886*238ab3e7SAndroid Build Coastguard Worker}
887*238ab3e7SAndroid Build Coastguard Worker```
888*238ab3e7SAndroid Build Coastguard Worker</details>
889*238ab3e7SAndroid Build Coastguard Worker
890*238ab3e7SAndroid Build Coastguard Worker<details>
891*238ab3e7SAndroid Build Coastguard Worker    <summary>Kotlin</summary>
892*238ab3e7SAndroid Build Coastguard Worker
893*238ab3e7SAndroid Build Coastguard Worker```kotlin
894*238ab3e7SAndroid Build Coastguard Workerclass TournamentWithNullsAdapter {
895*238ab3e7SAndroid Build Coastguard Worker  @ToJson fun toJson(writer: JsonWriter, tournament: Tournament?,
896*238ab3e7SAndroid Build Coastguard Worker    delegate: JsonAdapter<Tournament?>) {
897*238ab3e7SAndroid Build Coastguard Worker    val wasSerializeNulls: Boolean = writer.getSerializeNulls()
898*238ab3e7SAndroid Build Coastguard Worker    writer.setSerializeNulls(true)
899*238ab3e7SAndroid Build Coastguard Worker    try {
900*238ab3e7SAndroid Build Coastguard Worker      delegate.toJson(writer, tournament)
901*238ab3e7SAndroid Build Coastguard Worker    } finally {
902*238ab3e7SAndroid Build Coastguard Worker      writer.setLenient(wasSerializeNulls)
903*238ab3e7SAndroid Build Coastguard Worker    }
904*238ab3e7SAndroid Build Coastguard Worker  }
905*238ab3e7SAndroid Build Coastguard Worker}
906*238ab3e7SAndroid Build Coastguard Worker```
907*238ab3e7SAndroid Build Coastguard Worker</details>
908*238ab3e7SAndroid Build Coastguard Worker
909*238ab3e7SAndroid Build Coastguard Worker
910*238ab3e7SAndroid Build Coastguard WorkerWhen we use this to serialize a tournament, nulls are written! But nulls elsewhere in our JSON
911*238ab3e7SAndroid Build Coastguard Workerdocument are skipped as usual.
912*238ab3e7SAndroid Build Coastguard Worker
913*238ab3e7SAndroid Build Coastguard WorkerMoshi has a powerful composition system in its `JsonAdapter.Factory` interface. We can hook in to
914*238ab3e7SAndroid Build Coastguard Workerthe encoding and decoding process for any type, even without knowing about the types beforehand. In
915*238ab3e7SAndroid Build Coastguard Workerthis example, we customize types annotated `@AlwaysSerializeNulls`, which an annotation we create,
916*238ab3e7SAndroid Build Coastguard Workernot built-in to Moshi:
917*238ab3e7SAndroid Build Coastguard Worker
918*238ab3e7SAndroid Build Coastguard Worker<details open>
919*238ab3e7SAndroid Build Coastguard Worker    <summary>Java</summary>
920*238ab3e7SAndroid Build Coastguard Worker
921*238ab3e7SAndroid Build Coastguard Worker```java
922*238ab3e7SAndroid Build Coastguard Worker@Target(TYPE)
923*238ab3e7SAndroid Build Coastguard Worker@Retention(RUNTIME)
924*238ab3e7SAndroid Build Coastguard Workerpublic @interface AlwaysSerializeNulls {}
925*238ab3e7SAndroid Build Coastguard Worker```
926*238ab3e7SAndroid Build Coastguard Worker</details>
927*238ab3e7SAndroid Build Coastguard Worker
928*238ab3e7SAndroid Build Coastguard Worker<details>
929*238ab3e7SAndroid Build Coastguard Worker    <summary>Kotlin</summary>
930*238ab3e7SAndroid Build Coastguard Worker
931*238ab3e7SAndroid Build Coastguard Worker```kotlin
932*238ab3e7SAndroid Build Coastguard Worker@Target(TYPE)
933*238ab3e7SAndroid Build Coastguard Worker@Retention(RUNTIME)
934*238ab3e7SAndroid Build Coastguard Workerannotation class AlwaysSerializeNulls
935*238ab3e7SAndroid Build Coastguard Worker```
936*238ab3e7SAndroid Build Coastguard Worker</details>
937*238ab3e7SAndroid Build Coastguard Worker
938*238ab3e7SAndroid Build Coastguard Worker<details open>
939*238ab3e7SAndroid Build Coastguard Worker    <summary>Java</summary>
940*238ab3e7SAndroid Build Coastguard Worker
941*238ab3e7SAndroid Build Coastguard Worker```java
942*238ab3e7SAndroid Build Coastguard Worker@AlwaysSerializeNulls
943*238ab3e7SAndroid Build Coastguard Workerstatic class Car {
944*238ab3e7SAndroid Build Coastguard Worker  String make;
945*238ab3e7SAndroid Build Coastguard Worker  String model;
946*238ab3e7SAndroid Build Coastguard Worker  String color;
947*238ab3e7SAndroid Build Coastguard Worker}
948*238ab3e7SAndroid Build Coastguard Worker```
949*238ab3e7SAndroid Build Coastguard Worker</details>
950*238ab3e7SAndroid Build Coastguard Worker
951*238ab3e7SAndroid Build Coastguard Worker<details>
952*238ab3e7SAndroid Build Coastguard Worker    <summary>Kotlin</summary>
953*238ab3e7SAndroid Build Coastguard Worker
954*238ab3e7SAndroid Build Coastguard Worker```kotlin
955*238ab3e7SAndroid Build Coastguard Worker@AlwaysSerializeNulls
956*238ab3e7SAndroid Build Coastguard Workerclass Car(
957*238ab3e7SAndroid Build Coastguard Worker  val make: String?,
958*238ab3e7SAndroid Build Coastguard Worker  val model: String?,
959*238ab3e7SAndroid Build Coastguard Worker  val color: String?
960*238ab3e7SAndroid Build Coastguard Worker)
961*238ab3e7SAndroid Build Coastguard Worker```
962*238ab3e7SAndroid Build Coastguard Worker</details>
963*238ab3e7SAndroid Build Coastguard Worker
964*238ab3e7SAndroid Build Coastguard WorkerEach `JsonAdapter.Factory` interface is invoked by `Moshi` when it needs to build an adapter for a
965*238ab3e7SAndroid Build Coastguard Workeruser's type. The factory either returns an adapter to use, or null if it doesn't apply to the
966*238ab3e7SAndroid Build Coastguard Workerrequested type. In our case we match all classes that have our annotation.
967*238ab3e7SAndroid Build Coastguard Worker
968*238ab3e7SAndroid Build Coastguard Worker<details open>
969*238ab3e7SAndroid Build Coastguard Worker    <summary>Java</summary>
970*238ab3e7SAndroid Build Coastguard Worker
971*238ab3e7SAndroid Build Coastguard Worker```java
972*238ab3e7SAndroid Build Coastguard Workerstatic class AlwaysSerializeNullsFactory implements JsonAdapter.Factory {
973*238ab3e7SAndroid Build Coastguard Worker  @Override public JsonAdapter<?> create(
974*238ab3e7SAndroid Build Coastguard Worker      Type type, Set<? extends Annotation> annotations, Moshi moshi) {
975*238ab3e7SAndroid Build Coastguard Worker    Class<?> rawType = Types.getRawType(type);
976*238ab3e7SAndroid Build Coastguard Worker    if (!rawType.isAnnotationPresent(AlwaysSerializeNulls.class)) {
977*238ab3e7SAndroid Build Coastguard Worker      return null;
978*238ab3e7SAndroid Build Coastguard Worker    }
979*238ab3e7SAndroid Build Coastguard Worker
980*238ab3e7SAndroid Build Coastguard Worker    JsonAdapter<Object> delegate = moshi.nextAdapter(this, type, annotations);
981*238ab3e7SAndroid Build Coastguard Worker    return delegate.serializeNulls();
982*238ab3e7SAndroid Build Coastguard Worker  }
983*238ab3e7SAndroid Build Coastguard Worker}
984*238ab3e7SAndroid Build Coastguard Worker```
985*238ab3e7SAndroid Build Coastguard Worker</details>
986*238ab3e7SAndroid Build Coastguard Worker
987*238ab3e7SAndroid Build Coastguard Worker<details>
988*238ab3e7SAndroid Build Coastguard Worker    <summary>Kotlin</summary>
989*238ab3e7SAndroid Build Coastguard Worker
990*238ab3e7SAndroid Build Coastguard Worker```kotlin
991*238ab3e7SAndroid Build Coastguard Workerclass AlwaysSerializeNullsFactory : JsonAdapter.Factory {
992*238ab3e7SAndroid Build Coastguard Worker  override fun create(type: Type, annotations: Set<Annotation>, moshi: Moshi): JsonAdapter<*>? {
993*238ab3e7SAndroid Build Coastguard Worker    val rawType: Class<*> = type.rawType
994*238ab3e7SAndroid Build Coastguard Worker    if (!rawType.isAnnotationPresent(AlwaysSerializeNulls::class.java)) {
995*238ab3e7SAndroid Build Coastguard Worker      return null
996*238ab3e7SAndroid Build Coastguard Worker    }
997*238ab3e7SAndroid Build Coastguard Worker    val delegate: JsonAdapter<Any> = moshi.nextAdapter(this, type, annotations)
998*238ab3e7SAndroid Build Coastguard Worker    return delegate.serializeNulls()
999*238ab3e7SAndroid Build Coastguard Worker  }
1000*238ab3e7SAndroid Build Coastguard Worker}
1001*238ab3e7SAndroid Build Coastguard Worker```
1002*238ab3e7SAndroid Build Coastguard Worker</details>
1003*238ab3e7SAndroid Build Coastguard Worker
1004*238ab3e7SAndroid Build Coastguard WorkerAfter determining that it applies, the factory looks up Moshi's built-in adapter by calling
1005*238ab3e7SAndroid Build Coastguard Worker`Moshi.nextAdapter()`. This is key to the composition mechanism: adapters delegate to each other!
1006*238ab3e7SAndroid Build Coastguard WorkerThe composition in this example is simple: it applies the `serializeNulls()` transform on the
1007*238ab3e7SAndroid Build Coastguard Workerdelegate.
1008*238ab3e7SAndroid Build Coastguard Worker
1009*238ab3e7SAndroid Build Coastguard WorkerComposing adapters can be very sophisticated:
1010*238ab3e7SAndroid Build Coastguard Worker
1011*238ab3e7SAndroid Build Coastguard Worker * An adapter could transform the input object before it is JSON-encoded. A string could be
1012*238ab3e7SAndroid Build Coastguard Worker   trimmed or truncated; a value object could be simplified or normalized.
1013*238ab3e7SAndroid Build Coastguard Worker
1014*238ab3e7SAndroid Build Coastguard Worker * An adapter could repair the output object after it is JSON-decoded. It could fill-in missing
1015*238ab3e7SAndroid Build Coastguard Worker   data or discard unwanted data.
1016*238ab3e7SAndroid Build Coastguard Worker
1017*238ab3e7SAndroid Build Coastguard Worker * The JSON could be given extra structure, such as wrapping values in objects or arrays.
1018*238ab3e7SAndroid Build Coastguard Worker
1019*238ab3e7SAndroid Build Coastguard WorkerMoshi is itself built on the pattern of repeatedly composing adapters. For example, Moshi's built-in
1020*238ab3e7SAndroid Build Coastguard Workeradapter for `List<T>` delegates to the adapter of `T`, and calls it repeatedly.
1021*238ab3e7SAndroid Build Coastguard Worker
1022*238ab3e7SAndroid Build Coastguard Worker### Precedence
1023*238ab3e7SAndroid Build Coastguard Worker
1024*238ab3e7SAndroid Build Coastguard WorkerMoshi's composition mechanism tries to find the best adapter for each type. It starts with the first
1025*238ab3e7SAndroid Build Coastguard Workeradapter or factory registered with `Moshi.Builder.add()`, and proceeds until it finds an adapter for
1026*238ab3e7SAndroid Build Coastguard Workerthe target type.
1027*238ab3e7SAndroid Build Coastguard Worker
1028*238ab3e7SAndroid Build Coastguard WorkerIf a type can be matched multiple adapters, the earliest one wins.
1029*238ab3e7SAndroid Build Coastguard Worker
1030*238ab3e7SAndroid Build Coastguard WorkerTo register an adapter at the end of the list, use `Moshi.Builder.addLast()` instead. This is most
1031*238ab3e7SAndroid Build Coastguard Workeruseful when registering general-purpose adapters, such as the `KotlinJsonAdapterFactory` below.
1032*238ab3e7SAndroid Build Coastguard Worker
1033*238ab3e7SAndroid Build Coastguard WorkerKotlin
1034*238ab3e7SAndroid Build Coastguard Worker------
1035*238ab3e7SAndroid Build Coastguard Worker
1036*238ab3e7SAndroid Build Coastguard WorkerMoshi is a great JSON library for Kotlin. It understands Kotlin’s non-nullable types and default
1037*238ab3e7SAndroid Build Coastguard Workerparameter values. When you use Kotlin with Moshi you may use reflection, codegen, or both.
1038*238ab3e7SAndroid Build Coastguard Worker
1039*238ab3e7SAndroid Build Coastguard Worker#### Reflection
1040*238ab3e7SAndroid Build Coastguard Worker
1041*238ab3e7SAndroid Build Coastguard WorkerThe reflection adapter uses Kotlin’s reflection library to convert your Kotlin classes to and from
1042*238ab3e7SAndroid Build Coastguard WorkerJSON. Enable it by adding the `KotlinJsonAdapterFactory` to your `Moshi.Builder`:
1043*238ab3e7SAndroid Build Coastguard Worker
1044*238ab3e7SAndroid Build Coastguard Worker```kotlin
1045*238ab3e7SAndroid Build Coastguard Workerval moshi = Moshi.Builder()
1046*238ab3e7SAndroid Build Coastguard Worker    .addLast(KotlinJsonAdapterFactory())
1047*238ab3e7SAndroid Build Coastguard Worker    .build()
1048*238ab3e7SAndroid Build Coastguard Worker```
1049*238ab3e7SAndroid Build Coastguard Worker
1050*238ab3e7SAndroid Build Coastguard WorkerMoshi’s adapters are ordered by precedence, so you should use `addLast()` with
1051*238ab3e7SAndroid Build Coastguard Worker`KotlinJsonAdapterFactory`, and `add()` with your custom adapters.
1052*238ab3e7SAndroid Build Coastguard Worker
1053*238ab3e7SAndroid Build Coastguard WorkerThe reflection adapter requires the following additional dependency:
1054*238ab3e7SAndroid Build Coastguard Worker
1055*238ab3e7SAndroid Build Coastguard Worker```xml
1056*238ab3e7SAndroid Build Coastguard Worker<dependency>
1057*238ab3e7SAndroid Build Coastguard Worker  <groupId>com.squareup.moshi</groupId>
1058*238ab3e7SAndroid Build Coastguard Worker  <artifactId>moshi-kotlin</artifactId>
1059*238ab3e7SAndroid Build Coastguard Worker  <version>1.12.0</version>
1060*238ab3e7SAndroid Build Coastguard Worker</dependency>
1061*238ab3e7SAndroid Build Coastguard Worker```
1062*238ab3e7SAndroid Build Coastguard Worker
1063*238ab3e7SAndroid Build Coastguard Worker```kotlin
1064*238ab3e7SAndroid Build Coastguard Workerimplementation("com.squareup.moshi:moshi-kotlin:1.13.0")
1065*238ab3e7SAndroid Build Coastguard Worker```
1066*238ab3e7SAndroid Build Coastguard Worker
1067*238ab3e7SAndroid Build Coastguard WorkerNote that the reflection adapter transitively depends on the `kotlin-reflect` library which is a
1068*238ab3e7SAndroid Build Coastguard Worker2.5 MiB .jar file.
1069*238ab3e7SAndroid Build Coastguard Worker
1070*238ab3e7SAndroid Build Coastguard Worker#### Codegen
1071*238ab3e7SAndroid Build Coastguard Worker
1072*238ab3e7SAndroid Build Coastguard WorkerMoshi’s Kotlin codegen support is an annotation processor. It generates a small and fast adapter for
1073*238ab3e7SAndroid Build Coastguard Workereach of your Kotlin classes at compile time. Enable it by annotating each class that you want to
1074*238ab3e7SAndroid Build Coastguard Workerencode as JSON:
1075*238ab3e7SAndroid Build Coastguard Worker
1076*238ab3e7SAndroid Build Coastguard Worker```kotlin
1077*238ab3e7SAndroid Build Coastguard Worker@JsonClass(generateAdapter = true)
1078*238ab3e7SAndroid Build Coastguard Workerdata class BlackjackHand(
1079*238ab3e7SAndroid Build Coastguard Worker  val hidden_card: Card,
1080*238ab3e7SAndroid Build Coastguard Worker  val visible_cards: List<Card>
1081*238ab3e7SAndroid Build Coastguard Worker)
1082*238ab3e7SAndroid Build Coastguard Worker```
1083*238ab3e7SAndroid Build Coastguard Worker
1084*238ab3e7SAndroid Build Coastguard WorkerThe codegen adapter requires that your Kotlin types and their properties be either `internal` or
1085*238ab3e7SAndroid Build Coastguard Worker`public` (this is Kotlin’s default visibility).
1086*238ab3e7SAndroid Build Coastguard Worker
1087*238ab3e7SAndroid Build Coastguard WorkerKotlin codegen has no additional runtime dependency. You’ll need to [enable kapt][kapt] and then
1088*238ab3e7SAndroid Build Coastguard Workeradd the following to your build to enable the annotation processor:
1089*238ab3e7SAndroid Build Coastguard Worker
1090*238ab3e7SAndroid Build Coastguard Worker```xml
1091*238ab3e7SAndroid Build Coastguard Worker<dependency>
1092*238ab3e7SAndroid Build Coastguard Worker  <groupId>com.squareup.moshi</groupId>
1093*238ab3e7SAndroid Build Coastguard Worker  <artifactId>moshi-kotlin-codegen</artifactId>
1094*238ab3e7SAndroid Build Coastguard Worker  <version>1.12.0</version>
1095*238ab3e7SAndroid Build Coastguard Worker  <scope>provided</scope>
1096*238ab3e7SAndroid Build Coastguard Worker</dependency>
1097*238ab3e7SAndroid Build Coastguard Worker```
1098*238ab3e7SAndroid Build Coastguard Worker
1099*238ab3e7SAndroid Build Coastguard Worker```kotlin
1100*238ab3e7SAndroid Build Coastguard Workerkapt("com.squareup.moshi:moshi-kotlin-codegen:1.13.0")
1101*238ab3e7SAndroid Build Coastguard Worker```
1102*238ab3e7SAndroid Build Coastguard Worker
1103*238ab3e7SAndroid Build Coastguard WorkerYou must also have the `kotlin-stdlib` dependency on the classpath during compilation in order for
1104*238ab3e7SAndroid Build Coastguard Workerthe compiled code to have the required metadata annotations that Moshi's processor looks for.
1105*238ab3e7SAndroid Build Coastguard Worker
1106*238ab3e7SAndroid Build Coastguard Worker#### Limitations
1107*238ab3e7SAndroid Build Coastguard Worker
1108*238ab3e7SAndroid Build Coastguard WorkerIf your Kotlin class has a superclass, it must also be a Kotlin class. Neither reflection or codegen
1109*238ab3e7SAndroid Build Coastguard Workersupport Kotlin types with Java supertypes or Java types with Kotlin supertypes. If you need to
1110*238ab3e7SAndroid Build Coastguard Workerconvert such classes to JSON you must create a custom type adapter.
1111*238ab3e7SAndroid Build Coastguard Worker
1112*238ab3e7SAndroid Build Coastguard WorkerThe JSON encoding of Kotlin types is the same whether using reflection or codegen. Prefer codegen
1113*238ab3e7SAndroid Build Coastguard Workerfor better performance and to avoid the `kotlin-reflect` dependency; prefer reflection to convert
1114*238ab3e7SAndroid Build Coastguard Workerboth private and protected properties. If you have configured both, generated adapters will be used
1115*238ab3e7SAndroid Build Coastguard Workeron types that are annotated `@JsonClass(generateAdapter = true)`.
1116*238ab3e7SAndroid Build Coastguard Worker
1117*238ab3e7SAndroid Build Coastguard WorkerDownload
1118*238ab3e7SAndroid Build Coastguard Worker--------
1119*238ab3e7SAndroid Build Coastguard Worker
1120*238ab3e7SAndroid Build Coastguard WorkerDownload [the latest JAR][dl] or depend via Maven:
1121*238ab3e7SAndroid Build Coastguard Worker
1122*238ab3e7SAndroid Build Coastguard Worker```xml
1123*238ab3e7SAndroid Build Coastguard Worker<dependency>
1124*238ab3e7SAndroid Build Coastguard Worker  <groupId>com.squareup.moshi</groupId>
1125*238ab3e7SAndroid Build Coastguard Worker  <artifactId>moshi</artifactId>
1126*238ab3e7SAndroid Build Coastguard Worker  <version>1.12.0</version>
1127*238ab3e7SAndroid Build Coastguard Worker</dependency>
1128*238ab3e7SAndroid Build Coastguard Worker```
1129*238ab3e7SAndroid Build Coastguard Workeror Gradle:
1130*238ab3e7SAndroid Build Coastguard Worker```kotlin
1131*238ab3e7SAndroid Build Coastguard Workerimplementation("com.squareup.moshi:moshi:1.13.0")
1132*238ab3e7SAndroid Build Coastguard Worker```
1133*238ab3e7SAndroid Build Coastguard Worker
1134*238ab3e7SAndroid Build Coastguard WorkerSnapshots of the development version are available in [Sonatype's `snapshots` repository][snap].
1135*238ab3e7SAndroid Build Coastguard Worker
1136*238ab3e7SAndroid Build Coastguard Worker
1137*238ab3e7SAndroid Build Coastguard WorkerR8 / ProGuard
1138*238ab3e7SAndroid Build Coastguard Worker--------
1139*238ab3e7SAndroid Build Coastguard Worker
1140*238ab3e7SAndroid Build Coastguard WorkerMoshi contains minimally required rules for its own internals to work without need for consumers to embed their own. However if you are using reflective serialization and R8 or ProGuard, you must add keep rules in your proguard configuration file for your reflectively serialized classes.
1141*238ab3e7SAndroid Build Coastguard Worker
1142*238ab3e7SAndroid Build Coastguard Worker#### Enums
1143*238ab3e7SAndroid Build Coastguard Worker
1144*238ab3e7SAndroid Build Coastguard WorkerAnnotate enums with `@JsonClass(generateAdapter = false)` to prevent them from being removed/obfuscated from your code by R8/ProGuard.
1145*238ab3e7SAndroid Build Coastguard Worker
1146*238ab3e7SAndroid Build Coastguard WorkerLicense
1147*238ab3e7SAndroid Build Coastguard Worker--------
1148*238ab3e7SAndroid Build Coastguard Worker
1149*238ab3e7SAndroid Build Coastguard Worker    Copyright 2015 Square, Inc.
1150*238ab3e7SAndroid Build Coastguard Worker
1151*238ab3e7SAndroid Build Coastguard Worker    Licensed under the Apache License, Version 2.0 (the "License");
1152*238ab3e7SAndroid Build Coastguard Worker    you may not use this file except in compliance with the License.
1153*238ab3e7SAndroid Build Coastguard Worker    You may obtain a copy of the License at
1154*238ab3e7SAndroid Build Coastguard Worker
1155*238ab3e7SAndroid Build Coastguard Worker       http://www.apache.org/licenses/LICENSE-2.0
1156*238ab3e7SAndroid Build Coastguard Worker
1157*238ab3e7SAndroid Build Coastguard Worker    Unless required by applicable law or agreed to in writing, software
1158*238ab3e7SAndroid Build Coastguard Worker    distributed under the License is distributed on an "AS IS" BASIS,
1159*238ab3e7SAndroid Build Coastguard Worker    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1160*238ab3e7SAndroid Build Coastguard Worker    See the License for the specific language governing permissions and
1161*238ab3e7SAndroid Build Coastguard Worker    limitations under the License.
1162*238ab3e7SAndroid Build Coastguard Worker
1163*238ab3e7SAndroid Build Coastguard Worker
1164*238ab3e7SAndroid Build Coastguard Worker [dl]: https://search.maven.org/classic/remote_content?g=com.squareup.moshi&a=moshi&v=LATEST
1165*238ab3e7SAndroid Build Coastguard Worker [snap]: https://oss.sonatype.org/content/repositories/snapshots/com/squareup/moshi/
1166*238ab3e7SAndroid Build Coastguard Worker [okio]: https://github.com/square/okio/
1167*238ab3e7SAndroid Build Coastguard Worker [okhttp]: https://github.com/square/okhttp/
1168*238ab3e7SAndroid Build Coastguard Worker [gson]: https://github.com/google/gson/
1169*238ab3e7SAndroid Build Coastguard Worker [javadoc]: https://square.github.io/moshi/1.x/moshi/
1170*238ab3e7SAndroid Build Coastguard Worker [kapt]: https://kotlinlang.org/docs/reference/kapt.html
1171