1.1 candidate

This commit is contained in:
fangyidong
2009-01-23 06:28:59 +00:00
parent af440720f8
commit 0e046d1b85
21 changed files with 1803 additions and 605 deletions

View File

@@ -1 +1,2 @@
Fang Yidong <fangyidong@gmail.com> Yidong Fang
Chris Nokleberg

View File

@@ -1,5 +1,14 @@
ChangeLog ChangeLog
Version 1.1 (2009/01/23)
* Supports stoppable SAX-like content handler for streaming of JSON text
* Added JSONStreamAware to support streaming JSON text
* Added ContainerFactory to support creating arbitrary Map and List as JSON object and JSON array container during decoding
* Supports any Map and List as JSON object and JSON array container during encoding
* Added interface JSONAware
* Added ParseException to get detail error report while parsing
* Added escaping for Unicode characters that cause problems for browser JS eval
Version 1.02 (2009/01/10) Version 1.02 (2009/01/10)
* Updated json.lex to improve performance of the lexer * Updated json.lex to improve performance of the lexer
* Removed Rope.java and related junit test * Removed Rope.java and related junit test

View File

@@ -1,153 +1,2 @@
Simple Java toolkit for JSON (JSON.simple) Please visit:
========================================== http://code.google.com/p/json-simple/
http://www.JSON.org/java/json_simple.zip
1.Why the Simple Java toolkit (also named as JSON.simple) for JSON?
When I use JSON as the data exchange format between the AJAX client and JSP
for the first time, what worry me mostly is how to encode Java strings and
numbers correctly in the server side so the AJAX client will receive a well
formed JSON data. When I looked into the 'JSON in Java' directory in JSON
website,I found that wrappers to JSONObject and JSONArray can be simpler,
due to the simplicity of JSON itself. So I wrote the JSON.simple package.
2.Is it simple,really?
I think so. Take an example:
import org.json.simple.JSONObject;
JSONObject obj=new JSONObject();
obj.put("name","foo");
obj.put("num",new Integer(100));
obj.put("balance",new Double(1000.21));
obj.put("is_vip",new Boolean(true));
obj.put("nickname",null);
System.out.print(obj);
Result:
{"nickname":null,"num":100,"balance":1000.21,"is_vip":true,"name":"foo"}
The JSONObject.toString() will escape controls and specials correctly.
3.How to use JSON.simple in JSP?
Take an example in JSP:
<%@page contentType="text/html; charset=UTF-8"%>
<%@page import="org.json.simple.JSONObject"%>
<%
JSONObject obj=new JSONObject();
obj.put("name","foo");
obj.put("num",new Integer(100));
obj.put("balance",new Double(1000.21));
obj.put("is_vip",new Boolean(true));
obj.put("nickname",null);
out.print(obj);
out.flush();
%>
So the AJAX client will get the responseText.
4.Some details about JSONObject?
JSONObject inherits java.util.HashMap,so it don't have to worry about the
mapping things between keys and values. Feel free to use the Map methods
like get(), put(), and remove() and others. JSONObject.toString() will
combine key value pairs to get the JSON data string. Values will be escaped
into JSON quote string format if it's an instance of java.lang.String. Other
type of instance like java.lang.Number,java.lang.Boolean,null,JSONObject and
JSONArray will NOT escape, just take their java.lang.String.valueOf() result.
null value will be the JSON 'null' in the result.
It's still correct if you put an instance of JSONObject or JSONArray into an
instance of JSONObject or JSONArray. Take the example about:
JSONObject obj2=new JSONObject();
obj2.put("phone","123456");
obj2.put("zip","7890");
obj.put("contact",obj2);
System.out.print(obj);
Result:
{"nickname":null,"num":100,"contact":{"phone":"123456","zip":"7890"},"balance":1000.21,"is_vip":true,"name":"foo"}
The method JSONObject.escape() is used to escape Java string into JSON quote
string. Controls and specials will be escaped correctly into \b,\f,\r,\n,\t,
\",\\,\/,\uhhhh.
5.Some detail about JSONArray?
org.json.simple.JSONArray inherits java.util.ArrayList. Feel free to use the
List methods like get(),add(),remove(),iterator() and so on. The rules of
JSONArray.toString() is similar to JSONObject.toString(). Here's the example:
import org.json.simple.JSONArray;
JSONArray array=new JSONArray();
array.add("hello");
array.add(new Integer(123));
array.add(new Boolean(false));
array.add(null);
array.add(new Double(123.45));
array.add(obj2);//see above
System.out.print(array);
Result:
["hello",123,false,null,123.45,{"phone":"123456","zip":"7890"}]
6.What is JSONValue for?
org.json.simple.JSONValue is use to parse JSON data into Java Object.
In JSON, the topmost entity is JSON value, not the JSON object. But
it's not necessary to wrap JSON string,boolean,number and null again,
for the Java has already had the according classes: java.lang.String,
java.lang.Boolean,java.lang.Number and null. The mapping is:
JSON Java
------------------------------------------------
string <=> java.lang.String
number <=> java.lang.Number
true|false <=> java.lang.Boolean
null <=> null
array <=> org.json.simple.JSONArray
object <=> org.json.simple.JSONObject
------------------------------------------------
JSONValue has only one kind of method, JSONValue.parse(), which receives
a java.io.Reader or java.lang.String. Return type of JSONValue.parse()
is according to the mapping above. If the input is incorrect in syntax or
there's exceptions during the parsing, I choose to return null, ignoring
the exception: I have no idea if it's a serious implementaion, but I think
it's convenient to the user.
Here's the example:
String s="[0,{\"1\":{\"2\":{\"3\":{\"4\":[5,{\"6\":7}]}}}}]";
Object obj=JSONValue.parse(s);
JSONArray array=(JSONArray)obj;
System.out.println(array.get(1));
JSONObject obj2=(JSONObject)array.get(1);
System.out.println(obj2.get("1"));
Result:
{"1":{"2":{"3":{"4":[5,{"6":7}]}}}}
{"2":{"3":{"4":[5,{"6":7}]}}}
7.About the author.
I'm a Java EE developer on Linux.
I'm working on web systems and information retrieval systems.
I also develop 3D games and Flash games.
You can contact me through:
Fang Yidong<fangyidong@yahoo.com.cn>
Fang Yidong<fangyidong@gmail.com>
8.Project home.
http://code.google.com/p/json-simple/
http://www.JSON.org/java/json_simple.zip

View File

@@ -1 +1 @@
1.0.2 1.1

View File

@@ -1,5 +1,5 @@
<project name="json-simple" default="main" basedir="."> <project name="json-simple" default="main" basedir=".">
<property name="current-version" value="1.0.2"/> <property name="current-version" value="1.1"/>
<property name="jar-name" value="json_simple-${current-version}.jar"/> <property name="jar-name" value="json_simple-${current-version}.jar"/>
<target name="main" depends="jar"> <target name="main" depends="jar">
@@ -14,7 +14,6 @@
<target name="mkdir"> <target name="mkdir">
<mkdir dir="build/main"/> <mkdir dir="build/main"/>
<mkdir dir="build/test"/>
</target> </target>
<target name="compile" depends="mkdir"> <target name="compile" depends="mkdir">
@@ -25,30 +24,6 @@
source="1.2"/> source="1.2"/>
</target> </target>
<target name="compile-test" depends="compile">
<javac srcdir="test"
destdir="build/test"
includes="**/*.java"
target="1.2"
source="1.2">
<classpath>
<pathelement location="build/main"/>
</classpath>
</javac>
</target>
<target name="test" depends="compile-test">
<junit haltonfailure="yes" printsummary="yes">
<classpath>
<pathelement location="build/main"/>
<pathelement location="build/test"/>
</classpath>
<batchtest>
<fileset dir="test" includes="**/*Test.java,**/Test.java"/>
</batchtest>
</junit>
</target>
<target name="jar" depends="compile"> <target name="jar" depends="compile">
<jar destfile="lib/${jar-name}" <jar destfile="lib/${jar-name}"
basedir="build/main" basedir="build/main"

View File

