Author: doogie
Date: Wed Feb 10 22:47:30 2010
New Revision: 908712
URL: http://svn.apache.org/viewvc?rev=908712&view=rev
Log:
JSON reading/writing. May seem like it is uneeded, but a later commit
will add support for this becoming more extensible.
Added:
ofbiz/trunk/framework/base/src/org/ofbiz/base/json/
ofbiz/trunk/framework/base/src/org/ofbiz/base/json/JSON.jj
ofbiz/trunk/framework/base/src/org/ofbiz/base/json/JSONWriter.java
ofbiz/trunk/framework/base/src/org/ofbiz/base/json/test/
ofbiz/trunk/framework/base/src/org/ofbiz/base/json/test/JSONTests.java
Modified:
ofbiz/trunk/framework/base/build.xml
Modified: ofbiz/trunk/framework/base/build.xml
URL:
http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/build.xml?rev=908712&r1=908711&r2=908712&view=diff
==============================================================================
--- ofbiz/trunk/framework/base/build.xml (original)
+++ ofbiz/trunk/framework/base/build.xml Wed Feb 10 22:47:30 2010
@@ -39,6 +39,7 @@
<filelist id="test.classes" dir="${src.dir}">
<file name="org/ofbiz/base/util/test/IndentingWriterTests.java"/>
+ <file name="org/ofbiz/base/json/test/JSONTests.java"/>
<file name="org/ofbiz/base/conversion/test/MiscTests.java"/>
<file name="org/ofbiz/base/util/test/UtilIOTests.java"/>
<file name="org/ofbiz/base/test/BaseUnitTests.java"/>
@@ -66,6 +67,14 @@
</patternset>
</target>
+ <target name="gen-src">
+ <ofbiz-javacc dir="org/ofbiz/base/json" file="JSON"/>
+ </target>
+
+ <target name="classes" depends="prepare,gen-src">
+ <javac16/>
+ </target>
+
<target name="jar" depends="classes">
<jar jarfile="${build.dir}/lib/${name}.jar">
<fileset dir="${build.dir}/classes"/>
Added: ofbiz/trunk/framework/base/src/org/ofbiz/base/json/JSON.jj
URL:
http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/org/ofbiz/base/json/JSON.jj?rev=908712&view=auto
==============================================================================
--- ofbiz/trunk/framework/base/src/org/ofbiz/base/json/JSON.jj (added)
+++ ofbiz/trunk/framework/base/src/org/ofbiz/base/json/JSON.jj Wed Feb 10
22:47:30 2010
@@ -0,0 +1,320 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+
*******************************************************************************/
+options {
+ ERROR_REPORTING = true;
+ STATIC = false;
+// DEBUG_PARSER = true;
+// DEBUG_LOOKAHEAD = true;
+// DEBUG_TOKEN_MANAGER = true;
+ LOOKAHEAD = 1;
+// CHOICE_AMBIGUITY_CHECK = 3;
+// OTHER_AMBIGUITY_CHECK = 3;
+}
+
+PARSER_BEGIN(JSON)
+
+package org.ofbiz.base.json;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import javolution.util.FastMap;
+
+import org.ofbiz.base.util.UtilIO;
+
+public class JSON {
+ private boolean allowResolve;
+
+ public JSON(String fileName) {
+ this(System.in);
+ try { ReInit(new FileInputStream(new File(fileName))); }
+ catch(Exception e) { e.printStackTrace(); }
+// allowed[TEXT] = 1;
+// allowed[FIRST_COLUMN_TEXT] = 1;
+ }
+
+ public JSON allowResolve(boolean allowResolve) {
+ this.allowResolve = allowResolve;
+ token_source.SwitchTo(allowResolve ? RESOLVE : DEFAULT);
+ return this;
+ }
+}
+
+PARSER_END(JSON)
+TOKEN_MGR_DECLS: {
+ protected LinkedList stateStack = new LinkedList();
+ protected StringBuilder statePrefix = new StringBuilder();
+
+ protected void pushState(int state) {
+ //System.err.println(statePrefix + "push: " +
lexStateNames[curLexState] + " -> " + lexStateNames[state]);
+ stateStack.add(curLexState);
+ statePrefix.append(' ');
+ SwitchTo(state);
+ }
+
+ protected void popState() {
+ int oldState = (Integer) stateStack.removeLast();
+ statePrefix.setLength(statePrefix.length() - 1);
+ //System.err.println(statePrefix + "pop: " +
lexStateNames[curLexState] + " -> " + lexStateNames[oldState]);
+ SwitchTo(oldState);
+ }
+}
+<DEFAULT,RESOLVE>
+TOKEN:
+{
+ <OBJECT_BEGIN: "{">
+| <OBJECT_END: "}">
+| <ARRAY_BEGIN: "[">
+| <ARRAY_END: "]">
+| <ITEM_SEP: ",">
+| <KEY_SEP: ":">
+| <TRUE: "true">
+| <FALSE: "false">
+| <NULL: "null">
+| <WHOLE_NUMBER:
+ <NUMBER_PREFIX>
+ >
+| <FLOAT_NUMBER:
+ <NUMBER_PREFIX>
+ ("." (["0"-"9"])*)?
+ (
+ ["e", "E"]
+ (["+", "-"])?
+ (["0"-"9"])+
+ )?
+ >
+| <#NUMBER_PREFIX:
+ (["-"])?
+ (
+ "0"
+ | ["1"-"9"] (["0"-"9"])*
+ )
+ >
+}
+
+<DEFAULT,RESOLVE,IN_RESOLVE_VALUE>
+TOKEN:
+{
+ <STRING_START: "\""> { pushState(IN_STRING); }
+}
+
+<IN_RESOLVE_VALUE>
+TOKEN:
+{
+ <CLOSE_PAREN: ")"> { popState(); }
+}
+
+<RESOLVE>
+TOKEN:
+{
+ <RESOLVE_BEGIN: "resolve("> { pushState(IN_RESOLVE_VALUE); }
+}
+
+<IN_STRING>
+TOKEN:
+{
+ <CHARACTER: (~["\"","\\","\u0000"-"\u001f"])+>
+| <STRING_END: "\""> { popState(); }
+| <CONTROL_CHAR: "\\" ["\"", "\\", "/", "b","f","n","r","t"]>
+| <UNICODE: "\\u"
+ ["a"-"f", "A"-"F", "0"-"9"]
+ ["a"-"f", "A"-"F", "0"-"9"]
+ ["a"-"f", "A"-"F", "0"-"9"]
+ ["a"-"f", "A"-"F", "0"-"9"]
+ >
+}
+
+<DEFAULT,RESOLVE>
+SKIP:
+{
+ <WHITESPACE: [" ", "\r", "\n", "\t"]>
+}
+
+<*>
+MORE:
+{
+ <COMMENT_START: "/*"> { if (curLexState != IN_COMMENT)
pushState(IN_COMMENT); }
+}
+
+<IN_COMMENT>
+MORE:
+{
+ <(~[])>
+}
+
+<IN_COMMENT>
+MORE:
+{
+ <COMMENT_END: "*/"> { popState(); }
+}
+
+Object JSONValue():
+{ Object value; }
+{
+ value=JSONItem()
+ <EOF>
+ { return value; }
+}
+
+Object JSONItem():
+{ Object value; }
+{
+ (
+ value=JSONString()
+ | value=JSONLong()
+ | value=JSONFloat()
+ | value=JSONObject()
+ | value=JSONArray()
+ | value=True()
+ | value=False()
+ | value=Null()
+ | value=JSONResolve()
+ )
+ { return value; }
+}
+
+Object JSONResolve():
+{
+ String name, value;
+}
+{
+ <RESOLVE_BEGIN>
+ value=JSONString()
+ <CLOSE_PAREN>
+ {
+ try {
+ return UtilIO.readObject(value.toCharArray());
+ } catch (ClassNotFoundException e) {
+ throw generateParseException();
+ } catch (IOException e) {
+ throw generateParseException();
+ }
+ }
+}
+String JSONString():
+{
+ StringBuilder sb = new StringBuilder();
+}
+{
+ <STRING_START> (
+ <CHARACTER> { sb.append(getToken(0).image); }
+ | <CONTROL_CHAR> {
+ switch (getToken(0).image.charAt(1)) {
+ case '"': sb.append('"'); break;
+ 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;
+ }
+ }
+ | <UNICODE> {
+ int v = Integer.parseInt(getToken(0).image.substring(2), 16);
+ sb.append((char) v);
+ }
+ )*
+ <STRING_END>
+ { return sb.toString(); }
+}
+
+Long JSONLong():
+{}
+{
+ try {
+ <WHOLE_NUMBER> { return new Long(getToken(0).image); }
+ } catch (NumberFormatException e) {
+ throw generateParseException();
+ }
+}
+
+Double JSONFloat():
+{}
+{
+ try {
+ <FLOAT_NUMBER> { return new Double(getToken(0).image); }
+ } catch (NumberFormatException e) {
+ throw generateParseException();
+ }
+}
+
+Map<String, Object> JSONObject():
+{
+ Map<String, Object> map = FastMap.newInstance();
+}
+{
+ <OBJECT_BEGIN>
+ (<ITEM_SEP>)*
+ (JSONObjectEntry(map))? (<ITEM_SEP> (JSONObjectEntry(map))?)*
+ <OBJECT_END>
+ { return map; }
+}
+
+void JSONObjectEntry(Map<String, Object> map):
+{
+ String key;
+ Object value;
+}
+{
+ key=JSONString() <KEY_SEP> value=JSONItem()
+ { map.put(key, value); }
+}
+
+List JSONArray():
+{
+ ArrayList<Object> list = new ArrayList<Object>();
+ Object value;
+}
+{
+ <ARRAY_BEGIN>
+ (<ITEM_SEP>)*
+ (
+ value=JSONItem() { list.add(value); }
+ (
+ <ITEM_SEP>
+ (value=JSONItem() { list.add(value); })?
+ )*
+ )?
+ <ARRAY_END>
+ { return list; }
+}
+
+Boolean True():
+{}
+{
+ <TRUE> { return Boolean.TRUE; }
+}
+
+Boolean False():
+{}
+{
+ <FALSE> { return Boolean.FALSE; }
+}
+
+Object Null():
+{}
+{
+ <NULL> { return null; }
+}
Added: ofbiz/trunk/framework/base/src/org/ofbiz/base/json/JSONWriter.java
URL:
http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/org/ofbiz/base/json/JSONWriter.java?rev=908712&view=auto
==============================================================================
--- ofbiz/trunk/framework/base/src/org/ofbiz/base/json/JSONWriter.java (added)
+++ ofbiz/trunk/framework/base/src/org/ofbiz/base/json/JSONWriter.java Wed Feb
10 22:47:30 2010
@@ -0,0 +1,224 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.ofbiz.base.json;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.ofbiz.base.util.IndentingWriter;
+import org.ofbiz.base.util.UtilIO;
+
+public class JSONWriter {
+ private final IndentingWriter writer;
+ private final FallbackHandler fallbackHandler;
+
+ public JSONWriter(IndentingWriter writer) {
+ this(writer, StandardFallbackHandler);
+ }
+
+ public JSONWriter(IndentingWriter writer, FallbackHandler fallbackHandler)
{
+ this.writer = writer;
+ this.fallbackHandler = fallbackHandler;
+ }
+
+ public JSONWriter(Writer writer) {
+ this(writer instanceof IndentingWriter ? (IndentingWriter) writer :
new IndentingWriter(writer));
+ }
+
+ public JSONWriter(Writer writer, FallbackHandler fallbackHandler) {
+ this(writer instanceof IndentingWriter ? (IndentingWriter) writer :
new IndentingWriter(writer), fallbackHandler);
+ }
+
+ public IndentingWriter getWriter() {
+ return writer;
+ }
+
+ public JSONWriter close() throws IOException {
+ getWriter().close();
+ return this;
+ }
+
+ public JSONWriter write(byte b) throws IOException {
+ writer.write(Byte.toString(b));
+ return this;
+ }
+
+ public JSONWriter write(short s) throws IOException {
+ writer.write(Short.toString(s));
+ return this;
+ }
+
+ public JSONWriter write(int i) throws IOException {
+ writer.write(Integer.toString(i));
+ return this;
+ }
+
+ public JSONWriter write(long l) throws IOException {
+ writer.write(Long.toString(l));
+ return this;
+ }
+
+ public JSONWriter write(float f) throws IOException {
+ writer.write(Float.toString(f));
+ return this;
+ }
+
+ public JSONWriter write(double d) throws IOException {
+ writer.write(Double.toString(d));
+ return this;
+ }
+
+ public JSONWriter write(char c) throws IOException {
+ write(Character.toString(c));
+ return this;
+ }
+
+ public JSONWriter write(String s) throws IOException {
+ writer.write('"');
+ for (int i = 0; i < s.length(); i++) {
+ char c = s.charAt(i);
+ switch (c) {
+ case '\\': writer.write("\\\\"); continue;
+ case '/': writer.write("\\/"); continue;
+ case '"': writer.write("\\\""); continue;
+ case '\b': writer.write("\\b"); continue;
+ case '\f': writer.write("\\f"); continue;
+ case '\n': writer.write("\\n"); continue;
+ case '\r': writer.write("\\r"); continue;
+ case '\t': writer.write("\\t"); continue;
+ }
+ if (32 <= c && c >= 256) {
+ writer.write("\\u");
+ String n = Integer.toString((int) c, 16);
+ for (int j = 4 - n.length(); j > 0; j--) writer.write('0');
+ writer.write(n);
+ } else {
+ writer.write(c);
+ }
+ }
+ writer.write('"');
+ return this;
+ }
+
+ public <K, V> JSONWriter write(Map<K, V> m) throws IOException {
+ writer.write('{');
+ writer.push();
+ Iterator<Map.Entry<K, V>> it = m.entrySet().iterator();
+ if (it.hasNext()) writer.newline();
+ while (it.hasNext()) {
+ Map.Entry<K, V> entry = it.next();
+ write(entry.getKey());
+ writer.write(':');
+ writer.space();
+ write(entry.getValue());
+ if (it.hasNext()) writer.write(',');
+ writer.newline();
+ }
+ writer.pop();
+ writer.write('}');
+ return this;
+ }
+
+ public <E> JSONWriter write(Collection<E> c) throws IOException {
+ writer.write('[');
+ writer.push();
+ Iterator<E> it = c.iterator();
+ if (it.hasNext()) writer.newline();
+ while (it.hasNext()) {
+ write(it.next());
+ if (it.hasNext()) writer.write(',');
+ writer.newline();
+ }
+ writer.pop();
+ writer.write(']');
+ return this;
+ }
+
+ public <T> JSONWriter write(T... o) throws IOException {
+ writer.write('[');
+ writer.push();
+ for (int i = 0; i < o.length; i++) {
+ if (i != 0) writer.write(',');
+ writer.newline();
+ write(o[i]);
+ }
+ if (o.length > 0) writer.newline();
+ writer.pop();
+ writer.write(']');
+ return this;
+ }
+
+ public JSONWriter write(Object o) throws IOException {
+ if (o == null) {
+ writer.write("null");
+ return this;
+ } else if (o instanceof Boolean) {
+ writer.write(((Boolean) o).booleanValue() ? "true" : "false");
+ return this;
+ } else if (o instanceof String) {
+ return write((String) o);
+ } else if (o instanceof Map) {
+ return write((Map) o);
+ } else if (o instanceof Collection) {
+ return write((Collection) o);
+ } else if (o instanceof Byte) {
+ return write(((Byte) o).byteValue());
+ } else if (o instanceof Character) {
+ return write(((Character) o).charValue());
+ } else if (o instanceof Double) {
+ return write(((Double) o).doubleValue());
+ } else if (o instanceof Float) {
+ return write(((Float) o).floatValue());
+ } else if (o instanceof Integer) {
+ return write(((Integer) o).intValue());
+ } else if (o instanceof Long) {
+ return write(((Long) o).longValue());
+ } else if (o instanceof Short) {
+ return write(((Short) o).shortValue());
+ } else if (o.getClass().isArray()) {
+ return write((Object[]) o);
+ } else {
+ fallbackHandler.writeJSON(this, writer, o);
+ return this;
+ }
+ }
+
+ public interface FallbackHandler {
+ void writeJSON(JSONWriter json, Writer writer, Object o) throws
IOException;
+ }
+
+ public static final FallbackHandler StandardFallbackHandler = new
FallbackHandler() {
+ public void writeJSON(JSONWriter json, Writer writer, Object o) throws
IOException {
+ throw new IOException("Can't write(" + o + ":" + o.getClass() +
")");
+ }
+ };
+
+ public static final FallbackHandler ResolvingFallbackHandler = new
FallbackHandler() {
+ public void writeJSON(JSONWriter json, Writer writer, Object o) throws
IOException {
+ StringBuilder sb = new StringBuilder();
+ UtilIO.writeObject(sb, o);
+ writer.write("resolve(");
+ json.write(sb.toString());
+ writer.write(")");
+ }
+ };
+}
Added: ofbiz/trunk/framework/base/src/org/ofbiz/base/json/test/JSONTests.java
URL:
http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/org/ofbiz/base/json/test/JSONTests.java?rev=908712&view=auto
==============================================================================
--- ofbiz/trunk/framework/base/src/org/ofbiz/base/json/test/JSONTests.java
(added)
+++ ofbiz/trunk/framework/base/src/org/ofbiz/base/json/test/JSONTests.java Wed
Feb 10 22:47:30 2010
@@ -0,0 +1,289 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.ofbiz.base.json.test;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import org.ofbiz.base.json.JSON;
+import org.ofbiz.base.json.JSONConstants;
+import org.ofbiz.base.json.JSONWriter;
+import org.ofbiz.base.json.ParseException;
+import org.ofbiz.base.json.Token;
+import org.ofbiz.base.json.TokenMgrError;
+import org.ofbiz.base.test.GenericTestCaseBase;
+
+public class JSONTests extends GenericTestCaseBase {
+ public JSONTests(String name) {
+ super(name);
+ }
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ protected Object parseJSON(String value, boolean allowResolve) throws
Exception {
+ return new JSON(new
StringReader(value)).allowResolve(allowResolve).JSONValue();
+ }
+
+ protected String getJSON(Object object, boolean allowResolve) throws
Exception {
+ StringWriter writer = new StringWriter();
+ JSONWriter jsonWriter;
+ if (allowResolve) {
+ jsonWriter = new JSONWriter(writer,
JSONWriter.ResolvingFallbackHandler);
+ } else {
+ jsonWriter = new JSONWriter(writer);
+ };
+ jsonWriter.write(object);
+ return writer.toString();
+ }
+
+ protected void assertSimpleJSONByte(byte n, String json) throws Exception {
+ assertSimpleJSON("integer - byte", new Byte(n), json, new Long(n));
+ assertSimpleJSONShort((short) n, json);
+ }
+
+ protected void assertSimpleJSONShort(short n, String json) throws
Exception {
+ assertSimpleJSON("integer - short", new Integer(n), json, new Long(n));
+ assertSimpleJSONInteger((int) n, json);
+ }
+
+ protected void assertSimpleJSONInteger(int n, String json) throws
Exception {
+ assertSimpleJSON("integer - int", new Short((short) n), json, new
Long(n));
+ assertSimpleJSONLong((long) n, json);
+ }
+
+ protected void assertSimpleJSONLong(long n, String json) throws Exception {
+ assertSimpleJSON("integer - long", new Long(n), json, new Long(n));
+ }
+
+ protected void assertSimpleJSONFloat(float n, String json) throws
Exception {
+ assertSimpleJSON("float - float", new Float(n), json, new Double(n));
+ assertSimpleJSONDouble((double) n, json);
+ }
+
+ protected void assertSimpleJSONDouble(double n, String json) throws
Exception {
+ assertSimpleJSON("float - double", new Double(n), json);
+ }
+
+ protected void assertSimpleJSON(String type, Object object, String json)
throws Exception {
+ assertSimpleJSON(type, object, json, object);
+ }
+
+ protected void assertSimpleJSON(String type, Object before, String json,
Object after) throws Exception {
+ assertEquals("write " + type, json, getJSON(before, false));
+ assertEquals("parse " + type, after, parseJSON(json, false));
+ }
+
+ protected void assertResolveJSON(String type, Object obj, String json)
throws Exception {
+ assertEquals("write " + type, json, getJSON(obj, true));
+ assertEquals("parse " + type, obj, parseJSON(json, true));
+ }
+
+ public void testParseBasicTypes() throws Exception {
+ assertSimpleJSON("character", new Character('c'), "\"c\"", "c");
+ assertSimpleJSON("false", Boolean.FALSE, "false");
+ assertSimpleJSON("null", null, "null");
+ assertSimpleJSON("true", Boolean.TRUE, "true");
+ assertSimpleJSON("simple string", "foo", "\"foo\"");
+ assertSimpleJSONByte((byte) 42, "42");
+ assertSimpleJSONFloat(Float.valueOf("1.0625"), "1.0625");
+ assertSimpleJSON(
+ "complex string",
+ "quote(\") backslash(\\) forwardslash(/) backspace(\b)
formfeed(\f) newline(\n) carriagereturn(\r) tab(\t) trademark(\u2122)",
+ "\"quote(\\\") backslash(\\\\) forwardslash(\\/) backspace(\\b)
formfeed(\\f) newline(\\n) carriagereturn(\\r) tab(\\t) trademark(\\u2122)\""
+ );
+ }
+
+ public void testParseComplexTypes() throws Exception {
+ assertEquals(
+ "parse simple array",
+ list(new Object[] {"foo", new Long(1234), new Double(5.678)}),
+ parseJSON("[, ,\t,\r,\n,\r\n,\"foo\", 1234, 5.678,]", false)
+ );
+ assertSimpleJSON(
+ "simple empty list",
+ list(new Object[] {}),
+ "[]"
+ );
+ assertSimpleJSON(
+ "simple empty array",
+ new Object[] {},
+ "[]",
+ list(new Object[] {})
+ );
+ assertSimpleJSON(
+ "simple array->list",
+ new Object[] {"foo", new Long(1234), new Double(5.678)},
+ "[\n \"foo\",\n 1234,\n 5.678\n]",
+ list(new Object[] {"foo", new Long(1234), new Double(5.678)})
+ );
+ assertSimpleJSON(
+ "simple array",
+ list(new Object[] {"foo", new Long(1234), new Double(5.678)}),
+ "[\n \"foo\",\n 1234,\n 5.678\n]",
+ list(new Object[] {"foo", new Long(1234), new Double(5.678)})
+ );
+ assertEquals(
+ "parse simple map",
+ map(new Object[] {"foo", new Long(1234), "bar", new
Double(5.678)}),
+ parseJSON("{, ,\t,\r,\n,\r\n,\"foo\": 1234, \"bar\": 5.678,}",
false)
+ );
+ assertSimpleJSON(
+ "parse map",
+ map(new Object[] {"foo", new Long(1234), "bar", new
Double(5.678)}),
+ "{\n \"foo\": 1234,\n \"bar\": 5.678\n}"
+ );
+ assertSimpleJSON(
+ "parse empty map",
+ map(new Object[] {}),
+ "{}"
+ );
+ assertEquals(
+ "parse nested map",
+ map(new Object[] {
+ "string", "this is a string",
+ "integer", new Long(5000),
+ "double", new Double(3.1415926),
+ "array", new Object[] {
+ "string",
+ new Long(6000)
+ },
+ "list", list(new Object[] {
+ "nested string",
+ "something",
+ }),
+ "empty-list", new ArrayList(),
+ "empty-array", new String[0],
+ "empty-map", new HashMap(),
+ }),
+ parseJSON("{\"string\": \"this is a string\", \"integer\": 5000,
\"double\": 3.1415926, \"array\": [\"string\", 6000], \"list\": [\"nested
string\", \"something\"], \"empty-list\": [], \"empty-array\": [],
\"empty-map\": {}}", false)
+ );
+ }
+
+ public void testParseErrors() throws Exception {
+ for (char c = 1; c < 1024; c++) {
+ switch (c) {
+ case '[':
+ doParseExceptionTest("[:", JSONConstants.KEY_SEP);
+ break;
+ case ']':
+ doParseExceptionTest("]", JSONConstants.ARRAY_END);
+ break;
+ case '{':
+ doParseExceptionTest("{:", JSONConstants.KEY_SEP);
+ break;
+ case '}':
+ doParseExceptionTest("}", JSONConstants.OBJECT_END);
+ break;
+ case ':':
+ doParseExceptionTest(":", JSONConstants.KEY_SEP);
+ break;
+ case ',':
+ doParseExceptionTest(",", JSONConstants.ITEM_SEP);
+ break;
+ case '"':
+ doParseExceptionTest("\"", JSONConstants.EOF);
+ break;
+ case 't':
+ doParseExceptionTest("true:", JSONConstants.KEY_SEP);
+ break;
+ case 'f':
+ doParseExceptionTest("false:", JSONConstants.KEY_SEP);
+ break;
+ case 'n':
+ doParseExceptionTest("null:", JSONConstants.KEY_SEP);
+ break;
+ case '-': // numbers
+ case '.':
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ break;
+ case '\t':
+ doWhitespaceExceptionTest(Character.toString(c), 8);
+ break;
+ case '\n':
+ case '\r':
+ case ' ':
+ doWhitespaceExceptionTest(Character.toString(c), 1);
+ break;
+ default:
+ doTokenMgrErrorTest(c);
+ break;
+ }
+ }
+ }
+
+ protected void doWhitespaceExceptionTest(String s, int column) {
+ ParseException caught = null;
+ try {
+ new JSON(new StringReader(s)).JSONValue();
+ } catch (ParseException e) {
+ caught = e;
+ } finally {
+ assertNotNull("caught exception", caught);
+ assertNotNull("next token(" + s + ")", caught.currentToken);
+ Token next = caught.currentToken.next;
+ assertEquals("next token(" + s + ") is eof", 0, next.kind);
+ assertEquals("begin line(" + s + ")", 1, next.beginLine);
+ assertEquals("begin column(" + s + ")", column, next.beginColumn);
+ }
+ }
+
+ protected void doParseExceptionTest(String s, int nextKind) {
+ ParseException caught = null;
+ try {
+ new JSON(new StringReader(s)).JSONValue();
+ } catch (ParseException e) {
+ caught = e;
+ } finally {
+ assertNotNull("caught exception", caught);
+ assertNotNull("exception message(" + s + ")", caught.getMessage());
+ assertNotNull("next token(" + s + ")", caught.currentToken);
+ Token next = caught.currentToken.next;
+ assertEquals("next token(" + s + ") is correct", nextKind,
next.kind);
+ assertEquals("begin line(" + s + ")", 1, next.beginLine);
+ assertEquals("begin column(" + s + ")", s.length(),
next.beginColumn);
+ }
+ }
+
+ protected void doTokenMgrErrorTest(char c) throws Exception {
+ TokenMgrError caught = null;
+ try {
+ parseJSON(c + "\"string\"", false);
+ } catch (TokenMgrError e) {
+ caught = e;
+ } finally {
+ assertNotNull("No TokenMgrError thrown for character(" + ((int) c)
+ ")", caught);
+ // FIXME: maybe extend javacc to return more info in TokenMgrError
+ }
+ }
+
+ public void testResolve() throws Exception {
+ assertResolveJSON("url", new URL("http://ofbiz.apache.org"),
"resolve(\"java.net.URL:http:\\/\\/ofbiz.apache.org\")");
+ }
+}