Patch new JSON APIs with changes informed by GSON.
Change-Id: I86c12a123080cc06ab23d11d1563bb52c5902517
This commit is contained in:
@ -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>
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
core/java/android/util/MalformedJsonException.java
Normal file
31
core/java/android/util/MalformedJsonException.java
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
@ -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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,10 +16,11 @@
|
||||
|
||||
package android.util;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public final class JsonWriterTest extends TestCase {
|
||||
|
||||
@ -119,7 +120,7 @@ public final class JsonWriterTest extends TestCase {
|
||||
JsonWriter jsonWriter = new JsonWriter(stringWriter);
|
||||
jsonWriter.beginObject();
|
||||
jsonWriter.name("a");
|
||||
jsonWriter.value(null);
|
||||
jsonWriter.value((String) null);
|
||||
jsonWriter.endObject();
|
||||
assertEquals("{\"a\":null}", stringWriter.toString());
|
||||
}
|
||||
@ -145,6 +146,27 @@ public final class JsonWriterTest extends TestCase {
|
||||
}
|
||||
}
|
||||
|
||||
public void testNonFiniteBoxedDoubles() throws IOException {
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
JsonWriter jsonWriter = new JsonWriter(stringWriter);
|
||||
jsonWriter.beginArray();
|
||||
try {
|
||||
jsonWriter.value(new Double(Double.NaN));
|
||||
fail();
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
try {
|
||||
jsonWriter.value(new Double(Double.NEGATIVE_INFINITY));
|
||||
fail();
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
try {
|
||||
jsonWriter.value(new Double(Double.POSITIVE_INFINITY));
|
||||
fail();
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
public void testDoubles() throws IOException {
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
JsonWriter jsonWriter = new JsonWriter(stringWriter);
|
||||
@ -189,6 +211,22 @@ public final class JsonWriterTest extends TestCase {
|
||||
+ "9223372036854775807]", stringWriter.toString());
|
||||
}
|
||||
|
||||
public void testNumbers() throws IOException {
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
JsonWriter jsonWriter = new JsonWriter(stringWriter);
|
||||
jsonWriter.beginArray();
|
||||
jsonWriter.value(new BigInteger("0"));
|
||||
jsonWriter.value(new BigInteger("9223372036854775808"));
|
||||
jsonWriter.value(new BigInteger("-9223372036854775809"));
|
||||
jsonWriter.value(new BigDecimal("3.141592653589793238462643383"));
|
||||
jsonWriter.endArray();
|
||||
jsonWriter.close();
|
||||
assertEquals("[0,"
|
||||
+ "9223372036854775808,"
|
||||
+ "-9223372036854775809,"
|
||||
+ "3.141592653589793238462643383]", stringWriter.toString());
|
||||
}
|
||||
|
||||
public void testBooleans() throws IOException {
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
JsonWriter jsonWriter = new JsonWriter(stringWriter);
|
||||
|
Reference in New Issue
Block a user