com.sun.grizzly.cometd.util.JSONParser Maven / Gradle / Ivy
The newest version!
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2007-2010 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
// ========================================================================
// Copyright 2006 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ========================================================================
/** JSONParser Parser and Generator.
*
* This class provides some static methods to convert POJOs to and from JSONParser
* notation. The mapping from JSONParser to java is:
* object ==> Map
* array ==> Object[]
* number ==> Double or Long
* string ==> String
* null ==> null
* bool ==> Boolean
*
*
* The java to JSONParser mapping is:
* String --> string
* Number --> number
* Map --> object
* List --> array
* Array --> array
* null --> null
* Boolean--> boolean
* Object --> string (dubious!)
*
*
* The interface {@link JSONParser.Generator} may be implemented by classes that know how to render themselves as JSONParser and
* the {@link #toString(Object)} method will use {@link JSONParser.Generator#addJSON(StringBuffer)} to generate the JSONParser.
* The class {@link JSONParser.Literal} may be used to hold pre-gnerated JSONParser object.
*
* @author gregw
*
*/
package com.sun.grizzly.cometd.util;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
public class JSONParser {
private JSONParser(){}
public static String toString(Object object) {
StringBuffer buffer = new StringBuffer();
append(buffer,object);
return buffer.toString();
}
public static String toString(Map object) {
StringBuffer buffer = new StringBuffer();
appendMap(buffer,object);
return buffer.toString();
}
public static String toString(Object[] array) {
StringBuffer buffer = new StringBuffer();
appendArray(buffer,array);
return buffer.toString();
}
/**
* @param s String containing JSONParser object or array.
* @return A Map, Object array or primitive array parsed from the JSONParser.
*/
public static Object parse(String s) {
return parse(new Source(s));
}
/**
* Append object as JSONParser to string buffer.
* @param buffer
* @param object
*/
public static void append(StringBuffer buffer, Object object) {
if (object==null)
buffer.append("null");
else if (object instanceof Generator)
appendJSON(buffer, (Generator)object);
else if (object instanceof Map)
appendMap(buffer, (Map)object);
else if (object instanceof List)
appendArray(buffer,((List)object).toArray());
else if (object.getClass().isArray())
appendArray(buffer,object);
else if (object instanceof Number)
appendNumber(buffer,(Number)object);
else if (object instanceof Boolean)
appendBoolean(buffer,(Boolean)object);
else if (object instanceof String)
appendString(buffer,(String)object);
else
// TODO - maybe some bean stuff?
appendString(buffer,object.toString());
}
private static void appendNull(StringBuffer buffer) {
buffer.append("null");
}
private static void appendJSON(StringBuffer buffer, Generator generator) {
generator.addJSON(buffer);
}
private static void appendMap(StringBuffer buffer, Map object) {
if (object==null) {
appendNull(buffer);
return;
}
buffer.append('{');
Iterator iter = object.entrySet().iterator();
while(iter.hasNext()) {
Map.Entry entry = (Map.Entry)iter.next();
quote(buffer,entry.getKey().toString());
buffer.append(':');
append(buffer,entry.getValue());
if (iter.hasNext())
buffer.append(',');
}
buffer.append('}');
}
private static void appendArray(StringBuffer buffer, Object array) {
if (array==null) {
appendNull(buffer);
return;
}
buffer.append('[');
int length = Array.getLength(array);
for (int i=0;i1) {
switch(c) {
case '*' :
comment_state=3;
break;
case '/' :
if (comment_state==3)
comment_state=0;
else
comment_state=2;
break;
default:
comment_state=2;
}
}
// handle // comment
else if (comment_state<0) {
switch(c) {
case '\r' :
case '\n' :
comment_state=0;
break;
default:
break;
}
}
// handle unknown
else {
switch(c) {
case '{' :
return parseObject(source);
case '[' :
return parseArray(source);
case '"' :
return parseString(source);
case '-' :
return parseNumber(source);
case 'n' :
complete("null",source);
return null;
case 't' :
complete("true",source);
return Boolean.TRUE;
case 'f' :
complete("false",source);
return Boolean.FALSE;
case '/' :
comment_state=1;
break;
default :
if (Character.isDigit(c))
return parseNumber(source);
else if (Character.isWhitespace(c))
break;
throw new IllegalStateException("unknown char "+c);
}
}
source.next();
}
return null;
}
private static Map parseObject(Source source) {
if (source.next()!='{')
throw new IllegalStateException();
Map map = new HashMap();
char next = seekTo("\"}",source);
while(source.hasNext()) {
if (next=='}') {
source.next();
break;
}
String name=parseString(source);
seekTo(':',source);
source.next();
Object value=parse(source);
map.put(name,value);
seekTo(",}",source);
next=source.next();
if (next=='}')
break;
else
next = seekTo("\"}",source);
}
return map;
}
private static Object parseArray(Source source) {
if (source.next()!='[')
throw new IllegalStateException();
ArrayList list=new ArrayList();
boolean coma=true;
while(source.hasNext()) {
char c=source.peek();
switch(c) {
case ']':
source.next();
return list.toArray(new Object[list.size()]);
case ',':
if (coma)
throw new IllegalStateException();
coma=true;
source.next();
default:
if (Character.isWhitespace(c))
source.next();
else {
coma=false;
list.add(parse(source));
}
}
}
throw new IllegalStateException("unexpected end of array");
}
private static String parseString(Source source) {
if (source.next()!='"')
throw new IllegalStateException();
boolean escape=false;
StringBuffer b = new StringBuffer();
while(source.hasNext()) {
char c=source.next();
if (escape) {
escape=false;
switch (c) {
case 'n':
b.append('\n');
break;
case 'r':
b.append('\r');
break;
case 't':
b.append('\t');
break;
case 'f':
b.append('\f');
break;
case 'b':
b.append('\b');
break;
case 'u':
b.append((char)(
(convertHexDigit((byte)source.next())<<24)+
(convertHexDigit((byte)source.next())<<16)+
(convertHexDigit((byte)source.next())<<8)+
(convertHexDigit((byte)source.next()))
)
);
break;
default:
b.append(c);
}
} else if (c=='\\') {
escape=true;
continue;
} else if (c=='\"')
break;
else
b.append(c);
}
return b.toString();
}
private static Number parseNumber(Source source) {
int start=source.index();
int end=-1;
boolean is_double=false;
while(source.hasNext()&&end<0) {
char c=source.peek();
switch(c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '-':
source.next();
break;
case '.':
case 'e':
case 'E':
is_double=true;
source.next();
break;
default:
end=source.index();
}
}
String s = end>=0?source.from(start,end):source.from(start);
if (is_double)
return new Double(s);
else
return new Long(s);
}
private static void seekTo(char seek, Source source) {
while(source.hasNext()) {
char c=source.peek();
if (c==seek)
return;
if (!Character.isWhitespace(c))
throw new IllegalStateException("Unexpected '"+c+" while seeking '"+seek+"'");
source.next();
}
throw new IllegalStateException("Expected '"+seek+"'");
}
private static char seekTo(String seek, Source source) {
while(source.hasNext()) {
char c=source.peek();
if(seek.indexOf(c)>=0) {
return c;
}
if (!Character.isWhitespace(c))
throw new IllegalStateException("Unexpected '"+c+"' while seeking one of '"+seek+"'");
source.next();
}
throw new IllegalStateException("Expected one of '"+seek+"'");
}
private static void complete(String seek, Source source) {
int i=0;
while(source.hasNext()&& i= '0') && (b <= '9')) return (byte)(b - '0');
if ((b >= 'a') && (b <= 'f')) return (byte)(b - 'a' + 10);
if ((b >= 'A') && (b <= 'F')) return (byte)(b - 'A' + 10);
return 0;
}
}