diff --git a/moshi/src/main/java/com/squareup/moshi/JsonReader.java b/moshi/src/main/java/com/squareup/moshi/JsonReader.java index a2c06c3..fb908ce 100644 --- a/moshi/src/main/java/com/squareup/moshi/JsonReader.java +++ b/moshi/src/main/java/com/squareup/moshi/JsonReader.java @@ -17,6 +17,9 @@ package com.squareup.moshi; import java.io.Closeable; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; import okio.Buffer; import okio.BufferedSource; import okio.ByteString; @@ -390,6 +393,57 @@ public abstract class JsonReader implements Closeable { */ public abstract void skipValue() throws IOException; + /** + * Returns the value of the next token, consuming it. The result may be a string, number, boolean, + * null, map, or list, according to the JSON structure. + * + * @throws JsonDataException if the next token is not a literal value, if a JSON object has a + * duplicate key. + */ + public final Object readJsonValue() throws IOException { + switch (peek()) { + case BEGIN_ARRAY: + List list = new ArrayList<>(); + beginArray(); + while (hasNext()) { + list.add(readJsonValue()); + } + endArray(); + return list; + + case BEGIN_OBJECT: + Map map = new LinkedHashTreeMap<>(); + beginObject(); + while (hasNext()) { + String name = nextName(); + Object value = readJsonValue(); + Object replaced = map.put(name, value); + if (replaced != null) { + throw new JsonDataException("Map key '" + name + "' has multiple values at path " + + getPath() + ": " + replaced + " and " + value); + } + } + endObject(); + return map; + + case STRING: + return nextString(); + + case NUMBER: + return nextDouble(); + + case BOOLEAN: + return nextBoolean(); + + case NULL: + return nextNull(); + + default: + throw new IllegalStateException( + "Expected a value but was " + peek() + " at path " + getPath()); + } + } + /** * Returns a JsonPath to * the current location in the JSON value. diff --git a/moshi/src/main/java/com/squareup/moshi/StandardJsonAdapters.java b/moshi/src/main/java/com/squareup/moshi/StandardJsonAdapters.java index 034c5d6..6c8b77b 100644 --- a/moshi/src/main/java/com/squareup/moshi/StandardJsonAdapters.java +++ b/moshi/src/main/java/com/squareup/moshi/StandardJsonAdapters.java @@ -18,11 +18,8 @@ package com.squareup.moshi; import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.reflect.Type; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.LinkedHashMap; -import java.util.List; import java.util.Map; import java.util.Set; @@ -272,47 +269,7 @@ final class StandardJsonAdapters { } @Override public Object fromJson(JsonReader reader) throws IOException { - switch (reader.peek()) { - case BEGIN_ARRAY: - List list = new ArrayList<>(); - reader.beginArray(); - while (reader.hasNext()) { - list.add(fromJson(reader)); - } - reader.endArray(); - return list; - - case BEGIN_OBJECT: - Map map = new LinkedHashTreeMap<>(); - reader.beginObject(); - while (reader.hasNext()) { - String name = reader.nextName(); - Object value = fromJson(reader); - Object replaced = map.put(name, value); - if (replaced != null) { - throw new JsonDataException("Map key '" + name + "' has multiple values at path " - + reader.getPath() + ": " + replaced + " and " + value); - } - } - reader.endObject(); - return map; - - case STRING: - return reader.nextString(); - - case NUMBER: - return reader.nextDouble(); - - case BOOLEAN: - return reader.nextBoolean(); - - case NULL: - return reader.nextNull(); - - default: - throw new IllegalStateException("Expected a value but was " + reader.peek() - + " at path " + reader.getPath()); - } + return reader.readJsonValue(); } @Override public void toJson(JsonWriter writer, Object value) throws IOException { diff --git a/moshi/src/test/java/com/squareup/moshi/JsonReaderTest.java b/moshi/src/test/java/com/squareup/moshi/JsonReaderTest.java index bfb5664..dbb0d62 100644 --- a/moshi/src/test/java/com/squareup/moshi/JsonReaderTest.java +++ b/moshi/src/test/java/com/squareup/moshi/JsonReaderTest.java @@ -17,6 +17,8 @@ package com.squareup.moshi; import java.io.EOFException; import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; @@ -912,4 +914,35 @@ public final class JsonReaderTest { assertThat(reader.nextString()).isEqualTo("a"); reader.endArray(); } + + @Test public void readJsonValueInt() throws IOException { + JsonReader reader = newReader("1"); + Object value = reader.readJsonValue(); + assertThat(value).isEqualTo(1.0); + } + + @Test public void readJsonValueMap() throws IOException { + JsonReader reader = newReader("{\"hello\": \"world\"}"); + Object value = reader.readJsonValue(); + assertThat(value).isEqualTo(Collections.singletonMap("hello", "world")); + } + + @Test public void readJsonValueList() throws IOException { + JsonReader reader = newReader("[\"a\", \"b\"]"); + Object value = reader.readJsonValue(); + assertThat(value).isEqualTo(Arrays.asList("a", "b")); + } + + @Test public void readJsonValueListMultipleTypes() throws IOException { + JsonReader reader = newReader("[\"a\", 5, false]"); + Object value = reader.readJsonValue(); + assertThat(value).isEqualTo(Arrays.asList("a", 5.0, false)); + } + + @Test public void readJsonValueNestedListInMap() throws IOException { + JsonReader reader = newReader("{\"pizzas\": [\"cheese\", \"pepperoni\"]}"); + Object value = reader.readJsonValue(); + assertThat(value).isEqualTo( + Collections.singletonMap("pizzas", Arrays.asList("cheese", "pepperoni"))); + } }