@@ -5,20 +5,28 @@ package org.json.simple.parser;
%{ %{
private StringBuffer sb=new StringBuffer(); private StringBuffer sb=new StringBuffer();
int getPosition(){
return yychar;
}
%} %}
%switch %table
%unicode %unicode
%state STRING_BEGIN %state STRING_BEGIN
%yylexthrow ParseException
%char
HEX_D = [a-fA-F0-9] HEX_D = [a-fA-F0-9]
INT = [-]?[0-9]+ INT = [-]?[0-9]+
DOUBLE = {INT}((\.[0-9]+)?([eE][-+]?[0-9]+)?) DOUBLE = {INT}((\.[0-9]+)?([eE][-+]?[0-9]+)?)
WS = [ \t\r\n] WS = [ \t\r\n]
UNESCAPED_CH = [^\"\\] UNESCAPED_CH = [^\"\\]
FALLBACK_CH = .
%% %%
<STRING_BEGIN> \" { yybegin(YYINITIAL);return new Yytoken(Yytoken.TYPE_VALUE,sb.toString());} <STRING_BEGIN> \" { yybegin(YYINITIAL);return new Yytoken(Yytoken.TYPE_VALUE, sb.toString());}
<STRING_BEGIN> {UNESCAPED_CH}+ { sb.append(yytext());} <STRING_BEGIN> {UNESCAPED_CH}+ { sb.append(yytext());}
<STRING_BEGIN> \\\" {sb.append('"');} <STRING_BEGIN> \\\" {sb.append('"');}
<STRING_BEGIN> \\\\ {sb.append('\\');} <STRING_BEGIN> \\\\ {sb.append('\\');}
@@ -28,15 +36,21 @@ UNESCAPED_CH = [^\"\\]
<STRING_BEGIN> \\n {sb.append('\n');} <STRING_BEGIN> \\n {sb.append('\n');}
<STRING_BEGIN> \\r {sb.append('\r');} <STRING_BEGIN> \\r {sb.append('\r');}
<STRING_BEGIN> \\t {sb.append('\t');} <STRING_BEGIN> \\t {sb.append('\t');}
<STRING_BEGIN> \\u{HEX_D}{HEX_D}{HEX_D}{HEX_D} { int ch=Integer.parseInt(yytext().substring(2),16); <STRING_BEGIN> \\u{HEX_D}{HEX_D}{HEX_D}{HEX_D} { try{
int ch=Integer.parseInt(yytext().substring(2),16);
sb.append((char)ch); sb.append((char)ch);
} }
catch(Exception e){
throw new ParseException(yychar, ParseException.ERROR_UNEXPECTED_EXCEPTION, e);
}
}
<STRING_BEGIN> \\ {sb.append('\\');}
<YYINITIAL> \" { sb.delete(0, sb.length());yybegin(STRING_BEGIN);} <YYINITIAL> \" { sb.delete(0, sb.length());yybegin(STRING_BEGIN);}
<YYINITIAL> {INT} { Long val=Long.valueOf(yytext()); return new Yytoken(Yytoken.TYPE_VALUE,val);} <YYINITIAL> {INT} { Long val=Long.valueOf(yytext()); return new Yytoken(Yytoken.TYPE_VALUE, val);}
<YYINITIAL> {DOUBLE} { Double val=Double.valueOf(yytext()); return new Yytoken(Yytoken.TYPE_VALUE,val);} <YYINITIAL> {DOUBLE} { Double val=Double.valueOf(yytext()); return new Yytoken(Yytoken.TYPE_VALUE, val);}
<YYINITIAL> "true"|"false" { Boolean val=Boolean.valueOf(yytext()); return new Yytoken(Yytoken.TYPE_VALUE,val);} <YYINITIAL> "true"|"false" { Boolean val=Boolean.valueOf(yytext()); return new Yytoken(Yytoken.TYPE_VALUE, val);}
<YYINITIAL> "null" { return new Yytoken(Yytoken.TYPE_VALUE,null);} <YYINITIAL> "null" { return new Yytoken(Yytoken.TYPE_VALUE, null);}
<YYINITIAL> "{" { return new Yytoken(Yytoken.TYPE_LEFT_BRACE,null);} <YYINITIAL> "{" { return new Yytoken(Yytoken.TYPE_LEFT_BRACE,null);}
<YYINITIAL> "}" { return new Yytoken(Yytoken.TYPE_RIGHT_BRACE,null);} <YYINITIAL> "}" { return new Yytoken(Yytoken.TYPE_RIGHT_BRACE,null);}
<YYINITIAL> "[" { return new Yytoken(Yytoken.TYPE_LEFT_SQUARE,null);} <YYINITIAL> "[" { return new Yytoken(Yytoken.TYPE_LEFT_SQUARE,null);}
@@ -44,3 +58,4 @@ UNESCAPED_CH = [^\"\\]
<YYINITIAL> "," { return new Yytoken(Yytoken.TYPE_COMMA,null);} <YYINITIAL> "," { return new Yytoken(Yytoken.TYPE_COMMA,null);}
<YYINITIAL> ":" { return new Yytoken(Yytoken.TYPE_COLON,null);} <YYINITIAL> ":" { return new Yytoken(Yytoken.TYPE_COLON,null);}
<YYINITIAL> {WS}+ {} <YYINITIAL> {WS}+ {}
<YYINITIAL> {FALLBACK_CH} { throw new ParseException(yychar, ParseException.ERROR_UNEXPECTED_CHAR, new Character(yycharat(0)));}

BIN
lib/json_simple-1.1.jar Normal file

Binary file not shown.

View File

@@ -0,0 +1,147 @@
/*
* $Id: ItemList.java,v 1.1 2006/04/15 14:10:48 platform Exp $
* Created on 2006-3-24
*/
package org.json.simple;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
/**
* |a:b:c| => |a|,|b|,|c|
* |:| => ||,||
* |a:| => |a|,||
* @author FangYidong<fangyidong@yahoo.com.cn>
*/
public class ItemList {
private String sp=",";
List items=new ArrayList();
public ItemList(){}
public ItemList(String s){
this.split(s,sp,items);
}
public ItemList(String s,String sp){
this.sp=s;
this.split(s,sp,items);
}
public ItemList(String s,String sp,boolean isMultiToken){
split(s,sp,items,isMultiToken);
}
public List getItems(){
return this.items;
}
public String[] getArray(){
return (String[])this.items.toArray();
}
public void split(String s,String sp,List append,boolean isMultiToken){
if(s==null || sp==null)
return;
if(isMultiToken){
StringTokenizer tokens=new StringTokenizer(s,sp);
while(tokens.hasMoreTokens()){
append.add(tokens.nextToken().trim());
}
}
else{
this.split(s,sp,append);
}
}
public void split(String s,String sp,List append){
if(s==null || sp==null)
return;
int pos=0;
int prevPos=0;
do{
prevPos=pos;
pos=s.indexOf(sp,pos);
if(pos==-1)
break;
append.add(s.substring(prevPos,pos).trim());
pos+=sp.length();
}while(pos!=-1);
append.add(s.substring(prevPos).trim());
}
public void setSP(String sp){
this.sp=sp;
}
public void add(int i,String item){
if(item==null)
return;
items.add(i,item.trim());
}
public void add(String item){
if(item==null)
return;
items.add(item.trim());
}
public void addAll(ItemList list){
items.addAll(list.items);
}
public void addAll(String s){
this.split(s,sp,items);
}
public void addAll(String s,String sp){
this.split(s,sp,items);
}
public void addAll(String s,String sp,boolean isMultiToken){
this.split(s,sp,items,isMultiToken);
}
/**
* @param i 0-based
* @return
*/
public String get(int i){
return (String)items.get(i);
}
public int size(){
return items.size();
}
public String toString(){
return toString(sp);
}
public String toString(String sp){
StringBuffer sb=new StringBuffer();
for(int i=0;i<items.size();i++){
if(i==0)
sb.append(items.get(i));
else{
sb.append(sp);
sb.append(items.get(i));
}
}
return sb.toString();
}
public void clear(){
items.clear();
}
public void reset(){
sp=",";
items.clear();
}
}

View File

@@ -4,30 +4,104 @@
*/ */
package org.json.simple; package org.json.simple;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List;
/** /**
* A JSON array. JSONObject supports java.util.List interface.
*
* @author FangYidong<fangyidong@yahoo.com.cn> * @author FangYidong<fangyidong@yahoo.com.cn>
*/ */
public class JSONArray extends ArrayList { public class JSONArray extends ArrayList implements List, JSONAware, JSONStreamAware {
public String toString(){ private static final long serialVersionUID = 3957988303675231981L;
Iterator iter=iterator();
/**
* Encode a list into JSON text and write it to out.
* If this list is also a JSONStreamAware or a JSONAware, JSONStreamAware and JSONAware specific behaviours will be ignored at this top level.
*
* @see org.json.simple.JSONValue#writeJSONString(Object, Writer)
*
* @param list
* @param out
*/
public static void writeJSONString(List list, Writer out) throws IOException{
if(list == null){
out.write("null");
return;
}
boolean first = true;
Iterator iter=list.iterator();
out.write('[');
while(iter.hasNext()){
if(first)
first = false;
else
out.write(',');
Object value=iter.next();
if(value == null){
out.write("null");
continue;
}
JSONValue.writeJSONString(value, out);
}
out.write(']');
}
public void writeJSONString(Writer out) throws IOException{
writeJSONString(this, out);
}
/**
* Convert a list to JSON text. The result is a JSON array.
* If this list is also a JSONAware, JSONAware specific behaviours will be omitted at this top level.
*
* @see org.json.simple.JSONValue#toJSONString(Object)
*
* @param list
* @return JSON text, or "null" if list is null.
*/
public static String toJSONString(List list){
if(list == null)
return "null";
boolean first = true; boolean first = true;
StringBuffer sb = new StringBuffer(); StringBuffer sb = new StringBuffer();
Iterator iter=list.iterator();
sb.append('['); sb.append('[');
while(iter.hasNext()){ while(iter.hasNext()){
if (first) { if(first)
first = false; first = false;
} else { else
sb.append(','); sb.append(',');
Object value=iter.next();
if(value == null){
sb.append("null");
continue;
} }
JSONObject.escapeValue(iter.next(), sb); sb.append(JSONValue.toJSONString(value));
} }
sb.append(']'); sb.append(']');
return sb.toString(); return sb.toString();
} }
public String toJSONString(){
return toJSONString(this);
}
public String toString() {
return toJSONString();
}
} }

View File

@@ -0,0 +1,12 @@
package org.json.simple;
/**
* Beans that support customized output of JSON text shall implement this interface.
* @author FangYidong<fangyidong@yahoo.com.cn>
*/
public interface JSONAware {
/**
* @return JSON text
*/
String toJSONString();
}

View File

@@ -4,121 +4,126 @@
*/ */
package org.json.simple; package org.json.simple;
import java.io.IOException;
import java.io.Writer;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
/** /**
* A JSON object. Key value pairs are unordered. JSONObject supports java.util.Map interface.
*
* @author FangYidong<fangyidong@yahoo.com.cn> * @author FangYidong<fangyidong@yahoo.com.cn>
*/ */
public class JSONObject extends HashMap{ public class JSONObject extends HashMap implements Map, JSONAware, JSONStreamAware{
private static final long serialVersionUID = -503443796854799292L;
public String toString(){ /**
Iterator iter=entrySet().iterator(); * Encode a map into JSON text and write it to out.
* If this map is also a JSONAware or JSONStreamAware, JSONAware or JSONStreamAware specific behaviours will be ignored at this top level.
*
* @see org.json.simple.JSONValue#writeJSONString(Object, Writer)
*
* @param map
* @param out
*/
public static void writeJSONString(Map map, Writer out) throws IOException {
if(map == null){
out.write("null");
return;
}
boolean first = true; boolean first = true;
Iterator iter=map.entrySet().iterator();
out.write('{');
while(iter.hasNext()){
if(first)
first = false;
else
out.write(',');
Map.Entry entry=(Map.Entry)iter.next();
out.write('\"');
out.write(escape(String.valueOf(entry.getKey())));
out.write('\"');
out.write(':');
JSONValue.writeJSONString(entry.getValue(), out);
}
out.write('}');
}
public void writeJSONString(Writer out) throws IOException{
writeJSONString(this, out);
}
/**
* Convert a map to JSON text. The result is a JSON object.
* If this map is also a JSONAware, JSONAware specific behaviours will be omitted at this top level.
*
* @see org.json.simple.JSONValue#toJSONString(Object)
*
* @param map
* @return JSON text, or "null" if map is null.
*/
public static String toJSONString(Map map){
if(map == null)
return "null";
StringBuffer sb = new StringBuffer(); StringBuffer sb = new StringBuffer();
boolean first = true;
Iterator iter=map.entrySet().iterator();
sb.append('{'); sb.append('{');
while(iter.hasNext()){ while(iter.hasNext()){
if (first) { if(first)
first = false; first = false;
} else { else
sb.append(','); sb.append(',');
}
Map.Entry entry=(Map.Entry)iter.next(); Map.Entry entry=(Map.Entry)iter.next();
toString(entry.getKey().toString(), entry.getValue(), sb); toJSONString(String.valueOf(entry.getKey()),entry.getValue(), sb);
} }
sb.append('}'); sb.append('}');
return sb.toString(); return sb.toString();
} }
public static String toString(String key, Object value){ public String toJSONString(){
return toString(key, value, new StringBuffer()).toString(); return toJSONString(this);
} }
private static StringBuffer toString(String key, Object value, StringBuffer sb){ private static String toJSONString(String key,Object value, StringBuffer sb){
sb.append('\"'); sb.append('\"');
escape(key, sb); if(key == null)
sb.append("\":"); sb.append("null");
escapeValue(value, sb); else
return sb; JSONValue.escape(key, sb);
sb.append('\"').append(':');
sb.append(JSONValue.toJSONString(value));
return sb.toString();
} }
// Package-protected for JSONArray public String toString(){
static void escapeValue(Object value, StringBuffer sb) { return toJSONString();
if (value instanceof String){
sb.append('\"');
escape((String) value, sb);
sb.append('\"');
} else {
sb.append(String.valueOf(value));
} }
public static String toString(String key,Object value){
StringBuffer sb = new StringBuffer();
toJSONString(key, value, sb);
return sb.toString();
} }
/** /**
* " => \" , \ => \\ * Escape quotes, \, /, \r, \n, \b, \f, \t and other control characters (U+0000 through U+001F).
* It's the same as JSONValue.escape() only for compatibility here.
*
* @see org.json.simple.JSONValue#escape(String)
*
* @param s * @param s
* @return * @return
*/ */
public static String escape(String s){ public static String escape(String s){
if(s==null) return JSONValue.escape(s);
return null;
StringBuffer sb = new StringBuffer();
escape(s, sb);
return sb.toString();
}
// Package-protected for JSONArray
static void escape(String s, StringBuffer sb) {
for(int i=0;i<s.length();i++){
char ch=s.charAt(i);
switch(ch){
case '"':
sb.append("\\\"");
break;
case '\\':
sb.append("\\\\");
break;
case '\b':
sb.append("\\b");
break;
case '\f':
sb.append("\\f");
break;
case '\n':
sb.append("\\n");
break;
case '\r':
sb.append("\\r");
break;
case '\t':
sb.append("\\t");
break;
case '/':
sb.append("\\/");
break;
case '\u0085': // Next Line
sb.append("\\u0085");
break;
case '\u2028': // Line Separator
sb.append("\\u2028");
break;
case '\u2029': // Paragraph Separator
sb.append("\\u2029");
break;
default:
if(ch>='\u0000' && ch<='\u001F'){
String ss=Integer.toHexString(ch);
sb.append("\\u");
for(int k=0;k<4-ss.length();k++){
sb.append('0');
}
sb.append(ss.toUpperCase());
}
else{
sb.append(ch);
}
}
}//for
} }
} }

View File

@@ -0,0 +1,15 @@
package org.json.simple;
import java.io.IOException;
import java.io.Writer;
/**
* Beans that support customized output of JSON text to a writer shall implement this interface.
* @author FangYidong<fangyidong@yahoo.com.cn>
*/
public interface JSONStreamAware {
/**
* write JSON string to out.
*/
void writeJSONString(Writer out) throws IOException;
}

View File

@@ -4,10 +4,15 @@
*/ */
package org.json.simple; package org.json.simple;
import java.io.IOException;
import java.io.Reader; import java.io.Reader;
import java.io.StringReader; import java.io.StringReader;
import java.io.Writer;
import java.util.List;
import java.util.Map;
import org.json.simple.parser.JSONParser; import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
/** /**
@@ -15,9 +20,21 @@ import org.json.simple.parser.JSONParser;
*/ */
public class JSONValue { public class JSONValue {
/** /**
* parse into java object from input source. * Parse JSON text into java object from the input source.
* Please use parseWithException() if you don't want to ignore the exception.
*
* @see org.json.simple.parser.JSONParser#parse(Reader)
* @see #parseWithException(Reader)
*
* @param in * @param in
* @return instance of : JSONObject,JSONArray,String,Boolean,Long,Double or null * @return Instance of the following:
* org.json.simple.JSONObject,
* org.json.simple.JSONArray,
* java.lang.String,
* java.lang.Number,
* java.lang.Boolean,
* null
*
*/ */
public static Object parse(Reader in){ public static Object parse(Reader in){
try{ try{
@@ -33,4 +50,231 @@ public class JSONValue {
StringReader in=new StringReader(s); StringReader in=new StringReader(s);
return parse(in); return parse(in);
} }
/**
* Parse JSON text into java object from the input source.
*
* @see org.json.simple.parser.JSONParser
*
* @param in
* @return Instance of the following:
* org.json.simple.JSONObject,
* org.json.simple.JSONArray,
* java.lang.String,
* java.lang.Number,
* java.lang.Boolean,
* null
*
* @throws IOException
* @throws ParseException
*/
public static Object parseWithException(Reader in) throws IOException, ParseException{
JSONParser parser=new JSONParser();
return parser.parse(in);
}
public static Object parseWithException(String s) throws ParseException{
JSONParser parser=new JSONParser();
return parser.parse(s);
}
/**
* Encode an object into JSON text and write it to out.
* <p>
* If this object is a Map or a List, and it's also a JSONStreamAware or a JSONAware, JSONStreamAware or JSONAware will be considered firstly.
* <p>
* DO NOT call this method from writeJSONString(Writer) of a class that implements both JSONStreamAware and (Map or List) with
* "this" as the first parameter, use JSONObject.writeJSONString(Map, Writer) or JSONArray.writeJSONString(List, Writer) instead.
*
* @see org.json.simple.JSONObject#writeJSONString(Map, Writer)
* @see org.json.simple.JSONArray#writeJSONString(List, Writer)
*
* @param value
* @param writer
*/
public static void writeJSONString(Object value, Writer out) throws IOException {
if(value == null){
out.write("null");
return;
}
if(value instanceof String){
out.write('\"');
out.write(escape((String)value));
out.write('\"');
return;
}
if(value instanceof Double){
if(((Double)value).isInfinite() || ((Double)value).isNaN())
out.write("null");
else
out.write(value.toString());
return;
}
if(value instanceof Float){
if(((Float)value).isInfinite() || ((Float)value).isNaN())
out.write("null");
else
out.write(value.toString());
return;
}
if(value instanceof Number){
out.write(value.toString());
return;
}
if(value instanceof Boolean){
out.write(value.toString());
return;
}
if((value instanceof JSONStreamAware)){
((JSONStreamAware)value).writeJSONString(out);
return;
}
if((value instanceof JSONAware)){
out.write(((JSONAware)value).toJSONString());
return;
}
if(value instanceof Map){
JSONObject.writeJSONString((Map)value, out);
return;
}
if(value instanceof List){
JSONArray.writeJSONString((List)value, out);
return;
}
out.write(value.toString());
}
/**
* Convert an object to JSON text.
* <p>
* If this object is a Map or a List, and it's also a JSONAware, JSONAware will be considered firstly.
* <p>
* DO NOT call this method from toJSONString() of a class that implements both JSONAware and Map or List with
* "this" as the parameter, use JSONObject.toJSONString(Map) or JSONArray.toJSONString(List) instead.
*
* @see org.json.simple.JSONObject#toJSONString(Map)
* @see org.json.simple.JSONArray#toJSONString(List)
*
* @param value
* @return JSON text, or "null" if value is null or it's an NaN or an INF number.
*/
public static String toJSONString(Object value){
if(value == null)
return "null";
if(value instanceof String)
return "\""+escape((String)value)+"\"";
if(value instanceof Double){
if(((Double)value).isInfinite() || ((Double)value).isNaN())
return "null";
else
return value.toString();
}
if(value instanceof Float){
if(((Float)value).isInfinite() || ((Float)value).isNaN())
return "null";
else
return value.toString();
}
if(value instanceof Number)
return value.toString();
if(value instanceof Boolean)
return value.toString();
if((value instanceof JSONAware))
return ((JSONAware)value).toJSONString();
if(value instanceof Map)
return JSONObject.toJSONString((Map)value);
if(value instanceof List)
return JSONArray.toJSONString((List)value);
return value.toString();
}
/**
* Escape quotes, \, /, \r, \n, \b, \f, \t and other control characters (U+0000 through U+001F).
* @param s
* @return
*/
public static String escape(String s){
if(s==null)
return null;
StringBuffer sb = new StringBuffer();
escape(s, sb);
return sb.toString();
}
/**
* @param s - Must not be null.
* @param sb
*/
static void escape(String s, StringBuffer sb) {
for(int i=0;i<s.length();i++){
char ch=s.charAt(i);
switch(ch){
case '"':
sb.append("\\\"");
break;
case '\\':
sb.append("\\\\");
break;
case '\b':
sb.append("\\b");
break;
case '\f':
sb.append("\\f");
break;
case '\n':
sb.append("\\n");
break;
case '\r':
sb.append("\\r");
break;
case '\t':
sb.append("\\t");
break;
case '/':
sb.append("\\/");
break;
case '\u0085': // Next Line
sb.append("\\u0085");
break;
case '\u2028': // Line Separator
sb.append("\\u2028");
break;
case '\u2029': // Paragraph Separator
sb.append("\\u2029");
break;
default:
if(ch>='\u0000' && ch<='\u001F'){
String ss=Integer.toHexString(ch);
sb.append("\\u");
for(int k=0;k<4-ss.length();k++){
sb.append('0');
}
sb.append(ss.toUpperCase());
}
else{
sb.append(ch);
}
}
}//for
}
} }

View File

@@ -0,0 +1,23 @@
package org.json.simple.parser;
import java.util.List;
import java.util.Map;
/**
* Container factory for creating containers for JSON object and JSON array.
*
* @see org.json.simple.parser.JSONParser#parse(java.io.Reader, ContainerFactory)
*
* @author FangYidong<fangyidong@yahoo.com.cn>
*/
public interface ContainerFactory {
/**
* @return A Map instance to store JSON object, or null if you want to use org.json.simple.JSONObject.
*/
Map createObjectContainer();
/**
* @return A List instance to store JSON array, or null if you want to use org.json.simple.JSONArray.
*/
List creatArrayContainer();
}

View File

@@ -0,0 +1,99 @@
package org.json.simple.parser;
import java.io.IOException;
/**
* A simplified and stoppable SAX-like content handler for stream processing of JSON text.
*
* @see org.xml.sax.ContentHandler
*
* @author FangYidong<fangyidong@yahoo.com.cn>
*/
public interface ContentHandler {
/**
* Receive notification of the beginning of JSON processing.
*
* User can throw a ParseException with errorType ParseException.INFO_USER_STOP to let the parser stop.
*
* @throws ParseException
* JSONParser will stop and throw the same exception to the caller when receiving this exception.
*/
void startJSON() throws ParseException, IOException;
/**
* Receive notification of the end of JSON processing.
*
* @return false if the handler wants to stop parsing after return.
* @throws ParseException
*/
void endJSON() throws ParseException, IOException;
/**
* Receive notification of the beginning of a JSON object.
*
* @return false if the handler wants to stop parsing after return.
* @throws ParseException
*/
boolean startObject() throws ParseException, IOException;
/**
* Receive notification of the end of a JSON object.
*
* @return false if the handler wants to stop parsing after return.
* @throws ParseException
*/
boolean endObject() throws ParseException, IOException;
/**
* Receive notification of the beginning of a JSON object key value pair.
*
* @param key - Key of a JSON object key value pair.
*
* @return false if the handler wants to stop parsing after return.
* @throws ParseException
*/
boolean startObjectEntry(String key) throws ParseException, IOException;
/**
* Receive notification of the end of the value of previous object entry.
*
* @return false if the handler wants to stop parsing after return.
* @throws ParseException
*/
boolean endObjectEntry() throws ParseException, IOException;
/**
* Receive notification of the beginning of a JSON array.
*
* @return false if the handler wants to stop parsing after return.
* @throws ParseException
*/
boolean startArray() throws ParseException, IOException;
/**
* Receive notification of the end of a JSON array.
*
* @return false if the handler wants to stop parsing after return.
* @throws ParseException
*/
boolean endArray() throws ParseException, IOException;
/**
* Receive notification of the JSON primitive values:
* java.lang.String,
* java.lang.Number,
* java.lang.Boolean
* null
*
* @param value - Instance of the following:
* java.lang.String,
* java.lang.Number,
* java.lang.Boolean
* null
*
* @return false if the handler wants to stop parsing after return.
* @throws ParseException
*/
boolean primitive(Object value) throws ParseException, IOException;
}

View File

@@ -4,14 +4,20 @@
*/ */
package org.json.simple.parser; package org.json.simple.parser;
import java.io.IOException;
import java.io.Reader; import java.io.Reader;
import java.io.StringReader;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.json.simple.JSONArray; import org.json.simple.JSONArray;
import org.json.simple.JSONObject; import org.json.simple.JSONObject;
/** /**
* Parser for JSON text. Please note that JSONParser is NOT thread-safe.
*
* @author FangYidong<fangyidong@yahoo.com.cn> * @author FangYidong<fangyidong@yahoo.com.cn>
*/ */
public class JSONParser { public class JSONParser {
@@ -20,10 +26,11 @@ public class JSONParser {
public static final int S_IN_OBJECT=2; public static final int S_IN_OBJECT=2;
public static final int S_IN_ARRAY=3; public static final int S_IN_ARRAY=3;
public static final int S_PASSED_PAIR_KEY=4; public static final int S_PASSED_PAIR_KEY=4;
public static final int S_IN_PAIR_VALUE=5;
public static final int S_END=6;
public static final int S_IN_ERROR=-1; public static final int S_IN_ERROR=-1;
private LinkedList statusStack = new LinkedList(); private LinkedList handlerStatusStack;
private LinkedList valueStack = new LinkedList();
private Yylex lexer = new Yylex((Reader)null); private Yylex lexer = new Yylex((Reader)null);
private Yytoken token = null; private Yytoken token = null;
private int status = S_INIT; private int status = S_INIT;
@@ -35,22 +42,80 @@ public class JSONParser {
return status.intValue(); return status.intValue();
} }
private void reset(Reader in) throws Exception{ /**
statusStack.clear(); * Reset the parser to the initial state without resetting the underlying reader.
valueStack.clear(); *
lexer.yyreset(in); */
public void reset(){
token = null; token = null;
status = S_INIT; status = S_INIT;
handlerStatusStack = null;
} }
public Object parse(Reader in) throws Exception{ /**
* Reset the parser to the initial state with a new character reader.
*
* @param in - The new character reader.
* @throws IOException
* @throws ParseException
*/
public void reset(Reader in){
lexer.yyreset(in);
reset();
}
/**
* @return The position of the beginning of the current token.
*/
public int getPosition(){
return lexer.getPosition();
}
public Object parse(String s) throws ParseException{
return parse(s, (ContainerFactory)null);
}
public Object parse(String s, ContainerFactory containerFactory) throws ParseException{
StringReader in=new StringReader(s);
try{
return parse(in, containerFactory);
}
catch(IOException ie){
/*
* Actually it will never happen.
*/
throw new ParseException(-1, ParseException.ERROR_UNEXPECTED_EXCEPTION, ie);
}
}
public Object parse(Reader in) throws IOException, ParseException{
return parse(in, (ContainerFactory)null);
}
/**
* Parse JSON text into java object from the input source.
*
* @param in
* @param containerFactory - Use this factory to createyour own JSON object and JSON array containers.
* @return Instance of the following:
* org.json.simple.JSONObject,
* org.json.simple.JSONArray,
* java.lang.String,
* java.lang.Number,
* java.lang.Boolean,
* null
*
* @throws IOException
* @throws ParseException
*/
public Object parse(Reader in, ContainerFactory containerFactory) throws IOException, ParseException{
reset(in); reset(in);
LinkedList statusStack = new LinkedList();
LinkedList valueStack = new LinkedList();
try{ try{
do{ do{
token=lexer.yylex(); nextToken();
if(token==null)
token=new Yytoken(Yytoken.TYPE_EOF,null);
switch(status){ switch(status){
case S_INIT: case S_INIT:
switch(token.type){ switch(token.type){
@@ -62,12 +127,12 @@ public class JSONParser {
case Yytoken.TYPE_LEFT_BRACE: case Yytoken.TYPE_LEFT_BRACE:
status=S_IN_OBJECT; status=S_IN_OBJECT;
statusStack.addFirst(new Integer(status)); statusStack.addFirst(new Integer(status));
valueStack.addFirst(new JSONObject()); valueStack.addFirst(createObjectContainer(containerFactory));
break; break;
case Yytoken.TYPE_LEFT_SQUARE: case Yytoken.TYPE_LEFT_SQUARE:
status=S_IN_ARRAY; status=S_IN_ARRAY;
statusStack.addFirst(new Integer(status)); statusStack.addFirst(new Integer(status));
valueStack.addFirst(new JSONArray()); valueStack.addFirst(createArrayContainer(containerFactory));
break; break;
default: default:
status=S_IN_ERROR; status=S_IN_ERROR;
@@ -78,7 +143,7 @@ public class JSONParser {
if(token.type==Yytoken.TYPE_EOF) if(token.type==Yytoken.TYPE_EOF)
return valueStack.removeFirst(); return valueStack.removeFirst();
else else
return null; throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
case S_IN_OBJECT: case S_IN_OBJECT:
switch(token.type){ switch(token.type){
@@ -118,15 +183,15 @@ public class JSONParser {
case Yytoken.TYPE_VALUE: case Yytoken.TYPE_VALUE:
statusStack.removeFirst(); statusStack.removeFirst();
String key=(String)valueStack.removeFirst(); String key=(String)valueStack.removeFirst();
JSONObject parent=(JSONObject)valueStack.getFirst(); Map parent=(Map)valueStack.getFirst();
parent.put(key,token.value); parent.put(key,token.value);
status=peekStatus(statusStack); status=peekStatus(statusStack);
break; break;
case Yytoken.TYPE_LEFT_SQUARE: case Yytoken.TYPE_LEFT_SQUARE:
statusStack.removeFirst(); statusStack.removeFirst();
key=(String)valueStack.removeFirst(); key=(String)valueStack.removeFirst();
parent=(JSONObject)valueStack.getFirst(); parent=(Map)valueStack.getFirst();
JSONArray newArray=new JSONArray(); List newArray=createArrayContainer(containerFactory);
parent.put(key,newArray); parent.put(key,newArray);
status=S_IN_ARRAY; status=S_IN_ARRAY;
statusStack.addFirst(new Integer(status)); statusStack.addFirst(new Integer(status));
@@ -135,8 +200,8 @@ public class JSONParser {
case Yytoken.TYPE_LEFT_BRACE: case Yytoken.TYPE_LEFT_BRACE:
statusStack.removeFirst(); statusStack.removeFirst();
key=(String)valueStack.removeFirst(); key=(String)valueStack.removeFirst();
parent=(JSONObject)valueStack.getFirst(); parent=(Map)valueStack.getFirst();
JSONObject newObject=new JSONObject(); Map newObject=createObjectContainer(containerFactory);
parent.put(key,newObject); parent.put(key,newObject);
status=S_IN_OBJECT; status=S_IN_OBJECT;
statusStack.addFirst(new Integer(status)); statusStack.addFirst(new Integer(status));
@@ -152,7 +217,7 @@ public class JSONParser {
case Yytoken.TYPE_COMMA: case Yytoken.TYPE_COMMA:
break; break;
case Yytoken.TYPE_VALUE: case Yytoken.TYPE_VALUE:
JSONArray val=(JSONArray)valueStack.getFirst(); List val=(List)valueStack.getFirst();
val.add(token.value); val.add(token.value);
break; break;
case Yytoken.TYPE_RIGHT_SQUARE: case Yytoken.TYPE_RIGHT_SQUARE:
@@ -166,16 +231,16 @@ public class JSONParser {
} }
break; break;
case Yytoken.TYPE_LEFT_BRACE: case Yytoken.TYPE_LEFT_BRACE:
val=(JSONArray)valueStack.getFirst(); val=(List)valueStack.getFirst();
JSONObject newObject=new JSONObject(); Map newObject=createObjectContainer(containerFactory);
val.add(newObject); val.add(newObject);
status=S_IN_OBJECT; status=S_IN_OBJECT;
statusStack.addFirst(new Integer(status)); statusStack.addFirst(new Integer(status));
valueStack.addFirst(newObject); valueStack.addFirst(newObject);
break; break;
case Yytoken.TYPE_LEFT_SQUARE: case Yytoken.TYPE_LEFT_SQUARE:
val=(JSONArray)valueStack.getFirst(); val=(List)valueStack.getFirst();
JSONArray newArray=new JSONArray(); List newArray=createArrayContainer(containerFactory);
val.add(newArray); val.add(newArray);
status=S_IN_ARRAY; status=S_IN_ARRAY;
statusStack.addFirst(new Integer(status)); statusStack.addFirst(new Integer(status));
@@ -186,15 +251,283 @@ public class JSONParser {
}//inner switch }//inner switch
break; break;
case S_IN_ERROR: case S_IN_ERROR:
return null; throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
}//switch }//switch
if(status==S_IN_ERROR) if(status==S_IN_ERROR){
return null; throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
}
}while(token.type!=Yytoken.TYPE_EOF); }while(token.type!=Yytoken.TYPE_EOF);
} }
catch(Exception e){ catch(IOException ie){
throw ie;
}
throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
}
private void nextToken() throws ParseException, IOException{
token = lexer.yylex();
if(token == null)
token = new Yytoken(Yytoken.TYPE_EOF, null);
}
private Map createObjectContainer(ContainerFactory containerFactory){
if(containerFactory == null)
return new JSONObject();
Map m = containerFactory.createObjectContainer();
if(m == null)
return new JSONObject();
return m;
}
private List createArrayContainer(ContainerFactory containerFactory){
if(containerFactory == null)
return new JSONArray();
List l = containerFactory.creatArrayContainer();
if(l == null)
return new JSONArray();
return l;
}
public void parse(String s, ContentHandler contentHandler) throws ParseException{
parse(s, contentHandler, false);
}
public void parse(String s, ContentHandler contentHandler, boolean isResume) throws ParseException{
StringReader in=new StringReader(s);
try{
parse(in, contentHandler, isResume);
}
catch(IOException ie){
/*
* Actually it will never happen.
*/
throw new ParseException(-1, ParseException.ERROR_UNEXPECTED_EXCEPTION, ie);
}
}
public void parse(Reader in, ContentHandler contentHandler) throws IOException, ParseException{
parse(in, contentHandler, false);
}
/**
* Stream processing of JSON text.
*
* @see ContentHandler
*
* @param in
* @param contentHandler
* @param isResume - Indicates if it continues previous parsing operation.
* If set to true, resume parsing the old stream, and parameter 'in' will be ignored.
* If this method is called for the first time in this instance, isResume will be ignored.
*
* @throws IOException
* @throws ParseException
*/
public void parse(Reader in, ContentHandler contentHandler, boolean isResume) throws IOException, ParseException{
if(!isResume){
reset(in);
handlerStatusStack = new LinkedList();
}
else{
if(handlerStatusStack == null){
isResume = false;
reset(in);
handlerStatusStack = new LinkedList();
}
}
LinkedList statusStack = handlerStatusStack;
try{
do{
switch(status){
case S_INIT:
contentHandler.startJSON();
nextToken();
switch(token.type){
case Yytoken.TYPE_VALUE:
status=S_IN_FINISHED_VALUE;
statusStack.addFirst(new Integer(status));
if(!contentHandler.primitive(token.value))
return;
break;
case Yytoken.TYPE_LEFT_BRACE:
status=S_IN_OBJECT;
statusStack.addFirst(new Integer(status));
if(!contentHandler.startObject())
return;
break;
case Yytoken.TYPE_LEFT_SQUARE:
status=S_IN_ARRAY;
statusStack.addFirst(new Integer(status));
if(!contentHandler.startArray())
return;
break;
default:
status=S_IN_ERROR;
}//inner switch
break;
case S_IN_FINISHED_VALUE:
nextToken();
if(token.type==Yytoken.TYPE_EOF){
contentHandler.endJSON();
status = S_END;
return;
}
else{
status = S_IN_ERROR;
throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
}
case S_IN_OBJECT:
nextToken();
switch(token.type){
case Yytoken.TYPE_COMMA:
break;
case Yytoken.TYPE_VALUE:
if(token.value instanceof String){
String key=(String)token.value;
status=S_PASSED_PAIR_KEY;
statusStack.addFirst(new Integer(status));
if(!contentHandler.startObjectEntry(key))
return;
}
else{
status=S_IN_ERROR;
}
break;
case Yytoken.TYPE_RIGHT_BRACE:
if(statusStack.size()>1){
statusStack.removeFirst();
status=peekStatus(statusStack);
}
else{
status=S_IN_FINISHED_VALUE;
}
if(!contentHandler.endObject())
return;
break;
default:
status=S_IN_ERROR;
break;
}//inner switch
break;
case S_PASSED_PAIR_KEY:
nextToken();
switch(token.type){
case Yytoken.TYPE_COLON:
break;
case Yytoken.TYPE_VALUE:
statusStack.removeFirst();
status=peekStatus(statusStack);
if(!contentHandler.primitive(token.value))
return;
if(!contentHandler.endObjectEntry())
return;
break;
case Yytoken.TYPE_LEFT_SQUARE:
statusStack.removeFirst();
statusStack.addFirst(new Integer(S_IN_PAIR_VALUE));
status=S_IN_ARRAY;
statusStack.addFirst(new Integer(status));
if(!contentHandler.startArray())
return;
break;
case Yytoken.TYPE_LEFT_BRACE:
statusStack.removeFirst();
statusStack.addFirst(new Integer(S_IN_PAIR_VALUE));
status=S_IN_OBJECT;
statusStack.addFirst(new Integer(status));
if(!contentHandler.startObject())
return;
break;
default:
status=S_IN_ERROR;
}
break;
case S_IN_PAIR_VALUE:
/*
* S_IN_PAIR_VALUE is just a marker to indicate the end of an object entry, it doesn't proccess any token,
* therefore delay consuming token until next round.
*/
statusStack.removeFirst();
status = peekStatus(statusStack);
if(!contentHandler.endObjectEntry())
return;
break;
case S_IN_ARRAY:
nextToken();
switch(token.type){
case Yytoken.TYPE_COMMA:
break;
case Yytoken.TYPE_VALUE:
if(!contentHandler.primitive(token.value))
return;
break;
case Yytoken.TYPE_RIGHT_SQUARE:
if(statusStack.size()>1){
statusStack.removeFirst();
status=peekStatus(statusStack);
}
else{
status=S_IN_FINISHED_VALUE;
}
if(!contentHandler.endArray())
return;
break;
case Yytoken.TYPE_LEFT_BRACE:
status=S_IN_OBJECT;
statusStack.addFirst(new Integer(status));
if(!contentHandler.startObject())
return;
break;
case Yytoken.TYPE_LEFT_SQUARE:
status=S_IN_ARRAY;
statusStack.addFirst(new Integer(status));
if(!contentHandler.startArray())
return;
break;
default:
status=S_IN_ERROR;
}//inner switch
break;
case S_END:
return;
case S_IN_ERROR:
throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
}//switch
if(status==S_IN_ERROR){
throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
}
}while(token.type!=Yytoken.TYPE_EOF);
}
catch(IOException ie){
status = S_IN_ERROR;
throw ie;
}
catch(ParseException pe){
status = S_IN_ERROR;
throw pe;
}
catch(RuntimeException re){
status = S_IN_ERROR;
throw re;
}
catch(Error e){
status = S_IN_ERROR;
throw e; throw e;
} }
return null;
status = S_IN_ERROR;
throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
} }
} }

View File

@@ -0,0 +1,90 @@
package org.json.simple.parser;
/**
* ParseException explains why and where the error occurs in source JSON text.
*
* @author FangYidong<fangyidong@yahoo.com.cn>
*
*/
public class ParseException extends Exception {
private static final long serialVersionUID = -7880698968187728548L;
public static final int ERROR_UNEXPECTED_CHAR = 0;
public static final int ERROR_UNEXPECTED_TOKEN = 1;
public static final int ERROR_UNEXPECTED_EXCEPTION = 2;
private int errorType;
private Object unexpectedObject;
private int position;
public ParseException(int errorType){
this(-1, errorType, null);
}
public ParseException(int errorType, Object unexpectedObject){
this(-1, errorType, unexpectedObject);
}
public ParseException(int position, int errorType, Object unexpectedObject){
this.position = position;
this.errorType = errorType;
this.unexpectedObject = unexpectedObject;
}
public int getErrorType() {
return errorType;
}
public void setErrorType(int errorType) {
this.errorType = errorType;
}
/**
* @see org.json.simple.parser.JSONParser#getPosition()
*
* @return The character position (starting with 0) of the input where the error occurs.
*/
public int getPosition() {
return position;
}
public void setPosition(int position) {
this.position = position;
}
/**
* @see org.json.simple.parser.Yytoken
*
* @return One of the following base on the value of errorType:
* ERROR_UNEXPECTED_CHAR java.lang.Character
* ERROR_UNEXPECTED_TOKEN org.json.simple.parser.Yytoken
* ERROR_UNEXPECTED_EXCEPTION java.lang.Exception
*/
public Object getUnexpectedObject() {
return unexpectedObject;
}
public void setUnexpectedObject(Object unexpectedObject) {
this.unexpectedObject = unexpectedObject;
}
public String toString(){
StringBuffer sb = new StringBuffer();
switch(errorType){
case ERROR_UNEXPECTED_CHAR:
sb.append("Unexpected character (").append(unexpectedObject).append(") at position ").append(position).append(".");
break;
case ERROR_UNEXPECTED_TOKEN:
sb.append("Unexpected token ").append(unexpectedObject).append(" at position ").append(position).append(".");
break;
case ERROR_UNEXPECTED_EXCEPTION:
sb.append("Unexpected exception at position ").append(position).append(": ").append(unexpectedObject);
break;
default:
sb.append("Unkown error at position ").append(position).append(".");
break;
}
return sb.toString();
}
}

View File

@@ -28,11 +28,11 @@ class Yylex {
* Translates characters to character classes * Translates characters to character classes
*/ */
private static final String ZZ_CMAP_PACKED = private static final String ZZ_CMAP_PACKED =
"\11\0\2\7\2\0\1\7\22\0\1\7\1\0\1\11\10\0\1\6"+ "\11\0\1\7\1\7\2\0\1\7\22\0\1\7\1\0\1\11\10\0"+
"\1\31\1\2\1\4\1\12\12\3\1\32\6\0\4\1\1\5\1\1"+ "\1\6\1\31\1\2\1\4\1\12\12\3\1\32\6\0\4\1\1\5"+
"\24\0\1\27\1\10\1\30\3\0\1\22\1\13\2\1\1\21\1\14"+ "\1\1\24\0\1\27\1\10\1\30\3\0\1\22\1\13\2\1\1\21"+
"\5\0\1\23\1\0\1\15\3\0\1\16\1\24\1\17\1\20\5\0"+ "\1\14\5\0\1\23\1\0\1\15\3\0\1\16\1\24\1\17\1\20"+
"\1\25\1\0\1\26\uff82\0"; "\5\0\1\25\1\0\1\26\uff82\0";
/** /**
* Translates characters to character classes * Translates characters to character classes
@@ -45,13 +45,14 @@ class Yylex {
private static final int [] ZZ_ACTION = zzUnpackAction(); private static final int [] ZZ_ACTION = zzUnpackAction();
private static final String ZZ_ACTION_PACKED_0 = private static final String ZZ_ACTION_PACKED_0 =
"\3\0\1\1\1\2\1\3\3\0\1\4\1\5\1\6"+ "\2\0\2\1\1\2\1\3\1\4\3\1\1\5\1\6"+
"\1\7\1\10\1\11\1\12\1\0\1\13\5\0\1\14"+ "\1\7\1\10\1\11\1\12\1\13\1\14\1\15\5\0"+
"\1\15\1\16\1\17\1\20\1\21\1\22\1\23\1\0"+ "\1\14\1\16\1\17\1\20\1\21\1\22\1\23\1\24"+
"\1\24\1\0\1\24\4\0\1\25\1\26\2\0\1\27"; "\1\0\1\25\1\0\1\25\4\0\1\26\1\27\2\0"+
"\1\30";
private static int [] zzUnpackAction() { private static int [] zzUnpackAction() {
int [] result = new int[44]; int [] result = new int[45];
int offset = 0; int offset = 0;
offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result); offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result);
return result; return result;
@@ -70,6 +71,111 @@ class Yylex {
} }
/**
* Translates a state to a row index in the transition table
*/
private static final int [] ZZ_ROWMAP = zzUnpackRowMap();
private static final String ZZ_ROWMAP_PACKED_0 =
"\0\0\0\33\0\66\0\121\0\154\0\207\0\66\0\242"+
"\0\275\0\330\0\66\0\66\0\66\0\66\0\66\0\66"+
"\0\363\0\u010e\0\66\0\u0129\0\u0144\0\u015f\0\u017a\0\u0195"+
"\0\66\0\66\0\66\0\66\0\66\0\66\0\66\0\66"+
"\0\u01b0\0\u01cb\0\u01e6\0\u01e6\0\u0201\0\u021c\0\u0237\0\u0252"+
"\0\66\0\66\0\u026d\0\u0288\0\66";
private static int [] zzUnpackRowMap() {
int [] result = new int[45];
int offset = 0;
offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result);
return result;
}
private static int zzUnpackRowMap(String packed, int offset, int [] result) {
int i = 0; /* index in packed string */
int j = offset; /* index in unpacked array */
int l = packed.length();
while (i < l) {
int high = packed.charAt(i++) << 16;
result[j++] = high | packed.charAt(i++);
}
return j;
}
/**
* The transition table of the DFA
*/
private static final int ZZ_TRANS [] = {
2, 2, 3, 4, 2, 2, 2, 5, 2, 6,
2, 2, 7, 8, 2, 9, 2, 2, 2, 2,
2, 10, 11, 12, 13, 14, 15, 16, 16, 16,
16, 16, 16, 16, 16, 17, 18, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, 4, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, 4, 19, 20, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, 20, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, 5, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
21, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, 22, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
23, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, 16, 16, 16, 16, 16, 16, 16,
16, -1, -1, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
-1, -1, -1, -1, -1, -1, -1, -1, 24, 25,
26, 27, 28, 29, 30, 31, 32, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
33, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, 34, 35, -1, -1,
34, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
36, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, 37, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, 38, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, 39, -1, 39, -1, 39, -1, -1,
-1, -1, -1, 39, 39, -1, -1, -1, -1, 39,
39, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, 33, -1, 20, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, 20, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, 35,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, 38, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, 40,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, 41, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, 42, -1, 42, -1, 42,
-1, -1, -1, -1, -1, 42, 42, -1, -1, -1,
-1, 42, 42, -1, -1, -1, -1, -1, -1, -1,
-1, -1, 43, -1, 43, -1, 43, -1, -1, -1,
-1, -1, 43, 43, -1, -1, -1, -1, 43, 43,
-1, -1, -1, -1, -1, -1, -1, -1, -1, 44,
-1, 44, -1, 44, -1, -1, -1, -1, -1, 44,
44, -1, -1, -1, -1, 44, 44, -1, -1, -1,
-1, -1, -1, -1, -1,
};
/* error codes */ /* error codes */
private static final int ZZ_UNKNOWN_ERROR = 0; private static final int ZZ_UNKNOWN_ERROR = 0;
private static final int ZZ_NO_MATCH = 1; private static final int ZZ_NO_MATCH = 1;
@@ -82,6 +188,35 @@ class Yylex {
"Error: pushback value was too large" "Error: pushback value was too large"
}; };
/**
* ZZ_ATTRIBUTE[aState] contains the attributes of state <code>aState</code>
*/
private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute();
private static final String ZZ_ATTRIBUTE_PACKED_0 =
"\2\0\1\11\3\1\1\11\3\1\6\11\2\1\1\11"+
"\5\0\10\11\1\0\1\1\1\0\1\1\4\0\2\11"+
"\2\0\1\11";
private static int [] zzUnpackAttribute() {
int [] result = new int[45];
int offset = 0;
offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result);
return result;
}
private static int zzUnpackAttribute(String packed, int offset, int [] result) {
int i = 0; /* index in packed string */
int j = offset; /* index in unpacked array */
int l = packed.length();
while (i < l) {
int count = packed.charAt(i++);
int value = packed.charAt(i++);
do result[j++] = value; while (--count > 0);
}
return j;
}
/** the input device */ /** the input device */
private java.io.Reader zzReader; private java.io.Reader zzReader;
@@ -131,6 +266,10 @@ class Yylex {
/* user code: */ /* user code: */
private StringBuffer sb=new StringBuffer(); private StringBuffer sb=new StringBuffer();
int getPosition(){
return yychar;
}
/** /**
@@ -163,7 +302,7 @@ private StringBuffer sb=new StringBuffer();
char [] map = new char[0x10000]; char [] map = new char[0x10000];
int i = 0; /* index in packed string */ int i = 0; /* index in packed string */
int j = 0; /* index in unpacked array */ int j = 0; /* index in unpacked array */
while (i < 88) { while (i < 90) {
int count = packed.charAt(i++); int count = packed.charAt(i++);
char value = packed.charAt(i++); char value = packed.charAt(i++);
do map[j++] = value; while (--count > 0); do map[j++] = value; while (--count > 0);
@@ -359,7 +498,7 @@ private StringBuffer sb=new StringBuffer();
* @return the next token * @return the next token
* @exception java.io.IOException if any I/O-Error occurs * @exception java.io.IOException if any I/O-Error occurs
*/ */
public Yytoken yylex() throws java.io.IOException { public Yytoken yylex() throws java.io.IOException, ParseException {
int zzInput; int zzInput;
int zzAction; int zzAction;
@@ -370,10 +509,15 @@ private StringBuffer sb=new StringBuffer();
char [] zzBufferL = zzBuffer; char [] zzBufferL = zzBuffer;
char [] zzCMapL = ZZ_CMAP; char [] zzCMapL = ZZ_CMAP;
int [] zzTransL = ZZ_TRANS;
int [] zzRowMapL = ZZ_ROWMAP;
int [] zzAttrL = ZZ_ATTRIBUTE;
while (true) { while (true) {
zzMarkedPosL = zzMarkedPos; zzMarkedPosL = zzMarkedPos;
yychar+= zzMarkedPosL-zzStartRead;
zzAction = -1; zzAction = -1;
zzCurrentPosL = zzCurrentPos = zzStartRead = zzMarkedPosL; zzCurrentPosL = zzCurrentPos = zzStartRead = zzMarkedPosL;
@@ -408,225 +552,15 @@ private StringBuffer sb=new StringBuffer();
zzInput = zzBufferL[zzCurrentPosL++]; zzInput = zzBufferL[zzCurrentPosL++];
} }
} }
zzInput = zzCMapL[zzInput]; int zzNext = zzTransL[ zzRowMapL[zzState] + zzCMapL[zzInput] ];
if (zzNext == -1) break zzForAction;
zzState = zzNext;
boolean zzIsFinal = false; int zzAttributes = zzAttrL[zzState];
boolean zzNoLookAhead = false; if ( (zzAttributes & 1) == 1 ) {
zzForNext: { switch (zzState) {
case 0:
switch (zzInput) {
case 2: zzState = 2; break zzForNext;
case 3: zzIsFinal = true; zzState = 3; break zzForNext;
case 7: zzIsFinal = true; zzState = 4; break zzForNext;
case 9: zzIsFinal = true; zzNoLookAhead = true; zzState = 5; break zzForNext;
case 12: zzState = 6; break zzForNext;
case 13: zzState = 7; break zzForNext;
case 15: zzState = 8; break zzForNext;
case 21: zzIsFinal = true; zzNoLookAhead = true; zzState = 9; break zzForNext;
case 22: zzIsFinal = true; zzNoLookAhead = true; zzState = 10; break zzForNext;
case 23: zzIsFinal = true; zzNoLookAhead = true; zzState = 11; break zzForNext;
case 24: zzIsFinal = true; zzNoLookAhead = true; zzState = 12; break zzForNext;
case 25: zzIsFinal = true; zzNoLookAhead = true; zzState = 13; break zzForNext;
case 26: zzIsFinal = true; zzNoLookAhead = true; zzState = 14; break zzForNext;
default: break zzForAction;
}
case 1:
switch (zzInput) {
case 8: zzState = 16; break zzForNext;
case 9: zzIsFinal = true; zzNoLookAhead = true; zzState = 17; break zzForNext;
default: zzIsFinal = true; zzState = 15; break zzForNext;
}
case 2:
switch (zzInput) {
case 3: zzIsFinal = true; zzState = 3; break zzForNext;
default: break zzForAction;
}
case 3:
switch (zzInput) {
case 3: zzIsFinal = true; break zzForNext;
case 4: zzState = 18; break zzForNext;
case 5:
case 17: zzState = 19; break zzForNext;
default: break zzForAction;
}
case 4:
switch (zzInput) {
case 7: zzIsFinal = true; break zzForNext;
default: break zzForAction;
}
case 6:
switch (zzInput) {
case 18: zzState = 20; break zzForNext;
default: break zzForAction;
}
case 7:
switch (zzInput) {
case 16: zzState = 21; break zzForNext;
default: break zzForAction;
}
case 8:
switch (zzInput) {
case 14: zzState = 22; break zzForNext;
default: break zzForAction;
}
case 15:
switch (zzInput) {
case 8:
case 9: break zzForAction;
default: zzIsFinal = true; break zzForNext;
}
case 16:
switch (zzInput) {
case 8: zzIsFinal = true; zzNoLookAhead = true; zzState = 23; break zzForNext;
case 9: zzIsFinal = true; zzNoLookAhead = true; zzState = 24; break zzForNext;
case 10: zzIsFinal = true; zzNoLookAhead = true; zzState = 25; break zzForNext;
case 11: zzIsFinal = true; zzNoLookAhead = true; zzState = 26; break zzForNext;
case 12: zzIsFinal = true; zzNoLookAhead = true; zzState = 27; break zzForNext;
case 13: zzIsFinal = true; zzNoLookAhead = true; zzState = 28; break zzForNext;
case 14: zzIsFinal = true; zzNoLookAhead = true; zzState = 29; break zzForNext;
case 15: zzIsFinal = true; zzNoLookAhead = true; zzState = 30; break zzForNext;
case 16: zzState = 31; break zzForNext;
default: break zzForAction;
}
case 18:
switch (zzInput) {
case 3: zzIsFinal = true; zzState = 32; break zzForNext;
default: break zzForAction;
}
case 19:
switch (zzInput) {
case 2:
case 6: zzState = 33; break zzForNext;
case 3: zzIsFinal = true; zzState = 34; break zzForNext;
default: break zzForAction;
}
case 20:
switch (zzInput) {
case 19: zzState = 35; break zzForNext;
default: break zzForAction;
}
case 21:
switch (zzInput) {
case 19: zzState = 36; break zzForNext;
default: break zzForAction;
}
case 22:
switch (zzInput) {
case 16: zzState = 37; break zzForNext;
default: break zzForAction;
}
case 31:
switch (zzInput) {
case 1:
case 3:
case 5:
case 11:
case 12:
case 17:
case 18: zzState = 38; break zzForNext;
default: break zzForAction;
}
case 32:
switch (zzInput) {
case 5:
case 17: zzState = 19; break zzForNext;
case 3: zzIsFinal = true; break zzForNext;
default: break zzForAction;
}
case 33:
switch (zzInput) {
case 3: zzIsFinal = true; zzState = 34; break zzForNext;
default: break zzForAction;
}
case 34:
switch (zzInput) {
case 3: zzIsFinal = true; break zzForNext;
default: break zzForAction;
}
case 35:
switch (zzInput) {
case 20: zzState = 37; break zzForNext;
default: break zzForAction;
}
case 36:
switch (zzInput) {
case 19: zzIsFinal = true; zzNoLookAhead = true; zzState = 39; break zzForNext;
default: break zzForAction;
}
case 37:
switch (zzInput) {
case 17: zzIsFinal = true; zzNoLookAhead = true; zzState = 40; break zzForNext;
default: break zzForAction;
}
case 38:
switch (zzInput) {
case 1:
case 3:
case 5:
case 11:
case 12:
case 17:
case 18: zzState = 41; break zzForNext;
default: break zzForAction;
}
case 41:
switch (zzInput) {
case 1:
case 3:
case 5:
case 11:
case 12:
case 17:
case 18: zzState = 42; break zzForNext;
default: break zzForAction;
}
case 42:
switch (zzInput) {
case 1:
case 3:
case 5:
case 11:
case 12:
case 17:
case 18: zzIsFinal = true; zzNoLookAhead = true; zzState = 43; break zzForNext;
default: break zzForAction;
}
default:
// if this is ever reached, there is a serious bug in JFlex
zzScanError(ZZ_UNKNOWN_ERROR);
break;
} }
if ( zzIsFinal ) {
zzAction = zzState; zzAction = zzState;
zzMarkedPosL = zzCurrentPosL; zzMarkedPosL = zzCurrentPosL;
if ( zzNoLookAhead ) break zzForAction; if ( (zzAttributes & 8) == 8 ) break zzForAction;
} }
} }
@@ -636,99 +570,108 @@ private StringBuffer sb=new StringBuffer();
zzMarkedPos = zzMarkedPosL; zzMarkedPos = zzMarkedPosL;
switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) { switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) {
case 10: case 11:
{ sb.append(yytext()); { sb.append(yytext());
} }
case 24: break; case 25: break;
case 3: case 4:
{ sb.delete(0, sb.length());yybegin(STRING_BEGIN); { sb.delete(0, sb.length());yybegin(STRING_BEGIN);
} }
case 25: break; case 26: break;
case 15: case 16:
{ sb.append('\b'); { sb.append('\b');
} }
case 26: break; case 27: break;
case 5: case 6:
{ return new Yytoken(Yytoken.TYPE_RIGHT_BRACE,null); { return new Yytoken(Yytoken.TYPE_RIGHT_BRACE,null);
} }
case 27: break; case 28: break;
case 23:
{ Boolean val=Boolean.valueOf(yytext()); return new Yytoken(Yytoken.TYPE_VALUE, val);
}
case 29: break;
case 22:
{ return new Yytoken(Yytoken.TYPE_VALUE, null);
}
case 30: break;
case 13:
{ yybegin(YYINITIAL);return new Yytoken(Yytoken.TYPE_VALUE, sb.toString());
}
case 31: break;
case 12: case 12:
{ sb.append('\\'); { sb.append('\\');
} }
case 28: break;
case 20:
{ Double val=Double.valueOf(yytext()); return new Yytoken(Yytoken.TYPE_VALUE,val);
}
case 29: break;
case 1:
{ Long val=Long.valueOf(yytext()); return new Yytoken(Yytoken.TYPE_VALUE,val);
}
case 30: break;
case 7:
{ return new Yytoken(Yytoken.TYPE_RIGHT_SQUARE,null);
}
case 31: break;
case 18:
{ sb.append('\r');
}
case 32: break; case 32: break;
case 21: case 21:
{ return new Yytoken(Yytoken.TYPE_VALUE,null); { Double val=Double.valueOf(yytext()); return new Yytoken(Yytoken.TYPE_VALUE, val);
} }
case 33: break; case 33: break;
case 14: case 1:
{ sb.append('/'); { throw new ParseException(yychar, ParseException.ERROR_UNEXPECTED_CHAR, new Character(yycharat(0)));
} }
case 34: break; case 34: break;
case 9: case 8:
{ return new Yytoken(Yytoken.TYPE_COLON,null); { return new Yytoken(Yytoken.TYPE_RIGHT_SQUARE,null);
} }
case 35: break; case 35: break;
case 11: case 19:
{ yybegin(YYINITIAL);return new Yytoken(Yytoken.TYPE_VALUE,sb.toString()); { sb.append('\r');
} }
case 36: break; case 36: break;
case 13: case 15:
{ sb.append('"'); { sb.append('/');
} }
case 37: break; case 37: break;
case 4: case 10:
{ return new Yytoken(Yytoken.TYPE_LEFT_BRACE,null); { return new Yytoken(Yytoken.TYPE_COLON,null);
} }
case 38: break; case 38: break;
case 16: case 14:
{ sb.append('\f'); { sb.append('"');
} }
case 39: break; case 39: break;
case 19: case 5:
{ sb.append('\t'); { return new Yytoken(Yytoken.TYPE_LEFT_BRACE,null);
} }
case 40: break; case 40: break;
case 6: case 17:
{ return new Yytoken(Yytoken.TYPE_LEFT_SQUARE,null); { sb.append('\f');
} }
case 41: break; case 41: break;
case 23: case 24:
{ int ch=Integer.parseInt(yytext().substring(2),16); { try{
int ch=Integer.parseInt(yytext().substring(2),16);
sb.append((char)ch); sb.append((char)ch);
} }
catch(Exception e){
throw new ParseException(yychar, ParseException.ERROR_UNEXPECTED_EXCEPTION, e);
}
}
case 42: break; case 42: break;
case 22: case 20:
{ Boolean val=Boolean.valueOf(yytext()); return new Yytoken(Yytoken.TYPE_VALUE,val); { sb.append('\t');
} }
case 43: break; case 43: break;
case 17: case 7:
{ sb.append('\n'); { return new Yytoken(Yytoken.TYPE_LEFT_SQUARE,null);
} }
case 44: break; case 44: break;
case 8: case 2:
{ return new Yytoken(Yytoken.TYPE_COMMA,null); { Long val=Long.valueOf(yytext()); return new Yytoken(Yytoken.TYPE_VALUE, val);
} }
case 45: break; case 45: break;
case 2: case 18:
{ { sb.append('\n');
} }
case 46: break; case 46: break;
case 9:
{ return new Yytoken(Yytoken.TYPE_COMMA,null);
}
case 47: break;
case 3:
{
}
case 48: break;
default: default:
if (zzInput == YYEOF && zzStartRead == zzCurrentPos) { if (zzInput == YYEOF && zzStartRead == zzCurrentPos) {
zzAtEOF = true; zzAtEOF = true;

View File

@@ -26,6 +26,33 @@ public class Yytoken {
} }
public String toString(){ public String toString(){
return String.valueOf(type+"=>|"+value+"|"); StringBuffer sb = new StringBuffer();
switch(type){
case TYPE_VALUE:
sb.append("VALUE(").append(value).append(")");
break;
case TYPE_LEFT_BRACE:
sb.append("LEFT BRACE({)");
break;
case TYPE_RIGHT_BRACE:
sb.append("RIGHT BRACE(})");
break;
case TYPE_LEFT_SQUARE:
sb.append("LEFT SQUARE([)");
break;
case TYPE_RIGHT_SQUARE:
sb.append("RIGHT SQUARE(])");
break;
case TYPE_COMMA:
sb.append("COMMA(,)");
break;
case TYPE_COLON:
sb.append("COLON(:)");
break;
case TYPE_EOF:
sb.append("END OF FILE");
break;
}
return sb.toString();
} }
} }

View File

@@ -4,10 +4,22 @@
*/ */
package org.json.simple; package org.json.simple;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.json.simple.parser.ContainerFactory;
import org.json.simple.parser.ContentHandler;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
/** /**
* @author FangYidong<fangyidong@yahoo.com.cn> * @author FangYidong<fangyidong@yahoo.com.cn>
@@ -46,6 +58,241 @@ public class Test extends TestCase{
obj=JSONValue.parse(s); obj=JSONValue.parse(s);
assertEquals("hello\bworld\"abc\tdef\\ghi\rjkl\n123中",((List)obj).get(0).toString()); assertEquals("hello\bworld\"abc\tdef\\ghi\rjkl\n123中",((List)obj).get(0).toString());
JSONParser parser = new JSONParser();
s="{\"name\":";
try{
obj = parser.parse(s);
}
catch(ParseException pe){
assertEquals(ParseException.ERROR_UNEXPECTED_TOKEN, pe.getErrorType());
assertEquals(8, pe.getPosition());
}
s="{\"name\":}";
try{
obj = parser.parse(s);
}
catch(ParseException pe){
assertEquals(ParseException.ERROR_UNEXPECTED_TOKEN, pe.getErrorType());
assertEquals(8, pe.getPosition());
}
s="{\"name";
try{
obj = parser.parse(s);
}
catch(ParseException pe){
assertEquals(ParseException.ERROR_UNEXPECTED_TOKEN, pe.getErrorType());
assertEquals(6, pe.getPosition());
}
s = "[[null, 123.45, \"a\\\tb c\"}, true]";
try{
parser.parse(s);
}
catch(ParseException pe){
assertEquals(24, pe.getPosition());
System.out.println("Error at character position: " + pe.getPosition());
switch(pe.getErrorType()){
case ParseException.ERROR_UNEXPECTED_TOKEN:
System.out.println("Unexpected token: " + pe.getUnexpectedObject());
break;
case ParseException.ERROR_UNEXPECTED_CHAR:
System.out.println("Unexpected character: " + pe.getUnexpectedObject());
break;
case ParseException.ERROR_UNEXPECTED_EXCEPTION:
((Exception)pe.getUnexpectedObject()).printStackTrace();
break;
}
}
s = "{\"first\": 123, \"second\": [4, 5, 6], \"third\": 789}";
ContainerFactory containerFactory = new ContainerFactory(){
public List creatArrayContainer() {
return new LinkedList();
}
public Map createObjectContainer() {
return new LinkedHashMap();
}
};
try{
Map json = (Map)parser.parse(s, containerFactory);
Iterator iter = json.entrySet().iterator();
System.out.println("==iterate result==");
while(iter.hasNext()){
Map.Entry entry = (Map.Entry)iter.next();
System.out.println(entry.getKey() + "=>" + entry.getValue());
}
System.out.println("==toJSONString()==");
System.out.println(JSONValue.toJSONString(json));
assertEquals("{\"first\":123,\"second\":[4,5,6],\"third\":789}", JSONValue.toJSONString(json));
}
catch(ParseException pe){
pe.printStackTrace();
}
s = "{\"first\": 123, \"second\": [{\"s1\":{\"s11\":\"v11\"}}, 4, 5, 6], \"third\": 789}";
ContentHandler myHandler = new ContentHandler() {
public boolean endArray() throws ParseException {
System.out.println("endArray()");
return true;
}
public void endJSON() throws ParseException {
System.out.println("endJSON()");
}
public boolean endObject() throws ParseException {
System.out.println("endObject()");
return true;
}
public boolean endObjectEntry() throws ParseException {
System.out.println("endObjectEntry()");
return true;
}
public boolean primitive(Object value) throws ParseException {
System.out.println("primitive(): " + value);
return true;
}
public boolean startArray() throws ParseException {
System.out.println("startArray()");
return true;
}
public void startJSON() throws ParseException {
System.out.println("startJSON()");
}
public boolean startObject() throws ParseException {
System.out.println("startObject()");
return true;
}
public boolean startObjectEntry(String key) throws ParseException {
System.out.println("startObjectEntry(), key:" + key);
return true;
}
};
try{
parser.parse(s, myHandler);
}
catch(ParseException pe){
pe.printStackTrace();
}
class KeyFinder implements ContentHandler{
private Object value;
private boolean found = false;
private boolean end = false;
private String key;
private String matchKey;
public void setMatchKey(String matchKey){
this.matchKey = matchKey;
}
public Object getValue(){
return value;
}
public boolean isEnd(){
return end;
}
public void setFound(boolean found){
this.found = found;
}
public boolean isFound(){
return found;
}
public void startJSON() throws ParseException, IOException {
found = false;
end = false;
}
public void endJSON() throws ParseException, IOException {
end = true;
}
public boolean primitive(Object value) throws ParseException, IOException {
if(key != null){
if(key.equals(matchKey)){
found = true;
this.value = value;
key = null;
return false;
}
}
return true;
}
public boolean startArray() throws ParseException, IOException {
return true;
}
public boolean startObject() throws ParseException, IOException {
return true;
}
public boolean startObjectEntry(String key) throws ParseException, IOException {
this.key = key;
return true;
}
public boolean endArray() throws ParseException, IOException {
return false;
}
public boolean endObject() throws ParseException, IOException {
return true;
}
public boolean endObjectEntry() throws ParseException, IOException {
return true;
}
};
s = "{\"first\": 123, \"second\": [{\"k1\":{\"id\":\"id1\"}}, 4, 5, 6, {\"id\": 123}], \"third\": 789, \"id\": null}";
parser.reset();
KeyFinder keyFinder = new KeyFinder();
keyFinder.setMatchKey("id");
int i = 0;
try{
while(!keyFinder.isEnd()){
parser.parse(s, keyFinder, true);
if(keyFinder.isFound()){
i++;
keyFinder.setFound(false);
System.out.println("found id:");
System.out.println(keyFinder.getValue());
if(i == 1)
assertEquals("id1", keyFinder.getValue());
if(i == 2){
assertTrue(keyFinder.getValue() instanceof Number);
assertEquals("123", String.valueOf(keyFinder.getValue()));
}
if(i == 3)
assertTrue(null == keyFinder.getValue());
}
}
}
catch(ParseException pe){
pe.printStackTrace();
}
} }
public void testEncode() throws Exception{ public void testEncode() throws Exception{
@@ -78,5 +325,67 @@ public class Test extends TestCase{
System.out.println(array1); System.out.println(array1);
System.out.println(); System.out.println();
assertEquals("[\"abc\\u0010a\\/\",123,222.123,true,{\"weight\":60.21,\"age\":27,\"name\":\"fang\",\"is_developer\":true}]",array1.toString()); assertEquals("[\"abc\\u0010a\\/\",123,222.123,true,{\"weight\":60.21,\"age\":27,\"name\":\"fang\",\"is_developer\":true}]",array1.toString());
List list = new ArrayList();
list.add("abc\u0010a/");
list.add(new Integer(123));
list.add(new Double(222.123));
list.add(new Boolean(true));
list.add(null);
System.out.println("======list==========");
System.out.println(JSONArray.toJSONString(list));
System.out.println();
assertEquals("[\"abc\\u0010a\\/\",123,222.123,true,null]",JSONArray.toJSONString(list));
Map map = new HashMap();
map.put("name","fang");
map.put("age",new Integer(27));
map.put("is_developer",new Boolean(true));
map.put("weight",new Double(60.21));
map.put("array1",list);
System.out.println("======map with list===========");
System.out.println(map);
System.out.println();
assertEquals("{\"array1\":[\"abc\\u0010a\\/\",123,222.123,true,null],\"weight\":60.21,\"age\":27,\"name\":\"fang\",\"is_developer\":true}",JSONObject.toJSONString(map));
Map m1 = new LinkedHashMap();
Map m2 = new HashMap();
List l1 = new LinkedList();
m1.put("k11","v11");
m1.put("k12","v12");
m1.put("k13", "v13");
m2.put("k21","v21");
m2.put("k22","v22");
m2.put("k23","v23");
l1.add(m1);
l1.add(m2);
String jsonString = JSONValue.toJSONString(l1);
System.out.println(jsonString);
assertEquals("[{\"k11\":\"v11\",\"k12\":\"v12\",\"k13\":\"v13\"},{\"k22\":\"v22\",\"k21\":\"v21\",\"k23\":\"v23\"}]", jsonString);
StringWriter out = new StringWriter();
JSONValue.writeJSONString(l1, out);
jsonString = out.toString();
System.out.println(jsonString);
assertEquals("[{\"k11\":\"v11\",\"k12\":\"v12\",\"k13\":\"v13\"},{\"k22\":\"v22\",\"k21\":\"v21\",\"k23\":\"v23\"}]", jsonString);
List l2 = new LinkedList();
Map m3 = new LinkedHashMap();
m3.put("k31", "v3");
m3.put("k32", new Double(123.45));
m3.put("k33", new Boolean(false));
m3.put("k34", null);
l2.add("vvv");
l2.add("1.23456789123456789");
l2.add(new Boolean(true));
l2.add(null);
m3.put("k35", l2);
m1.put("k14", m3);
out = new StringWriter();
JSONValue.writeJSONString(l1, out);
jsonString = out.toString();
System.out.println(jsonString);
assertEquals("[{\"k11\":\"v11\",\"k12\":\"v12\",\"k13\":\"v13\",\"k14\":{\"k31\":\"v3\",\"k32\":123.45,\"k33\":false,\"k34\":null,\"k35\":[\"vvv\",\"1.23456789123456789\",true,null]}},{\"k22\":\"v22\",\"k21\":\"v21\",\"k23\":\"v23\"}]",jsonString);
} }
} }

View File

@@ -1,5 +1,6 @@
package org.json.simple.parser; package org.json.simple.parser;
import java.io.IOException;
import java.io.StringReader; import java.io.StringReader;
import junit.framework.TestCase; import junit.framework.TestCase;
@@ -38,13 +39,40 @@ public class YylexTest extends TestCase {
System.out.println(s); System.out.println(s);
in = new StringReader(s); in = new StringReader(s);
lexer=new Yylex(in); lexer=new Yylex(in);
Error err=null; ParseException err=null;
try{ try{
token=lexer.yylex(); token=lexer.yylex();
} }
catch(Error e){ catch(ParseException e){
err=e; err=e;
System.out.println("error:"+err); System.out.println("error:"+err);
assertEquals(ParseException.ERROR_UNEXPECTED_CHAR, e.getErrorType());
assertEquals(0,e.getPosition());
assertEquals(new Character('\b'),e.getUnexpectedObject());
}
catch(IOException ie){
throw ie;
}
assertTrue(err!=null);
s="{a : b}";
System.out.println(s);
in = new StringReader(s);
lexer=new Yylex(in);
err=null;
try{
lexer.yylex();
token=lexer.yylex();
}
catch(ParseException e){
err=e;
System.out.println("error:"+err);
assertEquals(ParseException.ERROR_UNEXPECTED_CHAR, e.getErrorType());
assertEquals(new Character('a'),e.getUnexpectedObject());
assertEquals(1,e.getPosition());
}
catch(IOException ie){
throw ie;
} }
assertTrue(err!=null); assertTrue(err!=null);
} }