/*
* 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.apache.cordova.json4j;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.util.Enumeration;
import java.util.Hashtable;
import org.apache.cordova.json4j.internal.JSON4JStringReader;
import org.apache.cordova.json4j.internal.JSON4JStringWriter;
import org.apache.cordova.json4j.internal.NumberUtil;
import org.apache.cordova.json4j.internal.Parser;
import org.apache.cordova.json4j.internal.Serializer;
import org.apache.cordova.json4j.internal.SerializerVerbose;
/**
* Models a JSON Object.
*
* Extension of Hashtable that only allows String keys, and values which are JSON-able (such as a Java Bean).
* <BR><BR>
* JSON-able values are: null, and instances of String, Boolean, Number, JSONObject and JSONArray.
* <BR><BR>
* Instances of this class are not thread-safe.
*/
public class JSONObject extends Hashtable implements JSONArtifact {
private static final long serialVersionUID = -3269263069889337298L;
/**
* A constant definition reference to Java null.
* Provided for API compatibility with other JSON parsers.
*/
public static final Object NULL = new Null();
/**
* Return whether the object is a valid value for a property.
* @param object The object to check for validity as a JSON property value.
* @return boolean indicating if the provided object is directly convertable to JSON.
*/
public static boolean isValidObject(Object object) {
if (null == object) return true;
return isValidType(object.getClass());
}
/**
* Return whether the class is a valid type of value for a property.
* @param clazz The class type to check for validity as a JSON object type.
* @return boolean indicating if the provided class is directly convertable to JSON.
*/
public static boolean isValidType(Class clazz) {
if (null == clazz) throw new IllegalArgumentException();
if (String.class == clazz) return true;
if (Boolean.class == clazz) return true;
if (JSONObject.class.isAssignableFrom(clazz)) return true;
if (JSONArray.class == clazz) return true;
if (NumberUtil.isNumber(clazz)) return true;
if (JSONObject.NULL == clazz) return true;
if (JSONString.class.isAssignableFrom(clazz)) return true;
return false;
}
/**
* Create a new instance of this class.
*/
public JSONObject() {
super();
}
/**
* Create a new instance of this class taking selected values from the underlying one.
* @param obj The JSONObject to extract values from.
* @param keys The keys to take from the JSONObject and apply to this instance.
* @throws JSONException Thrown if a key is duplicated in the string[] keys
*/
public JSONObject(JSONObject obj, String[] keys) throws JSONException{
super();
if (keys != null && keys.length > 0) {
for (int i = 0; i < keys.length; i++) {
if (this.containsKey(keys[i])) {
throw new JSONException("Duplicate key: " + keys[i]);
}
try {
this.put(keys[i], obj.get(keys[i]));
} catch (Exception ex) {
JSONException jex = new JSONException("Error occurred during JSONObject creation");
jex.setCause(ex);
throw jex;
}
}
}
}
/**
* Create a new instance of this class from the provided JSON object string.
* Note: This is the same as new JSONObject(str, false); Parsing in non-strict mode.
* @param str The JSON string to parse.
* @throws JSONException Thrown when the string passed is null, or malformed JSON..
*/
public JSONObject(String str) throws JSONException {
super();
JSON4JStringReader reader = new JSON4JStringReader(str);
(new Parser(reader)).parse(this);
}
/**
* Create a new instance of this class from the provided JSON object string.
* @param str The JSON string to parse.
* @param strict Whether or not to parse in 'strict' mode, meaning all strings must be quoted (including identifiers), and comments are not allowed.
* @throws JSONException Thrown when the string passed is null, or malformed JSON..
*/
public JSONObject(String str, boolean strict) throws JSONException {
super();
JSON4JStringReader reader = new JSON4JStringReader(str);
(new Parser(reader, strict)).parse(this);
}
/**
* Create a new instance of this class from the data provided from the reader. The reader content must be a JSON object string.
* Note: The reader will not be closed, that is left to the caller.
* Note: This is the same as new JSONObject(rdr, false); Parsing in non-strict mode.
* @throws JSONException Thrown when the string passed is null, or malformed JSON..
*/
public JSONObject(Reader rdr) throws JSONException {
(new Parser(rdr)).parse(this);
}
/**
* Create a new instance of this class from the data provided from the reader. The reader content must be a JSON object string.
* Note: The reader will not be closed, that is left to the caller.
* @param rdr The reader from which to read the JSON.
* @param strict Whether or not to parse in 'strict' mode, meaning all strings must be quoted (including identifiers), and comments are not allowed.
* @throws JSONException Thrown when the string passed is null, or malformed JSON..
*/
public JSONObject(Reader rdr, boolean strict) throws JSONException {
(new Parser(rdr, strict)).parse(this);
}
/**
* Create a new instance of this class from the data provided from the input stream. The stream content must be a JSON object string.
* Note: The input stream content is assumed to be UTF-8 encoded.
* Note: The InputStream will not be closed, that is left to the caller.
* Note: This is the same as new JSONObject(is, false); Parsing in non-strict mode.
* @param is The InputStream from which to read the JSON.
* @throws JSONException Thrown when the string passed is null, or malformed JSON..
*/
public JSONObject (InputStream is) throws JSONException {
InputStreamReader isr = null;
if (is != null) {
try {
isr = new InputStreamReader(is, "UTF-8");
} catch (Exception ex) {
isr = new InputStreamReader(is);
}
} else {
throw new JSONException("InputStream cannot be null");
}
(new Parser(isr)).parse(true, this);
}
/**
* Create a new instance of this class from the data provided from the input stream. The stream content must be a JSON object string.
* Note: The input stream content is assumed to be UTF-8 encoded.
* Note: The InputStream will not be closed, that is left to the caller.
* @param i