Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit eb97c0dd authored by Jesse Wilson's avatar Jesse Wilson
Browse files

Patch new JSON APIs with changes informed by GSON.

Change-Id: I86c12a123080cc06ab23d11d1563bb52c5902517
parent b3fbd7e0
Loading
Loading
Loading
Loading
+70 −16
Original line number Diff line number Diff line
@@ -198616,6 +198616,17 @@
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
<method name="isLenient"
 return="boolean"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="nextBoolean"
 return="boolean"
 abstract="false"
@@ -198746,21 +198757,6 @@
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
<method name="syntaxError"
 return="java.io.IOException"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="message" type="java.lang.String">
</parameter>
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
</class>
<class name="JsonToken"
 extends="java.lang.Enum"
@@ -198893,6 +198889,17 @@
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
<method name="isLenient"
 return="boolean"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="name"
 return="android.util.JsonWriter"
 abstract="false"
@@ -198934,6 +198941,19 @@
<parameter name="indent" type="java.lang.String">
</parameter>
</method>
<method name="setLenient"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="lenient" type="boolean">
</parameter>
</method>
<method name="value"
 return="android.util.JsonWriter"
 abstract="false"
@@ -198994,6 +199014,21 @@
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
<method name="value"
 return="android.util.JsonWriter"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="value" type="java.lang.Number">
</parameter>
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
</class>
<class name="Log"
 extends="java.lang.Object"
@@ -199373,6 +199408,25 @@
</parameter>
</method>
</class>
<class name="MalformedJsonException"
 extends="java.io.IOException"
 abstract="false"
 static="false"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
<constructor name="MalformedJsonException"
 type="android.util.MalformedJsonException"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="message" type="java.lang.String">
</parameter>
</constructor>
</class>
<class name="MonthDisplayHelper"
 extends="java.lang.Object"
 abstract="false"
@@ -258003,7 +258057,7 @@
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="t" type="T">
<parameter name="arg0" type="T">
</parameter>
</method>
</interface>
+21 −13
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.util;

