blob: 7b5ccd9f8301b9f201d60904708fb3c3a7c6c1b4 [file] [log] [blame]
/*
* Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.json.client;
import com.google.gwt.core.client.JavaScriptException;
import com.google.gwt.core.client.JavaScriptObject;
/**
* Parses the string representation of a JSON object into a set of
* JSONValue-derived objects.
*
* @see com.google.gwt.json.client.JSONValue
*/
public class JSONParser {
static final JavaScriptObject typeMap = initTypeMap();
/**
* Evaluates a trusted JSON string and returns its JSONValue representation.
* CAUTION! For efficiency, this method is implemented using the JavaScript
* <code>eval()</code> function, which can execute arbitrary script. DO NOT
* pass an untrusted string into this method.
*
* @param jsonString a JSON object to parse
* @return a JSONValue that has been built by parsing the JSON string
* @throws NullPointerException if <code>jsonString</code> is
* <code>null</code>
* @throws IllegalArgumentException if <code>jsonString</code> is empty
*/
public static JSONValue parse(String jsonString) {
if (jsonString == null) {
throw new NullPointerException();
}
if (jsonString.length() == 0) {
throw new IllegalArgumentException("empty argument");
}
try {
return evaluate(jsonString);
} catch (JavaScriptException ex) {
throw new JSONException(ex);
}
}
static void throwUnknownTypeException(String typeString) {
throw new JSONException("Unexpected typeof result '" + typeString
+ "'; please report this bug to the GWT team");
}
/**
* Called from {@link #initTypeMap()}.
*/
@SuppressWarnings("unused")
private static JSONValue createBoolean(boolean v) {
return JSONBoolean.getInstance(v);
}
/**
* Called from {@link #initTypeMap()}.
*/
@SuppressWarnings("unused")
private static JSONValue createNumber(double v) {
return new JSONNumber(v);
}
/**
* Called from {@link #initTypeMap()}. If we get here, <code>o</code> is
* either <code>null</code> (not <code>undefined</code>) or a JavaScript
* object.
*/
@SuppressWarnings("unused")
private static native JSONValue createObject(Object o) /*-{
if (!o) {
return @com.google.gwt.json.client.JSONNull::getInstance()();
}
var v = o.valueOf ? o.valueOf() : o;
if (v !== o) {
// It was a primitive wrapper, unwrap it and try again.
var func = @com.google.gwt.json.client.JSONParser::typeMap[typeof v];
return func ? func(v) : @com.google.gwt.json.client.JSONParser::throwUnknownTypeException(Ljava/lang/String;)(typeof v);
} else if (o instanceof Array || o instanceof $wnd.Array) {
// Looks like an Array; wrap as JSONArray.
// NOTE: this test can fail for objects coming from a different window,
// but we know of no reliable tests to determine if something is an Array
// in all cases.
return @com.google.gwt.json.client.JSONArray::new(Lcom/google/gwt/core/client/JavaScriptObject;)(o);
} else {
// This is a basic JavaScript object; wrap as JSONObject.
// Subobjects will be created on demand.
return @com.google.gwt.json.client.JSONObject::new(Lcom/google/gwt/core/client/JavaScriptObject;)(o);
}
}-*/;
/**
* Called from {@link #initTypeMap()}.
*/
@SuppressWarnings("unused")
private static JSONValue createString(String v) {
return new JSONString(v);
}
/**
* Called from {@link #initTypeMap()}. This method returns a
* <code>null</code> pointer, representing JavaScript <code>undefined</code>.
*/
@SuppressWarnings("unused")
private static JSONValue createUndefined() {
return null;
}
/**
* This method converts <code>jsonString</code> into a JSONValue.
*/
private static native JSONValue evaluate(String jsonString) /*-{
var v = eval('(' + jsonString + ')');
var func = @com.google.gwt.json.client.JSONParser::typeMap[typeof v];
return func ? func(v) : @com.google.gwt.json.client.JSONParser::throwUnknownTypeException(Ljava/lang/String;)(typeof v);
}-*/;
private static native JavaScriptObject initTypeMap() /*-{
return {
"boolean": @com.google.gwt.json.client.JSONParser::createBoolean(Z),
"number": @com.google.gwt.json.client.JSONParser::createNumber(D),
"string": @com.google.gwt.json.client.JSONParser::createString(Ljava/lang/String;),
"object": @com.google.gwt.json.client.JSONParser::createObject(Ljava/lang/Object;),
"function": @com.google.gwt.json.client.JSONParser::createObject(Ljava/lang/Object;),
"undefined": @com.google.gwt.json.client.JSONParser::createUndefined(),
}
}-*/;
/**
* Not instantiable.
*/
private JSONParser() {
}
}