FileDocCategorySizeDatePackage
JsonWriter.javaAPI DocAndroid 5.1 API16498Thu Mar 12 22:22:10 GMT 2015android.util

JsonWriter

public final class JsonWriter extends Object implements Closeable
Writes a JSON (RFC 4627) encoded value to a stream, one token at a time. The stream includes both literal values (strings, numbers, booleans and nulls) as well as the begin and end delimiters of objects and arrays.

Encoding JSON

To encode your data as JSON, create a new {@code JsonWriter}. Each JSON document must contain one top-level array or object. Call methods on the writer as you walk the structure's contents, nesting arrays and objects as necessary:
  • To write arrays, first call {@link #beginArray()}. Write each of the array's elements with the appropriate {@link #value} methods or by nesting other arrays and objects. Finally close the array using {@link #endArray()}.
  • To write objects, first call {@link #beginObject()}. Write each of the object's properties by alternating calls to {@link #name} with the property's value. Write property values with the appropriate {@link #value} method or by nesting other objects or arrays. Finally close the object using {@link #endObject()}.

Example

Suppose we'd like to encode a stream of messages such as the following:
 {@code
[
{
"id": 912345678901,
"text": "How do I write JSON on Android?",
"geo": null,
"user": {
"name": "android_newb",
"followers_count": 41
}
},
{
"id": 912345678902,
"text": "@android_newb just use android.util.JsonWriter!",
"geo": [50.454722, -104.606667],
"user": {
"name": "jesse",
"followers_count": 2
}
}
]}
This code encodes the above structure:
 {@code
public void writeJsonStream(OutputStream out, List messages) throws IOException {
JsonWriter writer = new JsonWriter(new OutputStreamWriter(out, "UTF-8"));
writer.setIndent(" ");
writeMessagesArray(writer, messages);
writer.close();
}

public void writeMessagesArray(JsonWriter writer, List messages) throws IOException {
writer.beginArray();
for (Message message : messages) {
writeMessage(writer, message);
}
writer.endArray();
}

public void writeMessage(JsonWriter writer, Message message) throws IOException {
writer.beginObject();
writer.name("id").value(message.getId());
writer.name("text").value(message.getText());
if (message.getGeo() != null) {
writer.name("geo");
writeDoublesArray(writer, message.getGeo());
} else {
writer.name("geo").nullValue();
}
writer.name("user");
writeUser(writer, message.getUser());
writer.endObject();
}

public void writeUser(JsonWriter writer, User user) throws IOException {
writer.beginObject();
writer.name("name").value(user.getName());
writer.name("followers_count").value(user.getFollowersCount());
writer.endObject();
}

public void writeDoublesArray(JsonWriter writer, List doubles) throws IOException {
writer.beginArray();
for (Double value : doubles) {
writer.value(value);
}
writer.endArray();
}}

Each {@code JsonWriter} may be used to write a single JSON stream. Instances of this class are not thread safe. Calls that would result in a malformed JSON string will fail with an {@link IllegalStateException}.

Fields Summary
private final Writer
out
The output data, containing at most one top-level array or object.
private final List
stack
private String
indent
A string containing a full set of spaces for a single level of indentation, or null for no pretty printing.
private String
separator
The name/value separator; either ":" or ": ".
private boolean
lenient
Constructors Summary
public JsonWriter(Writer out)
Creates a new instance that writes a JSON-encoded stream to {@code out}. For best performance, ensure {@link Writer} is buffered; wrapping in {@link java.io.BufferedWriter BufferedWriter} if necessary.


                                    
       
        if (out == null) {
            throw new NullPointerException("out == null");
        }
        this.out = out;
    
Methods Summary
private voidbeforeName()
Inserts any necessary separators and whitespace before a name. Also adjusts the stack to expect the name's value.

        JsonScope context = peek();
        if (context == JsonScope.NONEMPTY_OBJECT) { // first in object
            out.write(',");
        } else if (context != JsonScope.EMPTY_OBJECT) { // not in an object!
            throw new IllegalStateException("Nesting problem: " + stack);
        }
        newline();
        replaceTop(JsonScope.DANGLING_NAME);
    
private voidbeforeValue(boolean root)
Inserts any necessary separators and whitespace before a literal value, inline array, or inline object. Also adjusts the stack to expect either a closing bracket or another element.

param
root true if the value is a new array or object, the two values permitted as top-level elements.

        switch (peek()) {
            case EMPTY_DOCUMENT: // first in document
                if (!lenient && !root) {
                    throw new IllegalStateException(
                            "JSON must start with an array or an object.");
                }
                replaceTop(JsonScope.NONEMPTY_DOCUMENT);
                break;

            case EMPTY_ARRAY: // first in array
                replaceTop(JsonScope.NONEMPTY_ARRAY);
                newline();
                break;

            case NONEMPTY_ARRAY: // another in array
                out.append(',");
                newline();
                break;

            case DANGLING_NAME: // value for name
                out.append(separator);
                replaceTop(JsonScope.NONEMPTY_OBJECT);
                break;

            case NONEMPTY_DOCUMENT:
                throw new IllegalStateException(
                        "JSON must have only one top-level value.");

            default:
                throw new IllegalStateException("Nesting problem: " + stack);
        }
    
public android.util.JsonWriterbeginArray()
Begins encoding a new array. Each call to this method must be paired with a call to {@link #endArray}.

return
this writer.

        return open(JsonScope.EMPTY_ARRAY, "[");
    
public android.util.JsonWriterbeginObject()
Begins encoding a new object. Each call to this method must be paired with a call to {@link #endObject}.

return
this writer.

        return open(JsonScope.EMPTY_OBJECT, "{");
    
private android.util.JsonWriterclose(JsonScope empty, JsonScope nonempty, java.lang.String closeBracket)
Closes the current scope by appending any necessary whitespace and the given bracket.

        JsonScope context = peek();
        if (context != nonempty && context != empty) {
            throw new IllegalStateException("Nesting problem: " + stack);
        }

        stack.remove(stack.size() - 1);
        if (context == nonempty) {
            newline();
        }
        out.write(closeBracket);
        return this;
    
public voidclose()
Flushes and closes this writer and the underlying {@link Writer}.

throws
IOException if the JSON document is incomplete.

        out.close();

        if (peek() != JsonScope.NONEMPTY_DOCUMENT) {
            throw new IOException("Incomplete document");
        }
    
public android.util.JsonWriterendArray()
Ends encoding the current array.

return
this writer.

        return close(JsonScope.EMPTY_ARRAY, JsonScope.NONEMPTY_ARRAY, "]");
    
public android.util.JsonWriterendObject()
Ends encoding the current object.

return
this writer.

        return close(JsonScope.EMPTY_OBJECT, JsonScope.NONEMPTY_OBJECT, "}");
    
public voidflush()
Ensures all buffered data is written to the underlying {@link Writer} and flushes that writer.

        out.flush();
    
public booleanisLenient()
Returns true if this writer has relaxed syntax rules.

        return lenient;
    
public android.util.JsonWritername(java.lang.String name)
Encodes the property name.

param
name the name of the forthcoming value. May not be null.
return
this writer.

        if (name == null) {
            throw new NullPointerException("name == null");
        }
        beforeName();
        string(name);
        return this;
    
private voidnewline()

        if (indent == null) {
            return;
        }

        out.write("\n");
        for (int i = 1; i < stack.size(); i++) {
            out.write(indent);
        }
    
public android.util.JsonWriternullValue()
Encodes {@code null}.

return
this writer.

        beforeValue(false);
        out.write("null");
        return this;
    
private android.util.JsonWriteropen(JsonScope empty, java.lang.String openBracket)
Enters a new scope by appending any necessary whitespace and the given bracket.

        beforeValue(true);
        stack.add(empty);
        out.write(openBracket);
        return this;
    
private JsonScopepeek()
Returns the value on the top of the stack.

        return stack.get(stack.size() - 1);
    
private voidreplaceTop(JsonScope topOfStack)
Replace the value on the top of the stack with the given value.

        stack.set(stack.size() - 1, topOfStack);
    
public voidsetIndent(java.lang.String indent)
Sets the indentation string to be repeated for each level of indentation in the encoded document. If {@code indent.isEmpty()} the encoded document will be compact. Otherwise the encoded document will be more human-readable.

param
indent a string containing only whitespace.

        if (indent.isEmpty()) {
            this.indent = null;
            this.separator = ":";
        } else {
            this.indent = indent;
            this.separator = ": ";
        }
    
public voidsetLenient(boolean lenient)
Configure this writer to relax its syntax rules. By default, this writer only emits well-formed JSON as specified by RFC 4627. Setting the writer to lenient permits the following:
  • Top-level values of any type. With strict writing, the top-level value must be an object or an array.
  • Numbers may be {@link Double#isNaN() NaNs} or {@link Double#isInfinite() infinities}.

        this.lenient = lenient;
    
private voidstring(java.lang.String value)

        out.write("\"");
        for (int i = 0, length = value.length(); i < length; i++) {
            char c = value.charAt(i);

            /*
             * From RFC 4627, "All Unicode characters may be placed within the
             * quotation marks except for the characters that must be escaped:
             * quotation mark, reverse solidus, and the control characters
             * (U+0000 through U+001F)."
             *
             * We also escape '\u2028' and '\u2029', which JavaScript interprets
             * as newline characters. This prevents eval() from failing with a
             * syntax error.
             * http://code.google.com/p/google-gson/issues/detail?id=341
             */
            switch (c) {
                case '"":
                case '\\":
                    out.write('\\");
                    out.write(c);
                    break;

                case '\t":
                    out.write("\\t");
                    break;

                case '\b":
                    out.write("\\b");
                    break;

                case '\n":
                    out.write("\\n");
                    break;

                case '\r":
                    out.write("\\r");
                    break;

                case '\f":
                    out.write("\\f");
                    break;

                case '\u2028":
                case '\u2029":
                    out.write(String.format("\\u%04x", (int) c));
                    break;

                default:
                    if (c <= 0x1F) {
                        out.write(String.format("\\u%04x", (int) c));
                    } else {
                        out.write(c);
                    }
                    break;
            }

        }
        out.write("\"");
    
public android.util.JsonWritervalue(java.lang.String value)
Encodes {@code value}.

param
value the literal string value, or null to encode a null literal.
return
this writer.

        if (value == null) {
            return nullValue();
        }
        beforeValue(false);
        string(value);
        return this;
    
public android.util.JsonWritervalue(boolean value)
Encodes {@code value}.

return
this writer.

        beforeValue(false);
        out.write(value ? "true" : "false");
        return this;
    
public android.util.JsonWritervalue(double value)
Encodes {@code value}.

param
value a finite value. May not be {@link Double#isNaN() NaNs} or {@link Double#isInfinite() infinities} unless this writer is lenient.
return
this writer.

        if (!lenient && (Double.isNaN(value) || Double.isInfinite(value))) {
            throw new IllegalArgumentException("Numeric values must be finite, but was " + value);
        }
        beforeValue(false);
        out.append(Double.toString(value));
        return this;
    
public android.util.JsonWritervalue(long value)
Encodes {@code value}.

return
this writer.

        beforeValue(false);
        out.write(Long.toString(value));
        return this;
    
public android.util.JsonWritervalue(java.lang.Number value)
Encodes {@code value}.

param
value a finite value. May not be {@link Double#isNaN() NaNs} or {@link Double#isInfinite() infinities} unless this writer is lenient.
return
this writer.

        if (value == null) {
            return nullValue();
        }

        String string = value.toString();
        if (!lenient &&
                (string.equals("-Infinity") || string.equals("Infinity") || string.equals("NaN"))) {
            throw new IllegalArgumentException("Numeric values must be finite, but was " + value);
        }
        beforeValue(false);
        out.append(string);
        return this;