1
0
Fork 0
mirror of https://github.com/ethauvin/JSON-java.git synced 2025-06-17 07:50:52 -07:00

Updates for supporting the Android API

This commit is contained in:
John J. Aylward 2017-06-21 11:52:15 -04:00
parent 5024f2d210
commit e8b1b66888
9 changed files with 198 additions and 101 deletions

View file

@ -1,7 +1,5 @@
package org.json; package org.json;
import java.util.Map.Entry;
/* /*
Copyright (c) 2002 JSON.org Copyright (c) 2002 JSON.org
@ -24,7 +22,7 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
*/ */
/** /**
* Convert a web browser cookie list string to a JSONObject and back. * Convert a web browser cookie list string to a JSONObject and back.
@ -69,17 +67,17 @@ public class CookieList {
*/ */
public static String toString(JSONObject jo) throws JSONException { public static String toString(JSONObject jo) throws JSONException {
boolean b = false; boolean b = false;
StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
for (final Entry<String,?> entry : jo.entrySet()) { // Don't use the new entrySet API to maintain Android support
final String key = entry.getKey(); for (final String key : jo.keySet()) {
final Object value = entry.getValue(); final Object value = jo.opt(key);
if (!JSONObject.NULL.equals(value)) { if (!JSONObject.NULL.equals(value)) {
if (b) { if (b) {
sb.append(';'); sb.append(';');
} }
sb.append(Cookie.escape(key)); sb.append(Cookie.escape(key));
sb.append("="); sb.append("=");
sb.append(Cookie.escape(value.toString())); sb.append(Cookie.escape(value.toString()));
b = true; b = true;
} }
} }

View file

@ -25,7 +25,6 @@ SOFTWARE.
*/ */
import java.util.Locale; import java.util.Locale;
import java.util.Map.Entry;
/** /**
* Convert an HTTP header to a JSONObject and back. * Convert an HTTP header to a JSONObject and back.
@ -145,11 +144,12 @@ public class HTTP {
throw new JSONException("Not enough material for an HTTP header."); throw new JSONException("Not enough material for an HTTP header.");
} }
sb.append(CRLF); sb.append(CRLF);
for (final Entry<String,?> entry : jo.entrySet()) { // Don't use the new entrySet API to maintain Android support
final String key = entry.getKey(); for (final String key : jo.keySet()) {
String value = jo.optString(key);
if (!"HTTP-Version".equals(key) && !"Status-Code".equals(key) && if (!"HTTP-Version".equals(key) && !"Status-Code".equals(key) &&
!"Reason-Phrase".equals(key) && !"Method".equals(key) && !"Reason-Phrase".equals(key) && !"Method".equals(key) &&
!"Request-URI".equals(key) && !JSONObject.NULL.equals(entry.getValue())) { !"Request-URI".equals(key) && !JSONObject.NULL.equals(value)) {
sb.append(key); sb.append(key);
sb.append(": "); sb.append(": ");
sb.append(jo.optString(key)); sb.append(jo.optString(key));

View file

@ -1,7 +1,5 @@
package org.json; package org.json;
import java.util.Map.Entry;
/* /*
Copyright (c) 2008 JSON.org Copyright (c) 2008 JSON.org
@ -416,10 +414,10 @@ public class JSONML {
// Emit the attributes // Emit the attributes
for (final Entry<String, ?> entry : jo.entrySet()) { // Don't use the new entrySet API to maintain Android support
final String key = entry.getKey(); for (final String key : jo.keySet()) {
final Object value = jo.opt(key);
XML.noSpace(key); XML.noSpace(key);
final Object value = entry.getValue();
if (value != null) { if (value != null) {
sb.append(' '); sb.append(' ');
sb.append(XML.escape(key)); sb.append(XML.escape(key));
@ -495,11 +493,11 @@ public class JSONML {
//Emit the attributes //Emit the attributes
for (final Entry<String, ?> entry : jo.entrySet()) { // Don't use the new entrySet API to maintain Android support
final String key = entry.getKey(); for (final String key : jo.keySet()) {
if (!"tagName".equals(key) && !"childNodes".equals(key)) { if (!"tagName".equals(key) && !"childNodes".equals(key)) {
XML.noSpace(key); XML.noSpace(key);
value = entry.getValue(); value = jo.opt(key);
if (value != null) { if (value != null) {
sb.append(' '); sb.append(' ');
sb.append(XML.escape(key)); sb.append(XML.escape(key));

View file

@ -1908,6 +1908,8 @@ public class JSONObject {
* A String. * A String.
* @return A simple JSON value. * @return A simple JSON value.
*/ */
// Changes to this method must be copied to the corresponding method in
// the XML class to keep full support for Android
public static Object stringToValue(String string) { public static Object stringToValue(String string) {
if (string.equals("")) { if (string.equals("")) {
return string; return string;
@ -2065,55 +2067,11 @@ public class JSONObject {
* If the value is or contains an invalid number. * If the value is or contains an invalid number.
*/ */
public static String valueToString(Object value) throws JSONException { public static String valueToString(Object value) throws JSONException {
if (value == null || value.equals(null)) { // moves the implementation to JSONWriter as:
return "null"; // 1. It makes more sense to be part of the writer class
} // 2. For Android support this method is not available. By implementing it in the Writer
if (value instanceof JSONString) { // Android users can use the writer with the built in Android JSONObject implementation.
Object object; return JSONWriter.valueToString(value);
try {
object = ((JSONString) value).toJSONString();
} catch (Exception e) {
throw new JSONException(e);
}
if (object instanceof String) {
return (String) object;
}
throw new JSONException("Bad value from toJSONString: " + object);
}
if (value instanceof Number) {
// not all Numbers may match actual JSON Numbers. i.e. Fractions or Complex
final String numberAsString = numberToString((Number) value);
try {
// Use the BigDecimal constructor for it's parser to validate the format.
@SuppressWarnings("unused")
BigDecimal unused = new BigDecimal(numberAsString);
// Close enough to a JSON number that we will return it unquoted
return numberAsString;
} catch (NumberFormatException ex){
// The Number value is not a valid JSON number.
// Instead we will quote it as a string
return quote(numberAsString);
}
}
if (value instanceof Boolean || value instanceof JSONObject
|| value instanceof JSONArray) {
return value.toString();
}
if (value instanceof Map) {
Map<?, ?> map = (Map<?, ?>) value;
return new JSONObject(map).toString();
}
if (value instanceof Collection) {
Collection<?> coll = (Collection<?>) value;
return new JSONArray(coll).toString();
}
if (value.getClass().isArray()) {
return new JSONArray(value).toString();
}
if(value instanceof Enum<?>){
return quote(((Enum<?>)value).name());
}
return quote(value.toString());
} }
/** /**

View file

@ -5,7 +5,9 @@ import static java.lang.String.format;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.URLDecoder; import java.net.URLDecoder;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.util.*; import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/* /*
Copyright (c) 2002 JSON.org Copyright (c) 2002 JSON.org
@ -181,7 +183,7 @@ public class JSONPointer {
* @return the result of the evaluation * @return the result of the evaluation
* @throws JSONPointerException if an error occurs during evaluation * @throws JSONPointerException if an error occurs during evaluation
*/ */
public Object queryFrom(Object document) { public Object queryFrom(Object document) throws JSONPointerException {
if (this.refTokens.isEmpty()) { if (this.refTokens.isEmpty()) {
return document; return document;
} }
@ -205,10 +207,9 @@ public class JSONPointer {
* @param current the JSONArray to be evaluated * @param current the JSONArray to be evaluated
* @param indexToken the array index in string form * @param indexToken the array index in string form
* @return the matched object. If no matching item is found a * @return the matched object. If no matching item is found a
* JSONPointerException is thrown * @throws JSONPointerException is thrown if the index is out of bounds
*/ */
@SuppressWarnings("boxing") private Object readByIndexToken(Object current, String indexToken) throws JSONPointerException {
private Object readByIndexToken(Object current, String indexToken) {
try { try {
int index = Integer.parseInt(indexToken); int index = Integer.parseInt(indexToken);
JSONArray currentArr = (JSONArray) current; JSONArray currentArr = (JSONArray) current;
@ -216,7 +217,11 @@ public class JSONPointer {
throw new JSONPointerException(format("index %d is out of bounds - the array has %d elements", index, throw new JSONPointerException(format("index %d is out of bounds - the array has %d elements", index,
currentArr.length())); currentArr.length()));
} }
return currentArr.get(index); try {
return currentArr.get(index);
} catch (JSONException e) {
throw new JSONPointerException("Error reading value at index position " + index, e);
}
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
throw new JSONPointerException(format("%s is not an array index", indexToken), e); throw new JSONPointerException(format("%s is not an array index", indexToken), e);
} }

View file

@ -1,6 +1,9 @@
package org.json; package org.json;
import java.io.IOException; import java.io.IOException;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.Map;
/* /*
Copyright (c) 2006 JSON.org Copyright (c) 2006 JSON.org
@ -117,6 +120,9 @@ public class JSONWriter {
} }
this.writer.append(string); this.writer.append(string);
} catch (IOException e) { } catch (IOException e) {
// Android as of API 25 does not support this exception constructor
// however we won't worry about it. If an exception is happening here
// it will just throw a "Method not found" exception instead.
throw new JSONException(e); throw new JSONException(e);
} }
if (this.mode == 'o') { if (this.mode == 'o') {
@ -164,6 +170,9 @@ public class JSONWriter {
try { try {
this.writer.append(c); this.writer.append(c);
} catch (IOException e) { } catch (IOException e) {
// Android as of API 25 does not support this exception constructor
// however we won't worry about it. If an exception is happening here
// it will just throw a "Method not found" exception instead.
throw new JSONException(e); throw new JSONException(e);
} }
this.comma = true; this.comma = true;
@ -204,7 +213,12 @@ public class JSONWriter {
} }
if (this.mode == 'k') { if (this.mode == 'k') {
try { try {
this.stack[this.top - 1].putOnce(string, Boolean.TRUE); JSONObject topObject = this.stack[this.top - 1];
// don't use the built in putOnce method to maintain Android support
if(topObject.has(string)) {
throw new JSONException("Duplicate key \"" + string + "\"");
}
topObject.put(string, true);
if (this.comma) { if (this.comma) {
this.writer.append(','); this.writer.append(',');
} }
@ -214,6 +228,9 @@ public class JSONWriter {
this.mode = 'o'; this.mode = 'o';
return this; return this;
} catch (IOException e) { } catch (IOException e) {
// Android as of API 25 does not support this exception constructor
// however we won't worry about it. If an exception is happening here
// it will just throw a "Method not found" exception instead.
throw new JSONException(e); throw new JSONException(e);
} }
} }
@ -280,6 +297,81 @@ public class JSONWriter {
this.top += 1; this.top += 1;
} }
/**
* Make a JSON text of an Object value. If the object has an
* value.toJSONString() method, then that method will be used to produce the
* JSON text. The method is required to produce a strictly conforming text.
* If the object does not contain a toJSONString method (which is the most
* common case), then a text will be produced by other means. If the value
* is an array or Collection, then a JSONArray will be made from it and its
* toJSONString method will be called. If the value is a MAP, then a
* JSONObject will be made from it and its toJSONString method will be
* called. Otherwise, the value's toString method will be called, and the
* result will be quoted.
*
* <p>
* Warning: This method assumes that the data structure is acyclical.
*
* @param value
* The value to be serialized.
* @return a printable, displayable, transmittable representation of the
* object, beginning with <code>{</code>&nbsp;<small>(left
* brace)</small> and ending with <code>}</code>&nbsp;<small>(right
* brace)</small>.
* @throws JSONException
* If the value is or contains an invalid number.
*/
public static String valueToString(Object value) throws JSONException {
if (value == null || value.equals(null)) {
return "null";
}
if (value instanceof JSONString) {
Object object;
try {
object = ((JSONString) value).toJSONString();
} catch (Exception e) {
throw new JSONException(e);
}
if (object instanceof String) {
return (String) object;
}
throw new JSONException("Bad value from toJSONString: " + object);
}
if (value instanceof Number) {
// not all Numbers may match actual JSON Numbers. i.e. Fractions or Complex
final String numberAsString = JSONObject.numberToString((Number) value);
try {
// Use the BigDecimal constructor for it's parser to validate the format.
@SuppressWarnings("unused")
BigDecimal unused = new BigDecimal(numberAsString);
// Close enough to a JSON number that we will return it unquoted
return numberAsString;
} catch (NumberFormatException ex){
// The Number value is not a valid JSON number.
// Instead we will quote it as a string
return JSONObject.quote(numberAsString);
}
}
if (value instanceof Boolean || value instanceof JSONObject
|| value instanceof JSONArray) {
return value.toString();
}
if (value instanceof Map) {
Map<?, ?> map = (Map<?, ?>) value;
return new JSONObject(map).toString();
}
if (value instanceof Collection) {
Collection<?> coll = (Collection<?>) value;
return new JSONArray(coll).toString();
}
if (value.getClass().isArray()) {
return new JSONArray(value).toString();
}
if(value instanceof Enum<?>){
return JSONObject.quote(((Enum<?>)value).name());
}
return JSONObject.quote(value.toString());
}
/** /**
* Append either the value <code>true</code> or the value * Append either the value <code>true</code> or the value
@ -321,6 +413,6 @@ public class JSONWriter {
* @throws JSONException If the value is out of sequence. * @throws JSONException If the value is out of sequence.
*/ */
public JSONWriter value(Object object) throws JSONException { public JSONWriter value(Object object) throws JSONException {
return this.append(JSONObject.valueToString(object)); return this.append(valueToString(object));
} }
} }

View file

@ -25,7 +25,6 @@ SOFTWARE.
*/ */
import java.util.Enumeration; import java.util.Enumeration;
import java.util.Map.Entry;
import java.util.Properties; import java.util.Properties;
/** /**
@ -61,10 +60,11 @@ public class Property {
public static Properties toProperties(JSONObject jo) throws JSONException { public static Properties toProperties(JSONObject jo) throws JSONException {
Properties properties = new Properties(); Properties properties = new Properties();
if (jo != null) { if (jo != null) {
for (final Entry<String, ?> entry : jo.entrySet()) { // Don't use the new entrySet API to maintain Android support
Object value = entry.getValue(); for (final String key : jo.keySet()) {
Object value = jo.opt(key);
if (!JSONObject.NULL.equals(value)) { if (!JSONObject.NULL.equals(value)) {
properties.put(entry.getKey(), value.toString()); properties.put(key, value.toString());
} }
} }
} }

View file

@ -25,7 +25,6 @@ SOFTWARE.
*/ */
import java.util.Iterator; import java.util.Iterator;
import java.util.Map.Entry;
/** /**
* This provides static methods to convert an XML text into a JSONObject, and to * This provides static methods to convert an XML text into a JSONObject, and to
@ -430,11 +429,49 @@ public class XML {
* @return JSON value of this string or the string * @return JSON value of this string or the string
*/ */
public static Object stringToValue(String string) { public static Object stringToValue(String string) {
Object ret = JSONObject.stringToValue(string); if (string.equals("")) {
if(ret instanceof String){ return string;
return unescape((String)ret);
} }
return ret; if (string.equalsIgnoreCase("true")) {
return Boolean.TRUE;
}
if (string.equalsIgnoreCase("false")) {
return Boolean.FALSE;
}
if (string.equalsIgnoreCase("null")) {
return JSONObject.NULL;
}
/*
* If it might be a number, try converting it. If a number cannot be
* produced, then the value will just be a string.
*/
char initial = string.charAt(0);
if ((initial >= '0' && initial <= '9') || initial == '-') {
try {
// if we want full Big Number support this block can be replaced with:
// return stringToNumber(string);
if (string.indexOf('.') > -1 || string.indexOf('e') > -1
|| string.indexOf('E') > -1 || "-0".equals(string)) {
Double d = Double.valueOf(string);
if (!d.isInfinite() && !d.isNaN()) {
return d;
}
} else {
Long myLong = Long.valueOf(string);
if (string.equals(myLong.toString())) {
if (myLong.longValue() == myLong.intValue()) {
return Integer.valueOf(myLong.intValue());
}
return myLong;
}
}
} catch (Exception ignore) {
}
}
return unescape(string);
} }
/** /**
@ -482,8 +519,11 @@ public class XML {
public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException { public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException {
JSONObject jo = new JSONObject(); JSONObject jo = new JSONObject();
XMLTokener x = new XMLTokener(string); XMLTokener x = new XMLTokener(string);
while (x.more() && x.skipPast("<")) { while (x.more()) {
parse(x, jo, null, keepStrings); x.skipPast("<");
if(x.more()) {
parse(x, jo, null, keepStrings);
}
} }
return jo; return jo;
} }
@ -526,10 +566,10 @@ public class XML {
} }
// Loop thru the keys. // Loop thru the keys.
// don't use the new entrySet accessor to maintain Android Support
jo = (JSONObject) object; jo = (JSONObject) object;
for (final Entry<String, ?> entry : jo.entrySet()) { for (final String key : jo.keySet()) {
final String key = entry.getKey(); Object value = jo.opt(key);
Object value = entry.getValue();
if (value == null) { if (value == null) {
value = ""; value = "";
} else if (value.getClass().isArray()) { } else if (value.getClass().isArray()) {
@ -540,13 +580,14 @@ public class XML {
if ("content".equals(key)) { if ("content".equals(key)) {
if (value instanceof JSONArray) { if (value instanceof JSONArray) {
ja = (JSONArray) value; ja = (JSONArray) value;
int i = 0; int jaLength = ja.length();
for (Object val : ja) { // don't use the new iterator API to maintain support for Android
for (int i = 0; i < jaLength; i++) {
if (i > 0) { if (i > 0) {
sb.append('\n'); sb.append('\n');
} }
Object val = ja.opt(i);
sb.append(escape(val.toString())); sb.append(escape(val.toString()));
i++;
} }
} else { } else {
sb.append(escape(value.toString())); sb.append(escape(value.toString()));
@ -556,7 +597,10 @@ public class XML {
} else if (value instanceof JSONArray) { } else if (value instanceof JSONArray) {
ja = (JSONArray) value; ja = (JSONArray) value;
for (Object val : ja) { int jaLength = ja.length();
// don't use the new iterator API to maintain support for Android
for (int i = 0; i < jaLength; i++) {
Object val = ja.opt(i);
if (val instanceof JSONArray) { if (val instanceof JSONArray) {
sb.append('<'); sb.append('<');
sb.append(key); sb.append(key);
@ -597,7 +641,10 @@ public class XML {
} else { } else {
ja = (JSONArray) object; ja = (JSONArray) object;
} }
for (Object val : ja) { int jaLength = ja.length();
// don't use the new iterator API to maintain support for Android
for (int i = 0; i < jaLength; i++) {
Object val = ja.opt(i);
// XML does not have good support for arrays. If an array // XML does not have good support for arrays. If an array
// appears in a place where XML is lacking, synthesize an // appears in a place where XML is lacking, synthesize an
// <array> element. // <array> element.

View file

@ -297,9 +297,8 @@ public class XMLTokener extends JSONTokener {
* Skip characters until past the requested string. * Skip characters until past the requested string.
* If it is not found, we are left at the end of the source with a result of false. * If it is not found, we are left at the end of the source with a result of false.
* @param to A string to skip past. * @param to A string to skip past.
* @throws JSONException
*/ */
public boolean skipPast(String to) throws JSONException { public void skipPast(String to) {
boolean b; boolean b;
char c; char c;
int i; int i;
@ -316,7 +315,7 @@ public class XMLTokener extends JSONTokener {
for (i = 0; i < length; i += 1) { for (i = 0; i < length; i += 1) {
c = next(); c = next();
if (c == 0) { if (c == 0) {
return false; return;
} }
circle[i] = c; circle[i] = c;
} }
@ -343,14 +342,14 @@ public class XMLTokener extends JSONTokener {
/* If we exit the loop with b intact, then victory is ours. */ /* If we exit the loop with b intact, then victory is ours. */
if (b) { if (b) {
return true; return;
} }
/* Get the next character. If there isn't one, then defeat is ours. */ /* Get the next character. If there isn't one, then defeat is ours. */
c = next(); c = next();
if (c == 0) { if (c == 0) {
return false; return;
} }
/* /*
* Shove the character in the circle buffer and advance the * Shove the character in the circle buffer and advance the