public abstract class JsonReader extends Object implements Closeable
JsonReader
.
Next, create handler methods for each structure in your JSON text. You'll need a method for each object type and for each array type.
beginArray()
to consume the array's opening bracket. Then create a
while loop that accumulates values, terminating when hasNext()
is false. Finally, read the array's closing bracket by calling endArray()
.
beginObject()
to consume the object's opening brace. Then create a
while loop that assigns values to local variables based on their name.
This loop should terminate when hasNext()
is false. Finally,
read the object's closing brace by calling endObject()
.
When a nested object or array is encountered, delegate to the corresponding handler method.
When an unknown name is encountered, strict parsers should fail with an
exception. Lenient parsers should call skipValue()
to recursively
skip the value's nested tokens, which may otherwise conflict.
If a value may be null, you should first check using peek()
.
Null literals can be consumed using either nextNull()
or skipValue()
.
[
{
"id": 912345678901,
"text": "How do I read a JSON stream in Java?",
"geo": null,
"user": {
"name": "json_newb",
"followers_count": 41
}
},
{
"id": 912345678902,
"text": "@json_newb just use JsonReader!",
"geo": [50.454722, -104.606667],
"user": {
"name": "jesse",
"followers_count": 2
}
}
]
This code implements the parser for the above structure:
public List<Message> readJsonStream(BufferedSource source) throws IOException {
JsonReader reader = JsonReader.of(source);
try {
return readMessagesArray(reader);
} finally {
reader.close();
}
}
public List<Message> readMessagesArray(JsonReader reader) throws IOException {
List<Message> messages = new ArrayList<Message>();
reader.beginArray();
while (reader.hasNext()) {
messages.add(readMessage(reader));
}
reader.endArray();
return messages;
}
public Message readMessage(JsonReader reader) throws IOException {
long id = -1;
String text = null;
User user = null;
List<Double> geo = null;
reader.beginObject();
while (reader.hasNext()) {
String name = reader.nextName();
if (name.equals("id")) {
id = reader.nextLong();
} else if (name.equals("text")) {
text = reader.nextString();
} else if (name.equals("geo") && reader.peek() != Token.NULL) {
geo = readDoublesArray(reader);
} else if (name.equals("user")) {
user = readUser(reader);
} else {
reader.skipValue();
}
}
reader.endObject();
return new Message(id, text, user, geo);
}
public List<Double> readDoublesArray(JsonReader reader) throws IOException {
List<Double> doubles = new ArrayList<Double>();
reader.beginArray();
while (reader.hasNext()) {
doubles.add(reader.nextDouble());
}
reader.endArray();
return doubles;
}
public User readUser(JsonReader reader) throws IOException {
String username = null;
int followersCount = -1;
reader.beginObject();
while (reader.hasNext()) {
String name = reader.nextName();
if (name.equals("name")) {
username = reader.nextString();
} else if (name.equals("followers_count")) {
followersCount = reader.nextInt();
} else {
reader.skipValue();
}
}
reader.endObject();
return new User(username, followersCount);
}
[1, "1"]
may be read using either nextInt()
or nextString()
.
This behavior is intended to prevent lossy numeric conversions: double is
JavaScript's only numeric type and very large values like 9007199254740993
cannot be represented exactly on that platform. To minimize
precision loss, extremely large values should be written and read as strings
in JSON.
Each JsonReader
may be used to read a single JSON stream. Instances
of this class are not thread safe.
Modifier and Type | Class and Description |
---|---|
static class |
JsonReader.Options
A set of strings to be chosen with
selectName(com.squareup.moshi.JsonReader.Options) or selectString(com.squareup.moshi.JsonReader.Options) . |
static class |
JsonReader.Token
A structure, name, or value type in a JSON-encoded string.
|
Modifier and Type | Method and Description |
---|---|
abstract void |
beginArray()
Consumes the next token from the JSON stream and asserts that it is the beginning of a new
array.
|
abstract void |
beginObject()
Consumes the next token from the JSON stream and asserts that it is the beginning of a new
object.
|
abstract void |
endArray()
Consumes the next token from the JSON stream and asserts that it is the
end of the current array.
|
abstract void |
endObject()
Consumes the next token from the JSON stream and asserts that it is the end of the current
object.
|
boolean |
failOnUnknown()
Returns true if this parser forbids skipping names and values.
|
String |
getPath()
Returns a JsonPath to
the current location in the JSON value.
|
abstract boolean |
hasNext()
Returns true if the current array or object has another element.
|
boolean |
isLenient()
Returns true if this parser is liberal in what it accepts.
|
abstract boolean |
nextBoolean()
Returns the boolean value of the next token, consuming it.
|
abstract double |
nextDouble()
Returns the double value of the next token, consuming it.
|
abstract int |
nextInt()
Returns the int value of the next token, consuming it.
|
abstract long |
nextLong()
Returns the long value of the next token, consuming it.
|
abstract String |
nextName()
Returns the next token, a property name, and consumes it.
|
abstract <T> T |
nextNull()
Consumes the next token from the JSON stream and asserts that it is a literal null.
|
abstract String |
nextString()
Returns the string value of the next token, consuming it.
|
static JsonReader |
of(okio.BufferedSource source)
Returns a new instance that reads UTF-8 encoded JSON from
source . |
abstract JsonReader.Token |
peek()
Returns the type of the next token without consuming it.
|
abstract JsonReader |
peekJson()
Returns a new
JsonReader that can read data from this JsonReader without
consuming it. |
Object |
readJsonValue()
Returns the value of the next token, consuming it.
|
abstract int |
selectName(JsonReader.Options options)
If the next token is a property name that's in
options , this
consumes it and returns its index. |
abstract int |
selectString(JsonReader.Options options)
If the next token is a string that's in
options , this
consumes it and returns its index. |
void |
setFailOnUnknown(boolean failOnUnknown)
Configure whether this parser throws a
JsonDataException when skipValue() is
called. |
void |
setLenient(boolean lenient)
Configure this parser to be liberal in what it accepts.
|
abstract void |
skipName()
Skips the next token, consuming it.
|
abstract void |
skipValue()
Skips the next value recursively.
|
@CheckReturnValue public static JsonReader of(okio.BufferedSource source)
source
.public final void setLenient(boolean lenient)
infinities
.
//
or #
and
ending with a newline character.
/*
and ending with
*
/
. Such comments may not be nested.
'single quoted'
.
'single quoted'
.
;
instead of ,
.
=
or =>
instead of
:
.
;
instead of ,
.
@CheckReturnValue public final boolean isLenient()
public final void setFailOnUnknown(boolean failOnUnknown)
JsonDataException
when skipValue()
is
called. By default this parser permits values to be skipped.
Forbid skipping to prevent unrecognized values from being silently ignored. This option is useful in development and debugging because it means a typo like "locatiom" will be detected early. It's potentially harmful in production because it complicates revising a JSON schema.
@CheckReturnValue public final boolean failOnUnknown()
public abstract void beginArray() throws IOException
IOException
public abstract void endArray() throws IOException
IOException
public abstract void beginObject() throws IOException
IOException
public abstract void endObject() throws IOException
IOException
@CheckReturnValue public abstract boolean hasNext() throws IOException
IOException
@CheckReturnValue public abstract JsonReader.Token peek() throws IOException
IOException
@CheckReturnValue public abstract String nextName() throws IOException
JsonDataException
- if the next token in the stream is not a property name.IOException
@CheckReturnValue public abstract int selectName(JsonReader.Options options) throws IOException
options
, this
consumes it and returns its index. Otherwise this returns -1 and no name is consumed.IOException
public abstract void skipName() throws IOException
This throws a JsonDataException
if this parser has been configured to fail on unknown names.
IOException
public abstract String nextString() throws IOException
JsonDataException
- if the next token is not a string or if this reader is closed.IOException
@CheckReturnValue public abstract int selectString(JsonReader.Options options) throws IOException
options
, this
consumes it and returns its index. Otherwise this returns -1 and no string is consumed.IOException
public abstract boolean nextBoolean() throws IOException
JsonDataException
- if the next token is not a boolean or if this reader is closed.IOException
@Nullable public abstract <T> T nextNull() throws IOException
JsonDataException
- if the next token is not null or if this reader is closed.IOException
public abstract double nextDouble() throws IOException
Double.parseDouble(String)
.JsonDataException
- if the next token is not a literal value, or if the next literal
value cannot be parsed as a double, or is non-finite.IOException
public abstract long nextLong() throws IOException
long
, this method throws.JsonDataException
- if the next token is not a literal value, if the next literal value
cannot be parsed as a number, or exactly represented as a long.IOException
public abstract int nextInt() throws IOException
int
, this method throws.JsonDataException
- if the next token is not a literal value, if the next literal value
cannot be parsed as a number, or exactly represented as an int.IOException
public abstract void skipValue() throws IOException
This throws a JsonDataException
if this parser has been configured to fail on unknown values.
IOException
@Nullable public final Object readJsonValue() throws IOException
JsonDataException
- if the next token is not a literal value, if a JSON object has a
duplicate key.IOException
@CheckReturnValue public abstract JsonReader peekJson()
JsonReader
that can read data from this JsonReader
without
consuming it. The returned reader becomes invalid once this one is next read or closed.
For example, we can use peek()
to lookahead and read the same data multiple times.
Buffer buffer = new Buffer();
buffer.writeUtf8("[123, 456, 789]")
JsonReader jsonReader = JsonReader.of(buffer);
jsonReader.beginArray();
jsonReader.nextInt(); // Returns 123, reader contains 456, 789 and ].
JsonReader peek = reader.peekReader();
peek.nextInt() // Returns 456.
peek.nextInt() // Returns 789.
peek.endArray()
jsonReader.nextInt() // Returns 456, reader contains 789 and ].
@CheckReturnValue public final String getPath()
Copyright © 2018. All rights reserved.