modified org.json.* library to fit into the YaCy environment

as drop-in replacement.
Also made some fixes and enhancements to the library.
pull/355/head
Michael Peter Christen 5 years ago
parent 60dc1241a3
commit ea8df27e95

@ -14,6 +14,14 @@
* limitations under the License. * limitations under the License.
*/ */
/*
* This class was taken from
* https://android.googlesource.com/platform/libcore/+/refs/heads/master/json/src/main/java/org/json
* and slightly modified (by mc@yacy.net):
* - fixed "statement unnecessary nested" warnings
* - added asserts
*/
package org.json; package org.json;
class JSON { class JSON {
@ -28,6 +36,7 @@ class JSON {
} }
static Boolean toBoolean(Object value) { static Boolean toBoolean(Object value) {
assert value != null;
if (value instanceof Boolean) { if (value instanceof Boolean) {
return (Boolean) value; return (Boolean) value;
} else if (value instanceof String) { } else if (value instanceof String) {
@ -42,6 +51,7 @@ class JSON {
} }
static Double toDouble(Object value) { static Double toDouble(Object value) {
assert value != null;
if (value instanceof Double) { if (value instanceof Double) {
return (Double) value; return (Double) value;
} else if (value instanceof Number) { } else if (value instanceof Number) {
@ -56,6 +66,7 @@ class JSON {
} }
static Integer toInteger(Object value) { static Integer toInteger(Object value) {
assert value != null;
if (value instanceof Integer) { if (value instanceof Integer) {
return (Integer) value; return (Integer) value;
} else if (value instanceof Number) { } else if (value instanceof Number) {
@ -70,6 +81,7 @@ class JSON {
} }
static Long toLong(Object value) { static Long toLong(Object value) {
assert value != null;
if (value instanceof Long) { if (value instanceof Long) {
return (Long) value; return (Long) value;
} else if (value instanceof Number) { } else if (value instanceof Number) {
@ -84,6 +96,7 @@ class JSON {
} }
static String toString(Object value) { static String toString(Object value) {
assert value != null;
if (value instanceof String) { if (value instanceof String) {
return (String) value; return (String) value;
} else if (value != null) { } else if (value != null) {
@ -96,21 +109,20 @@ class JSON {
String requiredType) throws JSONException { String requiredType) throws JSONException {
if (actual == null) { if (actual == null) {
throw new JSONException("Value at " + indexOrName + " is null."); throw new JSONException("Value at " + indexOrName + " is null.");
} else {
throw new JSONException("Value " + actual + " at " + indexOrName
+ " of type " + actual.getClass().getName()
+ " cannot be converted to " + requiredType);
} }
throw new JSONException("Value " + actual + " at " + indexOrName
+ " of type " + actual.getClass().getName()
+ " cannot be converted to " + requiredType);
} }
public static JSONException typeMismatch(Object actual, String requiredType) public static JSONException typeMismatch(Object actual, String requiredType)
throws JSONException { throws JSONException {
if (actual == null) { if (actual == null) {
throw new JSONException("Value is null."); throw new JSONException("Value is null.");
} else {
throw new JSONException("Value " + actual
+ " of type " + actual.getClass().getName()
+ " cannot be converted to " + requiredType);
} }
throw new JSONException("Value " + actual
+ " of type " + actual.getClass().getName()
+ " cannot be converted to " + requiredType);
} }
} }

@ -14,14 +14,22 @@
* limitations under the License. * limitations under the License.
*/ */
/*
* This class was taken from
* https://android.googlesource.com/platform/libcore/+/refs/heads/master/json/src/main/java/org/json
* and slightly modified (by mc@yacy.net):
* - removed dependency from other libraries (i.e. android.compat.annotation)
* - fixed "statement unnecessary nested" warnings
* - fixed raw type declarations
* - added initializer with capacity and trimToSize to reduce memory usage
*/
package org.json; package org.json;
import android.compat.annotation.UnsupportedAppUsage;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.List;
// Note: this class was written without inspecting the non-free org.json sourcecode. // Note: this class was written without inspecting the non-free org.json sourcecode.
@ -49,8 +57,7 @@ import java.util.List;
*/ */
public class JSONArray { public class JSONArray {
@UnsupportedAppUsage private final ArrayList<Object> values;
private final List<Object> values;
/** /**
* Creates a {@code JSONArray} with no values. * Creates a {@code JSONArray} with no values.
@ -59,6 +66,26 @@ public class JSONArray {
values = new ArrayList<Object>(); values = new ArrayList<Object>();
} }
/**
* Creates a {@code JSONArray} with no values and the specified initial capacity.
*
* @param initialCapacity the initial capacity of the list
* @throws IllegalArgumentException if the specified initial capacity
* is negative
*/
public JSONArray(int initialCapacity) {
values = new ArrayList<Object>(initialCapacity);
}
/**
* Trims the capacity of this <tt>JSONArray</tt> instance to be the
* list's current size. An application can use this operation to minimize
* the storage of an <tt>JSONArray</tt> instance.
*/
public void trimToSize() {
this.values.trimToSize();
}
/** /**
* Creates a new {@code JSONArray} by copying all values from the given * Creates a new {@code JSONArray} by copying all values from the given
* collection. * collection.
@ -68,10 +95,10 @@ public class JSONArray {
* inconsistent state. * inconsistent state.
*/ */
/* Accept a raw type for API compatibility */ /* Accept a raw type for API compatibility */
public JSONArray(Collection copyFrom) { public JSONArray(Collection<?> copyFrom) {
this(); this(copyFrom == null ? 0 : copyFrom.size());
if (copyFrom != null) { if (copyFrom != null) {
for (Iterator it = copyFrom.iterator(); it.hasNext();) { for (Iterator<?> it = copyFrom.iterator(); it.hasNext();) {
put(JSONObject.wrap(it.next())); put(JSONObject.wrap(it.next()));
} }
} }
@ -498,9 +525,8 @@ public class JSONArray {
Object object = get(index); Object object = get(index);
if (object instanceof JSONArray) { if (object instanceof JSONArray) {
return (JSONArray) object; return (JSONArray) object;
} else {
throw JSON.typeMismatch(index, object, "JSONArray");
} }
throw JSON.typeMismatch(index, object, "JSONArray");
} }
/** /**
@ -523,9 +549,8 @@ public class JSONArray {
Object object = get(index); Object object = get(index);
if (object instanceof JSONObject) { if (object instanceof JSONObject) {
return (JSONObject) object; return (JSONObject) object;
} else {
throw JSON.typeMismatch(index, object, "JSONObject");
} }
throw JSON.typeMismatch(index, object, "JSONObject");
} }
/** /**
@ -609,7 +634,6 @@ public class JSONArray {
return stringer.toString(); return stringer.toString();
} }
@UnsupportedAppUsage
void writeTo(JSONStringer stringer) throws JSONException { void writeTo(JSONStringer stringer) throws JSONException {
stringer.array(); stringer.array();
for (Object value : values) { for (Object value : values) {

@ -14,6 +14,14 @@
* limitations under the License. * limitations under the License.
*/ */
/*
* This class was taken from
* https://android.googlesource.com/platform/libcore/+/refs/heads/master/json/src/main/java/org/json
* and slightly modified (by mc@yacy.net):
* - removed dependency from other libraries (i.e. android.compat.annotation)
* - added generated serialVersionUID
*/
package org.json; package org.json;
// Note: this class was written without inspecting the non-free org.json sourcecode. // Note: this class was written without inspecting the non-free org.json sourcecode.
@ -43,6 +51,8 @@ package org.json;
*/ */
public class JSONException extends Exception { public class JSONException extends Exception {
private static final long serialVersionUID = -325665605382928224L;
public JSONException(String s) { public JSONException(String s) {
super(s); super(s);
} }

@ -14,19 +14,28 @@
* limitations under the License. * limitations under the License.
*/ */
package org.json; /*
* This class was taken from
* https://android.googlesource.com/platform/libcore/+/refs/heads/master/json/src/main/java/org/json
* and slightly modified (by mc@yacy.net):
* - removed dependency from other libraries (i.e. android.compat.annotation)
* - fixed "statement unnecessary nested" warnings
* - fixed raw type declarations
* - added keepOrder option to initializer to reduce memory footprint if order is not required
* - added deprecated flag to has() an get() methods (see comment in code)
* - inlined opt() where appropriate
*/
import android.compat.annotation.UnsupportedAppUsage; package org.json;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import libcore.util.NonNull;
import libcore.util.Nullable;
// Note: this class was written without inspecting the non-free org.json sourcecode. // Note: this class was written without inspecting the non-free org.json sourcecode.
@ -84,7 +93,6 @@ import libcore.util.Nullable;
*/ */
public class JSONObject { public class JSONObject {
@UnsupportedAppUsage
private static final Double NEGATIVE_ZERO = -0d; private static final Double NEGATIVE_ZERO = -0d;
/** /**
@ -102,7 +110,7 @@ public class JSONObject {
* returning true when compared to {@code null}. Its {@link #toString} * returning true when compared to {@code null}. Its {@link #toString}
* method returns "null". * method returns "null".
*/ */
@NonNull public static final Object NULL = new Object() { public static final Object NULL = new Object() {
@Override public boolean equals(Object o) { @Override public boolean equals(Object o) {
return o == this || o == null; // API specifies this broken equals implementation return o == this || o == null; // API specifies this broken equals implementation
} }
@ -113,8 +121,7 @@ public class JSONObject {
} }
}; };
@UnsupportedAppUsage private final Map<String, Object> nameValuePairs;
private final LinkedHashMap<String, Object> nameValuePairs;
/** /**
* Creates a {@code JSONObject} with no name/value mappings. * Creates a {@code JSONObject} with no name/value mappings.
@ -123,6 +130,15 @@ public class JSONObject {
nameValuePairs = new LinkedHashMap<String, Object>(); nameValuePairs = new LinkedHashMap<String, Object>();
} }
/**
* Creates a {@code JSONObject} with no name/value mappings.
*
* @param keepOrder if set to true, the elements will preserve its insert order
*/
public JSONObject(boolean keepOrder) {
nameValuePairs = keepOrder ? new LinkedHashMap<String, Object>() : new HashMap<String, Object>();
}
/** /**
* Creates a new {@code JSONObject} by copying all name/value mappings from * Creates a new {@code JSONObject} by copying all name/value mappings from
* the given map. * the given map.
@ -132,9 +148,9 @@ public class JSONObject {
* @throws NullPointerException if any of the map's keys are null. * @throws NullPointerException if any of the map's keys are null.
*/ */
/* (accept a raw type for API compatibility) */ /* (accept a raw type for API compatibility) */
public JSONObject(@NonNull Map copyFrom) { public JSONObject(Map<?, ?> copyFrom) {
this(); this();
Map<?, ?> contentsTyped = (Map<?, ?>) copyFrom; Map<?, ?> contentsTyped = copyFrom;
for (Map.Entry<?, ?> entry : contentsTyped.entrySet()) { for (Map.Entry<?, ?> entry : contentsTyped.entrySet()) {
/* /*
* Deviate from the original by checking that keys are non-null and * Deviate from the original by checking that keys are non-null and
@ -157,7 +173,7 @@ public class JSONObject {
* @throws JSONException if the parse fails or doesn't yield a * @throws JSONException if the parse fails or doesn't yield a
* {@code JSONObject}. * {@code JSONObject}.
*/ */
public JSONObject(@NonNull JSONTokener readFrom) throws JSONException { public JSONObject(JSONTokener readFrom) throws JSONException {
/* /*
* Getting the parser to populate this could get tricky. Instead, just * Getting the parser to populate this could get tricky. Instead, just
* parse to temporary JSONObject and then steal the data from that. * parse to temporary JSONObject and then steal the data from that.
@ -178,7 +194,7 @@ public class JSONObject {
* @throws JSONException if the parse fails or doesn't yield a {@code * @throws JSONException if the parse fails or doesn't yield a {@code
* JSONObject}. * JSONObject}.
*/ */
public JSONObject(@NonNull String json) throws JSONException { public JSONObject(String json) throws JSONException {
this(new JSONTokener(json)); this(new JSONTokener(json));
} }
@ -187,10 +203,10 @@ public class JSONObject {
* from the given object. Names that aren't present in {@code copyFrom} will * from the given object. Names that aren't present in {@code copyFrom} will
* be skipped. * be skipped.
*/ */
public JSONObject(@NonNull JSONObject copyFrom, @NonNull String @NonNull [] names) throws JSONException { public JSONObject(JSONObject copyFrom, String [] names) {
this(); this();
for (String name : names) { for (String name : names) {
Object value = copyFrom.opt(name); Object value = copyFrom.nameValuePairs.get(name);
if (value != null) { if (value != null) {
nameValuePairs.put(name, value); nameValuePairs.put(name, value);
} }
@ -210,7 +226,7 @@ public class JSONObject {
* *
* @return this object. * @return this object.
*/ */
@NonNull public JSONObject put(@NonNull String name, boolean value) throws JSONException { public JSONObject put(String name, boolean value) throws JSONException {
nameValuePairs.put(checkName(name), value); nameValuePairs.put(checkName(name), value);
return this; return this;
} }
@ -223,7 +239,7 @@ public class JSONObject {
* {@link Double#isInfinite() infinities}. * {@link Double#isInfinite() infinities}.
* @return this object. * @return this object.
*/ */
@NonNull public JSONObject put(@NonNull String name, double value) throws JSONException { public JSONObject put(String name, double value) throws JSONException {
nameValuePairs.put(checkName(name), JSON.checkDouble(value)); nameValuePairs.put(checkName(name), JSON.checkDouble(value));
return this; return this;
} }
@ -234,7 +250,7 @@ public class JSONObject {
* *
* @return this object. * @return this object.
*/ */
@NonNull public JSONObject put(@NonNull String name, int value) throws JSONException { public JSONObject put(String name, int value) throws JSONException {
nameValuePairs.put(checkName(name), value); nameValuePairs.put(checkName(name), value);
return this; return this;
} }
@ -245,7 +261,7 @@ public class JSONObject {
* *
* @return this object. * @return this object.
*/ */
@NonNull public JSONObject put(@NonNull String name, long value) throws JSONException { public JSONObject put(String name, long value) throws JSONException {
nameValuePairs.put(checkName(name), value); nameValuePairs.put(checkName(name), value);
return this; return this;
} }
@ -261,7 +277,7 @@ public class JSONObject {
* infinities}. * infinities}.
* @return this object. * @return this object.
*/ */
@NonNull public JSONObject put(@NonNull String name, @Nullable Object value) throws JSONException { public JSONObject put(String name, Object value) throws JSONException {
if (value == null) { if (value == null) {
nameValuePairs.remove(name); nameValuePairs.remove(name);
return this; return this;
@ -278,7 +294,7 @@ public class JSONObject {
* Equivalent to {@code put(name, value)} when both parameters are non-null; * Equivalent to {@code put(name, value)} when both parameters are non-null;
* does nothing otherwise. * does nothing otherwise.
*/ */
@NonNull public JSONObject putOpt(@Nullable String name, @Nullable Object value) throws JSONException { public JSONObject putOpt(String name, Object value) throws JSONException {
if (name == null || value == null) { if (name == null || value == null) {
return this; return this;
} }
@ -305,7 +321,7 @@ public class JSONObject {
*/ */
// TODO: Change {@code append) to {@link #append} when append is // TODO: Change {@code append) to {@link #append} when append is
// unhidden. // unhidden.
@NonNull public JSONObject accumulate(@NonNull String name, @Nullable Object value) throws JSONException { public JSONObject accumulate(String name, Object value) throws JSONException {
Object current = nameValuePairs.get(checkName(name)); Object current = nameValuePairs.get(checkName(name));
if (current == null) { if (current == null) {
return put(name, value); return put(name, value);
@ -315,7 +331,7 @@ public class JSONObject {
JSONArray array = (JSONArray) current; JSONArray array = (JSONArray) current;
array.checkedPut(value); array.checkedPut(value);
} else { } else {
JSONArray array = new JSONArray(); JSONArray array = new JSONArray(2);
array.checkedPut(current); array.checkedPut(current);
array.checkedPut(value); array.checkedPut(value);
nameValuePairs.put(name, array); nameValuePairs.put(name, array);
@ -334,7 +350,6 @@ public class JSONObject {
* *
* @hide * @hide
*/ */
@UnsupportedAppUsage
public JSONObject append(String name, Object value) throws JSONException { public JSONObject append(String name, Object value) throws JSONException {
Object current = nameValuePairs.get(checkName(name)); Object current = nameValuePairs.get(checkName(name));
@ -354,7 +369,6 @@ public class JSONObject {
return this; return this;
} }
@UnsupportedAppUsage
String checkName(String name) throws JSONException { String checkName(String name) throws JSONException {
if (name == null) { if (name == null) {
throw new JSONException("Names must be non-null"); throw new JSONException("Names must be non-null");
@ -368,7 +382,7 @@ public class JSONObject {
* @return the value previously mapped by {@code name}, or null if there was * @return the value previously mapped by {@code name}, or null if there was
* no such mapping. * no such mapping.
*/ */
@Nullable public Object remove(@Nullable String name) { public Object remove(String name) {
return nameValuePairs.remove(name); return nameValuePairs.remove(name);
} }
@ -376,7 +390,7 @@ public class JSONObject {
* Returns true if this object has no mapping for {@code name} or if it has * Returns true if this object has no mapping for {@code name} or if it has
* a mapping whose value is {@link #NULL}. * a mapping whose value is {@link #NULL}.
*/ */
public boolean isNull(@Nullable String name) { public boolean isNull(String name) {
Object value = nameValuePairs.get(name); Object value = nameValuePairs.get(name);
return value == null || value == NULL; return value == null || value == NULL;
} }
@ -384,8 +398,13 @@ public class JSONObject {
/** /**
* Returns true if this object has a mapping for {@code name}. The mapping * Returns true if this object has a mapping for {@code name}. The mapping
* may be {@link #NULL}. * may be {@link #NULL}.
*
* This method has the deprecated flag because usage of this method leads to poor
* code performance if used in combination with get(). Its much better to opt() and
* check the result instead of doing two look-ups (first has(), then get()).
*/ */
public boolean has(@Nullable String name) { @Deprecated
public boolean has(String name) {
return nameValuePairs.containsKey(name); return nameValuePairs.containsKey(name);
} }
@ -393,8 +412,13 @@ public class JSONObject {
* Returns the value mapped by {@code name}, or throws if no such mapping exists. * Returns the value mapped by {@code name}, or throws if no such mapping exists.
* *
* @throws JSONException if no such mapping exists. * @throws JSONException if no such mapping exists.
*
* This method has the deprecated flag because usage of this method leads to poor
* code performance if used in combination with has(). Its much better to opt() and
* check the result instead of doing two look-ups (first has(), then get()).
*/ */
@NonNull public Object get(@NonNull String name) throws JSONException { @Deprecated
public Object get(String name) throws JSONException {
Object result = nameValuePairs.get(name); Object result = nameValuePairs.get(name);
if (result == null) { if (result == null) {
throw new JSONException("No value for " + name); throw new JSONException("No value for " + name);
@ -406,7 +430,7 @@ public class JSONObject {
* Returns the value mapped by {@code name}, or null if no such mapping * Returns the value mapped by {@code name}, or null if no such mapping
* exists. * exists.
*/ */
@Nullable public Object opt(@Nullable String name) { public Object opt(String name) {
return nameValuePairs.get(name); return nameValuePairs.get(name);
} }
@ -417,7 +441,7 @@ public class JSONObject {
* @throws JSONException if the mapping doesn't exist or cannot be coerced * @throws JSONException if the mapping doesn't exist or cannot be coerced
* to a boolean. * to a boolean.
*/ */
public boolean getBoolean(@NonNull String name) throws JSONException { public boolean getBoolean(String name) throws JSONException {
Object object = get(name); Object object = get(name);
Boolean result = JSON.toBoolean(object); Boolean result = JSON.toBoolean(object);
if (result == null) { if (result == null) {
@ -430,7 +454,7 @@ public class JSONObject {
* Returns the value mapped by {@code name} if it exists and is a boolean or * Returns the value mapped by {@code name} if it exists and is a boolean or
* can be coerced to a boolean, or false otherwise. * can be coerced to a boolean, or false otherwise.
*/ */
public boolean optBoolean(@Nullable String name) { public boolean optBoolean(String name) {
return optBoolean(name, false); return optBoolean(name, false);
} }
@ -438,8 +462,8 @@ public class JSONObject {
* Returns the value mapped by {@code name} if it exists and is a boolean or * Returns the value mapped by {@code name} if it exists and is a boolean or
* can be coerced to a boolean, or {@code fallback} otherwise. * can be coerced to a boolean, or {@code fallback} otherwise.
*/ */
public boolean optBoolean(@Nullable String name, boolean fallback) { public boolean optBoolean(String name, boolean fallback) {
Object object = opt(name); Object object = nameValuePairs.get(name);
Boolean result = JSON.toBoolean(object); Boolean result = JSON.toBoolean(object);
return result != null ? result : fallback; return result != null ? result : fallback;
} }
@ -451,7 +475,7 @@ public class JSONObject {
* @throws JSONException if the mapping doesn't exist or cannot be coerced * @throws JSONException if the mapping doesn't exist or cannot be coerced
* to a double. * to a double.
*/ */
public double getDouble(@NonNull String name) throws JSONException { public double getDouble(String name) throws JSONException {
Object object = get(name); Object object = get(name);
Double result = JSON.toDouble(object); Double result = JSON.toDouble(object);
if (result == null) { if (result == null) {
@ -464,7 +488,7 @@ public class JSONObject {
* Returns the value mapped by {@code name} if it exists and is a double or * Returns the value mapped by {@code name} if it exists and is a double or
* can be coerced to a double, or {@code NaN} otherwise. * can be coerced to a double, or {@code NaN} otherwise.
*/ */
public double optDouble(@Nullable String name) { public double optDouble(String name) {
return optDouble(name, Double.NaN); return optDouble(name, Double.NaN);
} }
@ -472,8 +496,8 @@ public class JSONObject {
* Returns the value mapped by {@code name} if it exists and is a double or * Returns the value mapped by {@code name} if it exists and is a double or
* can be coerced to a double, or {@code fallback} otherwise. * can be coerced to a double, or {@code fallback} otherwise.
*/ */
public double optDouble(@Nullable String name, double fallback) { public double optDouble(String name, double fallback) {
Object object = opt(name); Object object = nameValuePairs.get(name);
Double result = JSON.toDouble(object); Double result = JSON.toDouble(object);
return result != null ? result : fallback; return result != null ? result : fallback;
} }
@ -485,7 +509,7 @@ public class JSONObject {
* @throws JSONException if the mapping doesn't exist or cannot be coerced * @throws JSONException if the mapping doesn't exist or cannot be coerced
* to an int. * to an int.
*/ */
public int getInt(@NonNull String name) throws JSONException { public int getInt(String name) throws JSONException {
Object object = get(name); Object object = get(name);
Integer result = JSON.toInteger(object); Integer result = JSON.toInteger(object);
if (result == null) { if (result == null) {
@ -498,7 +522,7 @@ public class JSONObject {
* Returns the value mapped by {@code name} if it exists and is an int or * Returns the value mapped by {@code name} if it exists and is an int or
* can be coerced to an int, or 0 otherwise. * can be coerced to an int, or 0 otherwise.
*/ */
public int optInt(@Nullable String name) { public int optInt(String name) {
return optInt(name, 0); return optInt(name, 0);
} }
@ -506,8 +530,8 @@ public class JSONObject {
* Returns the value mapped by {@code name} if it exists and is an int or * Returns the value mapped by {@code name} if it exists and is an int or
* can be coerced to an int, or {@code fallback} otherwise. * can be coerced to an int, or {@code fallback} otherwise.
*/ */
public int optInt(@Nullable String name, int fallback) { public int optInt(String name, int fallback) {
Object object = opt(name); Object object = nameValuePairs.get(name);
Integer result = JSON.toInteger(object); Integer result = JSON.toInteger(object);
return result != null ? result : fallback; return result != null ? result : fallback;
} }
@ -521,7 +545,7 @@ public class JSONObject {
* @throws JSONException if the mapping doesn't exist or cannot be coerced * @throws JSONException if the mapping doesn't exist or cannot be coerced
* to a long. * to a long.
*/ */
public long getLong(@NonNull String name) throws JSONException { public long getLong(String name) throws JSONException {
Object object = get(name); Object object = get(name);
Long result = JSON.toLong(object); Long result = JSON.toLong(object);
if (result == null) { if (result == null) {
@ -535,7 +559,7 @@ public class JSONObject {
* can be coerced to a long, or 0 otherwise. Note that JSON represents numbers as doubles, * can be coerced to a long, or 0 otherwise. Note that JSON represents numbers as doubles,
* so this is <a href="#lossy">lossy</a>; use strings to transfer numbers via JSON. * so this is <a href="#lossy">lossy</a>; use strings to transfer numbers via JSON.
*/ */
public long optLong(@Nullable String name) { public long optLong(String name) {
return optLong(name, 0L); return optLong(name, 0L);
} }
@ -545,8 +569,8 @@ public class JSONObject {
* numbers as doubles, so this is <a href="#lossy">lossy</a>; use strings to transfer * numbers as doubles, so this is <a href="#lossy">lossy</a>; use strings to transfer
* numbers via JSON. * numbers via JSON.
*/ */
public long optLong(@Nullable String name, long fallback) { public long optLong(String name, long fallback) {
Object object = opt(name); Object object = nameValuePairs.get(name);
Long result = JSON.toLong(object); Long result = JSON.toLong(object);
return result != null ? result : fallback; return result != null ? result : fallback;
} }
@ -557,7 +581,7 @@ public class JSONObject {
* *
* @throws JSONException if no such mapping exists. * @throws JSONException if no such mapping exists.
*/ */
@NonNull public String getString(@NonNull String name) throws JSONException { public String getString(String name) throws JSONException {
Object object = get(name); Object object = get(name);
String result = JSON.toString(object); String result = JSON.toString(object);
if (result == null) { if (result == null) {
@ -570,7 +594,7 @@ public class JSONObject {
* Returns the value mapped by {@code name} if it exists, coercing it if * Returns the value mapped by {@code name} if it exists, coercing it if
* necessary, or the empty string if no such mapping exists. * necessary, or the empty string if no such mapping exists.
*/ */
@NonNull public String optString(@Nullable String name) { public String optString(String name) {
return optString(name, ""); return optString(name, "");
} }
@ -578,8 +602,8 @@ public class JSONObject {
* Returns the value mapped by {@code name} if it exists, coercing it if * Returns the value mapped by {@code name} if it exists, coercing it if
* necessary, or {@code fallback} if no such mapping exists. * necessary, or {@code fallback} if no such mapping exists.
*/ */
@NonNull public String optString(@Nullable String name, @NonNull String fallback) { public String optString(String name, String fallback) {
Object object = opt(name); Object object = nameValuePairs.get(name);
String result = JSON.toString(object); String result = JSON.toString(object);
return result != null ? result : fallback; return result != null ? result : fallback;
} }
@ -591,21 +615,20 @@ public class JSONObject {
* @throws JSONException if the mapping doesn't exist or is not a {@code * @throws JSONException if the mapping doesn't exist or is not a {@code
* JSONArray}. * JSONArray}.
*/ */
@NonNull public JSONArray getJSONArray(@NonNull String name) throws JSONException { public JSONArray getJSONArray(String name) throws JSONException {
Object object = get(name); Object object = get(name);
if (object instanceof JSONArray) { if (object instanceof JSONArray) {
return (JSONArray) object; return (JSONArray) object;
} else {
throw JSON.typeMismatch(name, object, "JSONArray");
} }
throw JSON.typeMismatch(name, object, "JSONArray");
} }
/** /**
* Returns the value mapped by {@code name} if it exists and is a {@code * Returns the value mapped by {@code name} if it exists and is a {@code
* JSONArray}, or null otherwise. * JSONArray}, or null otherwise.
*/ */
@Nullable public JSONArray optJSONArray(@Nullable String name) { public JSONArray optJSONArray(String name) {
Object object = opt(name); Object object = nameValuePairs.get(name);
return object instanceof JSONArray ? (JSONArray) object : null; return object instanceof JSONArray ? (JSONArray) object : null;
} }
@ -616,21 +639,20 @@ public class JSONObject {
* @throws JSONException if the mapping doesn't exist or is not a {@code * @throws JSONException if the mapping doesn't exist or is not a {@code
* JSONObject}. * JSONObject}.
*/ */
@NonNull public JSONObject getJSONObject(@NonNull String name) throws JSONException { public JSONObject getJSONObject(String name) throws JSONException {
Object object = get(name); Object object = get(name);
if (object instanceof JSONObject) { if (object instanceof JSONObject) {
return (JSONObject) object; return (JSONObject) object;
} else {
throw JSON.typeMismatch(name, object, "JSONObject");
} }
throw JSON.typeMismatch(name, object, "JSONObject");
} }
/** /**
* Returns the value mapped by {@code name} if it exists and is a {@code * Returns the value mapped by {@code name} if it exists and is a {@code
* JSONObject}, or null otherwise. * JSONObject}, or null otherwise.
*/ */
@Nullable public JSONObject optJSONObject(@Nullable String name) { public JSONObject optJSONObject(String name) {
Object object = opt(name); Object object = nameValuePairs.get(name);
return object instanceof JSONObject ? (JSONObject) object : null; return object instanceof JSONObject ? (JSONObject) object : null;
} }
@ -639,8 +661,7 @@ public class JSONObject {
* array contains null for names that aren't mapped. This method returns * array contains null for names that aren't mapped. This method returns
* null if {@code names} is either null or empty. * null if {@code names} is either null or empty.
*/ */
@Nullable public JSONArray toJSONArray(@Nullable JSONArray names) throws JSONException { public JSONArray toJSONArray(JSONArray names) {
JSONArray result = new JSONArray();
if (names == null) { if (names == null) {
return null; return null;
} }
@ -648,9 +669,10 @@ public class JSONObject {
if (length == 0) { if (length == 0) {
return null; return null;
} }
JSONArray result = new JSONArray(length);
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
String name = JSON.toString(names.opt(i)); String name = JSON.toString(names.opt(i));
result.put(opt(name)); result.put(nameValuePairs.get(name));
} }
return result; return result;
} }
@ -662,7 +684,7 @@ public class JSONObject {
* modified after the iterator is returned, the iterator's behavior is * modified after the iterator is returned, the iterator's behavior is
* undefined. The order of the keys is undefined. * undefined. The order of the keys is undefined.
*/ */
@NonNull public Iterator<@NonNull String> keys() { public Iterator<String> keys() {
return nameValuePairs.keySet().iterator(); return nameValuePairs.keySet().iterator();
} }
@ -676,8 +698,6 @@ public class JSONObject {
* *
* @hide. * @hide.
*/ */
@UnsupportedAppUsage
@libcore.api.CorePlatformApi
public Set<String> keySet() { public Set<String> keySet() {
return nameValuePairs.keySet(); return nameValuePairs.keySet();
} }
@ -686,7 +706,7 @@ public class JSONObject {
* Returns an array containing the string names in this object. This method * Returns an array containing the string names in this object. This method
* returns null if this object contains no mappings. * returns null if this object contains no mappings.
*/ */
@Nullable public JSONArray names() { public JSONArray names() {
return nameValuePairs.isEmpty() return nameValuePairs.isEmpty()
? null ? null
: new JSONArray(new ArrayList<String>(nameValuePairs.keySet())); : new JSONArray(new ArrayList<String>(nameValuePairs.keySet()));
@ -696,7 +716,7 @@ public class JSONObject {
* Encodes this object as a compact JSON string, such as: * Encodes this object as a compact JSON string, such as:
* <pre>{"query":"Pizza","locations":[94043,90210]}</pre> * <pre>{"query":"Pizza","locations":[94043,90210]}</pre>
*/ */
@Override @NonNull public String toString() { @Override public String toString() {
try { try {
JSONStringer stringer = new JSONStringer(); JSONStringer stringer = new JSONStringer();
writeTo(stringer); writeTo(stringer);
@ -721,13 +741,12 @@ public class JSONObject {
* @param indentSpaces the number of spaces to indent for each level of * @param indentSpaces the number of spaces to indent for each level of
* nesting. * nesting.
*/ */
@NonNull public String toString(int indentSpaces) throws JSONException { public String toString(int indentSpaces) throws JSONException {
JSONStringer stringer = new JSONStringer(indentSpaces); JSONStringer stringer = new JSONStringer(indentSpaces);
writeTo(stringer); writeTo(stringer);
return stringer.toString(); return stringer.toString();
} }
@UnsupportedAppUsage
void writeTo(JSONStringer stringer) throws JSONException { void writeTo(JSONStringer stringer) throws JSONException {
stringer.object(); stringer.object();
for (Map.Entry<String, Object> entry : nameValuePairs.entrySet()) { for (Map.Entry<String, Object> entry : nameValuePairs.entrySet()) {
@ -742,7 +761,7 @@ public class JSONObject {
* @param number a finite value. May not be {@link Double#isNaN() NaNs} or * @param number a finite value. May not be {@link Double#isNaN() NaNs} or
* {@link Double#isInfinite() infinities}. * {@link Double#isInfinite() infinities}.
*/ */
@NonNull public static String numberToString(@NonNull Number number) throws JSONException { public static String numberToString(Number number) throws JSONException {
if (number == null) { if (number == null) {
throw new JSONException("Number must be non-null"); throw new JSONException("Number must be non-null");
} }
@ -756,7 +775,7 @@ public class JSONObject {
} }
long longValue = number.longValue(); long longValue = number.longValue();
if (doubleValue == (double) longValue) { if (doubleValue == longValue) {
return Long.toString(longValue); return Long.toString(longValue);
} }
@ -770,7 +789,7 @@ public class JSONObject {
* @param data the string to encode. Null will be interpreted as an empty * @param data the string to encode. Null will be interpreted as an empty
* string. * string.
*/ */
@NonNull public static String quote(@Nullable String data) { public static String quote(String data) {
if (data == null) { if (data == null) {
return "\"\""; return "\"\"";
} }
@ -797,7 +816,7 @@ public class JSONObject {
* Otherwise if the object is from a {@code java} package, returns the result of {@code toString}. * Otherwise if the object is from a {@code java} package, returns the result of {@code toString}.
* If wrapping fails, returns null. * If wrapping fails, returns null.
*/ */
@Nullable public static Object wrap(@Nullable Object o) { public static Object wrap(Object o) {
if (o == null) { if (o == null) {
return NULL; return NULL;
} }
@ -809,12 +828,12 @@ public class JSONObject {
} }
try { try {
if (o instanceof Collection) { if (o instanceof Collection) {
return new JSONArray((Collection) o); return new JSONArray((Collection<?>) o);
} else if (o.getClass().isArray()) { } else if (o.getClass().isArray()) {
return new JSONArray(o); return new JSONArray(o);
} }
if (o instanceof Map) { if (o instanceof Map) {
return new JSONObject((Map) o); return new JSONObject((Map<?, ?>) o);
} }
if (o instanceof Boolean || if (o instanceof Boolean ||
o instanceof Byte || o instanceof Byte ||

@ -14,9 +14,15 @@
* limitations under the License. * limitations under the License.
*/ */
/*
* This class was taken from
* https://android.googlesource.com/platform/libcore/+/refs/heads/master/json/src/main/java/org/json
* and slightly modified (by mc@yacy.net):
* - removed dependency from other libraries (i.e. android.compat.annotation)
*/
package org.json; package org.json;
import android.compat.annotation.UnsupportedAppUsage;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@ -62,7 +68,6 @@ import java.util.List;
public class JSONStringer { public class JSONStringer {
/** The output data, containing at most one top-level array or object. */ /** The output data, containing at most one top-level array or object. */
@UnsupportedAppUsage
final StringBuilder out = new StringBuilder(); final StringBuilder out = new StringBuilder();
/** /**
@ -113,21 +118,18 @@ public class JSONStringer {
* Unlike the original implementation, this stack isn't limited to 20 * Unlike the original implementation, this stack isn't limited to 20
* levels of nesting. * levels of nesting.
*/ */
@UnsupportedAppUsage
private final List<Scope> stack = new ArrayList<Scope>(); private final List<Scope> stack = new ArrayList<Scope>();
/** /**
* A string containing a full set of spaces for a single level of * A string containing a full set of spaces for a single level of
* indentation, or null for no pretty printing. * indentation, or null for no pretty printing.
*/ */
@UnsupportedAppUsage
private final String indent; private final String indent;
public JSONStringer() { public JSONStringer() {
indent = null; indent = null;
} }
@UnsupportedAppUsage
JSONStringer(int indentSpaces) { JSONStringer(int indentSpaces) {
char[] indentChars = new char[indentSpaces]; char[] indentChars = new char[indentSpaces];
Arrays.fill(indentChars, ' '); Arrays.fill(indentChars, ' ');
@ -176,7 +178,6 @@ public class JSONStringer {
* Enters a new scope by appending any necessary whitespace and the given * Enters a new scope by appending any necessary whitespace and the given
* bracket. * bracket.
*/ */
@UnsupportedAppUsage
JSONStringer open(Scope empty, String openBracket) throws JSONException { JSONStringer open(Scope empty, String openBracket) throws JSONException {
if (stack.isEmpty() && out.length() > 0) { if (stack.isEmpty() && out.length() > 0) {
throw new JSONException("Nesting problem: multiple top-level roots"); throw new JSONException("Nesting problem: multiple top-level roots");
@ -191,7 +192,6 @@ public class JSONStringer {
* Closes the current scope by appending any necessary whitespace and the * Closes the current scope by appending any necessary whitespace and the
* given bracket. * given bracket.
*/ */
@UnsupportedAppUsage
JSONStringer close(Scope empty, Scope nonempty, String closeBracket) throws JSONException { JSONStringer close(Scope empty, Scope nonempty, String closeBracket) throws JSONException {
Scope context = peek(); Scope context = peek();
if (context != nonempty && context != empty) { if (context != nonempty && context != empty) {
@ -209,7 +209,6 @@ public class JSONStringer {
/** /**
* Returns the value on the top of the stack. * Returns the value on the top of the stack.
*/ */
@UnsupportedAppUsage
private Scope peek() throws JSONException { private Scope peek() throws JSONException {
if (stack.isEmpty()) { if (stack.isEmpty()) {
throw new JSONException("Nesting problem"); throw new JSONException("Nesting problem");
@ -220,7 +219,6 @@ public class JSONStringer {
/** /**
* Replace the value on the top of the stack with the given value. * Replace the value on the top of the stack with the given value.
*/ */
@UnsupportedAppUsage
private void replaceTop(Scope topOfStack) { private void replaceTop(Scope topOfStack) {
stack.set(stack.size() - 1, topOfStack); stack.set(stack.size() - 1, topOfStack);
} }
@ -308,7 +306,6 @@ public class JSONStringer {
return this; return this;
} }
@UnsupportedAppUsage
private void string(String value) { private void string(String value) {
out.append("\""); out.append("\"");
for (int i = 0, length = value.length(); i < length; i++) { for (int i = 0, length = value.length(); i < length; i++) {
@ -360,7 +357,6 @@ public class JSONStringer {
out.append("\""); out.append("\"");
} }
@UnsupportedAppUsage
private void newline() { private void newline() {
if (indent == null) { if (indent == null) {
return; return;
@ -391,7 +387,6 @@ public class JSONStringer {
* Inserts any necessary separators and whitespace before a name. Also * Inserts any necessary separators and whitespace before a name. Also
* adjusts the stack to expect the key's value. * adjusts the stack to expect the key's value.
*/ */
@UnsupportedAppUsage
private void beforeKey() throws JSONException { private void beforeKey() throws JSONException {
Scope context = peek(); Scope context = peek();
if (context == Scope.NONEMPTY_OBJECT) { // first in object if (context == Scope.NONEMPTY_OBJECT) { // first in object
@ -408,7 +403,6 @@ public class JSONStringer {
* inline array, or inline object. Also adjusts the stack to expect either a * inline array, or inline object. Also adjusts the stack to expect either a
* closing bracket or another element. * closing bracket or another element.
*/ */
@UnsupportedAppUsage
private void beforeValue() throws JSONException { private void beforeValue() throws JSONException {
if (stack.isEmpty()) { if (stack.isEmpty()) {
return; return;

@ -14,9 +14,19 @@
* limitations under the License. * limitations under the License.
*/ */
/*
* This class was taken from
* https://android.googlesource.com/platform/libcore/+/refs/heads/master/json/src/main/java/org/json
* and slightly modified (by mc@yacy.net):
* - removed dependency from other libraries (i.e. android.compat.annotation)
* - fixed "statement unnecessary nested" warnings
* - added class initialization with reader object
*/
package org.json; package org.json;
import android.compat.annotation.UnsupportedAppUsage; import java.io.IOException;
import java.io.Reader;
// Note: this class was written without inspecting the non-free org.json sourcecode. // Note: this class was written without inspecting the non-free org.json sourcecode.
@ -64,16 +74,28 @@ import android.compat.annotation.UnsupportedAppUsage;
public class JSONTokener { public class JSONTokener {
/** The input JSON. */ /** The input JSON. */
@UnsupportedAppUsage
private final String in; private final String in;
/** /**
* The index of the next character to be returned by {@link #next}. When * The index of the next character to be returned by {@link #next}. When
* the input is exhausted, this equals the input's length. * the input is exhausted, this equals the input's length.
*/ */
@UnsupportedAppUsage
private int pos; private int pos;
public JSONTokener(Reader reader) throws IOException {
final char[] buffer = new char[2048];
final StringBuilder out = new StringBuilder();
int charsRead;
while((charsRead = reader.read(buffer, 0, buffer.length)) > 0) {
out.append(buffer, 0, charsRead);
}
String in = out.toString();
if (in != null && in.startsWith("\ufeff")) {
in = in.substring(1);
}
this.in = in;
}
/** /**
* @param in JSON encoded string. Null is not permitted and will yield a * @param in JSON encoded string. Null is not permitted and will yield a
* tokener that throws {@code NullPointerExceptions} when methods are * tokener that throws {@code NullPointerExceptions} when methods are
@ -116,7 +138,6 @@ public class JSONTokener {
} }
} }
@UnsupportedAppUsage
private int nextCleanInternal() throws JSONException { private int nextCleanInternal() throws JSONException {
while (pos < in.length()) { while (pos < in.length()) {
int c = in.charAt(pos++); int c = in.charAt(pos++);
@ -176,7 +197,6 @@ public class JSONTokener {
* is terminated by "\r\n", the '\n' must be consumed as whitespace by the * is terminated by "\r\n", the '\n' must be consumed as whitespace by the
* caller. * caller.
*/ */
@UnsupportedAppUsage
private void skipToEndOfLine() { private void skipToEndOfLine() {
for (; pos < in.length(); pos++) { for (; pos < in.length(); pos++) {
char c = in.charAt(pos); char c = in.charAt(pos);
@ -212,10 +232,9 @@ public class JSONTokener {
if (builder == null) { if (builder == null) {
// a new string avoids leaking memory // a new string avoids leaking memory
return new String(in.substring(start, pos - 1)); return new String(in.substring(start, pos - 1));
} else {
builder.append(in, start, pos - 1);
return builder.toString();
} }
builder.append(in, start, pos - 1);
return builder.toString();
} }
if (c == '\\') { if (c == '\\') {
@ -240,7 +259,6 @@ public class JSONTokener {
* been read. This supports both unicode escapes "u000A" and two-character * been read. This supports both unicode escapes "u000A" and two-character
* escapes "\n". * escapes "\n".
*/ */
@UnsupportedAppUsage
private char readEscapeCharacter() throws JSONException { private char readEscapeCharacter() throws JSONException {
char escaped = in.charAt(pos++); char escaped = in.charAt(pos++);
switch (escaped) { switch (escaped) {
@ -284,7 +302,6 @@ public class JSONTokener {
* values will be returned as an Integer, Long, or Double, in that order of * values will be returned as an Integer, Long, or Double, in that order of
* preference. * preference.
*/ */
@UnsupportedAppUsage
private Object readLiteral() throws JSONException { private Object readLiteral() throws JSONException {
String literal = nextToInternal("{}[]/\\:,=;# \t\f"); String literal = nextToInternal("{}[]/\\:,=;# \t\f");
@ -313,9 +330,8 @@ public class JSONTokener {
long longValue = Long.parseLong(number, base); long longValue = Long.parseLong(number, base);
if (longValue <= Integer.MAX_VALUE && longValue >= Integer.MIN_VALUE) { if (longValue <= Integer.MAX_VALUE && longValue >= Integer.MIN_VALUE) {
return (int) longValue; return (int) longValue;
} else {
return longValue;
} }
return longValue;
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
/* /*
* This only happens for integral numbers greater than * This only happens for integral numbers greater than
@ -339,7 +355,6 @@ public class JSONTokener {
* Returns the string up to but not including any of the given characters or * Returns the string up to but not including any of the given characters or
* a newline character. This does not consume the excluded character. * a newline character. This does not consume the excluded character.
*/ */
@UnsupportedAppUsage
private String nextToInternal(String excluded) { private String nextToInternal(String excluded) {
int start = pos; int start = pos;
for (; pos < in.length(); pos++) { for (; pos < in.length(); pos++) {
@ -355,7 +370,6 @@ public class JSONTokener {
* Reads a sequence of key/value pairs and the trailing closing brace '}' of * Reads a sequence of key/value pairs and the trailing closing brace '}' of
* an object. The opening brace '{' should have already been read. * an object. The opening brace '{' should have already been read.
*/ */
@UnsupportedAppUsage
private JSONObject readObject() throws JSONException { private JSONObject readObject() throws JSONException {
JSONObject result = new JSONObject(); JSONObject result = new JSONObject();
@ -372,10 +386,9 @@ public class JSONTokener {
if (!(name instanceof String)) { if (!(name instanceof String)) {
if (name == null) { if (name == null) {
throw syntaxError("Names cannot be null"); throw syntaxError("Names cannot be null");
} else {
throw syntaxError("Names must be strings, but " + name
+ " is of type " + name.getClass().getName());
} }
throw syntaxError("Names must be strings, but " + name
+ " is of type " + name.getClass().getName());
} }
/* /*
@ -411,7 +424,6 @@ public class JSONTokener {
* "[]" yields an empty array, but "[,]" returns a two-element array * "[]" yields an empty array, but "[,]" returns a two-element array
* equivalent to "[null,null]". * equivalent to "[null,null]".
*/ */
@UnsupportedAppUsage
private JSONArray readArray() throws JSONException { private JSONArray readArray() throws JSONException {
JSONArray result = new JSONArray(); JSONArray result = new JSONArray();
@ -585,9 +597,8 @@ public class JSONTokener {
if (index != -1) { if (index != -1) {
pos = index; pos = index;
return to; return to;
} else {
return '\0';
} }
return '\0';
} }
/** /**

Loading…
Cancel
Save