Merge branch '1.5.x'

pull/11498/merge
Phillip Webb 7 years ago
commit 87bccb96f1

@ -36,6 +36,24 @@
<proc>none</proc> <proc>none</proc>
</configuration> </configuration>
</plugin> </plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<id>add-json-shade-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${basedir}/src/json-shade/java</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins> </plugins>
</build> </build>
</project> </project>

@ -0,0 +1,5 @@
## Shaded JSON
This source was originally taken from `com.vaadin.external.google:android-json` which
provides a clean room re-implementation of the `org.json` APIs and does not include the
"Do not use for evil" clause.

@ -17,9 +17,7 @@
package org.springframework.boot.configurationprocessor.json; package org.springframework.boot.configurationprocessor.json;
class JSON { class JSON {
/**
* Returns the input if it is a JSON-permissible value; throws otherwise.
*/
static double checkDouble(double d) throws JSONException { static double checkDouble(double d) throws JSONException {
if (Double.isInfinite(d) || Double.isNaN(d)) { if (Double.isInfinite(d) || Double.isNaN(d)) {
throw new JSONException("Forbidden numeric value: " + d); throw new JSONException("Forbidden numeric value: " + d);
@ -31,12 +29,12 @@ class JSON {
if (value instanceof Boolean) { if (value instanceof Boolean) {
return (Boolean) value; return (Boolean) value;
} }
else if (value instanceof String) { if (value instanceof String) {
String stringValue = (String) value; String stringValue = (String) value;
if ("true".equalsIgnoreCase(stringValue)) { if ("true".equalsIgnoreCase(stringValue)) {
return true; return true;
} }
else if ("false".equalsIgnoreCase(stringValue)) { if ("false".equalsIgnoreCase(stringValue)) {
return false; return false;
} }
} }
@ -47,10 +45,10 @@ class JSON {
if (value instanceof Double) { if (value instanceof Double) {
return (Double) value; return (Double) value;
} }
else if (value instanceof Number) { if (value instanceof Number) {
return ((Number) value).doubleValue(); return ((Number) value).doubleValue();
} }
else if (value instanceof String) { if (value instanceof String) {
try { try {
return Double.valueOf((String) value); return Double.valueOf((String) value);
} }
@ -64,10 +62,10 @@ class JSON {
if (value instanceof Integer) { if (value instanceof Integer) {
return (Integer) value; return (Integer) value;
} }
else if (value instanceof Number) { if (value instanceof Number) {
return ((Number) value).intValue(); return ((Number) value).intValue();
} }
else if (value instanceof String) { if (value instanceof String) {
try { try {
return (int) Double.parseDouble((String) value); return (int) Double.parseDouble((String) value);
} }
@ -81,10 +79,10 @@ class JSON {
if (value instanceof Long) { if (value instanceof Long) {
return (Long) value; return (Long) value;
} }
else if (value instanceof Number) { if (value instanceof Number) {
return ((Number) value).longValue(); return ((Number) value).longValue();
} }
else if (value instanceof String) { if (value instanceof String) {
try { try {
return (long) Double.parseDouble((String) value); return (long) Double.parseDouble((String) value);
} }
@ -98,7 +96,7 @@ class JSON {
if (value instanceof String) { if (value instanceof String) {
return (String) value; return (String) value;
} }
else if (value != null) { if (value != null) {
return String.valueOf(value); return String.valueOf(value);
} }
return null; return null;
@ -109,11 +107,9 @@ class JSON {
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 "
throw new JSONException("Value " + actual + " at " + indexOrName + actual.getClass().getName() + " cannot be converted to "
+ " of type " + actual.getClass().getName() + requiredType);
+ " cannot be converted to " + requiredType);
}
} }
public static JSONException typeMismatch(Object actual, String requiredType) public static JSONException typeMismatch(Object actual, String requiredType)
@ -121,10 +117,9 @@ class JSON {
if (actual == null) { if (actual == null) {
throw new JSONException("Value is null."); throw new JSONException("Value is null.");
} }
else { throw new JSONException(
throw new JSONException("Value " + actual "Value " + actual + " of type " + actual.getClass().getName()
+ " of type " + actual.getClass().getName() + " cannot be converted to " + requiredType);
+ " cannot be converted to " + requiredType);
}
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright (C) 2010 The Android Open Source Project
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -22,29 +22,27 @@ import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
// Note: this class was written without inspecting the non-free org.json source code. // Note: this class was written without inspecting the non-free org.json sourcecode.
/** /**
* A dense indexed sequence of values. Values may be any mix of * A dense indexed sequence of values. Values may be any mix of {@link JSONObject
* {@link JSONObject JSONObjects}, other {@link JSONArray JSONArrays}, Strings, * JSONObjects}, other {@link JSONArray JSONArrays}, Strings, Booleans, Integers, Longs,
* Booleans, Integers, Longs, Doubles, {@code null} or {@link JSONObject#NULL}. * Doubles, {@code null} or {@link JSONObject#NULL}. Values may not be
* Values may not be {@link Double#isNaN() NaNs}, {@link Double#isInfinite() * {@link Double#isNaN() NaNs}, {@link Double#isInfinite() infinities}, or of any type not
* infinities}, or of any type not listed here. * listed here.
* * <p>
* <p>{@code JSONArray} has the same type coercion behavior and * {@code JSONArray} has the same type coercion behavior and optional/mandatory accessors
* optional/mandatory accessors as {@link JSONObject}. See that class' * as {@link JSONObject}. See that class' documentation for details.
* documentation for details. * <p>
* * <strong>Warning:</strong> this class represents null in two incompatible ways: the
* <p><strong>Warning:</strong> this class represents null in two incompatible * standard Java {@code null} reference, and the sentinel value {@link JSONObject#NULL}.
* ways: the standard Java {@code null} reference, and the sentinel value {@link * In particular, {@code get} fails if the requested index holds the null reference, but
* JSONObject#NULL}. In particular, {@code get} fails if the requested index * succeeds if it holds {@code JSONObject.NULL}.
* holds the null reference, but succeeds if it holds {@code JSONObject.NULL}. * <p>
* * Instances of this class are not thread safe. Although this class is nonfinal, it was
* <p>Instances of this class are not thread safe. Although this class is * not designed for inheritance and should not be subclassed. In particular, self-use by
* nonfinal, it was not designed for inheritance and should not be subclassed. * overridable methods is not specified. See <i>Effective Java</i> Item 17, "Design and
* In particular, self-use by overridable methods is not specified. See * Document or inheritance or else prohibit it" for further information.
* <i>Effective Java</i> Item 17, "Design and Document or inheritance or else
* prohibit it" for further information.
*/ */
public class JSONArray { public class JSONArray {
@ -58,37 +56,31 @@ public class JSONArray {
} }
/** /**
* 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. * @param copyFrom a collection whose values are of supported types. Unsupported
* * values are not permitted and will yield an array in an inconsistent state.
* @param copyFrom a collection whose values are of supported types.
* Unsupported values are not permitted and will yield an array in an
* inconsistent state.
*/ */
/* Accept a raw type for API compatibility */ /* Accept a raw type for API compatibility */
@SuppressWarnings("rawtypes")
public JSONArray(Collection copyFrom) { public JSONArray(Collection copyFrom) {
this(); this();
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()));
} }
} }
} }
/** /**
* Creates a new {@code JSONArray} with values from the next array in the * Creates a new {@code JSONArray} with values from the next array in the tokener.
* tokener. * @param readFrom a tokener whose nextValue() method will yield a {@code JSONArray}.
* * @throws JSONException if the parse fails or doesn't yield a {@code JSONArray}.
* @param readFrom a tokener whose nextValue() method will yield a
* {@code JSONArray}.
* @throws JSONException if the parse fails or doesn't yield a
* {@code JSONArray}.
* @throws JSONException if processing of json failed * @throws JSONException if processing of json failed
*/ */
public JSONArray(JSONTokener readFrom) throws JSONException { public JSONArray(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
* parse to temporary JSONArray and then steal the data from that. * temporary JSONArray and then steal the data from that.
*/ */
Object object = readFrom.nextValue(); Object object = readFrom.nextValue();
if (object instanceof JSONArray) { if (object instanceof JSONArray) {
@ -101,7 +93,6 @@ public class JSONArray {
/** /**
* Creates a new {@code JSONArray} with values from the JSON string. * Creates a new {@code JSONArray} with values from the JSON string.
*
* @param json a JSON-encoded string containing an array. * @param json a JSON-encoded string containing an array.
* @throws JSONException if the parse fails or doesn't yield a {@code * @throws JSONException if the parse fails or doesn't yield a {@code
* JSONArray}. * JSONArray}.
@ -149,7 +140,7 @@ public class JSONArray {
* Appends {@code value} to the end of this array. * Appends {@code value} to the end of this array.
* *
* @param value a finite value. May not be {@link Double#isNaN() NaNs} or * @param value a finite value. May not be {@link Double#isNaN() NaNs} or
* {@link Double#isInfinite() infinities}. * {@link Double#isInfinite() infinities}.
* @return this array. * @return this array.
* @throws JSONException if processing of json failed * @throws JSONException if processing of json failed
*/ */
@ -181,11 +172,10 @@ public class JSONArray {
/** /**
* Appends {@code value} to the end of this array. * Appends {@code value} to the end of this array.
* *
* @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, Integer,
* Integer, Long, Double, {@link JSONObject#NULL}, or {@code null}. May * Long, Double, {@link JSONObject#NULL}, or {@code null}. May not be
* not be {@link Double#isNaN() NaNs} or {@link Double#isInfinite() * {@link Double#isNaN() NaNs} or {@link Double#isInfinite() infinities}. Unsupported
* infinities}. Unsupported values are not permitted and will cause the * values are not permitted and will cause the array to be in an inconsistent state.
* array to be in an inconsistent state.
* @return this array. * @return this array.
*/ */
public JSONArray put(Object value) { public JSONArray put(Object value) {
@ -194,8 +184,8 @@ public class JSONArray {
} }
/** /**
* Sets the value at {@code index} to {@code value}, null padding this array * Sets the value at {@code index} to {@code value}, null padding this array to the
* to the required length if necessary. If a value already exists at {@code * required length if necessary. If a value already exists at {@code
* index}, it will be replaced. * index}, it will be replaced.
* @param index the index to set the value to * @param index the index to set the value to
* @param value the value * @param value the value
@ -207,12 +197,12 @@ public class JSONArray {
} }
/** /**
* Sets the value at {@code index} to {@code value}, null padding this array * Sets the value at {@code index} to {@code value}, null padding this array to the
* to the required length if necessary. If a value already exists at {@code * required length if necessary. If a value already exists at {@code
* index}, it will be replaced. * index}, it will be replaced.
* @param index the index to set the value to * @param index the index to set the value to
* @param value a finite value. May not be {@link Double#isNaN() NaNs} or * @param value a finite value. May not be {@link Double#isNaN() NaNs} or
* {@link Double#isInfinite() infinities}. * {@link Double#isInfinite() infinities}.
* @return this array. * @return this array.
* @throws JSONException if processing of json failed * @throws JSONException if processing of json failed
*/ */
@ -221,8 +211,8 @@ public class JSONArray {
} }
/** /**
* Sets the value at {@code index} to {@code value}, null padding this array * Sets the value at {@code index} to {@code value}, null padding this array to the
* to the required length if necessary. If a value already exists at {@code * required length if necessary. If a value already exists at {@code
* index}, it will be replaced. * index}, it will be replaced.
* @param index the index to set the value to * @param index the index to set the value to
* @param value the value * @param value the value
@ -234,8 +224,8 @@ public class JSONArray {
} }
/** /**
* Sets the value at {@code index} to {@code value}, null padding this array * Sets the value at {@code index} to {@code value}, null padding this array to the
* to the required length if necessary. If a value already exists at {@code * required length if necessary. If a value already exists at {@code
* index}, it will be replaced. * index}, it will be replaced.
* @param index the index to set the value to * @param index the index to set the value to
* @param value the value * @param value the value
@ -247,20 +237,20 @@ public class JSONArray {
} }
/** /**
* Sets the value at {@code index} to {@code value}, null padding this array * Sets the value at {@code index} to {@code value}, null padding this array to the
* to the required length if necessary. If a value already exists at {@code * required length if necessary. If a value already exists at {@code
* index}, it will be replaced. * index}, it will be replaced.
* @param index the index to set the value to * @param index the index to set the value to
* @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, Integer,
* Integer, Long, Double, {@link JSONObject#NULL}, or {@code null}. May * Long, Double, {@link JSONObject#NULL}, or {@code null}. May not be
* not be {@link Double#isNaN() NaNs} or {@link Double#isInfinite() * {@link Double#isNaN() NaNs} or {@link Double#isInfinite() infinities}.
* infinities}.
* @return this array. * @return this array.
* @throws JSONException if processing of json failed * @throws JSONException if processing of json failed
*/ */
public JSONArray put(int index, Object value) throws JSONException { public JSONArray put(int index, Object value) throws JSONException {
if (value instanceof Number) { if (value instanceof Number) {
// deviate from the original by checking all Numbers, not just floats & doubles // deviate from the original by checking all Numbers, not just floats &
// doubles
JSON.checkDouble(((Number) value).doubleValue()); JSON.checkDouble(((Number) value).doubleValue());
} }
while (this.values.size() <= index) { while (this.values.size() <= index) {
@ -271,8 +261,8 @@ public class JSONArray {
} }
/** /**
* Returns true if this array has no value at {@code index}, or if its value * Returns true if this array has no value at {@code index}, or if its value is the
* is the {@code null} reference or {@link JSONObject#NULL}. * {@code null} reference or {@link JSONObject#NULL}.
* @param index the index to set the value to * @param index the index to set the value to
* @return true if this array has no value at {@code index} * @return true if this array has no value at {@code index}
*/ */
@ -285,9 +275,9 @@ public class JSONArray {
* Returns the value at {@code index}. * Returns the value at {@code index}.
* @param index the index to get the value from * @param index the index to get the value from
* @return the value at {@code index}. * @return the value at {@code index}.
* @throws JSONException if this array has no value at {@code index}, or if * @throws JSONException if this array has no value at {@code index}, or if that value
* that value is the {@code null} reference. This method returns * is the {@code null} reference. This method returns normally if the value is
* normally if the value is {@code JSONObject#NULL}. * {@code JSONObject#NULL}.
*/ */
public Object get(int index) throws JSONException { public Object get(int index) throws JSONException {
try { try {
@ -298,13 +288,14 @@ public class JSONArray {
return value; return value;
} }
catch (IndexOutOfBoundsException e) { catch (IndexOutOfBoundsException e) {
throw new JSONException("Index " + index + " out of range [0.." + this.values.size() + ")"); throw new JSONException(
"Index " + index + " out of range [0.." + this.values.size() + ")");
} }
} }
/** /**
* Returns the value at {@code index}, or null if the array has no value * Returns the value at {@code index}, or null if the array has no value at
* at {@code index}. * {@code index}.
* @param index the index to get the value from * @param index the index to get the value from
* @return the value at {@code index} or {@code null} * @return the value at {@code index} or {@code null}
*/ */
@ -329,12 +320,12 @@ public class JSONArray {
} }
/** /**
* Returns the value at {@code index} if it exists and is a boolean or can * Returns the value at {@code index} if it exists and is a boolean or can be coerced
* be coerced to a boolean. * to a boolean.
* @param index the index to get the value from * @param index the index to get the value from
* @return the value at {@code index} * @return the value at {@code index}
* @throws JSONException if the value at {@code index} doesn't exist or * @throws JSONException if the value at {@code index} doesn't exist or cannot be
* cannot be coerced to a boolean. * coerced to a boolean.
*/ */
public boolean getBoolean(int index) throws JSONException { public boolean getBoolean(int index) throws JSONException {
Object object = get(index); Object object = get(index);
@ -346,8 +337,8 @@ public class JSONArray {
} }
/** /**
* Returns the value at {@code index} if it exists and is a boolean or can * Returns the value at {@code index} if it exists and is a boolean or can be coerced
* be coerced to a boolean. Returns false otherwise. * to a boolean. Returns false otherwise.
* @param index the index to get the value from * @param index the index to get the value from
* @return the {@code value} or {@code false} * @return the {@code value} or {@code false}
*/ */
@ -356,8 +347,8 @@ public class JSONArray {
} }
/** /**
* Returns the value at {@code index} if it exists and is a boolean or can * Returns the value at {@code index} if it exists and is a boolean or can be coerced
* be coerced to a boolean. Returns {@code fallback} otherwise. * to a boolean. Returns {@code fallback} otherwise.
* @param index the index to get the value from * @param index the index to get the value from
* @param fallback the fallback value * @param fallback the fallback value
* @return the value at {@code index} of {@code fallback} * @return the value at {@code index} of {@code fallback}
@ -369,12 +360,12 @@ public class JSONArray {
} }
/** /**
* Returns the value at {@code index} if it exists and is a double or can * Returns the value at {@code index} if it exists and is a double or can be coerced
* be coerced to a double. * to a double.
* @param index the index to get the value from * @param index the index to get the value from
* @return the {@code value} * @return the {@code value}
* @throws JSONException if the value at {@code index} doesn't exist or * @throws JSONException if the value at {@code index} doesn't exist or cannot be
* cannot be coerced to a double. * coerced to a double.
*/ */
public double getDouble(int index) throws JSONException { public double getDouble(int index) throws JSONException {
Object object = get(index); Object object = get(index);
@ -386,8 +377,8 @@ public class JSONArray {
} }
/** /**
* Returns the value at {@code index} if it exists and is a double or can * Returns the value at {@code index} if it exists and is a double or can be coerced
* be coerced to a double. Returns {@code NaN} otherwise. * to a double. Returns {@code NaN} otherwise.
* @param index the index to get the value from * @param index the index to get the value from
* @return the {@code value} or {@code NaN} * @return the {@code value} or {@code NaN}
*/ */
@ -396,8 +387,8 @@ public class JSONArray {
} }
/** /**
* Returns the value at {@code index} if it exists and is a double or can * Returns the value at {@code index} if it exists and is a double or can be coerced
* be coerced to a double. Returns {@code fallback} otherwise. * to a double. Returns {@code fallback} otherwise.
* @param index the index to get the value from * @param index the index to get the value from
* @param fallback the fallback value * @param fallback the fallback value
* @return the value at {@code index} of {@code fallback} * @return the value at {@code index} of {@code fallback}
@ -409,12 +400,12 @@ public class JSONArray {
} }
/** /**
* Returns the value at {@code index} if it exists and is an int or * Returns the value at {@code index} if it exists and is an int or can be coerced to
* can be coerced to an int. * an int.
* @param index the index to get the value from * @param index the index to get the value from
* @return the {@code value} * @return the {@code value}
* @throws JSONException if the value at {@code index} doesn't exist or * @throws JSONException if the value at {@code index} doesn't exist or cannot be
* cannot be coerced to a int. * coerced to a int.
*/ */
public int getInt(int index) throws JSONException { public int getInt(int index) throws JSONException {
Object object = get(index); Object object = get(index);
@ -426,8 +417,8 @@ public class JSONArray {
} }
/** /**
* Returns the value at {@code index} if it exists and is an int or * Returns the value at {@code index} if it exists and is an int or can be coerced to
* can be coerced to an int. Returns 0 otherwise. * an int. Returns 0 otherwise.
* @param index the index to get the value from * @param index the index to get the value from
* @return the {@code value} or {@code 0} * @return the {@code value} or {@code 0}
*/ */
@ -436,8 +427,8 @@ public class JSONArray {
} }
/** /**
* Returns the value at {@code index} if it exists and is an int or * Returns the value at {@code index} if it exists and is an int or can be coerced to
* can be coerced to an int. Returns {@code fallback} otherwise. * an int. Returns {@code fallback} otherwise.
* @param index the index to get the value from * @param index the index to get the value from
* @param fallback the fallback value * @param fallback the fallback value
* @return the value at {@code index} of {@code fallback} * @return the value at {@code index} of {@code fallback}
@ -449,13 +440,13 @@ public class JSONArray {
} }
/** /**
* Returns the value at {@code index} if it exists and is a long or * Returns the value at {@code index} if it exists and is a long or can be coerced to
* can be coerced to a long. * a long.
* @param index the index to get the value from * @param index the index to get the value from
* @return the {@code value} * @return the {@code value}
* *
* @throws JSONException if the value at {@code index} doesn't exist or * @throws JSONException if the value at {@code index} doesn't exist or cannot be
* cannot be coerced to a long. * coerced to a long.
*/ */
public long getLong(int index) throws JSONException { public long getLong(int index) throws JSONException {
Object object = get(index); Object object = get(index);
@ -467,8 +458,8 @@ public class JSONArray {
} }
/** /**
* Returns the value at {@code index} if it exists and is a long or * Returns the value at {@code index} if it exists and is a long or can be coerced to
* can be coerced to a long. Returns 0 otherwise. * a long. Returns 0 otherwise.
* @param index the index to get the value from * @param index the index to get the value from
* @return the {@code value} or {@code 0} * @return the {@code value} or {@code 0}
*/ */
@ -477,8 +468,8 @@ public class JSONArray {
} }
/** /**
* Returns the value at {@code index} if it exists and is a long or * Returns the value at {@code index} if it exists and is a long or can be coerced to
* can be coerced to a long. Returns {@code fallback} otherwise. * a long. Returns {@code fallback} otherwise.
* @param index the index to get the value from * @param index the index to get the value from
* @param fallback the fallback value * @param fallback the fallback value
* @return the value at {@code index} of {@code fallback} * @return the value at {@code index} of {@code fallback}
@ -490,8 +481,7 @@ public class JSONArray {
} }
/** /**
* Returns the value at {@code index} if it exists, coercing it if * Returns the value at {@code index} if it exists, coercing it if necessary.
* necessary.
* @param index the index to get the value from * @param index the index to get the value from
* @return the {@code value} * @return the {@code value}
* @throws JSONException if no such value exists. * @throws JSONException if no such value exists.
@ -506,8 +496,8 @@ public class JSONArray {
} }
/** /**
* Returns the value at {@code index} if it exists, coercing it if * Returns the value at {@code index} if it exists, coercing it if necessary. Returns
* necessary. Returns the empty string if no such value exists. * the empty string if no such value exists.
* @param index the index to get the value from * @param index the index to get the value from
* @return the {@code value} or an empty string * @return the {@code value} or an empty string
*/ */
@ -516,8 +506,8 @@ public class JSONArray {
} }
/** /**
* Returns the value at {@code index} if it exists, coercing it if * Returns the value at {@code index} if it exists, coercing it if necessary. Returns
* necessary. Returns {@code fallback} if no such value exists. * {@code fallback} if no such value exists.
* @param index the index to get the value from * @param index the index to get the value from
* @param fallback the fallback value * @param fallback the fallback value
* @return the value at {@code index} of {@code fallback} * @return the value at {@code index} of {@code fallback}
@ -587,11 +577,10 @@ public class JSONArray {
} }
/** /**
* Returns a new object whose values are the values in this array, and whose * Returns a new object whose values are the values in this array, and whose names are
* names are the values in {@code names}. Names and values are paired up by * the values in {@code names}. Names and values are paired up by index from 0 through
* index from 0 through to the shorter array's length. Names that are not * to the shorter array's length. Names that are not strings will be coerced to
* strings will be coerced to strings. This method returns null if either * strings. This method returns null if either array is empty.
* array is empty.
* @param names the property names * @param names the property names
* @return a json object * @return a json object
* @throws JSONException if processing of json failed * @throws JSONException if processing of json failed
@ -611,10 +600,9 @@ public class JSONArray {
/** /**
* Returns a new string by alternating this array's values with {@code * Returns a new string by alternating this array's values with {@code
* separator}. This array's string values are quoted and have their special * separator}. This array's string values are quoted and have their special characters
* characters escaped. For example, the array containing the strings '12" * escaped. For example, the array containing the strings '12" pizza', 'taco' and
* pizza', 'taco' and 'soda' joined on '+' returns this: * 'soda' joined on '+' returns this: <pre>"12\" pizza"+"taco"+"soda"</pre>
* <pre>"12\" pizza"+"taco"+"soda"</pre>
* @param separator the separator to use * @param separator the separator to use
* @return the joined value * @return the joined value
* @throws JSONException if processing of json failed * @throws JSONException if processing of json failed
@ -633,8 +621,7 @@ public class JSONArray {
} }
/** /**
* Encodes this array as a compact JSON string, such as: * Encodes this array as a compact JSON string, such as: <pre>[94043,90210]</pre>
* <pre>[94043,90210]</pre>
* @return a compact JSON string representation of this array * @return a compact JSON string representation of this array
*/ */
@Override @Override
@ -650,16 +637,13 @@ public class JSONArray {
} }
/** /**
* Encodes this array as a human readable JSON string for debugging, such * Encodes this array as a human readable JSON string for debugging, such as: <pre>
* as:
* <pre>
* [ * [
* 94043, * 94043,
* 90210 * 90210
* ]</pre> * ]</pre>
* *
* @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.
* @return a human readable JSON string of this array * @return a human readable JSON string of this array
* @throws JSONException if processing of json failed * @throws JSONException if processing of json failed
*/ */
@ -687,4 +671,5 @@ public class JSONArray {
// diverge from the original, which doesn't implement hashCode // diverge from the original, which doesn't implement hashCode
return this.values.hashCode(); return this.values.hashCode();
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright (C) 2010 The Android Open Source Project
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,23 +16,22 @@
package org.springframework.boot.configurationprocessor.json; package org.springframework.boot.configurationprocessor.json;
// Note: this class was written without inspecting the non-free org.json source code. // Note: this class was written without inspecting the non-free org.json sourcecode.
/** /**
* Thrown to indicate a problem with the JSON API. Such problems include: * Thrown to indicate a problem with the JSON API. Such problems include:
* <ul> * <ul>
* <li>Attempts to parse or construct malformed documents * <li>Attempts to parse or construct malformed documents
* <li>Use of null as a name * <li>Use of null as a name
* <li>Use of numeric types not available to JSON, such as {@link * <li>Use of numeric types not available to JSON, such as {@link Double#isNaN() NaNs} or
* Double#isNaN() NaNs} or {@link Double#isInfinite() infinities}. * {@link Double#isInfinite() infinities}.
* <li>Lookups using an out of range index or nonexistent name * <li>Lookups using an out of range index or nonexistent name
* <li>Type mismatches on lookups * <li>Type mismatches on lookups
* </ul> * </ul>
* * <p>
* <p>Although this is a checked exception, it is rarely recoverable. Most * Although this is a checked exception, it is rarely recoverable. Most callers should
* callers should simply wrap this exception in an unchecked exception and * simply wrap this exception in an unchecked exception and rethrow: <pre class="code">
* rethrow: * public JSONArray toJSONObject() {
* <pre> public JSONArray toJSONObject() {
* try { * try {
* JSONObject result = new JSONObject(); * JSONObject result = new JSONObject();
* ... * ...
@ -46,4 +45,5 @@ public class JSONException extends Exception {
public JSONException(String s) { public JSONException(String s) {
super(s); super(s);
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright (C) 2010 The Android Open Source Project
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -22,59 +22,55 @@ import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
// Note: this class was written without inspecting the non-free org.json source code. // Note: this class was written without inspecting the non-free org.json sourcecode.
/** /**
* A modifiable set of name/value mappings. Names are unique, non-null strings. * A modifiable set of name/value mappings. Names are unique, non-null strings. Values may
* Values may be any mix of {@link JSONObject JSONObjects}, {@link JSONArray * be any mix of {@link JSONObject JSONObjects}, {@link JSONArray JSONArrays}, Strings,
* JSONArrays}, Strings, Booleans, Integers, Longs, Doubles or {@link #NULL}. * Booleans, Integers, Longs, Doubles or {@link #NULL}. Values may not be {@code null},
* Values may not be {@code null}, {@link Double#isNaN() NaNs}, {@link * {@link Double#isNaN() NaNs}, {@link Double#isInfinite() infinities}, or of any type not
* Double#isInfinite() infinities}, or of any type not listed here. * listed here.
* * <p>
* <p>This class can coerce values to another type when requested. * This class can coerce values to another type when requested.
* <ul> * <ul>
* <li>When the requested type is a boolean, strings will be coerced using a * <li>When the requested type is a boolean, strings will be coerced using a
* case-insensitive comparison to "true" and "false". * case-insensitive comparison to "true" and "false".
* <li>When the requested type is a double, other {@link Number} types will * <li>When the requested type is a double, other {@link Number} types will be coerced
* be coerced using {@link Number#doubleValue() doubleValue}. Strings * using {@link Number#doubleValue() doubleValue}. Strings that can be coerced using
* that can be coerced using {@link Double#valueOf(String)} will be. * {@link Double#valueOf(String)} will be.
* <li>When the requested type is an int, other {@link Number} types will * <li>When the requested type is an int, other {@link Number} types will be coerced using
* be coerced using {@link Number#intValue() intValue}. Strings * {@link Number#intValue() intValue}. Strings that can be coerced using
* that can be coerced using {@link Double#valueOf(String)} will be, * {@link Double#valueOf(String)} will be, and then cast to int.
* and then cast to int. * <li><a name="lossy">When the requested type is a long, other {@link Number} types will
* <li><a name="lossy">When the requested type is a long, other {@link Number} types will * be coerced using {@link Number#longValue() longValue}. Strings that can be coerced
* be coerced using {@link Number#longValue() longValue}. Strings * using {@link Double#valueOf(String)} will be, and then cast to long. This two-step
* that can be coerced using {@link Double#valueOf(String)} will be, * conversion is lossy for very large values. For example, the string
* and then cast to long. This two-step conversion is lossy for very * "9223372036854775806" yields the long 9223372036854775807.</a>
* large values. For example, the string "9223372036854775806" yields the * <li>When the requested type is a String, other non-null values will be coerced using
* long 9223372036854775807.</a> * {@link String#valueOf(Object)}. Although null cannot be coerced, the sentinel value
* <li>When the requested type is a String, other non-null values will be * {@link JSONObject#NULL} is coerced to the string "null".
* coerced using {@link String#valueOf(Object)}. Although null cannot be
* coerced, the sentinel value {@link JSONObject#NULL} is coerced to the
* string "null".
* </ul> * </ul>
* * <p>
* <p>This class can look up both mandatory and optional values: * This class can look up both mandatory and optional values:
* <ul> * <ul>
* <li>Use <code>get<i>Type</i>()</code> to retrieve a mandatory value. This * <li>Use <code>get<i>Type</i>()</code> to retrieve a mandatory value. This fails with a
* fails with a {@code JSONException} if the requested name has no value * {@code JSONException} if the requested name has no value or if the value cannot be
* or if the value cannot be coerced to the requested type. * coerced to the requested type.
* <li>Use <code>opt<i>Type</i>()</code> to retrieve an optional value. This * <li>Use <code>opt<i>Type</i>()</code> to retrieve an optional value. This returns a
* returns a system- or user-supplied default if the requested name has no * system- or user-supplied default if the requested name has no value or if the value
* value or if the value cannot be coerced to the requested type. * cannot be coerced to the requested type.
* </ul> * </ul>
* * <p>
* <p><strong>Warning:</strong> this class represents null in two incompatible * <strong>Warning:</strong> this class represents null in two incompatible ways: the
* ways: the standard Java {@code null} reference, and the sentinel value {@link * standard Java {@code null} reference, and the sentinel value {@link JSONObject#NULL}.
* JSONObject#NULL}. In particular, calling {@code put(name, null)} removes the * In particular, calling {@code put(name, null)} removes the named entry from the object
* named entry from the object but {@code put(name, JSONObject.NULL)} stores an * but {@code put(name, JSONObject.NULL)} stores an entry whose value is
* entry whose value is {@code JSONObject.NULL}. * {@code JSONObject.NULL}.
* * <p>
* <p>Instances of this class are not thread safe. Although this class is * Instances of this class are not thread safe. Although this class is nonfinal, it was
* nonfinal, it was not designed for inheritance and should not be subclassed. * not designed for inheritance and should not be subclassed. In particular, self-use by
* In particular, self-use by overrideable methods is not specified. See * overrideable methods is not specified. See <i>Effective Java</i> Item 17, "Design and
* <i>Effective Java</i> Item 17, "Design and Document or inheritance or else * Document or inheritance or else prohibit it" for further information.
* prohibit it" for further information.
*/ */
public class JSONObject { public class JSONObject {
@ -84,27 +80,29 @@ public class JSONObject {
* A sentinel value used to explicitly define a name with no value. Unlike * A sentinel value used to explicitly define a name with no value. Unlike
* {@code null}, names with this value: * {@code null}, names with this value:
* <ul> * <ul>
* <li>show up in the {@link #names} array * <li>show up in the {@link #names} array
* <li>show up in the {@link #keys} iterator * <li>show up in the {@link #keys} iterator
* <li>return {@code true} for {@link #has(String)} * <li>return {@code true} for {@link #has(String)}
* <li>do not throw on {@link #get(String)} * <li>do not throw on {@link #get(String)}
* <li>are included in the encoded JSON string. * <li>are included in the encoded JSON string.
* </ul> * </ul>
* * <p>
* <p>This value violates the general contract of {@link Object#equals} by * This value violates the general contract of {@link Object#equals} by returning true
* returning true when compared to {@code null}. Its {@link #toString} * when compared to {@code null}. Its {@link #toString} method returns "null".
* method returns "null".
*/ */
public static final Object NULL = new Object() { public static final Object NULL = new Object() {
@Override @Override
public boolean equals(Object o) { 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
} }
@Override @Override
public String toString() { public String toString() {
return "null"; return "null";
} }
}; };
private final Map<String, Object> nameValuePairs; private final Map<String, Object> nameValuePairs;
@ -117,21 +115,22 @@ public class JSONObject {
} }
/** /**
* 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
* the given map. * map.
* *
* @param copyFrom a map whose keys are of type {@link String} and whose * @param copyFrom a map whose keys are of type {@link String} and whose values are of
* values are of supported types. * supported types.
* @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) */
@SuppressWarnings("rawtypes")
public JSONObject(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 of the
* of the proper type. (We still defer validating the values). * proper type. (We still defer validating the values).
*/ */
String key = (String) entry.getKey(); String key = (String) entry.getKey();
if (key == null) { if (key == null) {
@ -142,18 +141,15 @@ public class JSONObject {
} }
/** /**
* Creates a new {@code JSONObject} with name/value mappings from the next * Creates a new {@code JSONObject} with name/value mappings from the next object in
* object in the tokener. * the tokener.
* * @param readFrom a tokener whose nextValue() method will yield a {@code JSONObject}.
* @param readFrom a tokener whose nextValue() method will yield a * @throws JSONException if the parse fails or doesn't yield a {@code JSONObject}.
* {@code JSONObject}.
* @throws JSONException if the parse fails or doesn't yield a
* {@code JSONObject}.
*/ */
public JSONObject(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
* parse to temporary JSONObject and then steal the data from that. * temporary JSONObject and then steal the data from that.
*/ */
Object object = readFrom.nextValue(); Object object = readFrom.nextValue();
if (object instanceof JSONObject) { if (object instanceof JSONObject) {
@ -165,9 +161,7 @@ public class JSONObject {
} }
/** /**
* Creates a new {@code JSONObject} with name/value mappings from the JSON * Creates a new {@code JSONObject} with name/value mappings from the JSON string.
* string.
*
* @param json a JSON-encoded string containing an object. * @param json a JSON-encoded string containing an object.
* @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}.
@ -177,9 +171,8 @@ public class JSONObject {
} }
/** /**
* Creates a new {@code JSONObject} by copying mappings for the listed names * Creates a new {@code JSONObject} by copying mappings for the listed names from the
* from the given object. Names that aren't present in {@code copyFrom} will * given object. Names that aren't present in {@code copyFrom} will be skipped.
* be skipped.
* @param copyFrom the source * @param copyFrom the source
* @param names the property names * @param names the property names
* @throws JSONException if an error occurs * @throws JSONException if an error occurs
@ -203,8 +196,8 @@ public class JSONObject {
} }
/** /**
* Maps {@code name} to {@code value}, clobbering any existing name/value * Maps {@code name} to {@code value}, clobbering any existing name/value mapping with
* mapping with the same name. * the same name.
* @param name the name of the property * @param name the name of the property
* @param value the value of the property * @param value the value of the property
* @return this object. * @return this object.
@ -216,12 +209,11 @@ public class JSONObject {
} }
/** /**
* Maps {@code name} to {@code value}, clobbering any existing name/value * Maps {@code name} to {@code value}, clobbering any existing name/value mapping with
* mapping with the same name. * the same name.
*
* @param name the name of the property * @param name the name of the property
* @param value a finite value. May not be {@link Double#isNaN() NaNs} or * @param value a finite value. May not be {@link Double#isNaN() NaNs} or
* {@link Double#isInfinite() infinities}. * {@link Double#isInfinite() infinities}.
* @return this object. * @return this object.
* @throws JSONException if an error occurs * @throws JSONException if an error occurs
*/ */
@ -231,9 +223,8 @@ public class JSONObject {
} }
/** /**
* Maps {@code name} to {@code value}, clobbering any existing name/value * Maps {@code name} to {@code value}, clobbering any existing name/value mapping with
* mapping with the same name. * the same name.
*
* @param name the name of the property * @param name the name of the property
* @param value the value of the property * @param value the value of the property
* @return this object. * @return this object.
@ -245,9 +236,8 @@ public class JSONObject {
} }
/** /**
* Maps {@code name} to {@code value}, clobbering any existing name/value * Maps {@code name} to {@code value}, clobbering any existing name/value mapping with
* mapping with the same name. * the same name.
*
* @param name the name of the property * @param name the name of the property
* @param value the value of the property * @param value the value of the property
* @return this object. * @return this object.
@ -259,15 +249,13 @@ public class JSONObject {
} }
/** /**
* Maps {@code name} to {@code value}, clobbering any existing name/value * Maps {@code name} to {@code value}, clobbering any existing name/value mapping with
* mapping with the same name. If the value is {@code null}, any existing * the same name. If the value is {@code null}, any existing mapping for {@code name}
* mapping for {@code name} is removed. * is removed.
*
* @param name the name of the property * @param name the name of the property
* @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, Integer,
* Integer, Long, Double, {@link #NULL}, or {@code null}. May not be * Long, Double, {@link #NULL}, or {@code null}. May not be {@link Double#isNaN()
* {@link Double#isNaN() NaNs} or {@link Double#isInfinite() * NaNs} or {@link Double#isInfinite() infinities}.
* infinities}.
* @return this object. * @return this object.
* @throws JSONException if an error occurs * @throws JSONException if an error occurs
*/ */
@ -277,7 +265,8 @@ public class JSONObject {
return this; return this;
} }
if (value instanceof Number) { if (value instanceof Number) {
// deviate from the original by checking all Numbers, not just floats & doubles // deviate from the original by checking all Numbers, not just floats &
// doubles
JSON.checkDouble(((Number) value).doubleValue()); JSON.checkDouble(((Number) value).doubleValue());
} }
this.nameValuePairs.put(checkName(name), value); this.nameValuePairs.put(checkName(name), value);
@ -285,8 +274,8 @@ 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
* does nothing otherwise. * nothing otherwise.
* @param name the name of the property * @param name the name of the property
* @param value the value of the property * @param value the value of the property
* @return this object. * @return this object.
@ -300,17 +289,15 @@ public class JSONObject {
} }
/** /**
* Appends {@code value} to the array already mapped to {@code name}. If * Appends {@code value} to the array already mapped to {@code name}. If this object
* this object has no mapping for {@code name}, this inserts a new mapping. * has no mapping for {@code name}, this inserts a new mapping. If the mapping exists
* If the mapping exists but its value is not an array, the existing * but its value is not an array, the existing and new values are inserted in order
* and new values are inserted in order into a new array which is itself * into a new array which is itself mapped to {@code name}. In aggregate, this allows
* mapped to {@code name}. In aggregate, this allows values to be added to a * values to be added to a mapping one at a time.
* mapping one at a time.
*
* @param name the name of the property * @param name the name of the property
* @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, Integer,
* Integer, Long, Double, {@link #NULL} or null. May not be {@link * Long, Double, {@link #NULL} or null. May not be {@link Double#isNaN() NaNs} or
* Double#isNaN() NaNs} or {@link Double#isInfinite() infinities}. * {@link Double#isInfinite() infinities}.
* @return this object. * @return this object.
* @throws JSONException if an error occurs * @throws JSONException if an error occurs
*/ */
@ -349,16 +336,16 @@ public class JSONObject {
* Removes the named mapping if it exists; does nothing otherwise. * Removes the named mapping if it exists; does nothing otherwise.
* *
* @param name the name of the property * @param name the name of the property
* @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
* no such mapping. * mapping.
*/ */
public Object remove(String name) { public Object remove(String name) {
return this.nameValuePairs.remove(name); return this.nameValuePairs.remove(name);
} }
/** /**
* 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
* a mapping whose value is {@link #NULL}. * whose value is {@link #NULL}.
* @param name the name of the property * @param name the name of the property
* @return true if this object has no mapping for {@code name} * @return true if this object has no mapping for {@code name}
*/ */
@ -368,8 +355,8 @@ 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
* may be {@link #NULL}. * {@link #NULL}.
* @param name the name of the property * @param name the name of the property
* @return true if this object has a mapping for {@code name} * @return true if this object has a mapping for {@code name}
*/ */
@ -392,8 +379,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.
* @param name the name of the property * @param name the name of the property
* @return the value or {@code null} * @return the value or {@code null}
*/ */
@ -402,13 +388,12 @@ 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
* can be coerced to a boolean. * coerced to a boolean.
*
* @param name the name of the property * @param name the name of the property
* @return the value * @return the value
* @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
* to a boolean. * boolean.
*/ */
public boolean getBoolean(String name) throws JSONException { public boolean getBoolean(String name) throws JSONException {
Object object = get(name); Object object = get(name);
@ -420,8 +405,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
* can be coerced to a boolean. Returns false otherwise. * coerced to a boolean. Returns false otherwise.
* @param name the name of the property * @param name the name of the property
* @return the value or {@code null} * @return the value or {@code null}
*/ */
@ -430,8 +415,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
* can be coerced to a boolean. Returns {@code fallback} otherwise. * coerced to a boolean. Returns {@code fallback} otherwise.
* @param name the name of the property * @param name the name of the property
* @param fallback a fallback value * @param fallback a fallback value
* @return the value or {@code fallback} * @return the value or {@code fallback}
@ -443,13 +428,13 @@ 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
* can be coerced to a double. * coerced to a double.
* *
* @param name the name of the property * @param name the name of the property
* @return the value * @return the value
* @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
* to a double. * double.
*/ */
public double getDouble(String name) throws JSONException { public double getDouble(String name) throws JSONException {
Object object = get(name); Object object = get(name);
@ -461,8 +446,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
* can be coerced to a double. Returns {@code NaN} otherwise. * coerced to a double. Returns {@code NaN} otherwise.
* @param name the name of the property * @param name the name of the property
* @return the value or {@code NaN} * @return the value or {@code NaN}
*/ */
@ -471,8 +456,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
* can be coerced to a double. Returns {@code fallback} otherwise. * coerced to a double. Returns {@code fallback} otherwise.
* @param name the name of the property * @param name the name of the property
* @param fallback a fallback value * @param fallback a fallback value
* @return the value or {@code fallback} * @return the value or {@code fallback}
@ -484,12 +469,11 @@ 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
* can be coerced to an int. * coerced to an int.
* @param name the name of the property * @param name the name of the property
* @return the value * @return the value
* @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(String name) throws JSONException { public int getInt(String name) throws JSONException {
Object object = get(name); Object object = get(name);
@ -501,8 +485,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
* can be coerced to an int. Returns 0 otherwise. * coerced to an int. Returns 0 otherwise.
* @param name the name of the property * @param name the name of the property
* @return the value of {@code 0} * @return the value of {@code 0}
*/ */
@ -511,8 +495,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
* can be coerced to an int. Returns {@code fallback} otherwise. * coerced to an int. Returns {@code fallback} otherwise.
* @param name the name of the property * @param name the name of the property
* @param fallback a fallback value * @param fallback a fallback value
* @return the value or {@code fallback} * @return the value or {@code fallback}
@ -524,14 +508,12 @@ public class JSONObject {
} }
/** /**
* Returns the value mapped by {@code name} if it exists and is a long or * Returns the value mapped by {@code name} if it exists and is a long or can be
* can be coerced to a long. Note that JSON represents numbers as doubles, * coerced to a long. Note that JSON represents numbers as doubles, so this is
* so this is <a href="#lossy">lossy</a>; use strings to transfer numbers via JSON. * <a href="#lossy">lossy</a>; use strings to transfer numbers via JSON.
*
* @param name the name of the property * @param name the name of the property
* @return the value * @return the value
* @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(String name) throws JSONException { public long getLong(String name) throws JSONException {
Object object = get(name); Object object = get(name);
@ -543,9 +525,10 @@ public class JSONObject {
} }
/** /**
* Returns the value mapped by {@code name} if it exists and is a long or * Returns the value mapped by {@code name} if it exists and is a long or can be
* can be coerced to a long. Returns 0 otherwise. Note that JSON represents numbers as doubles, * coerced to a long. Returns 0 otherwise. Note that JSON represents numbers as
* so this is <a href="#lossy">lossy</a>; use strings to transfer numbers via JSON. * doubles, so this is <a href="#lossy">lossy</a>; use strings to transfer numbers via
* JSON.
* @param name the name of the property * @param name the name of the property
* @return the value or {@code 0L} * @return the value or {@code 0L}
*/ */
@ -554,8 +537,8 @@ public class JSONObject {
} }
/** /**
* Returns the value mapped by {@code name} if it exists and is a long or * Returns the value mapped by {@code name} if it exists and is a long or can be
* can be coerced to a long. Returns {@code fallback} otherwise. Note that JSON represents * coerced to a long. Returns {@code fallback} otherwise. Note that JSON represents
* 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.
* @param name the name of the property * @param name the name of the property
@ -569,8 +552,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.
* necessary.
* @param name the name of the property * @param name the name of the property
* @return the value * @return the value
* @throws JSONException if no such mapping exists. * @throws JSONException if no such mapping exists.
@ -585,8 +567,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.
* necessary. Returns the empty string if no such mapping exists. * Returns the empty string if no such mapping exists.
* @param name the name of the property * @param name the name of the property
* @return the value or an empty string * @return the value or an empty string
*/ */
@ -595,8 +577,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.
* necessary. Returns {@code fallback} if no such mapping exists. * Returns {@code fallback} if no such mapping exists.
* @param name the name of the property * @param name the name of the property
* @param fallback a fallback value * @param fallback a fallback value
* @return the value or {@code fallback} * @return the value or {@code fallback}
@ -666,9 +648,9 @@ public class JSONObject {
} }
/** /**
* Returns an array with the values corresponding to {@code names}. The * Returns an array with the values corresponding to {@code names}. The array contains
* array contains null for names that aren't mapped. This method returns * null for names that aren't mapped. This method returns null if {@code names} is
* null if {@code names} is either null or empty. * either null or empty.
* @param names the names of the properties * @param names the names of the properties
* @return the array * @return the array
*/ */
@ -689,26 +671,26 @@ public class JSONObject {
} }
/** /**
* Returns an iterator of the {@code String} names in this object. The * Returns an iterator of the {@code String} names in this object. The returned
* returned iterator supports {@link Iterator#remove() remove}, which will * iterator supports {@link Iterator#remove() remove}, which will remove the
* remove the corresponding mapping from this object. If this object is * corresponding mapping from this object. If this object is modified after the
* modified after the iterator is returned, the iterator's behavior is * iterator is returned, the iterator's behavior is undefined. The order of the keys
* undefined. The order of the keys is undefined. * is undefined.
* @return the keys * @return the keys
*/ */
/* Return a raw type for API compatibility */ /* Return a raw type for API compatibility */
@SuppressWarnings("rawtypes")
public Iterator keys() { public Iterator keys() {
return this.nameValuePairs.keySet().iterator(); return this.nameValuePairs.keySet().iterator();
} }
/** /**
* 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
* returns null if this object contains no mappings. * null if this object contains no mappings.
* @return the array * @return the array
*/ */
public JSONArray names() { public JSONArray names() {
return this.nameValuePairs.isEmpty() return this.nameValuePairs.isEmpty() ? null
? null
: new JSONArray(new ArrayList<String>(this.nameValuePairs.keySet())); : new JSONArray(new ArrayList<String>(this.nameValuePairs.keySet()));
} }
@ -730,9 +712,7 @@ public class JSONObject {
} }
/** /**
* Encodes this object as a human readable JSON string for debugging, such * Encodes this object as a human readable JSON string for debugging, such as: <pre>
* as:
* <pre>
* { * {
* "query": "Pizza", * "query": "Pizza",
* "locations": [ * "locations": [
@ -740,9 +720,7 @@ public class JSONObject {
* 90210 * 90210
* ] * ]
* }</pre> * }</pre>
* * @param indentSpaces the number of spaces to indent for each level of nesting.
* @param indentSpaces the number of spaces to indent for each level of
* nesting.
* @return a string representation of the object. * @return a string representation of the object.
* @throws JSONException if an error occurs * @throws JSONException if an error occurs
*/ */
@ -762,9 +740,8 @@ public class JSONObject {
/** /**
* Encodes the number as a JSON string. * Encodes the number as a JSON string.
*
* @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}.
* @return the encoded value * @return the encoded value
* @throws JSONException if an error occurs * @throws JSONException if an error occurs
*/ */
@ -782,7 +759,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);
} }
@ -790,11 +767,9 @@ public class JSONObject {
} }
/** /**
* Encodes {@code data} as a JSON string. This applies quotes and any * Encodes {@code data} as a JSON string. This applies quotes and any necessary
* necessary character escaping. * character escaping.
* * @param data the string to encode. Null will be interpreted as an empty string.
* @param data the string to encode. Null will be interpreted as an empty
* string.
* @return the quoted value * @return the quoted value
*/ */
public static String quote(String data) { public static String quote(String data) {
@ -815,18 +790,19 @@ public class JSONObject {
/** /**
* Wraps the given object if necessary. * Wraps the given object if necessary.
* * <p>
* <p>If the object is null or , returns {@link #NULL}. * If the object is null or , returns {@link #NULL}. If the object is a
* If the object is a {@code JSONArray} or {@code JSONObject}, no wrapping is necessary. * {@code JSONArray} or {@code JSONObject}, no wrapping is necessary. If the object is
* If the object is {@code NULL}, no wrapping is necessary. * {@code NULL}, no wrapping is necessary. If the object is an array or
* If the object is an array or {@code Collection}, returns an equivalent {@code JSONArray}. * {@code Collection}, returns an equivalent {@code JSONArray}. If the object is a
* If the object is a {@code Map}, returns an equivalent {@code JSONObject}. * {@code Map}, returns an equivalent {@code JSONObject}. If the object is a primitive
* If the object is a primitive wrapper type or {@code String}, returns the object. * wrapper type or {@code String}, returns the object. Otherwise if the object is from
* Otherwise if the object is from a {@code java} package, returns the result of {@code toString}. * a {@code java} package, returns the result of {@code toString}. If wrapping fails,
* If wrapping fails, returns null. * returns null.
* @param o the object to wrap * @param o the object to wrap
* @return the wrapped object * @return the wrapped object
*/ */
@SuppressWarnings("rawtypes")
public static Object wrap(Object o) { public static Object wrap(Object o) {
if (o == null) { if (o == null) {
return NULL; return NULL;
@ -847,15 +823,9 @@ public class JSONObject {
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 Character
o instanceof Byte || || o instanceof Double || o instanceof Float || o instanceof Integer
o instanceof Character || || o instanceof Long || o instanceof Short || o instanceof String) {
o instanceof Double ||
o instanceof Float ||
o instanceof Integer ||
o instanceof Long ||
o instanceof Short ||
o instanceof String) {
return o; return o;
} }
if (o.getClass().getPackage().getName().startsWith("java.")) { if (o.getClass().getPackage().getName().startsWith("java.")) {
@ -866,4 +836,5 @@ public class JSONObject {
} }
return null; return null;
} }
} }

@ -23,80 +23,77 @@ 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.
/** /**
* Implements {@link JSONObject#toString} and {@link JSONArray#toString}. Most * Implements {@link JSONObject#toString} and {@link JSONArray#toString}. Most application
* application developers should use those methods directly and disregard this * developers should use those methods directly and disregard this API. For example:<pre>
* API. For example:<pre>
* JSONObject object = ... * JSONObject object = ...
* String json = object.toString();</pre> * String json = object.toString();</pre>
* * <p>
* <p>Stringers only encode well-formed JSON strings. In particular: * Stringers only encode well-formed JSON strings. In particular:
* <ul> * <ul>
* <li>The stringer must have exactly one top-level array or object. * <li>The stringer must have exactly one top-level array or object.
* <li>Lexical scopes must be balanced: every call to {@link #array} must * <li>Lexical scopes must be balanced: every call to {@link #array} must have a matching
* have a matching call to {@link #endArray} and every call to {@link * call to {@link #endArray} and every call to {@link #object} must have a matching call
* #object} must have a matching call to {@link #endObject}. * to {@link #endObject}.
* <li>Arrays may not contain keys (property names). * <li>Arrays may not contain keys (property names).
* <li>Objects must alternate keys (property names) and values. * <li>Objects must alternate keys (property names) and values.
* <li>Values are inserted with either literal {@link #value(Object) value} * <li>Values are inserted with either literal {@link #value(Object) value} calls, or by
* calls, or by nesting arrays or objects. * nesting arrays or objects.
* </ul> * </ul>
* Calls that would result in a malformed JSON string will fail with a * Calls that would result in a malformed JSON string will fail with a
* {@link JSONException}. * {@link JSONException}.
* * <p>
* <p>This class provides no facility for pretty-printing (ie. indenting) * This class provides no facility for pretty-printing (ie. indenting) output. To encode
* output. To encode indented output, use {@link JSONObject#toString(int)} or * indented output, use {@link JSONObject#toString(int)} or
* {@link JSONArray#toString(int)}. * {@link JSONArray#toString(int)}.
* * <p>
* <p>Some implementations of the API support at most 20 levels of nesting. * Some implementations of the API support at most 20 levels of nesting. Attempts to
* Attempts to create more than 20 levels of nesting may fail with a {@link * create more than 20 levels of nesting may fail with a {@link JSONException}.
* JSONException}. * <p>
* * Each stringer may be used to encode a single top level value. Instances of this class
* <p>Each stringer may be used to encode a single top level value. Instances of * are not thread safe. Although this class is nonfinal, it was not designed for
* this class are not thread safe. Although this class is nonfinal, it was not * inheritance and should not be subclassed. In particular, self-use by overrideable
* designed for inheritance and should not be subclassed. In particular, * methods is not specified. See <i>Effective Java</i> Item 17,
* self-use by overrideable methods is not specified. See <i>Effective Java</i> * "Design and Document or inheritance or else prohibit it" for further information.
* Item 17, "Design and Document or inheritance or else prohibit it" for further
* information.
*/ */
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.
*/
final StringBuilder out = new StringBuilder(); final StringBuilder out = new StringBuilder();
/** /**
* Lexical scoping elements within this stringer, necessary to insert the * Lexical scoping elements within this stringer, necessary to insert the appropriate
* appropriate separator characters (ie. commas and colons) and to detect * separator characters (ie. commas and colons) and to detect nesting errors.
* nesting errors.
*/ */
enum Scope { enum Scope {
/** /**
* An array with no elements requires no separators or newlines before * An array with no elements requires no separators or newlines before it is
* it is closed. * closed.
*/ */
EMPTY_ARRAY, EMPTY_ARRAY,
/** /**
* A array with at least one value requires a comma and newline before * A array with at least one value requires a comma and newline before the next
* the next element. * element.
*/ */
NONEMPTY_ARRAY, NONEMPTY_ARRAY,
/** /**
* An object with no keys or values requires no separators or newlines * An object with no keys or values requires no separators or newlines before it
* before it is closed. * is closed.
*/ */
EMPTY_OBJECT, EMPTY_OBJECT,
/** /**
* An object whose most recent element is a key. The next element must * An object whose most recent element is a key. The next element must be a value.
* be a value.
*/ */
DANGLING_KEY, DANGLING_KEY,
/** /**
* An object with at least one name/value pair requires a comma and * An object with at least one name/value pair requires a comma and newline before
* newline before the next element. * the next element.
*/ */
NONEMPTY_OBJECT, NONEMPTY_OBJECT,
@ -104,18 +101,19 @@ public class JSONStringer {
* A special bracketless array needed by JSONStringer.join() and * A special bracketless array needed by JSONStringer.join() and
* JSONObject.quote() only. Not used for JSON encoding. * JSONObject.quote() only. Not used for JSON encoding.
*/ */
NULL, NULL
} }
/** /**
* Unlike the original implementation, this stack isn't limited to 20 * Unlike the original implementation, this stack isn't limited to 20 levels of
* levels of nesting. * nesting.
*/ */
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
* indentation, or null for no pretty printing. * for no pretty printing.
*/ */
private final String indent; private final String indent;
@ -130,9 +128,8 @@ public class JSONStringer {
} }
/** /**
* Begins encoding a new array. Each call to this method must be paired with * Begins encoding a new array. Each call to this method must be paired with a call to
* a call to {@link #endArray}. * {@link #endArray}.
*
* @return this stringer. * @return this stringer.
* @throws JSONException if processing of json failed * @throws JSONException if processing of json failed
*/ */
@ -142,7 +139,6 @@ public class JSONStringer {
/** /**
* Ends encoding the current array. * Ends encoding the current array.
*
* @return this stringer. * @return this stringer.
* @throws JSONException if processing of json failed * @throws JSONException if processing of json failed
*/ */
@ -151,9 +147,8 @@ public class JSONStringer {
} }
/** /**
* Begins encoding a new object. Each call to this method must be paired * Begins encoding a new object. Each call to this method must be paired with a call
* with a call to {@link #endObject}. * to {@link #endObject}.
*
* @return this stringer. * @return this stringer.
* @throws JSONException if processing of json failed * @throws JSONException if processing of json failed
*/ */
@ -163,7 +158,6 @@ public class JSONStringer {
/** /**
* Ends encoding the current object. * Ends encoding the current object.
*
* @return this stringer. * @return this stringer.
* @throws JSONException if processing of json failed * @throws JSONException if processing of json failed
*/ */
@ -172,8 +166,7 @@ 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.
* @param empty any necessary whitespace * @param empty any necessary whitespace
* @param openBracket the open bracket * @param openBracket the open bracket
* @return this object * @return this object
@ -190,14 +183,16 @@ 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
* given bracket. * bracket.
* @param empty any necessary whitespace * @param empty any necessary whitespace
* @param nonempty the current scope * @param nonempty the current scope
* @param closeBracket the close bracket * @param closeBracket the close bracket
* @return the JSON stringer
* @throws JSONException if processing of json failed * @throws JSONException if processing of json failed
*/ */
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) {
throw new JSONException("Nesting problem"); throw new JSONException("Nesting problem");
@ -233,10 +228,9 @@ public class JSONStringer {
/** /**
* Encodes {@code value}. * Encodes {@code value}.
* * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, Integer,
* @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, * Long, Double or null. May not be {@link Double#isNaN() NaNs} or
* Integer, Long, Double or null. May not be {@link Double#isNaN() NaNs} * {@link Double#isInfinite() infinities}.
* or {@link Double#isInfinite() infinities}.
* @return this stringer. * @return this stringer.
* @throws JSONException if processing of json failed * @throws JSONException if processing of json failed
*/ */
@ -257,9 +251,7 @@ public class JSONStringer {
beforeValue(); beforeValue();
if (value == null if (value == null || value instanceof Boolean || value == JSONObject.NULL) {
|| value instanceof Boolean
|| value == JSONObject.NULL) {
this.out.append(value); this.out.append(value);
} }
@ -276,7 +268,6 @@ public class JSONStringer {
/** /**
* Encodes {@code value} to this stringer. * Encodes {@code value} to this stringer.
*
* @param value the value to encode * @param value the value to encode
* @return this stringer. * @return this stringer.
* @throws JSONException if processing of json failed * @throws JSONException if processing of json failed
@ -292,9 +283,8 @@ public class JSONStringer {
/** /**
* Encodes {@code value} to this stringer. * Encodes {@code value} to this stringer.
*
* @param value a finite value. May not be {@link Double#isNaN() NaNs} or * @param value a finite value. May not be {@link Double#isNaN() NaNs} or
* {@link Double#isInfinite() infinities}. * {@link Double#isInfinite() infinities}.
* @return this stringer. * @return this stringer.
* @throws JSONException if processing of json failed * @throws JSONException if processing of json failed
*/ */
@ -309,7 +299,6 @@ public class JSONStringer {
/** /**
* Encodes {@code value} to this stringer. * Encodes {@code value} to this stringer.
*
* @param value the value to encode * @param value the value to encode
* @return this stringer. * @return this stringer.
* @throws JSONException if processing of json failed * @throws JSONException if processing of json failed
@ -329,46 +318,45 @@ public class JSONStringer {
char c = value.charAt(i); char c = value.charAt(i);
/* /*
* From RFC 4627, "All Unicode characters may be placed within the * From RFC 4627, "All Unicode characters may be placed within the quotation
* quotation marks except for the characters that must be escaped: * marks except for the characters that must be escaped: quotation mark,
* quotation mark, reverse solidus, and the control characters * reverse solidus, and the control characters (U+0000 through U+001F)."
* (U+0000 through U+001F)."
*/ */
switch (c) { switch (c) {
case '"': case '"':
case '\\': case '\\':
case '/': case '/':
this.out.append('\\').append(c); this.out.append('\\').append(c);
break; break;
case '\t': case '\t':
this.out.append("\\t"); this.out.append("\\t");
break; break;
case '\b': case '\b':
this.out.append("\\b"); this.out.append("\\b");
break; break;
case '\n': case '\n':
this.out.append("\\n"); this.out.append("\\n");
break; break;
case '\r': case '\r':
this.out.append("\\r"); this.out.append("\\r");
break; break;
case '\f': case '\f':
this.out.append("\\f"); this.out.append("\\f");
break; break;
default: default:
if (c <= 0x1F) { if (c <= 0x1F) {
this.out.append(String.format("\\u%04x", (int) c)); this.out.append(String.format("\\u%04x", (int) c));
} }
else { else {
this.out.append(c); this.out.append(c);
} }
break; break;
} }
} }
@ -388,7 +376,6 @@ public class JSONStringer {
/** /**
* Encodes the key (property name) to this stringer. * Encodes the key (property name) to this stringer.
*
* @param name the name of the forthcoming value. May not be null. * @param name the name of the forthcoming value. May not be null.
* @return this stringer. * @return this stringer.
* @throws JSONException if processing of json failed * @throws JSONException if processing of json failed
@ -403,8 +390,8 @@ 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
* adjusts the stack to expect the key's value. * stack to expect the key's value.
* @throws JSONException if processing of json failed * @throws JSONException if processing of json failed
*/ */
private void beforeKey() throws JSONException { private void beforeKey() throws JSONException {
@ -420,9 +407,9 @@ public class JSONStringer {
} }
/** /**
* Inserts any necessary separators and whitespace before a literal value, * Inserts any necessary separators and whitespace before a literal value, inline
* inline array, or inline object. Also adjusts the stack to expect either a * array, or inline object. Also adjusts the stack to expect either a closing bracket
* closing bracket or another element. * or another element.
* @throws JSONException if processing of json failed * @throws JSONException if processing of json failed
*/ */
private void beforeValue() throws JSONException { private void beforeValue() throws JSONException {
@ -450,17 +437,17 @@ public class JSONStringer {
/** /**
* Returns the encoded JSON string. * Returns the encoded JSON string.
* * <p>
* <p>If invoked with unterminated arrays or unclosed objects, this method's * If invoked with unterminated arrays or unclosed objects, this method's return value
* return value is undefined. * is undefined.
* * <p>
* <p><strong>Warning:</strong> although it contradicts the general contract * <strong>Warning:</strong> although it contradicts the general contract of
* of {@link Object#toString}, this method returns null if the stringer * {@link Object#toString}, this method returns null if the stringer contains no data.
* contains no data.
* @return the encoded JSON string. * @return the encoded JSON string.
*/ */
@Override @Override
public String toString() { public String toString() {
return this.out.length() == 0 ? null : this.out.toString(); return this.out.length() == 0 ? null : this.out.toString();
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright (C) 2010 The Android Open Source Project
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,13 +16,13 @@
package org.springframework.boot.configurationprocessor.json; package org.springframework.boot.configurationprocessor.json;
// Note: this class was written without inspecting the non-free org.json source code. // Note: this class was written without inspecting the non-free org.json sourcecode.
/** /**
* Parses a JSON (<a href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>) * Parses a JSON (<a href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>) encoded
* encoded string into the corresponding object. Most clients of * string into the corresponding object. Most clients of this class will use only need the
* this class will use only need the {@link #JSONTokener(String) constructor} * {@link #JSONTokener(String) constructor} and {@link #nextValue} method. Example usage:
* and {@link #nextValue} method. Example usage: <pre> * <pre>
* String json = "{" * String json = "{"
* + " \"query\": \"Pizza\", " * + " \"query\": \"Pizza\", "
* + " \"locations\": [ 94043, 90210 ] " * + " \"locations\": [ 94043, 90210 ] "
@ -31,49 +31,48 @@ package org.springframework.boot.configurationprocessor.json;
* JSONObject object = (JSONObject) new JSONTokener(json).nextValue(); * JSONObject object = (JSONObject) new JSONTokener(json).nextValue();
* String query = object.getString("query"); * String query = object.getString("query");
* JSONArray locations = object.getJSONArray("locations");</pre> * JSONArray locations = object.getJSONArray("locations");</pre>
* * <p>
* <p>For best interoperability and performance use JSON that complies with * For best interoperability and performance use JSON that complies with RFC 4627, such as
* RFC 4627, such as that generated by {@link JSONStringer}. For legacy reasons * that generated by {@link JSONStringer}. For legacy reasons this parser is lenient, so a
* this parser is lenient, so a successful parse does not indicate that the * successful parse does not indicate that the input string was valid JSON. All of the
* input string was valid JSON. All of the following syntax errors will be * following syntax errors will be ignored:
* ignored:
* <ul> * <ul>
* <li>End of line comments starting with {@code //} or {@code #} and ending * <li>End of line comments starting with {@code //} or {@code #} and ending with a
* with a newline character. * newline character.
* <li>C-style comments starting with {@code /*} and ending with * <li>C-style comments starting with {@code /*} and ending with {@code *}{@code /}. Such
* {@code *}{@code /}. Such comments may not be nested. * comments may not be nested.
* <li>Strings that are unquoted or {@code 'single quoted'}. * <li>Strings that are unquoted or {@code 'single quoted'}.
* <li>Hexadecimal integers prefixed with {@code 0x} or {@code 0X}. * <li>Hexadecimal integers prefixed with {@code 0x} or {@code 0X}.
* <li>Octal integers prefixed with {@code 0}. * <li>Octal integers prefixed with {@code 0}.
* <li>Array elements separated by {@code ;}. * <li>Array elements separated by {@code ;}.
* <li>Unnecessary array separators. These are interpreted as if null was the * <li>Unnecessary array separators. These are interpreted as if null was the omitted
* omitted value. * value.
* <li>Key-value pairs separated by {@code =} or {@code =>}. * <li>Key-value pairs separated by {@code =} or {@code =>}.
* <li>Key-value pairs separated by {@code ;}. * <li>Key-value pairs separated by {@code ;}.
* </ul> * </ul>
* * <p>
* <p>Each tokener may be used to parse a single JSON string. Instances of this * Each tokener may be used to parse a single JSON string. Instances of this class are not
* class are not thread safe. Although this class is nonfinal, it was not * thread safe. Although this class is nonfinal, it was not designed for inheritance and
* designed for inheritance and should not be subclassed. In particular, * should not be subclassed. In particular, self-use by overrideable methods is not
* self-use by overrideable methods is not specified. See <i>Effective Java</i> * specified. See <i>Effective Java</i> Item 17,
* Item 17, "Design and Document or inheritance or else prohibit it" for further * "Design and Document or inheritance or else prohibit it" for further information.
* information.
*/ */
public class JSONTokener { public class JSONTokener {
/** The input JSON. */ /**
* The input JSON.
*/
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
* the input is exhausted, this equals the input's length. * exhausted, this equals the input's length.
*/ */
private int pos; private int pos;
/** /**
* @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
* tokener that throws {@code NullPointerExceptions} when methods are * throws {@code NullPointerExceptions} when methods are called.
* called.
*/ */
public JSONTokener(String in) { public JSONTokener(String in) {
// consume an optional byte order mark (BOM) if it exists // consume an optional byte order mark (BOM) if it exists
@ -85,30 +84,29 @@ public class JSONTokener {
/** /**
* Returns the next value from the input. * Returns the next value from the input.
* * @return a {@link JSONObject}, {@link JSONArray}, String, Boolean, Integer, Long,
* @return a {@link JSONObject}, {@link JSONArray}, String, Boolean, * Double or {@link JSONObject#NULL}.
* Integer, Long, Double or {@link JSONObject#NULL}.
* @throws JSONException if the input is malformed. * @throws JSONException if the input is malformed.
*/ */
public Object nextValue() throws JSONException { public Object nextValue() throws JSONException {
int c = nextCleanInternal(); int c = nextCleanInternal();
switch (c) { switch (c) {
case -1: case -1:
throw syntaxError("End of input"); throw syntaxError("End of input");
case '{': case '{':
return readObject(); return readObject();
case '[': case '[':
return readArray(); return readArray();
case '\'': case '\'':
case '"': case '"':
return nextString((char) c); return nextString((char) c);
default: default:
this.pos--; this.pos--;
return readLiteral(); return readLiteral();
} }
} }
@ -116,50 +114,50 @@ public class JSONTokener {
while (this.pos < this.in.length()) { while (this.pos < this.in.length()) {
int c = this.in.charAt(this.pos++); int c = this.in.charAt(this.pos++);
switch (c) { switch (c) {
case '\t': case '\t':
case ' ': case ' ':
case '\n': case '\n':
case '\r': case '\r':
continue; continue;
case '/': case '/':
if (this.pos == this.in.length()) { if (this.pos == this.in.length()) {
return c; return c;
} }
char peek = this.in.charAt(this.pos); char peek = this.in.charAt(this.pos);
switch (peek) { switch (peek) {
case '*': case '*':
// skip a /* c-style comment */ // skip a /* c-style comment */
this.pos++; this.pos++;
int commentEnd = this.in.indexOf("*/", this.pos); int commentEnd = this.in.indexOf("*/", this.pos);
if (commentEnd == -1) { if (commentEnd == -1) {
throw syntaxError("Unterminated comment"); throw syntaxError("Unterminated comment");
}
this.pos = commentEnd + 2;
continue;
case '/':
// skip a // end-of-line comment
this.pos++;
skipToEndOfLine();
continue;
default:
return c;
} }
this.pos = commentEnd + 2;
continue;
case '#': case '/':
/* // skip a // end-of-line comment
* Skip a # hash end-of-line comment. The JSON RFC doesn't this.pos++;
* specify this behavior, but it's required to parse
* existing documents. See http://b/2571423.
*/
skipToEndOfLine(); skipToEndOfLine();
continue; continue;
default: default:
return c; return c;
}
case '#':
/*
* Skip a # hash end-of-line comment. The JSON RFC doesn't specify this
* behavior, but it's required to parse existing documents. See
* http://b/2571423.
*/
skipToEndOfLine();
continue;
default:
return c;
} }
} }
@ -167,9 +165,8 @@ public class JSONTokener {
} }
/** /**
* Advances the position until after the next newline character. If the line * Advances the position until after the next newline character. If the line is
* is terminated by "\r\n", the '\n' must be consumed as whitespace by the * terminated by "\r\n", the '\n' must be consumed as whitespace by the caller.
* caller.
*/ */
private void skipToEndOfLine() { private void skipToEndOfLine() {
for (; this.pos < this.in.length(); this.pos++) { for (; this.pos < this.in.length(); this.pos++) {
@ -182,22 +179,20 @@ public class JSONTokener {
} }
/** /**
* Returns the string up to but not including {@code quote}, unescaping any * Returns the string up to but not including {@code quote}, unescaping any character
* character escape sequences encountered along the way. The opening quote * escape sequences encountered along the way. The opening quote should have already
* should have already been read. This consumes the closing quote, but does * been read. This consumes the closing quote, but does not include it in the returned
* not include it in the returned string. * string.
*
* @param quote either ' or ". * @param quote either ' or ".
* @return the string up to but not including {@code quote} * @return the string up to but not including {@code quote}
* @throws NumberFormatException if any unicode escape sequences are * @throws NumberFormatException if any unicode escape sequences are malformed.
* malformed.
* @throws JSONException if processing of json failed * @throws JSONException if processing of json failed
*/ */
public String nextString(char quote) throws JSONException { public String nextString(char quote) throws JSONException {
/* /*
* For strings that are free of escape sequences, we can just extract * For strings that are free of escape sequences, we can just extract the result
* the result as a substring of the input. But if we encounter an escape * as a substring of the input. But if we encounter an escape sequence, we need to
* sequence, we need to use a StringBuilder to compose the result. * use a StringBuilder to compose the result.
*/ */
StringBuilder builder = null; StringBuilder builder = null;
@ -234,54 +229,50 @@ public class JSONTokener {
} }
/** /**
* Unescapes the character identified by the character or characters that * Unescapes the character identified by the character or characters that immediately
* immediately follow a backslash. The backslash '\' should have already * follow a backslash. The backslash '\' should have already been read. This supports
* been read. This supports both unicode escapes "u000A" and two-character * both unicode escapes "u000A" and two-character escapes "\n".
* escapes "\n".
*
* @return the unescaped char * @return the unescaped char
* @throws NumberFormatException if any unicode escape sequences are * @throws NumberFormatException if any unicode escape sequences are malformed.
* malformed.
* @throws JSONException if processing of json failed * @throws JSONException if processing of json failed
*/ */
private char readEscapeCharacter() throws JSONException { private char readEscapeCharacter() throws JSONException {
char escaped = this.in.charAt(this.pos++); char escaped = this.in.charAt(this.pos++);
switch (escaped) { switch (escaped) {
case 'u': case 'u':
if (this.pos + 4 > this.in.length()) { if (this.pos + 4 > this.in.length()) {
throw syntaxError("Unterminated escape sequence"); throw syntaxError("Unterminated escape sequence");
} }
String hex = this.in.substring(this.pos, this.pos + 4); String hex = this.in.substring(this.pos, this.pos + 4);
this.pos += 4; this.pos += 4;
return (char) Integer.parseInt(hex, 16); return (char) Integer.parseInt(hex, 16);
case 't': case 't':
return '\t'; return '\t';
case 'b': case 'b':
return '\b'; return '\b';
case 'n': case 'n':
return '\n'; return '\n';
case 'r': case 'r':
return '\r'; return '\r';
case 'f': case 'f':
return '\f'; return '\f';
case '\'': case '\'':
case '"': case '"':
case '\\': case '\\':
default: default:
return escaped; return escaped;
} }
} }
/** /**
* Reads a null, boolean, numeric or unquoted string literal value. Numeric * Reads a null, boolean, numeric or unquoted string literal value. Numeric values
* values will be returned as an Integer, Long, or Double, in that order of * will be returned as an Integer, Long, or Double, in that order of preference.
* preference.
* @return a literal value * @return a literal value
* @throws JSONException if processing of json failed * @throws JSONException if processing of json failed
*/ */
@ -324,9 +315,9 @@ public class JSONTokener {
} }
catch (NumberFormatException e) { catch (NumberFormatException e) {
/* /*
* This only happens for integral numbers greater than * This only happens for integral numbers greater than Long.MAX_VALUE,
* Long.MAX_VALUE, numbers in exponential form (5e-10) and * numbers in exponential form (5e-10) and unquoted strings. Fall through
* unquoted strings. Fall through to try floating point. * to try floating point.
*/ */
} }
} }
@ -343,10 +334,10 @@ 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
* a newline character. This does not consume the excluded character. * character. This does not consume the excluded character.
* @return the string up to but not including any of the given characters or * @return the string up to but not including any of the given characters or a newline
* a newline character * character
*/ */
private String nextToInternal(String excluded) { private String nextToInternal(String excluded) {
int start = this.pos; int start = this.pos;
@ -360,8 +351,8 @@ 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
* an object. The opening brace '{' should have already been read. * object. The opening brace '{' should have already been read.
* @return an object * @return an object
* @throws JSONException if processing of json failed * @throws JSONException if processing of json failed
*/ */
@ -390,9 +381,9 @@ public class JSONTokener {
} }
/* /*
* Expect the name/value separator to be either a colon ':', an * Expect the name/value separator to be either a colon ':', an equals sign
* equals sign '=', or an arrow "=>". The last two are bogus but we * '=', or an arrow "=>". The last two are bogus but we include them because
* include them because that's what the original implementation did. * that's what the original implementation did.
*/ */
int separator = nextCleanInternal(); int separator = nextCleanInternal();
if (separator != ':' && separator != '=') { if (separator != ':' && separator != '=') {
@ -405,22 +396,21 @@ public class JSONTokener {
result.put((String) name, nextValue()); result.put((String) name, nextValue());
switch (nextCleanInternal()) { switch (nextCleanInternal()) {
case '}': case '}':
return result; return result;
case ';': case ';':
case ',': case ',':
continue; continue;
default: default:
throw syntaxError("Unterminated object"); throw syntaxError("Unterminated object");
} }
} }
} }
/** /**
* Reads a sequence of values and the trailing closing brace ']' of an * Reads a sequence of values and the trailing closing brace ']' of an array. The
* array. The opening brace '[' should have already been read. Note that * opening brace '[' should have already been read. Note that "[]" yields an empty
* "[]" yields an empty array, but "[,]" returns a two-element array * array, but "[,]" returns a two-element array equivalent to "[null,null]".
* equivalent to "[null,null]".
* @return an array * @return an array
* @throws JSONException if processing of json failed * @throws JSONException if processing of json failed
*/ */
@ -432,41 +422,41 @@ public class JSONTokener {
while (true) { while (true) {
switch (nextCleanInternal()) { switch (nextCleanInternal()) {
case -1: case -1:
throw syntaxError("Unterminated array"); throw syntaxError("Unterminated array");
case ']': case ']':
if (hasTrailingSeparator) { if (hasTrailingSeparator) {
result.put(null);
}
return result;
case ',':
case ';':
/* A separator without a value first means "null". */
result.put(null); result.put(null);
hasTrailingSeparator = true; }
continue; return result;
default: case ',':
this.pos--; case ';':
/* A separator without a value first means "null". */
result.put(null);
hasTrailingSeparator = true;
continue;
default:
this.pos--;
} }
result.put(nextValue()); result.put(nextValue());
switch (nextCleanInternal()) { switch (nextCleanInternal()) {
case ']': case ']':
return result; return result;
case ',': case ',':
case ';': case ';':
hasTrailingSeparator = true; hasTrailingSeparator = true;
continue; continue;
default: default:
throw syntaxError("Unterminated array"); throw syntaxError("Unterminated array");
} }
} }
} }
/** /**
* Returns an exception containing the given message plus the current * Returns an exception containing the given message plus the current position and the
* position and the entire input string. * entire input string.
* @param message the message * @param message the message
* @return an exception * @return an exception
*/ */
@ -487,9 +477,9 @@ public class JSONTokener {
/* /*
* Legacy APIs. * Legacy APIs.
* *
* None of the methods below are on the critical path of parsing JSON * None of the methods below are on the critical path of parsing JSON documents. They
* documents. They exist only because they were exposed by the original * exist only because they were exposed by the original implementation and may be used
* implementation and may be used by some clients. * by some clients.
*/ */
public boolean more() { public boolean more() {
@ -569,4 +559,5 @@ public class JSONTokener {
return -1; return -1;
} }
} }
} }
Loading…
Cancel
Save