import java.io.EOFException;
import java.io.IOException;
import java.io.Reader;
import java.io.Closeable;
@@ -248,6 +249,13 @@ public final class JsonReader implements Closeable {
        this.lenient = lenient;
    }

    /**
     * Returns true if this parser is liberal in what it accepts.
     */
    public boolean isLenient() {
        return lenient;
    }

    /**
     * Consumes the next token from the JSON stream and asserts that it is the
     * beginning of a new array.
@@ -311,7 +319,7 @@ public final class JsonReader implements Closeable {
            case EMPTY_DOCUMENT:
                replaceTop(JsonScope.NONEMPTY_DOCUMENT);
                JsonToken firstToken = nextValue();
                if (token != JsonToken.BEGIN_ARRAY && token != JsonToken.BEGIN_OBJECT) {
                if (!lenient && token != JsonToken.BEGIN_ARRAY && token != JsonToken.BEGIN_OBJECT) {
                    throw new IOException(
                            "Expected JSON document to start with '[' or '{' but was " + token);
                }
@@ -327,7 +335,15 @@ public final class JsonReader implements Closeable {
            case NONEMPTY_OBJECT:
                return nextInObject(false);
            case NONEMPTY_DOCUMENT:
                return token = JsonToken.END_DOCUMENT;
                try {
                    JsonToken token = nextValue();
                    if (lenient) {
                        return token;
                    }
                    throw syntaxError("Expected EOF");
                } catch (EOFException e) {
                    return token = JsonToken.END_DOCUMENT; // TODO: avoid throwing here?
                }
            case CLOSED:
                throw new IllegalStateException("JsonReader is closed");
            default:
@@ -758,7 +774,7 @@ public final class JsonReader implements Closeable {
            }
        }

        throw syntaxError("End of input");
        throw new EOFException("End of input");
    }

    private void checkLenient() throws IOException {
@@ -1030,8 +1046,6 @@ public final class JsonReader implements Closeable {
     * form -12.34e+56. Fractional and exponential parts are optional. Leading
     * zeroes are not allowed in the value or exponential part, but are allowed
     * in the fraction.
     *
     * <p>This has a side effect of setting isInteger.
     */
    private JsonToken decodeNumber(char[] chars, int offset, int length) {
        int i = offset;
@@ -1085,8 +1099,8 @@ public final class JsonReader implements Closeable {
     * Throws a new IO exception with the given message and a context snippet
     * with this reader's content.
     */
    public IOException syntaxError(String message) throws IOException {
        throw new JsonSyntaxException(message + " near " + getSnippet());
    private IOException syntaxError(String message) throws IOException {
        throw new MalformedJsonException(message + " near " + getSnippet());
    }

    private CharSequence getSnippet() {
@@ -1097,10 +1111,4 @@ public final class JsonReader implements Closeable {
        snippet.append(buffer, pos, afterPos);
        return snippet;
    }

    private static class JsonSyntaxException extends IOException {
        private JsonSyntaxException(String s) {
            super(s);
        }
    }
}
+50 −4
Original line number Diff line number Diff line
@@ -138,6 +138,8 @@ public final class JsonWriter implements Closeable {
     */
    private String separator = ":";

    private boolean lenient;

    /**
     * Creates a new instance that writes a JSON-encoded stream to {@code out}.
     * For best performance, ensure {@link Writer} is buffered; wrapping in
@@ -168,6 +170,29 @@ public final class JsonWriter implements Closeable {
        }
    }

    /**
     * Configure this writer to relax its syntax rules. By default, this writer
     * only emits well-formed JSON as specified by <a
     * href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>. Setting the writer
     * to lenient permits the following:
     * <ul>
     *   <li>Top-level values of any type. With strict writing, the top-level
     *       value must be an object or an array.
     *   <li>Numbers may be {@link Double#isNaN() NaNs} or {@link
     *       Double#isInfinite() infinities}.
     * </ul>
     */
    public void setLenient(boolean lenient) {
        this.lenient = lenient;
    }

    /**
     * Returns true if this writer has relaxed syntax rules.
     */
    public boolean isLenient() {
        return lenient;
    }

    /**
     * Begins encoding a new array. Each call to this method must be paired with
     * a call to {@link #endArray}.
@@ -306,11 +331,11 @@ public final class JsonWriter implements Closeable {
     * Encodes {@code value}.
     *
     * @param value a finite value. May not be {@link Double#isNaN() NaNs} or
     *     {@link Double#isInfinite() infinities}.
     *     {@link Double#isInfinite() infinities} unless this writer is lenient.
     * @return this writer.
     */
    public JsonWriter value(double value) throws IOException {
        if (Double.isNaN(value) || Double.isInfinite(value)) {
        if (!lenient && (Double.isNaN(value) || Double.isInfinite(value))) {
            throw new IllegalArgumentException("Numeric values must be finite, but was " + value);
        }
        beforeValue(false);
@@ -329,6 +354,28 @@ public final class JsonWriter implements Closeable {
        return this;
    }

    /**
     * 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.
     */
    public JsonWriter value(Number value) throws IOException {
        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;
    }

    /**
     * Ensures all buffered data is written to the underlying {@link Writer}
     * and flushes that writer.
@@ -364,7 +411,6 @@ public final class JsonWriter implements Closeable {
            switch (c) {
                case '"':
                case '\\':
                case '/':
                    out.write('\\');
                    out.write(c);
                    break;
@@ -439,7 +485,7 @@ public final class JsonWriter implements Closeable {
    private void beforeValue(boolean root) throws IOException {
        switch (peek()) {
            case EMPTY_DOCUMENT: // first in document
                if (!root) {
                if (!lenient && !root) {
                    throw new IllegalStateException(
                            "JSON must start with an array or an object.");
                }
+31 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * 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 android.util;

import java.io.IOException;

/**
 * Thrown when a reader encounters malformed JSON. Some syntax errors can be
 * ignored by calling {@link JsonReader#setLenient(boolean)}.
 */
public final class MalformedJsonException extends IOException {
    private static final long serialVersionUID = 1L;

    public MalformedJsonException(String message) {
        super(message);
    }
}
+49 −4
Original line number Diff line number Diff line
@@ -16,11 +16,10 @@

package android.util;

import java.util.Arrays;
import junit.framework.TestCase;

import java.io.IOException;
import java.io.StringReader;
import java.util.Arrays;
import junit.framework.TestCase;

public final class JsonReaderTest extends TestCase {

@@ -677,7 +676,7 @@ public final class JsonReaderTest extends TestCase {
        try {
            reader.nextString();
            fail();
        } catch (IOException expected) {
        } catch (MalformedJsonException expected) {
        }
    }

@@ -811,4 +810,50 @@ public final class JsonReaderTest extends TestCase {
        reader.nextNull();
        reader.endArray();
    }

    public void testStrictMultipleTopLevelValues() throws IOException {
        JsonReader reader = new JsonReader(new StringReader("[] []"));
        reader.beginArray();
        reader.endArray();
        try {
            reader.peek();
            fail();
        } catch (IOException expected) {
        }
    }

    public void testLenientMultipleTopLevelValues() throws IOException {
        JsonReader reader = new JsonReader(new StringReader("[] true {}"));
        reader.setLenient(true);
        reader.beginArray();
        reader.endArray();
        assertEquals(true, reader.nextBoolean());
        reader.beginObject();
        reader.endObject();
        assertEquals(JsonToken.END_DOCUMENT, reader.peek());
    }

    public void testStrictTopLevelValueType() {
        JsonReader reader = new JsonReader(new StringReader("true"));
        try {
            reader.nextBoolean();
            fail();
        } catch (IOException expected) {
        }
    }

    public void testLenientTopLevelValueType() throws IOException {
        JsonReader reader = new JsonReader(new StringReader("true"));
        reader.setLenient(true);
        assertEquals(true, reader.nextBoolean());
    }

    public void testStrictNonExecutePrefix() {
        JsonReader reader = new JsonReader(new StringReader(")]}'\n []"));
        try {
            reader.beginArray();
            fail();
        } catch (IOException expected) {
        }
    }
}
Loading