一、前言
关于grizzly-webserver源码包中com.sun.grizzly.cometd.util.JSONParser解析类,进行对象及Map转为字符串toString、从各种类型追加(append/appendNull/appendJSON/appendMap/appendArray/appendBoolean/appendNumber/appendString)为JSON字符串、对于源对象进行解析parse对象、parseObject解析Map、解析对象为parseArray数组、解析字符串parseString、解析源为parseNumber数字。
二、源码说明
package com.sun.grizzly.cometd.util;@b@@b@import java.lang.reflect.Array;@b@import java.util.ArrayList;@b@import java.util.HashMap;@b@import java.util.Iterator;@b@import java.util.List;@b@import java.util.Map;@b@import java.util.Map.Entry;@b@import java.util.Set;@b@@b@public class JSONParser@b@{@b@ public static String toString(Object object)@b@ {@b@ StringBuilder buffer = new StringBuilder();@b@ append(buffer, object);@b@ return buffer.toString();@b@ }@b@@b@ public static String toString(Map object) {@b@ StringBuilder buffer = new StringBuilder();@b@ appendMap(buffer, object);@b@ return buffer.toString();@b@ }@b@@b@ public static String toString(Object[] array) {@b@ StringBuilder buffer = new StringBuilder();@b@ appendArray(buffer, array);@b@ return buffer.toString();@b@ }@b@@b@ public static Object parse(String s)@b@ {@b@ return parse(new Source(s));@b@ }@b@@b@ public static void append(StringBuilder buffer, Object object)@b@ {@b@ if (object == null)@b@ buffer.append("null");@b@ else if (object instanceof Generator)@b@ appendJSON(buffer, (Generator)object);@b@ else if (object instanceof Map)@b@ appendMap(buffer, (Map)object);@b@ else if (object instanceof List)@b@ appendArray(buffer, ((List)object).toArray());@b@ else if (object.getClass().isArray())@b@ appendArray(buffer, object);@b@ else if (object instanceof Number)@b@ appendNumber(buffer, (Number)object);@b@ else if (object instanceof Boolean)@b@ appendBoolean(buffer, (Boolean)object);@b@ else if (object instanceof String) {@b@ appendString(buffer, (String)object);@b@ }@b@ else@b@ appendString(buffer, object.toString());@b@ }@b@@b@ private static void appendNull(StringBuilder buffer) {@b@ buffer.append("null");@b@ }@b@@b@ private static void appendJSON(StringBuilder buffer, Generator generator) {@b@ generator.addJSON(buffer);@b@ }@b@@b@ private static void appendMap(StringBuilder buffer, Map object) {@b@ if (object == null) {@b@ appendNull(buffer);@b@ return;@b@ }@b@@b@ buffer.append('{');@b@ Iterator iter = object.entrySet().iterator();@b@ while (iter.hasNext()) {@b@ Map.Entry entry = (Map.Entry)iter.next();@b@ quote(buffer, entry.getKey().toString());@b@ buffer.append(':');@b@ append(buffer, entry.getValue());@b@ if (iter.hasNext())@b@ buffer.append(',');@b@ }@b@@b@ buffer.append('}');@b@ }@b@@b@ private static void appendArray(StringBuilder buffer, Object array) {@b@ if (array == null) {@b@ appendNull(buffer);@b@ return;@b@ }@b@@b@ buffer.append('[');@b@ int length = Array.getLength(array);@b@@b@ for (int i = 0; i < length; ++i) {@b@ if (i != 0)@b@ buffer.append(',');@b@ append(buffer, Array.get(array, i));@b@ }@b@@b@ buffer.append(']');@b@ }@b@@b@ private static void appendBoolean(StringBuilder buffer, Boolean b) {@b@ if (b == null) {@b@ appendNull(buffer);@b@ return;@b@ }@b@ buffer.append((b.booleanValue()) ? "true" : "false");@b@ }@b@@b@ private static void appendNumber(StringBuilder buffer, Number number) {@b@ if (number == null) {@b@ appendNull(buffer);@b@ return;@b@ }@b@ buffer.append(number);@b@ }@b@@b@ private static void appendString(StringBuilder buffer, String string) {@b@ if (string == null) {@b@ appendNull(buffer);@b@ return;@b@ }@b@@b@ quote(buffer, string);@b@ }@b@@b@ private static Object parse(Source source) {@b@ int comment_state = 0;@b@@b@ while (source.hasNext()) {@b@ char c = source.peek();@b@@b@ if (comment_state == 1) {@b@ switch (c)@b@ {@b@ case '/':@b@ comment_state = -1;@b@ break;@b@ case '*':@b@ comment_state = 2;@b@ }@b@ }@b@ else {@b@ if (comment_state > 1);@b@ switch (c)@b@ {@b@ case '*':@b@ comment_state = 3;@b@ break;@b@ case '/':@b@ if (comment_state == 3)@b@ comment_state = 0;@b@ else@b@ comment_state = 2;@b@ break;@b@ default:@b@ comment_state = 2; break label334:@b@@b@ if (comment_state < 0);@b@ switch (c)@b@ {@b@ case '\n':@b@ case '\r':@b@ comment_state = 0;@b@ break;@b@ default:@b@ break label334:@b@@b@ switch (c)@b@ {@b@ case '{':@b@ return parseObject(source);@b@ case '[':@b@ return parseArray(source);@b@ case '"':@b@ return parseString(source);@b@ case '-':@b@ return parseNumber(source);@b@ case 'n':@b@ complete("null", source);@b@ return null;@b@ case 't':@b@ complete("true", source);@b@ return Boolean.TRUE;@b@ case 'f':@b@ complete("false", source);@b@ return Boolean.FALSE;@b@ case '/':@b@ comment_state = 1;@b@ break;@b@ default:@b@ if (Character.isDigit(c))@b@ return parseNumber(source);@b@ if (Character.isWhitespace(c))@b@ break label334:@b@@b@ throw new IllegalStateException("unknown char " + c); } }@b@ }@b@ }@b@ label334: source.next();@b@ }@b@@b@ return null;@b@ }@b@@b@ private static Map parseObject(Source source) {@b@ if (source.next() != '{')@b@ throw new IllegalStateException();@b@ Map map = new HashMap();@b@@b@ char next = seekTo("\"}", source);@b@@b@ while (source.hasNext()) {@b@ if (next == '}') {@b@ source.next();@b@ break;@b@ }@b@@b@ String name = parseString(source);@b@ seekTo(':', source);@b@ source.next();@b@@b@ Object value = parse(source);@b@ map.put(name, value);@b@@b@ seekTo(",}", source);@b@ next = source.next();@b@ if (next == '}')@b@ break;@b@@b@ next = seekTo("\"}", source);@b@ }@b@@b@ return map;@b@ }@b@@b@ private static Object parseArray(Source source) {@b@ if (source.next() != '[')@b@ throw new IllegalStateException();@b@@b@ ArrayList list = new ArrayList();@b@ boolean coma = true;@b@@b@ while (source.hasNext()) {@b@ char c = source.peek();@b@ switch (c)@b@ {@b@ case ']':@b@ source.next();@b@ return list.toArray(new Object[list.size()]);@b@ case ',':@b@ if (coma)@b@ throw new IllegalStateException();@b@ coma = true;@b@ source.next();@b@ }@b@@b@ if (Character.isWhitespace(c)) {@b@ source.next();@b@ } else {@b@ coma = false;@b@ list.add(parse(source));@b@ }@b@@b@ }@b@@b@ throw new IllegalStateException("unexpected end of array");@b@ }@b@@b@ private static String parseString(Source source) {@b@ if (source.next() != '"')@b@ throw new IllegalStateException();@b@@b@ boolean escape = false;@b@ StringBuilder b = new StringBuilder();@b@ while (true) { char c;@b@ while (true) { if (!(source.hasNext())) break label281;@b@ c = source.next();@b@@b@ if (escape)@b@ escape = false;@b@ switch (c)@b@ {@b@ case 'n':@b@ b.append('\n');@b@ break;@b@ case 'r':@b@ b.append('\r');@b@ break;@b@ case 't':@b@ b.append('\t');@b@ break;@b@ case 'f':@b@ b.append('\f');@b@ break;@b@ case 'b':@b@ b.append('\b');@b@ break;@b@ case 'u':@b@ b.append((char)((convertHexDigit((byte)source.next()) << 24) + (convertHexDigit((byte)source.next()) << 16) + (convertHexDigit((byte)source.next()) << 8) + convertHexDigit((byte)source.next())));@b@@b@ break;@b@ case 'c':@b@ case 'd':@b@ case 'e':@b@ case 'g':@b@ case 'h':@b@ case 'i':@b@ case 'j':@b@ case 'k':@b@ case 'l':@b@ case 'm':@b@ case 'o':@b@ case 'p':@b@ case 'q':@b@ case 's':@b@ default:@b@ b.append(c); break label278:@b@@b@ if (c != '\\') break;@b@ escape = true; }@b@ }@b@ if (c == '"')@b@ break;@b@@b@ label278: b.append(c);@b@ }@b@@b@ label281: return b.toString();@b@ }@b@@b@ private static Number parseNumber(Source source) {@b@ int start = source.index();@b@ int end = -1;@b@ boolean is_double = false;@b@ while ((source.hasNext()) && (end < 0)) {@b@ char c = source.peek();@b@ switch (c)@b@ {@b@ case '-':@b@ case '0':@b@ case '1':@b@ case '2':@b@ case '3':@b@ case '4':@b@ case '5':@b@ case '6':@b@ case '7':@b@ case '8':@b@ case '9':@b@ source.next();@b@ break;@b@ case '.':@b@ case 'E':@b@ case 'e':@b@ is_double = true;@b@ source.next();@b@ break;@b@ case '/':@b@ case ':':@b@ case ';':@b@ case '<':@b@ case '=':@b@ case '>':@b@ case '?':@b@ case '@':@b@ case 'A':@b@ case 'B':@b@ case 'C':@b@ case 'D':@b@ case 'F':@b@ case 'G':@b@ case 'H':@b@ case 'I':@b@ case 'J':@b@ case 'K':@b@ case 'L':@b@ case 'M':@b@ case 'N':@b@ case 'O':@b@ case 'P':@b@ case 'Q':@b@ case 'R':@b@ case 'S':@b@ case 'T':@b@ case 'U':@b@ case 'V':@b@ case 'W':@b@ case 'X':@b@ case 'Y':@b@ case 'Z':@b@ case '[':@b@ case '\\':@b@ case ']':@b@ case '^':@b@ case '_':@b@ case ''':@b@ case 'a':@b@ case 'b':@b@ case 'c':@b@ case 'd':@b@ default:@b@ end = source.index();@b@ }@b@ }@b@ String s = (end >= 0) ? source.from(start, end) : source.from(start);@b@ if (is_double)@b@ return new Double(s);@b@@b@ return new Long(s);@b@ }@b@@b@ private static void seekTo(char seek, Source source) {@b@ while (source.hasNext()) {@b@ char c = source.peek();@b@ if (c == seek)@b@ return;@b@@b@ if (!(Character.isWhitespace(c)))@b@ throw new IllegalStateException("Unexpected '" + c + " while seeking '" + seek + "'");@b@ source.next();@b@ }@b@@b@ throw new IllegalStateException("Expected '" + seek + "'");@b@ }@b@@b@ private static char seekTo(String seek, Source source) {@b@ while (source.hasNext()) {@b@ char c = source.peek();@b@ if (seek.indexOf(c) >= 0) {@b@ return c;@b@ }@b@@b@ if (!(Character.isWhitespace(c)))@b@ throw new IllegalStateException("Unexpected '" + c + "' while seeking one of '" + seek + "'");@b@ source.next();@b@ }@b@@b@ throw new IllegalStateException("Expected one of '" + seek + "'");@b@ }@b@@b@ private static void complete(String seek, Source source) {@b@ int i = 0;@b@ while ((source.hasNext()) && (i < seek.length())) {@b@ char c = source.next();@b@ if (c != seek.charAt(i++))@b@ throw new IllegalStateException("Unexpected '" + c + " while seeking \"" + seek + "\"");@b@ }@b@@b@ if (i < seek.length())@b@ throw new IllegalStateException("Expected \"" + seek + "\"");@b@ }@b@@b@ public static String quote(String s)@b@ {@b@ if (s == null)@b@ return null;@b@ if (s.length() == 0)@b@ return "\"\"";@b@@b@ StringBuilder b = new StringBuilder(s.length() + 8);@b@ quote(b, s);@b@ return b.toString();@b@ }@b@@b@ public static void quote(StringBuilder buf, String s)@b@ {@b@ buf.append('"');@b@ for (int i = 0; i < s.length(); ++i)@b@ {@b@ char c = s.charAt(i);@b@ switch (c)@b@ {@b@ case '"':@b@ buf.append("\\\"");@b@ break;@b@ case '\\':@b@ buf.append("\\\\");@b@ break;@b@ case '\n':@b@ buf.append("\\n");@b@ break;@b@ case '\r':@b@ buf.append("\\r");@b@ break;@b@ case '\t':@b@ buf.append("\\t");@b@ break;@b@ case '\f':@b@ buf.append("\\f");@b@ break;@b@ case '\b':@b@ buf.append("\\b");@b@ break;@b@ default:@b@ buf.append(c);@b@ }@b@ }@b@@b@ buf.append('"');@b@ }@b@@b@ public static byte convertHexDigit(byte b)@b@ {@b@ if ((b >= 48) && (b <= 57)) return (byte)(b - 48);@b@ if ((b >= 97) && (b <= 102)) return (byte)(b - 97 + 10);@b@ if ((b >= 65) && (b <= 70)) return (byte)(b - 65 + 10);@b@ return 0;@b@ }@b@@b@ public static class Literal@b@ implements JSONParser.Generator@b@ {@b@ private String _json;@b@@b@ public Literal(String json)@b@ {@b@ JSONParser.parse(json);@b@ this._json = json;@b@ }@b@@b@ public String toString() {@b@ return this._json;@b@ }@b@@b@ public void addJSON(StringBuilder buffer) {@b@ buffer.append(this._json);@b@ }@b@ }@b@@b@ public static abstract interface Generator@b@ {@b@ public abstract void addJSON(StringBuilder paramStringBuilder);@b@ }@b@@b@ private static class Source@b@ {@b@ private final String string;@b@ private int index;@b@@b@ Source(String s)@b@ {@b@ int firstInd = s.indexOf("/*");@b@ int lastInd = s.lastIndexOf("*/");@b@ if ((firstInd != -1) && (lastInd != -1))@b@ s = s.substring(firstInd + 2, lastInd);@b@@b@ this.string = s;@b@ }@b@@b@ boolean hasNext() {@b@ return (this.index < this.string.length());@b@ }@b@@b@ char next() {@b@ return this.string.charAt(this.index++);@b@ }@b@@b@ char peek() {@b@ return this.string.charAt(this.index);@b@ }@b@@b@ int index() {@b@ return this.index;@b@ }@b@@b@ String from(int mark) {@b@ return this.string.substring(mark, this.index);@b@ }@b@@b@ String from(int mark, int end) {@b@ return this.string.substring(mark, end);@b@ }@b@ }@b@}