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