Refactored the Async parser interface out of JsonParser into a new class JsonParserAsync. Updated the JsonParser to detect Eof and return a null instead of throwing a ParseException.

This commit is contained in:
Inderjeet Singh 2009-05-14 20:18:45 +00:00
parent f2fd0b7d52
commit 6e59e502c2
9 changed files with 191 additions and 115 deletions

View File

@ -411,10 +411,7 @@ public final class Gson {
@SuppressWarnings("unchecked")
public <T> T fromJson(Reader json, Type typeOfT) throws JsonParseException {
JsonElement root = new JsonParser().parse(json);
JsonDeserializationContext context = new JsonDeserializationContextDefault(
createDefaultObjectNavigatorFactory(), deserializers, objectConstructor);
T target = (T) context.deserialize(root, typeOfT);
return target;
return fromJson(root, typeOfT);
}
/**
@ -458,6 +455,9 @@ public final class Gson {
*/
@SuppressWarnings("unchecked")
public <T> T fromJson(JsonElement json, Type typeOfT) throws JsonParseException {
if (json == null) {
return null;
}
JsonDeserializationContext context = new JsonDeserializationContextDefault(
createDefaultObjectNavigatorFactory(), deserializers, objectConstructor);
T target = (T) context.deserialize(json, typeOfT);

View File

@ -15,6 +15,7 @@
*/
package com.google.gson;
import java.io.EOFException;
import java.io.Reader;
import java.io.StringReader;
@ -27,21 +28,6 @@ import java.io.StringReader;
*/
public final class JsonParser {
/**
* Interface to provide ability to read multiple {@link JsonElement}s from a stream
* asynchronously.
*
* @since 1.4
*/
public interface AsyncReader {
/**
* Parse and return one {@link JsonElement}
* @since 1.4
*/
public JsonElement readElement();
}
/**
* Parses the specified JSON string into a parse tree
*
@ -75,41 +61,12 @@ public final class JsonParser {
throw new JsonParseException("Failed parsing JSON source: " + json + " to Json", e);
} catch (OutOfMemoryError e) {
throw new JsonParseException("Failed parsing JSON source: " + json + " to Json", e);
}
}
/**
* Returns {@link AsyncReader} to allow reading of multiple {@link JsonElement}s from the
* specified reader asynchronously.
*
* @param json The data stream containing JSON elements concatenated to each other.
* @return {@link AsyncReader} for reading {@link JsonElement}s asynchronously.
* @throws JsonParseException if the incoming stream is malformed JSON.
* @since 1.4
*/
public AsyncReader parseAsync(Reader json) throws JsonParseException {
return new AsyncReaderJavacc(json);
}
private static class AsyncReaderJavacc implements AsyncReader {
private final JsonParserJavacc parser;
private AsyncReaderJavacc(Reader json) {
parser = new JsonParserJavacc(json);
}
public JsonElement readElement() {
try {
JsonElement element = parser.parse();
return element;
} catch (TokenMgrError e) {
throw new JsonParseException("Failed parsing JSON source to Json", e);
} catch (ParseException e) {
throw new JsonParseException("Failed parsing JSON source to Json", e);
} catch (StackOverflowError e) {
throw new JsonParseException("Failed parsing JSON source to Json", e);
} catch (OutOfMemoryError e) {
throw new JsonParseException("Failed parsing JSON source to Json", e);
} catch (JsonParseException e) {
if (e.getCause() instanceof EOFException) {
return null;
} else {
throw e;
}
}
}
}
}
}

View File

@ -0,0 +1,77 @@
/*
* Copyright (C) 2009 Google Inc.
*
* 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 com.google.gson;
import java.io.EOFException;
import java.io.Reader;
import java.io.StringReader;
/**
* A parser that allows reading of multiple {@link JsonElement}s from the specified reader
* asynchronously.
*
* @author Inderjeet Singh
* @author Joel Leitch
* @since 1.4
*/
public final class JsonParserAsync {
private final JsonParserJavacc parser;
/**
* @param json The string containing JSON elements concatenated to each other.
* @since 1.4
*/
public JsonParserAsync(String json) {
this(new StringReader(json));
}
/**
* @param reader The data stream containing JSON elements concatenated to each other.
* @since 1.4
*/
public JsonParserAsync(Reader reader) {
parser = new JsonParserJavacc(reader);
}
/**
* Returns the next available {@link JsonElement} on the reader. Null if none available.
*
* @return the next available {@link JsonElement} on the reader. Null if none available.
* @throws JsonParseException if the incoming stream is malformed JSON.
* @since 1.4
*/
public JsonElement nextElement() throws JsonParseException {
try {
JsonElement element = parser.parse();
return element;
} catch (TokenMgrError e) {
throw new JsonParseException("Failed parsing JSON source to Json", e);
} catch (ParseException e) {
throw new JsonParseException("Failed parsing JSON source to Json", e);
} catch (StackOverflowError e) {
throw new JsonParseException("Failed parsing JSON source to Json", e);
} catch (OutOfMemoryError e) {
throw new JsonParseException("Failed parsing JSON source to Json", e);
} catch (JsonParseException e) {
if (e.getCause() instanceof EOFException) {
return null;
} else {
throw e;
}
}
}
}

View File

@ -1,5 +1,6 @@
/* Generated By:JavaCC: Do not edit this line. JsonParserJavacc.java */
package com.google.gson;
import java.io.EOFException;
@SuppressWarnings("all")
final class JsonParserJavacc implements JsonParserJavaccConstants {
@ -7,38 +8,60 @@ final class JsonParserJavacc implements JsonParserJavaccConstants {
final public JsonElement parse() throws ParseException {
JsonElement json = null;
switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
case 26:
jj_consume_token(26);
break;
default:
jj_la1[0] = jj_gen;
;
}
switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
case 27:
json = JsonObject();
break;
case 31:
json = JsonArray();
case 0:
jj_consume_token(0);
{if (true) throw new JsonParseException(new EOFException());}
break;
case DIGITS:
case NULL:
case NAN:
case INFINITY:
case BOOLEAN:
case SINGLE_QUOTE_LITERAL:
case DOUBLE_QUOTE_LITERAL:
case 26:
case 27:
case 31:
case 33:
json = JsonPrimitive();
break;
case NULL:
json = JsonNull();
switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
case 26:
jj_consume_token(26);
break;
default:
jj_la1[0] = jj_gen;
;
}
switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
case 27:
json = JsonObject();
break;
case 31:
json = JsonArray();
break;
case DIGITS:
case NAN:
case INFINITY:
case BOOLEAN:
case SINGLE_QUOTE_LITERAL:
case DOUBLE_QUOTE_LITERAL:
case 33:
json = JsonPrimitive();
break;
case NULL:
json = JsonNull();
break;
default:
jj_la1[1] = jj_gen;
jj_consume_token(-1);
throw new ParseException();
}
{if (true) return json;}
break;
default:
jj_la1[1] = jj_gen;
jj_la1[2] = jj_gen;
jj_consume_token(-1);
throw new ParseException();
}
{if (true) return json;}
throw new Error("Missing return statement in function");
}
@ -53,7 +76,7 @@ final class JsonParserJavacc implements JsonParserJavaccConstants {
Members(o);
break;
default:
jj_la1[2] = jj_gen;
jj_la1[3] = jj_gen;
;
}
jj_consume_token(28);
@ -76,7 +99,7 @@ final class JsonParserJavacc implements JsonParserJavaccConstants {
Members(o);
break;
default:
jj_la1[3] = jj_gen;
jj_la1[4] = jj_gen;
;
}
}
@ -104,7 +127,7 @@ final class JsonParserJavacc implements JsonParserJavaccConstants {
{if (true) return value;}
break;
default:
jj_la1[4] = jj_gen;
jj_la1[5] = jj_gen;
jj_consume_token(-1);
throw new ParseException();
}
@ -128,7 +151,7 @@ final class JsonParserJavacc implements JsonParserJavaccConstants {
Elements(array);
break;
default:
jj_la1[5] = jj_gen;
jj_la1[6] = jj_gen;
;
}
jj_consume_token(32);
@ -146,7 +169,7 @@ final class JsonParserJavacc implements JsonParserJavaccConstants {
Elements(array);
break;
default:
jj_la1[6] = jj_gen;
jj_la1[7] = jj_gen;
;
}
array.add(element);
@ -178,7 +201,7 @@ final class JsonParserJavacc implements JsonParserJavaccConstants {
o = JsonNull();
break;
default:
jj_la1[7] = jj_gen;
jj_la1[8] = jj_gen;
jj_consume_token(-1);
throw new ParseException();
}
@ -214,7 +237,7 @@ final class JsonParserJavacc implements JsonParserJavaccConstants {
{if (true) return value;}
break;
default:
jj_la1[8] = jj_gen;
jj_la1[9] = jj_gen;
jj_consume_token(-1);
throw new ParseException();
}
@ -239,7 +262,7 @@ final class JsonParserJavacc implements JsonParserJavaccConstants {
fracpart = JsonFrac();
break;
default:
jj_la1[9] = jj_gen;
jj_la1[10] = jj_gen;
;
}
switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
@ -247,7 +270,7 @@ final class JsonParserJavacc implements JsonParserJavaccConstants {
exppart = JsonExp();
break;
default:
jj_la1[10] = jj_gen;
jj_la1[11] = jj_gen;
;
}
Number n;
@ -261,7 +284,7 @@ final class JsonParserJavacc implements JsonParserJavaccConstants {
{if (true) return new JsonPrimitive(n);}
break;
default:
jj_la1[11] = jj_gen;
jj_la1[12] = jj_gen;
jj_consume_token(-1);
throw new ParseException();
}
@ -284,14 +307,14 @@ final class JsonParserJavacc implements JsonParserJavaccConstants {
negative = true;
break;
default:
jj_la1[12] = jj_gen;
jj_la1[13] = jj_gen;
;
}
jj_consume_token(INFINITY);
{if (true) return new JsonPrimitive(negative ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY);}
break;
default:
jj_la1[13] = jj_gen;
jj_la1[14] = jj_gen;
jj_consume_token(-1);
throw new ParseException();
}
@ -307,7 +330,7 @@ final class JsonParserJavacc implements JsonParserJavaccConstants {
negative = true;
break;
default:
jj_la1[14] = jj_gen;
jj_la1[15] = jj_gen;
;
}
digits = Digits();
@ -342,7 +365,7 @@ final class JsonParserJavacc implements JsonParserJavaccConstants {
t = jj_consume_token(IDENTIFIER_SANS_EXPONENT);
break;
default:
jj_la1[15] = jj_gen;
jj_la1[16] = jj_gen;
jj_consume_token(-1);
throw new ParseException();
}
@ -367,7 +390,7 @@ final class JsonParserJavacc implements JsonParserJavaccConstants {
t = jj_consume_token(DOUBLE_QUOTE_LITERAL);
break;
default:
jj_la1[16] = jj_gen;
jj_la1[17] = jj_gen;
jj_consume_token(-1);
throw new ParseException();
}
@ -427,7 +450,7 @@ final class JsonParserJavacc implements JsonParserJavaccConstants {
private Token jj_scanpos, jj_lastpos;
private int jj_la;
private int jj_gen;
final private int[] jj_la1 = new int[17];
final private int[] jj_la1 = new int[18];
static private int[] jj_la1_0;
static private int[] jj_la1_1;
static {
@ -435,10 +458,10 @@ final class JsonParserJavacc implements JsonParserJavaccConstants {
jj_la1_init_1();
}
private static void jj_la1_init_0() {
jj_la1_0 = new int[] {0x4000000,0x880307c0,0x31800,0x20000000,0x31800,0x880307c0,0x20000000,0x880307c0,0x30740,0x0,0x20,0x40,0x0,0x300,0x0,0x1800,0x30000,};
jj_la1_0 = new int[] {0x4000000,0x880307c0,0x8c0307c1,0x31800,0x20000000,0x31800,0x880307c0,0x20000000,0x880307c0,0x30740,0x0,0x20,0x40,0x0,0x300,0x0,0x1800,0x30000,};
}
private static void jj_la1_init_1() {
jj_la1_1 = new int[] {0x0,0x2,0x0,0x0,0x0,0x2,0x0,0x2,0x2,0x4,0x0,0x2,0x2,0x2,0x2,0x0,0x0,};
jj_la1_1 = new int[] {0x0,0x2,0x2,0x0,0x0,0x0,0x2,0x0,0x2,0x2,0x4,0x0,0x2,0x2,0x2,0x2,0x0,0x0,};
}
final private JJCalls[] jj_2_rtns = new JJCalls[1];
private boolean jj_rescan = false;
@ -455,7 +478,7 @@ final class JsonParserJavacc implements JsonParserJavaccConstants {
token = new Token();
jj_ntk = -1;
jj_gen = 0;
for (int i = 0; i < 17; i++) jj_la1[i] = -1;
for (int i = 0; i < 18; i++) jj_la1[i] = -1;
for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
}
@ -470,7 +493,7 @@ final class JsonParserJavacc implements JsonParserJavaccConstants {
token = new Token();
jj_ntk = -1;
jj_gen = 0;
for (int i = 0; i < 17; i++) jj_la1[i] = -1;
for (int i = 0; i < 18; i++) jj_la1[i] = -1;
for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
}
@ -481,7 +504,7 @@ final class JsonParserJavacc implements JsonParserJavaccConstants {
token = new Token();
jj_ntk = -1;
jj_gen = 0;
for (int i = 0; i < 17; i++) jj_la1[i] = -1;
for (int i = 0; i < 18; i++) jj_la1[i] = -1;
for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
}
@ -492,7 +515,7 @@ final class JsonParserJavacc implements JsonParserJavaccConstants {
token = new Token();
jj_ntk = -1;
jj_gen = 0;
for (int i = 0; i < 17; i++) jj_la1[i] = -1;
for (int i = 0; i < 18; i++) jj_la1[i] = -1;
for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
}
@ -502,7 +525,7 @@ final class JsonParserJavacc implements JsonParserJavaccConstants {
token = new Token();
jj_ntk = -1;
jj_gen = 0;
for (int i = 0; i < 17; i++) jj_la1[i] = -1;
for (int i = 0; i < 18; i++) jj_la1[i] = -1;
for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
}
@ -512,7 +535,7 @@ final class JsonParserJavacc implements JsonParserJavaccConstants {
token = new Token();
jj_ntk = -1;
jj_gen = 0;
for (int i = 0; i < 17; i++) jj_la1[i] = -1;
for (int i = 0; i < 18; i++) jj_la1[i] = -1;
for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
}
@ -629,7 +652,7 @@ final class JsonParserJavacc implements JsonParserJavaccConstants {
la1tokens[jj_kind] = true;
jj_kind = -1;
}
for (int i = 0; i < 17; i++) {
for (int i = 0; i < 18; i++) {
if (jj_la1[i] == jj_gen) {
for (int j = 0; j < 32; j++) {
if ((jj_la1_0[i] & (1<<j)) != 0) {

View File

@ -1,5 +1,6 @@
/* Generated By:JavaCC: Do not edit this line. JsonParserJavaccTokenManager.java */
package com.google.gson;
import java.io.EOFException;
/** Token Manager. */
@SuppressWarnings("all")

View File

@ -12,6 +12,7 @@ options {
PARSER_BEGIN(JsonParserJavacc)
package com.google.gson;
import java.io.EOFException;
@SuppressWarnings("all")
final class JsonParserJavacc {
@ -60,6 +61,9 @@ public JsonElement parse() :
JsonElement json = null;
}
{
(<EOF>){
throw new JsonParseException(new EOFException());
} |
[")]}'\n"]( json=JsonObject() |
json=JsonArray() |
json=JsonPrimitive() |

View File

@ -0,0 +1,19 @@
package com.google.gson;
import junit.framework.TestCase;
/**
* Unit tests for {@link JsonParserAsync}
*
* @author Inderjeet Singh
*/
public class JsonParserAsyncTest extends TestCase {
public void testParseTwoStrings() {
JsonParserAsync parser = new JsonParserAsync("'one' 'two'");
String actualOne = parser.nextElement().getAsString();
assertEquals("one", actualOne);
String actualTwo = parser.nextElement().getAsString();
assertEquals("two", actualTwo);
}
}

View File

@ -178,11 +178,8 @@ public class ObjectTest extends TestCase {
}
public void testNullDeserialization() throws Exception {
try {
gson.fromJson("", Object.class);
fail("Null strings should not be allowed");
} catch (JsonParseException expected) {
}
Object object = gson.fromJson("", Object.class);
assertNull(object);
}
public void testNullFieldsSerialization() throws Exception {

View File

@ -17,9 +17,8 @@ package com.google.gson.functional;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonParseException;
import com.google.gson.JsonParser;
import com.google.gson.JsonParser.AsyncReader;
import com.google.gson.JsonElement;
import com.google.gson.JsonParserAsync;
import com.google.gson.common.TestTypes.BagOfPrimitives;
import junit.framework.TestCase;
@ -93,11 +92,10 @@ public class ReadersWritersTest extends TestCase {
writer.write(gson.toJson("one").toCharArray());
writer.write(gson.toJson("two").toCharArray());
CharArrayReader reader = new CharArrayReader(writer.toCharArray());
JsonParser parser = new JsonParser();
AsyncReader asyncReader = parser.parseAsync(reader);
String actualOne = gson.fromJson(asyncReader.readElement(), String.class);
JsonParserAsync parser = new JsonParserAsync(reader);
String actualOne = gson.fromJson(parser.nextElement(), String.class);
assertEquals("one", actualOne);
String actualTwo = gson.fromJson(asyncReader.readElement(), String.class);
String actualTwo = gson.fromJson(parser.nextElement(), String.class);
assertEquals("two", actualTwo);
}
@ -109,11 +107,11 @@ public class ReadersWritersTest extends TestCase {
BagOfPrimitives expectedTwo = new BagOfPrimitives(2, 2, false, "two");
writer.write(gson.toJson(expectedTwo).toCharArray());
CharArrayReader reader = new CharArrayReader(writer.toCharArray());
JsonParser parser = new JsonParser();
AsyncReader asyncReader = parser.parseAsync(reader);
BagOfPrimitives actualOne = gson.fromJson(asyncReader.readElement(), BagOfPrimitives.class);
JsonParserAsync parser = new JsonParserAsync(reader);
BagOfPrimitives actualOne = gson.fromJson(parser.nextElement(), BagOfPrimitives.class);
assertEquals("one", actualOne.stringValue);
BagOfPrimitives actualTwo = gson.fromJson(asyncReader.readElement(), BagOfPrimitives.class);
BagOfPrimitives actualTwo = gson.fromJson(parser.nextElement(), BagOfPrimitives.class);
assertEquals("two", actualTwo.stringValue);
JsonElement jsonElement = parser.nextElement();
}
}