From 19c41eb18f3ec4933dc1224f22f5ae7e93ce0a67 Mon Sep 17 00:00:00 2001 From: David Mihola Date: Thu, 8 Oct 2015 09:38:09 +0200 Subject: [PATCH] Add recipe for `@FromJson` with non-String input. --- README.md | 76 ++++++++++++ .../moshi/recipes/CustomJsonAdapter.java | 117 ------------------ .../moshi/recipes/FromJsonWithoutStrings.java | 90 ++++++++++++++ 3 files changed, 166 insertions(+), 117 deletions(-) delete mode 100644 examples/src/main/java/com/squareup/moshi/recipes/CustomJsonAdapter.java create mode 100644 examples/src/main/java/com/squareup/moshi/recipes/FromJsonWithoutStrings.java diff --git a/README.md b/README.md index 04c704f..b107c7c 100644 --- a/README.md +++ b/README.md @@ -132,6 +132,82 @@ Voila: } ``` +Note that the method annotated with `@FromJson` does not need to take a String as an argument. Rather it can take +input of any type and Moshi will first parse the JSON to an object of that type and then use the `@FromJson` +method to produce the desired final value. Conversely, the method annotated with `@ToJson` does not have to produce +a String. + +Assume, for example, that we have to parse a JSON in which the date and time of an event are represented as two +separate strings. + +```json +{ + "title": "Blackjack tournament", + "begin_date": "20151010", + "begin_time": "17:04" +} +``` + +We would like to combine these two fields into one string to facilitate the date parsing at a +later point. That is, while the `EventJson` class corresponds to the JSON structure directly, we would rather +have an `Event` that looks like below (while we are at it, we are also changing the variable names to +CamelCase). + +```java +class EventJson { + String title; + String begin_date; + String begin_time; +} + +class Event { + String title; + String beginDateAndTime; +} + +``` + +To enable Moshi to do that transformation automatically we define a class with the `@FromJson` +(and `@ToJson`) methods: + +```java +class EventJsonAdapter { + + @FromJson + Event eventFromJson(EventJson eventJson) { + Event event = new Event(); + event.title = eventJson.title; + event.beginDateAndTime = eventJson.begin_date + " " + eventJson.begin_time; + return event; + } + + @ToJson + EventJson eventToJson(Event event) { + EventJson json = new EventJson(); + json.title = event.title; + json.begin_date = event.beginDateAndTime.substring(0, 8); + json.begin_time = event.beginDateAndTime.substring(9, 14); + return json; + } + +} +``` + +And register it with Moshi. + +```java +Moshi moshi = new Moshi.Builder() + .add(new EventJsonAdapter()) + .build(); +``` + +We can now use Moshi to parse the JSON directly to an `Event`. + +```java +JsonAdapter jsonAdapter = moshi.adapter(Event.class); +Event event = jsonAdapter.fromJson(json); +``` + ### Fails Gracefully Automatic databinding almost feels like magic. But unlike the black magic that typically accompanies diff --git a/examples/src/main/java/com/squareup/moshi/recipes/CustomJsonAdapter.java b/examples/src/main/java/com/squareup/moshi/recipes/CustomJsonAdapter.java deleted file mode 100644 index 2d24a96..0000000 --- a/examples/src/main/java/com/squareup/moshi/recipes/CustomJsonAdapter.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2015 Square, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.squareup.moshi.recipes; - -import com.squareup.moshi.JsonAdapter; -import com.squareup.moshi.JsonReader; -import com.squareup.moshi.JsonWriter; -import com.squareup.moshi.Moshi; - -import java.io.IOException; - -public final class CustomJsonAdapter { - - public void run() throws Exception { - // for some reason our JSON has date and time as separate fields - - // we will use a custom JsonAdapter to clean that up during parsing - String json = "" - + "{\n" - + " \"title\": \"Blackjack tournament\",\n" - + " \"beginDate\": \"20151006\",\n" - + " \"beginTime\": \"15:59\"\n" - + "}\n"; - - Moshi moshi = new Moshi.Builder() - .add(Event.class, new EventAdapter()) - .build(); - JsonAdapter jsonAdapter = moshi.adapter(Event.class); - - Event event = jsonAdapter.fromJson(json); - System.out.println(event); - System.out.println(jsonAdapter.toJson(event)); - } - - public static void main(String[] args) throws Exception { - new CustomJsonAdapter().run(); - } - - public static final class EventAdapter extends JsonAdapter { - @Override - public Event fromJson(JsonReader jsonReader) throws IOException { - String title = null; - String beginDate = null; - String beginTime = null; - - jsonReader.beginObject(); - while (jsonReader.hasNext()) { - String name = jsonReader.nextName(); - if (name.equals("title")) { - title = jsonReader.nextString(); - } else if (name.equals("beginDate")) { - beginDate = jsonReader.nextString(); - } else if (name.equals("beginTime")) { - beginTime = jsonReader.nextString(); - } else { - jsonReader.skipValue(); - } - } - jsonReader.endObject(); - - final String beginDateAndTime = (beginDate != null) && (beginTime != null) ? - beginDate + " " + beginTime : null; - - return new Event(title, beginDateAndTime); - } - - @Override - public void toJson(JsonWriter jsonWriter, Event event) throws IOException { - jsonWriter.beginObject(); - - if (event.title != null) { - jsonWriter.name("title"); - jsonWriter.value(event.title); - } - - if (event.beginDateAndTime != null) { - jsonWriter.name("beginDate"); - jsonWriter.value(event.beginDateAndTime.substring(0, 8)); - - jsonWriter.name("beginTime"); - jsonWriter.value(event.beginDateAndTime.substring(9, 14)); - } - - jsonWriter.endObject(); - } - } - - public static final class Event { - public final String title; - public final String beginDateAndTime; - - public Event(String title, String beginDateAndTime) { - this.title = title; - this.beginDateAndTime = beginDateAndTime; - } - - @Override - public String toString() { - return "Event{" + - "title='" + title + '\'' + - ", beginDateAndTime=" + beginDateAndTime + - '}'; - } - } -} diff --git a/examples/src/main/java/com/squareup/moshi/recipes/FromJsonWithoutStrings.java b/examples/src/main/java/com/squareup/moshi/recipes/FromJsonWithoutStrings.java new file mode 100644 index 0000000..e2f40f0 --- /dev/null +++ b/examples/src/main/java/com/squareup/moshi/recipes/FromJsonWithoutStrings.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2015 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.squareup.moshi.recipes; + +import com.squareup.moshi.FromJson; +import com.squareup.moshi.JsonAdapter; +import com.squareup.moshi.Moshi; +import com.squareup.moshi.ToJson; + +public final class FromJsonWithoutStrings { + + public void run() throws Exception { + // for some reason our JSON has date and time as separate fields - + // we will clean that up during parsing: Moshi will first parse + // the JSON directly to an EventJson and from that the EventJsonAdapter + // will create the actual Event + String json = "" + + "{\n" + + " \"title\": \"Blackjack tournament\",\n" + + " \"begin_date\": \"20151010\",\n" + + " \"begin_time\": \"17:04\"\n" + + "}\n"; + + Moshi moshi = new Moshi.Builder() + .add(new EventJsonAdapter()) + .build(); + JsonAdapter jsonAdapter = moshi.adapter(Event.class); + + Event event = jsonAdapter.fromJson(json); + System.out.println(event); + System.out.println(jsonAdapter.toJson(event)); + } + + public static void main(String[] args) throws Exception { + new FromJsonWithoutStrings().run(); + } + + private static final class EventJson { + String title; + String begin_date; + String begin_time; + } + + public static final class Event { + String title; + String beginDateAndTime; + + @Override + public String toString() { + return "Event{" + + "title='" + title + '\'' + + ", beginDateAndTime='" + beginDateAndTime + '\'' + + '}'; + } + } + + private static final class EventJsonAdapter { + + @FromJson + Event eventFromJson(EventJson eventJson) { + Event event = new Event(); + event.title = eventJson.title; + event.beginDateAndTime = eventJson.begin_date + " " + eventJson.begin_time; + return event; + } + + @ToJson + EventJson eventToJson(Event event) { + EventJson json = new EventJson(); + json.title = event.title; + json.begin_date = event.beginDateAndTime.substring(0, 8); + json.begin_time = event.beginDateAndTime.substring(9, 14); + return json; + } + + } +}