Name Date Size #Lines LOC

..--

.github/H25-Apr-2025-10277

examples/H25-Apr-2025-1,630992

gradle/H25-Apr-2025-6458

kotlin/tests/H25-Apr-2025-4,1943,148

moshi/H25-Apr-2025-21,93716,763

moshi-adapters/H25-Apr-2025-1,5671,043

moshi-kotlin/H25-Apr-2025-438304

moshi-kotlin-codegen/H25-Apr-2025-5,2864,108

.editorconfigH A D25-Apr-2025154 118

.gitattributesH A D25-Apr-202552 43

.gitignoreH A D25-Apr-2025232 3123

Android.bpH A D25-Apr-20251.4 KiB5046

CHANGELOG.mdH A D25-Apr-202525.2 KiB545426

CONTRIBUTING.mdH A D25-Apr-2025676 1711

LICENSEH A D25-Apr-202511.1 KiB203169

LICENSE.txtH A D25-Apr-202511.1 KiB203169

METADATAH A D25-Apr-2025393 2018

MODULE_LICENSE_APACHE2HD25-Apr-20250

OWNERSH A D25-Apr-202551 21

README.mdH A D25-Apr-202529.2 KiB1,171906

build.gradle.ktsH A D25-Apr-20254.9 KiB173141

deploy_javadoc.shH A D25-Apr-2025785 4219

gradle.propertiesH A D25-Apr-20251.1 KiB2724

gradlewH A D25-Apr-20257.9 KiB23598

gradlew.batH A D25-Apr-20252.7 KiB9068

releasing.mdH A D25-Apr-20251.6 KiB6244

settings.gradle.ktsH A D25-Apr-20251.1 KiB3819

README.md

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