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