diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/json/JSON.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/json/JSON.java index 607f3d87b34..9b1af91d77b 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/json/JSON.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/json/JSON.java @@ -17,100 +17,114 @@ package org.springframework.boot.configurationprocessor.json; class JSON { - /** - * Returns the input if it is a JSON-permissible value; throws otherwise. - */ - static double checkDouble(double d) throws JSONException { - if (Double.isInfinite(d) || Double.isNaN(d)) { - throw new JSONException("Forbidden numeric value: " + d); - } - return d; - } + /** + * Returns the input if it is a JSON-permissible value; throws otherwise. + */ + static double checkDouble(double d) throws JSONException { + if (Double.isInfinite(d) || Double.isNaN(d)) { + throw new JSONException("Forbidden numeric value: " + d); + } + return d; + } - static Boolean toBoolean(Object value) { - if (value instanceof Boolean) { - return (Boolean) value; - } else if (value instanceof String) { - String stringValue = (String) value; - if ("true".equalsIgnoreCase(stringValue)) { - return true; - } else if ("false".equalsIgnoreCase(stringValue)) { - return false; - } - } - return null; - } + static Boolean toBoolean(Object value) { + if (value instanceof Boolean) { + return (Boolean) value; + } + else if (value instanceof String) { + String stringValue = (String) value; + if ("true".equalsIgnoreCase(stringValue)) { + return true; + } + else if ("false".equalsIgnoreCase(stringValue)) { + return false; + } + } + return null; + } - static Double toDouble(Object value) { - if (value instanceof Double) { - return (Double) value; - } else if (value instanceof Number) { - return ((Number) value).doubleValue(); - } else if (value instanceof String) { - try { - return Double.valueOf((String) value); - } catch (NumberFormatException ignored) { - } - } - return null; - } + static Double toDouble(Object value) { + if (value instanceof Double) { + return (Double) value; + } + else if (value instanceof Number) { + return ((Number) value).doubleValue(); + } + else if (value instanceof String) { + try { + return Double.valueOf((String) value); + } + catch (NumberFormatException ignored) { + } + } + return null; + } - static Integer toInteger(Object value) { - if (value instanceof Integer) { - return (Integer) value; - } else if (value instanceof Number) { - return ((Number) value).intValue(); - } else if (value instanceof String) { - try { - return (int) Double.parseDouble((String) value); - } catch (NumberFormatException ignored) { - } - } - return null; - } + static Integer toInteger(Object value) { + if (value instanceof Integer) { + return (Integer) value; + } + else if (value instanceof Number) { + return ((Number) value).intValue(); + } + else if (value instanceof String) { + try { + return (int) Double.parseDouble((String) value); + } + catch (NumberFormatException ignored) { + } + } + return null; + } - static Long toLong(Object value) { - if (value instanceof Long) { - return (Long) value; - } else if (value instanceof Number) { - return ((Number) value).longValue(); - } else if (value instanceof String) { - try { - return (long) Double.parseDouble((String) value); - } catch (NumberFormatException ignored) { - } - } - return null; - } + static Long toLong(Object value) { + if (value instanceof Long) { + return (Long) value; + } + else if (value instanceof Number) { + return ((Number) value).longValue(); + } + else if (value instanceof String) { + try { + return (long) Double.parseDouble((String) value); + } + catch (NumberFormatException ignored) { + } + } + return null; + } - static String toString(Object value) { - if (value instanceof String) { - return (String) value; - } else if (value != null) { - return String.valueOf(value); - } - return null; - } + static String toString(Object value) { + if (value instanceof String) { + return (String) value; + } + else if (value != null) { + return String.valueOf(value); + } + return null; + } - public static JSONException typeMismatch(Object indexOrName, Object actual, - String requiredType) throws JSONException { - if (actual == null) { - throw new JSONException("Value at " + indexOrName + " is null."); - } else { - throw new JSONException("Value " + actual + " at " + indexOrName - + " of type " + actual.getClass().getName() - + " cannot be converted to " + requiredType); - } - } + public static JSONException typeMismatch(Object indexOrName, Object actual, + String requiredType) throws JSONException { + if (actual == null) { + throw new JSONException("Value at " + indexOrName + " is null."); + } + else { + throw new JSONException("Value " + actual + " at " + indexOrName + + " of type " + actual.getClass().getName() + + " cannot be converted to " + requiredType); + } + } - public static JSONException typeMismatch(Object actual, String requiredType) - throws JSONException { - if (actual == null) { - throw new JSONException("Value is null."); - } else { - throw new JSONException("Value " + actual - + " of type " + actual.getClass().getName() - + " cannot be converted to " + requiredType); - } - } + public static JSONException typeMismatch(Object actual, String requiredType) + throws JSONException { + if (actual == null) { + throw new JSONException("Value is null."); + } + else { + throw new JSONException("Value " + actual + + " of type " + actual.getClass().getName() + + " cannot be converted to " + requiredType); + } + } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/json/JSONArray.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/json/JSONArray.java index 25a2a7bfa2b..20cc6cb58cc 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/json/JSONArray.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/json/JSONArray.java @@ -48,568 +48,643 @@ import java.util.List; */ public class JSONArray { - private final List values; + private final List values; - /** - * Creates a {@code JSONArray} with no values. - */ - public JSONArray() { - values = new ArrayList(); - } + /** + * Creates a {@code JSONArray} with no values. + */ + public JSONArray() { + this.values = new ArrayList(); + } - /** - * Creates a new {@code JSONArray} by copying all values from the given - * 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. - */ - /* Accept a raw type for API compatibility */ - public JSONArray(Collection copyFrom) { - this(); - if (copyFrom != null) { - for (Iterator it = copyFrom.iterator(); it.hasNext();) { - put(JSONObject.wrap(it.next())); - } - } - } + /** + * Creates a new {@code JSONArray} by copying all values from the given + * 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. + */ + /* Accept a raw type for API compatibility */ + public JSONArray(Collection copyFrom) { + this(); + if (copyFrom != null) { + for (Iterator it = copyFrom.iterator(); it.hasNext(); ) { + put(JSONObject.wrap(it.next())); + } + } + } - /** - * Creates a new {@code JSONArray} with values from the next array in the - * 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}. - */ - public JSONArray(JSONTokener readFrom) throws JSONException { - /* - * Getting the parser to populate this could get tricky. Instead, just - * parse to temporary JSONArray and then steal the data from that. - */ - Object object = readFrom.nextValue(); - if (object instanceof JSONArray) { - values = ((JSONArray) object).values; - } else { - throw JSON.typeMismatch(object, "JSONArray"); - } - } + /** + * Creates a new {@code JSONArray} with values from the next array in the + * 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}. + * @throws JSONException if processing of json failed + */ + public JSONArray(JSONTokener readFrom) throws JSONException { + /* + * Getting the parser to populate this could get tricky. Instead, just + * parse to temporary JSONArray and then steal the data from that. + */ + Object object = readFrom.nextValue(); + if (object instanceof JSONArray) { + this.values = ((JSONArray) object).values; + } + else { + throw JSON.typeMismatch(object, "JSONArray"); + } + } - /** - * Creates a new {@code JSONArray} with values from the JSON string. - * - * @param json a JSON-encoded string containing an array. - * @throws JSONException if the parse fails or doesn't yield a {@code - * JSONArray}. - */ - public JSONArray(String json) throws JSONException { - this(new JSONTokener(json)); - } + /** + * Creates a new {@code JSONArray} with values from the JSON string. + * + * @param json a JSON-encoded string containing an array. + * @throws JSONException if the parse fails or doesn't yield a {@code + * JSONArray}. + */ + public JSONArray(String json) throws JSONException { + this(new JSONTokener(json)); + } - /** - * Creates a new {@code JSONArray} with values from the given primitive array. - */ - public JSONArray(Object array) throws JSONException { - if (!array.getClass().isArray()) { - throw new JSONException("Not a primitive array: " + array.getClass()); - } - final int length = Array.getLength(array); - values = new ArrayList(length); - for (int i = 0; i < length; ++i) { - put(JSONObject.wrap(Array.get(array, i))); - } - } + /** + * Creates a new {@code JSONArray} with values from the given primitive array. + * @param array a primitive array + * @throws JSONException if processing of json failed + */ + public JSONArray(Object array) throws JSONException { + if (!array.getClass().isArray()) { + throw new JSONException("Not a primitive array: " + array.getClass()); + } + final int length = Array.getLength(array); + this.values = new ArrayList(length); + for (int i = 0; i < length; ++i) { + put(JSONObject.wrap(Array.get(array, i))); + } + } - /** - * Returns the number of values in this array. - */ - public int length() { - return values.size(); - } + /** + * Returns the number of values in this array. + * @return the length of this array + */ + public int length() { + return this.values.size(); + } - /** - * Appends {@code value} to the end of this array. - * - * @return this array. - */ - public JSONArray put(boolean value) { - values.add(value); - return this; - } + /** + * Appends {@code value} to the end of this array. + * + * @param value the value + * @return this array. + */ + public JSONArray put(boolean value) { + this.values.add(value); + return this; + } - /** - * Appends {@code value} to the end of this array. - * - * @param value a finite value. May not be {@link Double#isNaN() NaNs} or - * {@link Double#isInfinite() infinities}. - * @return this array. - */ - public JSONArray put(double value) throws JSONException { - values.add(JSON.checkDouble(value)); - return this; - } + /** + * Appends {@code value} to the end of this array. + * + * @param value a finite value. May not be {@link Double#isNaN() NaNs} or + * {@link Double#isInfinite() infinities}. + * @return this array. + * @throws JSONException if processing of json failed + */ + public JSONArray put(double value) throws JSONException { + this.values.add(JSON.checkDouble(value)); + return this; + } - /** - * Appends {@code value} to the end of this array. - * - * @return this array. - */ - public JSONArray put(int value) { - values.add(value); - return this; - } + /** + * Appends {@code value} to the end of this array. + * @param value the value + * @return this array. + */ + public JSONArray put(int value) { + this.values.add(value); + return this; + } - /** - * Appends {@code value} to the end of this array. - * - * @return this array. - */ - public JSONArray put(long value) { - values.add(value); - return this; - } + /** + * Appends {@code value} to the end of this array. + * @param value the value + * @return this array. + */ + public JSONArray put(long value) { + this.values.add(value); + return this; + } - /** - * Appends {@code value} to the end of this array. - * - * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, - * Integer, Long, Double, {@link JSONObject#NULL}, or {@code null}. May - * not be {@link Double#isNaN() NaNs} or {@link Double#isInfinite() - * infinities}. Unsupported values are not permitted and will cause the - * array to be in an inconsistent state. - * @return this array. - */ - public JSONArray put(Object value) { - values.add(value); - return this; - } + /** + * Appends {@code value} to the end of this array. + * + * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, + * Integer, Long, Double, {@link JSONObject#NULL}, or {@code null}. May + * not be {@link Double#isNaN() NaNs} or {@link Double#isInfinite() + * infinities}. Unsupported values are not permitted and will cause the + * array to be in an inconsistent state. + * @return this array. + */ + public JSONArray put(Object value) { + this.values.add(value); + return this; + } - /** - * Sets the value at {@code index} to {@code value}, null padding this array - * to the required length if necessary. If a value already exists at {@code - * index}, it will be replaced. - * - * @return this array. - */ - public JSONArray put(int index, boolean value) throws JSONException { - return put(index, (Boolean) value); - } + /** + * Sets the value at {@code index} to {@code value}, null padding this array + * to the required length if necessary. If a value already exists at {@code + * index}, it will be replaced. + * @param index the index to set the value to + * @param value the value + * @return this array. + * @throws JSONException if processing of json failed + */ + public JSONArray put(int index, boolean value) throws JSONException { + return put(index, (Boolean) value); + } - /** - * Sets the value at {@code index} to {@code value}, null padding this array - * to the required length if necessary. If a value already exists at {@code - * index}, it will be replaced. - * - * @param value a finite value. May not be {@link Double#isNaN() NaNs} or - * {@link Double#isInfinite() infinities}. - * @return this array. - */ - public JSONArray put(int index, double value) throws JSONException { - return put(index, (Double) value); - } + /** + * Sets the value at {@code index} to {@code value}, null padding this array + * to the required length if necessary. If a value already exists at {@code + * index}, it will be replaced. + * @param index the index to set the value to + * @param value a finite value. May not be {@link Double#isNaN() NaNs} or + * {@link Double#isInfinite() infinities}. + * @return this array. + * @throws JSONException if processing of json failed + */ + public JSONArray put(int index, double value) throws JSONException { + return put(index, (Double) value); + } - /** - * Sets the value at {@code index} to {@code value}, null padding this array - * to the required length if necessary. If a value already exists at {@code - * index}, it will be replaced. - * - * @return this array. - */ - public JSONArray put(int index, int value) throws JSONException { - return put(index, (Integer) value); - } + /** + * Sets the value at {@code index} to {@code value}, null padding this array + * to the required length if necessary. If a value already exists at {@code + * index}, it will be replaced. + * @param index the index to set the value to + * @param value the value + * @return this array. + * @throws JSONException if processing of json failed + */ + public JSONArray put(int index, int value) throws JSONException { + return put(index, (Integer) value); + } - /** - * Sets the value at {@code index} to {@code value}, null padding this array - * to the required length if necessary. If a value already exists at {@code - * index}, it will be replaced. - * - * @return this array. - */ - public JSONArray put(int index, long value) throws JSONException { - return put(index, (Long) value); - } + /** + * Sets the value at {@code index} to {@code value}, null padding this array + * to the required length if necessary. If a value already exists at {@code + * index}, it will be replaced. + * @param index the index to set the value to + * @param value the value + * @return this array. + * @throws JSONException if processing of json failed + */ + public JSONArray put(int index, long value) throws JSONException { + return put(index, (Long) value); + } - /** - * Sets the value at {@code index} to {@code value}, null padding this array - * to the required length if necessary. If a value already exists at {@code - * index}, it will be replaced. - * - * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, - * Integer, Long, Double, {@link JSONObject#NULL}, or {@code null}. May - * not be {@link Double#isNaN() NaNs} or {@link Double#isInfinite() - * infinities}. - * @return this array. - */ - public JSONArray put(int index, Object value) throws JSONException { - if (value instanceof Number) { - // deviate from the original by checking all Numbers, not just floats & doubles - JSON.checkDouble(((Number) value).doubleValue()); - } - while (values.size() <= index) { - values.add(null); - } - values.set(index, value); - return this; - } + /** + * Sets the value at {@code index} to {@code value}, null padding this array + * to the required length if necessary. If a value already exists at {@code + * index}, it will be replaced. + * @param index the index to set the value to + * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, + * Integer, Long, Double, {@link JSONObject#NULL}, or {@code null}. May + * not be {@link Double#isNaN() NaNs} or {@link Double#isInfinite() + * infinities}. + * @return this array. + * @throws JSONException if processing of json failed + */ + public JSONArray put(int index, Object value) throws JSONException { + if (value instanceof Number) { + // deviate from the original by checking all Numbers, not just floats & doubles + JSON.checkDouble(((Number) value).doubleValue()); + } + while (this.values.size() <= index) { + this.values.add(null); + } + this.values.set(index, value); + return this; + } - /** - * Returns true if this array has no value at {@code index}, or if its value - * is the {@code null} reference or {@link JSONObject#NULL}. - */ - public boolean isNull(int index) { - Object value = opt(index); - return value == null || value == JSONObject.NULL; - } + /** + * Returns true if this array has no value at {@code index}, or if its value + * is the {@code null} reference or {@link JSONObject#NULL}. + * @param index the index to set the value to + * @return true if this array has no value at {@code index} + */ + public boolean isNull(int index) { + Object value = opt(index); + return value == null || value == JSONObject.NULL; + } - /** - * Returns the value at {@code index}. - * - * @throws JSONException if this array has no value at {@code index}, or if - * that value is the {@code null} reference. This method returns - * normally if the value is {@code JSONObject#NULL}. - */ - public Object get(int index) throws JSONException { - try { - Object value = values.get(index); - if (value == null) { - throw new JSONException("Value at " + index + " is null."); - } - return value; - } catch (IndexOutOfBoundsException e) { - throw new JSONException("Index " + index + " out of range [0.." + values.size() + ")"); - } - } + /** + * Returns the value at {@code index}. + * @param index the index to get the value from + * @return the value at {@code index}. + * @throws JSONException if this array has no value at {@code index}, or if + * that value is the {@code null} reference. This method returns + * normally if the value is {@code JSONObject#NULL}. + */ + public Object get(int index) throws JSONException { + try { + Object value = this.values.get(index); + if (value == null) { + throw new JSONException("Value at " + index + " is null."); + } + return value; + } + catch (IndexOutOfBoundsException e) { + 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 - * at {@code index}. - */ - public Object opt(int index) { - if (index < 0 || index >= values.size()) { - return null; - } - return values.get(index); - } + /** + * Returns the value at {@code index}, or null if the array has no value + * at {@code index}. + * @param index the index to get the value from + * @return the value at {@code index} or {@code null} + */ + public Object opt(int index) { + if (index < 0 || index >= this.values.size()) { + return null; + } + return this.values.get(index); + } - /** - * Removes and returns the value at {@code index}, or null if the array has no value - * at {@code index}. - */ - public Object remove(int index) { - if (index < 0 || index >= values.size()) { - return null; - } - return values.remove(index); - } + /** + * Removes and returns the value at {@code index}, or null if the array has no value + * at {@code index}. + * @param index the index of the value to remove + * @return the previous value at {@code index} + */ + public Object remove(int index) { + if (index < 0 || index >= this.values.size()) { + return null; + } + return this.values.remove(index); + } - /** - * Returns the value at {@code index} if it exists and is a boolean or can - * be coerced to a boolean. - * - * @throws JSONException if the value at {@code index} doesn't exist or - * cannot be coerced to a boolean. - */ - public boolean getBoolean(int index) throws JSONException { - Object object = get(index); - Boolean result = JSON.toBoolean(object); - if (result == null) { - throw JSON.typeMismatch(index, object, "boolean"); - } - return result; - } + /** + * Returns the value at {@code index} if it exists and is a boolean or can + * be coerced to a boolean. + * @param index the index to get the value from + * @return the value at {@code index} + * @throws JSONException if the value at {@code index} doesn't exist or + * cannot be coerced to a boolean. + */ + public boolean getBoolean(int index) throws JSONException { + Object object = get(index); + Boolean result = JSON.toBoolean(object); + if (result == null) { + throw JSON.typeMismatch(index, object, "boolean"); + } + return result; + } - /** - * Returns the value at {@code index} if it exists and is a boolean or can - * be coerced to a boolean. Returns false otherwise. - */ - public boolean optBoolean(int index) { - return optBoolean(index, false); - } + /** + * Returns the value at {@code index} if it exists and is a boolean or can + * be coerced to a boolean. Returns false otherwise. + * @param index the index to get the value from + * @return the {@code value} or {@code false} + */ + public boolean optBoolean(int index) { + return optBoolean(index, false); + } - /** - * Returns the value at {@code index} if it exists and is a boolean or can - * be coerced to a boolean. Returns {@code fallback} otherwise. - */ - public boolean optBoolean(int index, boolean fallback) { - Object object = opt(index); - Boolean result = JSON.toBoolean(object); - return result != null ? result : fallback; - } + /** + * Returns the value at {@code index} if it exists and is a boolean or can + * be coerced to a boolean. Returns {@code fallback} otherwise. + * @param index the index to get the value from + * @param fallback the fallback value + * @return the value at {@code index} of {@code fallback} + */ + public boolean optBoolean(int index, boolean fallback) { + Object object = opt(index); + Boolean result = JSON.toBoolean(object); + return result != null ? result : fallback; + } - /** - * Returns the value at {@code index} if it exists and is a double or can - * be coerced to a double. - * - * @throws JSONException if the value at {@code index} doesn't exist or - * cannot be coerced to a double. - */ - public double getDouble(int index) throws JSONException { - Object object = get(index); - Double result = JSON.toDouble(object); - if (result == null) { - throw JSON.typeMismatch(index, object, "double"); - } - return result; - } + /** + * Returns the value at {@code index} if it exists and is a double or can + * be coerced to a double. + * @param index the index to get the value from + * @return the {@code value} + * @throws JSONException if the value at {@code index} doesn't exist or + * cannot be coerced to a double. + */ + public double getDouble(int index) throws JSONException { + Object object = get(index); + Double result = JSON.toDouble(object); + if (result == null) { + throw JSON.typeMismatch(index, object, "double"); + } + return result; + } - /** - * Returns the value at {@code index} if it exists and is a double or can - * be coerced to a double. Returns {@code NaN} otherwise. - */ - public double optDouble(int index) { - return optDouble(index, Double.NaN); - } + /** + * Returns the value at {@code index} if it exists and is a double or can + * be coerced to a double. Returns {@code NaN} otherwise. + * @param index the index to get the value from + * @return the {@code value} or {@code NaN} + */ + public double optDouble(int index) { + return optDouble(index, Double.NaN); + } - /** - * Returns the value at {@code index} if it exists and is a double or can - * be coerced to a double. Returns {@code fallback} otherwise. - */ - public double optDouble(int index, double fallback) { - Object object = opt(index); - Double result = JSON.toDouble(object); - return result != null ? result : fallback; - } + /** + * Returns the value at {@code index} if it exists and is a double or can + * be coerced to a double. Returns {@code fallback} otherwise. + * @param index the index to get the value from + * @param fallback the fallback value + * @return the value at {@code index} of {@code fallback} + */ + public double optDouble(int index, double fallback) { + Object object = opt(index); + Double result = JSON.toDouble(object); + return result != null ? result : fallback; + } - /** - * Returns the value at {@code index} if it exists and is an int or - * can be coerced to an int. - * - * @throws JSONException if the value at {@code index} doesn't exist or - * cannot be coerced to a int. - */ - public int getInt(int index) throws JSONException { - Object object = get(index); - Integer result = JSON.toInteger(object); - if (result == null) { - throw JSON.typeMismatch(index, object, "int"); - } - return result; - } + /** + * Returns the value at {@code index} if it exists and is an int or + * can be coerced to an int. + * @param index the index to get the value from + * @return the {@code value} + * @throws JSONException if the value at {@code index} doesn't exist or + * cannot be coerced to a int. + */ + public int getInt(int index) throws JSONException { + Object object = get(index); + Integer result = JSON.toInteger(object); + if (result == null) { + throw JSON.typeMismatch(index, object, "int"); + } + return result; + } - /** - * Returns the value at {@code index} if it exists and is an int or - * can be coerced to an int. Returns 0 otherwise. - */ - public int optInt(int index) { - return optInt(index, 0); - } + /** + * Returns the value at {@code index} if it exists and is an int or + * can be coerced to an int. Returns 0 otherwise. + * @param index the index to get the value from + * @return the {@code value} or {@code 0} + */ + public int optInt(int index) { + return optInt(index, 0); + } - /** - * Returns the value at {@code index} if it exists and is an int or - * can be coerced to an int. Returns {@code fallback} otherwise. - */ - public int optInt(int index, int fallback) { - Object object = opt(index); - Integer result = JSON.toInteger(object); - return result != null ? result : fallback; - } + /** + * Returns the value at {@code index} if it exists and is an int or + * can be coerced to an int. Returns {@code fallback} otherwise. + * @param index the index to get the value from + * @param fallback the fallback value + * @return the value at {@code index} of {@code fallback} + */ + public int optInt(int index, int fallback) { + Object object = opt(index); + Integer result = JSON.toInteger(object); + return result != null ? result : fallback; + } - /** - * Returns the value at {@code index} if it exists and is a long or - * can be coerced to a long. - * - * @throws JSONException if the value at {@code index} doesn't exist or - * cannot be coerced to a long. - */ - public long getLong(int index) throws JSONException { - Object object = get(index); - Long result = JSON.toLong(object); - if (result == null) { - throw JSON.typeMismatch(index, object, "long"); - } - return result; - } + /** + * Returns the value at {@code index} if it exists and is a long or + * can be coerced to a long. + * @param index the index to get the value from + * @return the {@code value} + * + * @throws JSONException if the value at {@code index} doesn't exist or + * cannot be coerced to a long. + */ + public long getLong(int index) throws JSONException { + Object object = get(index); + Long result = JSON.toLong(object); + if (result == null) { + throw JSON.typeMismatch(index, object, "long"); + } + return result; + } - /** - * Returns the value at {@code index} if it exists and is a long or - * can be coerced to a long. Returns 0 otherwise. - */ - public long optLong(int index) { - return optLong(index, 0L); - } + /** + * Returns the value at {@code index} if it exists and is a long or + * can be coerced to a long. Returns 0 otherwise. + * @param index the index to get the value from + * @return the {@code value} or {@code 0} + */ + public long optLong(int index) { + return optLong(index, 0L); + } - /** - * Returns the value at {@code index} if it exists and is a long or - * can be coerced to a long. Returns {@code fallback} otherwise. - */ - public long optLong(int index, long fallback) { - Object object = opt(index); - Long result = JSON.toLong(object); - return result != null ? result : fallback; - } + /** + * Returns the value at {@code index} if it exists and is a long or + * can be coerced to a long. Returns {@code fallback} otherwise. + * @param index the index to get the value from + * @param fallback the fallback value + * @return the value at {@code index} of {@code fallback} + */ + public long optLong(int index, long fallback) { + Object object = opt(index); + Long result = JSON.toLong(object); + return result != null ? result : fallback; + } - /** - * Returns the value at {@code index} if it exists, coercing it if - * necessary. - * - * @throws JSONException if no such value exists. - */ - public String getString(int index) throws JSONException { - Object object = get(index); - String result = JSON.toString(object); - if (result == null) { - throw JSON.typeMismatch(index, object, "String"); - } - return result; - } + /** + * Returns the value at {@code index} if it exists, coercing it if + * necessary. + * @param index the index to get the value from + * @return the {@code value} + * @throws JSONException if no such value exists. + */ + public String getString(int index) throws JSONException { + Object object = get(index); + String result = JSON.toString(object); + if (result == null) { + throw JSON.typeMismatch(index, object, "String"); + } + return result; + } - /** - * Returns the value at {@code index} if it exists, coercing it if - * necessary. Returns the empty string if no such value exists. - */ - public String optString(int index) { - return optString(index, ""); - } + /** + * Returns the value at {@code index} if it exists, coercing it if + * necessary. Returns the empty string if no such value exists. + * @param index the index to get the value from + * @return the {@code value} or an empty string + */ + public String optString(int index) { + return optString(index, ""); + } - /** - * Returns the value at {@code index} if it exists, coercing it if - * necessary. Returns {@code fallback} if no such value exists. - */ - public String optString(int index, String fallback) { - Object object = opt(index); - String result = JSON.toString(object); - return result != null ? result : fallback; - } + /** + * Returns the value at {@code index} if it exists, coercing it if + * necessary. Returns {@code fallback} if no such value exists. + * @param index the index to get the value from + * @param fallback the fallback value + * @return the value at {@code index} of {@code fallback} + */ + public String optString(int index, String fallback) { + Object object = opt(index); + String result = JSON.toString(object); + return result != null ? result : fallback; + } - /** - * Returns the value at {@code index} if it exists and is a {@code - * JSONArray}. - * - * @throws JSONException if the value doesn't exist or is not a {@code - * JSONArray}. - */ - public JSONArray getJSONArray(int index) throws JSONException { - Object object = get(index); - if (object instanceof JSONArray) { - return (JSONArray) object; - } else { - throw JSON.typeMismatch(index, object, "JSONArray"); - } - } + /** + * Returns the value at {@code index} if it exists and is a {@code + * JSONArray}. + * @param index the index to get the value from + * @return the array at {@code index} + * @throws JSONException if the value doesn't exist or is not a {@code + * JSONArray}. + */ + public JSONArray getJSONArray(int index) throws JSONException { + Object object = get(index); + if (object instanceof JSONArray) { + return (JSONArray) object; + } + else { + throw JSON.typeMismatch(index, object, "JSONArray"); + } + } - /** - * Returns the value at {@code index} if it exists and is a {@code - * JSONArray}. Returns null otherwise. - */ - public JSONArray optJSONArray(int index) { - Object object = opt(index); - return object instanceof JSONArray ? (JSONArray) object : null; - } + /** + * Returns the value at {@code index} if it exists and is a {@code + * JSONArray}. Returns null otherwise. + * @param index the index to get the value from + * @return the array at {@code index} or {@code null} + */ + public JSONArray optJSONArray(int index) { + Object object = opt(index); + return object instanceof JSONArray ? (JSONArray) object : null; + } - /** - * Returns the value at {@code index} if it exists and is a {@code - * JSONObject}. - * - * @throws JSONException if the value doesn't exist or is not a {@code - * JSONObject}. - */ - public JSONObject getJSONObject(int index) throws JSONException { - Object object = get(index); - if (object instanceof JSONObject) { - return (JSONObject) object; - } else { - throw JSON.typeMismatch(index, object, "JSONObject"); - } - } + /** + * Returns the value at {@code index} if it exists and is a {@code + * JSONObject}. + * @param index the index to get the value from + * @return the object at {@code index} + * @throws JSONException if the value doesn't exist or is not a {@code + * JSONObject}. + */ + public JSONObject getJSONObject(int index) throws JSONException { + Object object = get(index); + if (object instanceof JSONObject) { + return (JSONObject) object; + } + else { + throw JSON.typeMismatch(index, object, "JSONObject"); + } + } - /** - * Returns the value at {@code index} if it exists and is a {@code - * JSONObject}. Returns null otherwise. - */ - public JSONObject optJSONObject(int index) { - Object object = opt(index); - return object instanceof JSONObject ? (JSONObject) object : null; - } + /** + * Returns the value at {@code index} if it exists and is a {@code + * JSONObject}. Returns null otherwise. + * @param index the index to get the value from + * @return the object at {@code index} or {@code null} + */ + public JSONObject optJSONObject(int index) { + Object object = opt(index); + return object instanceof JSONObject ? (JSONObject) object : null; + } - /** - * Returns a new object whose values are the values in this array, and whose - * names are the values in {@code names}. Names and values are paired up by - * index from 0 through to the shorter array's length. Names that are not - * strings will be coerced to strings. This method returns null if either - * array is empty. - */ - public JSONObject toJSONObject(JSONArray names) throws JSONException { - JSONObject result = new JSONObject(); - int length = Math.min(names.length(), values.size()); - if (length == 0) { - return null; - } - for (int i = 0; i < length; i++) { - String name = JSON.toString(names.opt(i)); - result.put(name, opt(i)); - } - return result; - } + /** + * Returns a new object whose values are the values in this array, and whose + * names are the values in {@code names}. Names and values are paired up by + * index from 0 through to the shorter array's length. Names that are not + * strings will be coerced to strings. This method returns null if either + * array is empty. + * @param names the property names + * @return a json object + * @throws JSONException if processing of json failed + */ + public JSONObject toJSONObject(JSONArray names) throws JSONException { + JSONObject result = new JSONObject(); + int length = Math.min(names.length(), this.values.size()); + if (length == 0) { + return null; + } + for (int i = 0; i < length; i++) { + String name = JSON.toString(names.opt(i)); + result.put(name, opt(i)); + } + return result; + } - /** - * Returns a new string by alternating this array's values with {@code - * separator}. This array's string values are quoted and have their special - * characters escaped. For example, the array containing the strings '12" - * pizza', 'taco' and 'soda' joined on '+' returns this: - *
"12\" pizza"+"taco"+"soda"
- */ - public String join(String separator) throws JSONException { - JSONStringer stringer = new JSONStringer(); - stringer.open(JSONStringer.Scope.NULL, ""); - for (int i = 0, size = values.size(); i < size; i++) { - if (i > 0) { - stringer.out.append(separator); - } - stringer.value(values.get(i)); - } - stringer.close(JSONStringer.Scope.NULL, JSONStringer.Scope.NULL, ""); - return stringer.out.toString(); - } + /** + * Returns a new string by alternating this array's values with {@code + * separator}. This array's string values are quoted and have their special + * characters escaped. For example, the array containing the strings '12" + * pizza', 'taco' and 'soda' joined on '+' returns this: + *
"12\" pizza"+"taco"+"soda"
+ * @param separator the separator to use + * @return the joined value + * @throws JSONException if processing of json failed + */ + public String join(String separator) throws JSONException { + JSONStringer stringer = new JSONStringer(); + stringer.open(JSONStringer.Scope.NULL, ""); + for (int i = 0, size = this.values.size(); i < size; i++) { + if (i > 0) { + stringer.out.append(separator); + } + stringer.value(this.values.get(i)); + } + stringer.close(JSONStringer.Scope.NULL, JSONStringer.Scope.NULL, ""); + return stringer.out.toString(); + } - /** - * Encodes this array as a compact JSON string, such as: - *
[94043,90210]
- */ - @Override public String toString() { - try { - JSONStringer stringer = new JSONStringer(); - writeTo(stringer); - return stringer.toString(); - } catch (JSONException e) { - return null; - } - } + /** + * Encodes this array as a compact JSON string, such as: + *
[94043,90210]
+ * @return a compact JSON string representation of this array + */ + @Override + public String toString() { + try { + JSONStringer stringer = new JSONStringer(); + writeTo(stringer); + return stringer.toString(); + } + catch (JSONException e) { + return null; + } + } - /** - * Encodes this array as a human readable JSON string for debugging, such - * as: - *
-     * [
-     *     94043,
-     *     90210
-     * ]
- * - * @param indentSpaces the number of spaces to indent for each level of - * nesting. - */ - public String toString(int indentSpaces) throws JSONException { - JSONStringer stringer = new JSONStringer(indentSpaces); - writeTo(stringer); - return stringer.toString(); - } + /** + * Encodes this array as a human readable JSON string for debugging, such + * as: + *
+	 * [
+	 *     94043,
+	 *     90210
+	 * ]
+ * + * @param indentSpaces the number of spaces to indent for each level of + * nesting. + * @return a human readable JSON string of this array + * @throws JSONException if processing of json failed + */ + public String toString(int indentSpaces) throws JSONException { + JSONStringer stringer = new JSONStringer(indentSpaces); + writeTo(stringer); + return stringer.toString(); + } - void writeTo(JSONStringer stringer) throws JSONException { - stringer.array(); - for (Object value : values) { - stringer.value(value); - } - stringer.endArray(); - } + void writeTo(JSONStringer stringer) throws JSONException { + stringer.array(); + for (Object value : this.values) { + stringer.value(value); + } + stringer.endArray(); + } - @Override public boolean equals(Object o) { - return o instanceof JSONArray && ((JSONArray) o).values.equals(values); - } + @Override + public boolean equals(Object o) { + return o instanceof JSONArray && ((JSONArray) o).values.equals(this.values); + } - @Override public int hashCode() { - // diverge from the original, which doesn't implement hashCode - return values.hashCode(); - } + @Override + public int hashCode() { + // diverge from the original, which doesn't implement hashCode + return this.values.hashCode(); + } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/json/JSONException.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/json/JSONException.java index f93a36736af..57c831eee28 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/json/JSONException.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/json/JSONException.java @@ -43,7 +43,7 @@ package org.springframework.boot.configurationprocessor.json; */ public class JSONException extends Exception { - public JSONException(String s) { - super(s); - } + public JSONException(String s) { + super(s); + } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/json/JSONObject.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/json/JSONObject.java index c1de1070dae..eb7f9cc5032 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/json/JSONObject.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/json/JSONObject.java @@ -78,698 +78,792 @@ import java.util.Map; */ public class JSONObject { - private static final Double NEGATIVE_ZERO = -0d; + private static final Double NEGATIVE_ZERO = -0d; - /** - * A sentinel value used to explicitly define a name with no value. Unlike - * {@code null}, names with this value: - *
    - *
  • show up in the {@link #names} array - *
  • show up in the {@link #keys} iterator - *
  • return {@code true} for {@link #has(String)} - *
  • do not throw on {@link #get(String)} - *
  • are included in the encoded JSON string. - *
- * - *

This value violates the general contract of {@link Object#equals} by - * returning true when compared to {@code null}. Its {@link #toString} - * method returns "null". - */ - public static final Object NULL = new Object() { - @Override public boolean equals(Object o) { - return o == this || o == null; // API specifies this broken equals implementation - } - @Override public String toString() { - return "null"; - } - }; + /** + * A sentinel value used to explicitly define a name with no value. Unlike + * {@code null}, names with this value: + *

    + *
  • show up in the {@link #names} array + *
  • show up in the {@link #keys} iterator + *
  • return {@code true} for {@link #has(String)} + *
  • do not throw on {@link #get(String)} + *
  • are included in the encoded JSON string. + *
+ * + *

This value violates the general contract of {@link Object#equals} by + * returning true when compared to {@code null}. Its {@link #toString} + * method returns "null". + */ + public static final Object NULL = new Object() { + @Override + public boolean equals(Object o) { + return o == this || o == null; // API specifies this broken equals implementation + } - private final Map nameValuePairs; + @Override + public String toString() { + return "null"; + } + }; - /** - * Creates a {@code JSONObject} with no name/value mappings. - */ - public JSONObject() { - nameValuePairs = new HashMap(); - } + private final Map nameValuePairs; - /** - * Creates a new {@code JSONObject} by copying all name/value mappings from - * the given map. - * - * @param copyFrom a map whose keys are of type {@link String} and whose - * values are of supported types. - * @throws NullPointerException if any of the map's keys are null. - */ - /* (accept a raw type for API compatibility) */ - public JSONObject(Map copyFrom) { - this(); - Map contentsTyped = (Map) copyFrom; - for (Map.Entry entry : contentsTyped.entrySet()) { - /* - * Deviate from the original by checking that keys are non-null and - * of the proper type. (We still defer validating the values). - */ - String key = (String) entry.getKey(); - if (key == null) { - throw new NullPointerException("key == null"); - } - nameValuePairs.put(key, wrap(entry.getValue())); - } - } + /** + * Creates a {@code JSONObject} with no name/value mappings. + */ + public JSONObject() { + this.nameValuePairs = new HashMap(); + } - /** - * Creates a new {@code JSONObject} with name/value mappings from the next - * object in the tokener. - * - * @param readFrom a tokener whose nextValue() method will yield a - * {@code JSONObject}. - * @throws JSONException if the parse fails or doesn't yield a - * {@code JSONObject}. - */ - public JSONObject(JSONTokener readFrom) throws JSONException { - /* - * Getting the parser to populate this could get tricky. Instead, just - * parse to temporary JSONObject and then steal the data from that. - */ - Object object = readFrom.nextValue(); - if (object instanceof JSONObject) { - this.nameValuePairs = ((JSONObject) object).nameValuePairs; - } else { - throw JSON.typeMismatch(object, "JSONObject"); - } - } + /** + * Creates a new {@code JSONObject} by copying all name/value mappings from + * the given map. + * + * @param copyFrom a map whose keys are of type {@link String} and whose + * values are of supported types. + * @throws NullPointerException if any of the map's keys are null. + */ + /* (accept a raw type for API compatibility) */ + public JSONObject(Map copyFrom) { + this(); + Map contentsTyped = (Map) copyFrom; + for (Map.Entry entry : contentsTyped.entrySet()) { + /* + * Deviate from the original by checking that keys are non-null and + * of the proper type. (We still defer validating the values). + */ + String key = (String) entry.getKey(); + if (key == null) { + throw new NullPointerException("key == null"); + } + this.nameValuePairs.put(key, wrap(entry.getValue())); + } + } - /** - * Creates a new {@code JSONObject} with name/value mappings from the JSON - * string. - * - * @param json a JSON-encoded string containing an object. - * @throws JSONException if the parse fails or doesn't yield a {@code - * JSONObject}. - */ - public JSONObject(String json) throws JSONException { - this(new JSONTokener(json)); - } + /** + * Creates a new {@code JSONObject} with name/value mappings from the next + * object in the tokener. + * + * @param readFrom a tokener whose nextValue() method will yield a + * {@code JSONObject}. + * @throws JSONException if the parse fails or doesn't yield a + * {@code JSONObject}. + */ + public JSONObject(JSONTokener readFrom) throws JSONException { + /* + * Getting the parser to populate this could get tricky. Instead, just + * parse to temporary JSONObject and then steal the data from that. + */ + Object object = readFrom.nextValue(); + if (object instanceof JSONObject) { + this.nameValuePairs = ((JSONObject) object).nameValuePairs; + } + else { + throw JSON.typeMismatch(object, "JSONObject"); + } + } - /** - * Creates a new {@code JSONObject} by copying mappings for the listed names - * from the given object. Names that aren't present in {@code copyFrom} will - * be skipped. - */ - public JSONObject(JSONObject copyFrom, String[] names) throws JSONException { - this(); - for (String name : names) { - Object value = copyFrom.opt(name); - if (value != null) { - nameValuePairs.put(name, value); - } - } - } + /** + * Creates a new {@code JSONObject} with name/value mappings from the JSON + * string. + * + * @param json a JSON-encoded string containing an object. + * @throws JSONException if the parse fails or doesn't yield a {@code + * JSONObject}. + */ + public JSONObject(String json) throws JSONException { + this(new JSONTokener(json)); + } - /** - * Returns the number of name/value mappings in this object. - */ - public int length() { - return nameValuePairs.size(); - } + /** + * Creates a new {@code JSONObject} by copying mappings for the listed names + * from the given object. Names that aren't present in {@code copyFrom} will + * be skipped. + * @param copyFrom the source + * @param names the property names + * @throws JSONException if an error occurs + */ + public JSONObject(JSONObject copyFrom, String[] names) throws JSONException { + this(); + for (String name : names) { + Object value = copyFrom.opt(name); + if (value != null) { + this.nameValuePairs.put(name, value); + } + } + } - /** - * Maps {@code name} to {@code value}, clobbering any existing name/value - * mapping with the same name. - * - * @return this object. - */ - public JSONObject put(String name, boolean value) throws JSONException { - nameValuePairs.put(checkName(name), value); - return this; - } + /** + * Returns the number of name/value mappings in this object. + * @return the number of name/value mappings in this object + */ + public int length() { + return this.nameValuePairs.size(); + } - /** - * Maps {@code name} to {@code value}, clobbering any existing name/value - * mapping with the same name. - * - * @param value a finite value. May not be {@link Double#isNaN() NaNs} or - * {@link Double#isInfinite() infinities}. - * @return this object. - */ - public JSONObject put(String name, double value) throws JSONException { - nameValuePairs.put(checkName(name), JSON.checkDouble(value)); - return this; - } + /** + * Maps {@code name} to {@code value}, clobbering any existing name/value + * mapping with the same name. + * @param name the name of the property + * @param value the value of the property + * @return this object. + * @throws JSONException if an error occurs + */ + public JSONObject put(String name, boolean value) throws JSONException { + this.nameValuePairs.put(checkName(name), value); + return this; + } - /** - * Maps {@code name} to {@code value}, clobbering any existing name/value - * mapping with the same name. - * - * @return this object. - */ - public JSONObject put(String name, int value) throws JSONException { - nameValuePairs.put(checkName(name), value); - return this; - } + /** + * Maps {@code name} to {@code value}, clobbering any existing name/value + * mapping with the same name. + * + * @param name the name of the property + * @param value a finite value. May not be {@link Double#isNaN() NaNs} or + * {@link Double#isInfinite() infinities}. + * @return this object. + * @throws JSONException if an error occurs + */ + public JSONObject put(String name, double value) throws JSONException { + this.nameValuePairs.put(checkName(name), JSON.checkDouble(value)); + return this; + } - /** - * Maps {@code name} to {@code value}, clobbering any existing name/value - * mapping with the same name. - * - * @return this object. - */ - public JSONObject put(String name, long value) throws JSONException { - nameValuePairs.put(checkName(name), value); - return this; - } + /** + * Maps {@code name} to {@code value}, clobbering any existing name/value + * mapping with the same name. + * + * @param name the name of the property + * @param value the value of the property + * @return this object. + * @throws JSONException if an error occurs + */ + public JSONObject put(String name, int value) throws JSONException { + this.nameValuePairs.put(checkName(name), value); + return this; + } - /** - * Maps {@code name} to {@code value}, clobbering any existing name/value - * mapping with the same name. If the value is {@code null}, any existing - * mapping for {@code name} is removed. - * - * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, - * Integer, Long, Double, {@link #NULL}, or {@code null}. May not be - * {@link Double#isNaN() NaNs} or {@link Double#isInfinite() - * infinities}. - * @return this object. - */ - public JSONObject put(String name, Object value) throws JSONException { - if (value == null) { - nameValuePairs.remove(name); - return this; - } - if (value instanceof Number) { - // deviate from the original by checking all Numbers, not just floats & doubles - JSON.checkDouble(((Number) value).doubleValue()); - } - nameValuePairs.put(checkName(name), value); - return this; - } + /** + * Maps {@code name} to {@code value}, clobbering any existing name/value + * mapping with the same name. + * + * @param name the name of the property + * @param value the value of the property + * @return this object. + * @throws JSONException if an error occurs + */ + public JSONObject put(String name, long value) throws JSONException { + this.nameValuePairs.put(checkName(name), value); + return this; + } - /** - * Equivalent to {@code put(name, value)} when both parameters are non-null; - * does nothing otherwise. - */ - public JSONObject putOpt(String name, Object value) throws JSONException { - if (name == null || value == null) { - return this; - } - return put(name, value); - } + /** + * Maps {@code name} to {@code value}, clobbering any existing name/value + * mapping with the same name. If the value is {@code null}, any existing + * mapping for {@code name} is removed. + * + * @param name the name of the property + * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, + * Integer, Long, Double, {@link #NULL}, or {@code null}. May not be + * {@link Double#isNaN() NaNs} or {@link Double#isInfinite() + * infinities}. + * @return this object. + * @throws JSONException if an error occurs + */ + public JSONObject put(String name, Object value) throws JSONException { + if (value == null) { + this.nameValuePairs.remove(name); + return this; + } + if (value instanceof Number) { + // deviate from the original by checking all Numbers, not just floats & doubles + JSON.checkDouble(((Number) value).doubleValue()); + } + this.nameValuePairs.put(checkName(name), value); + return this; + } - /** - * Appends {@code value} to the array already mapped to {@code name}. If - * this object has no mapping for {@code name}, this inserts a new mapping. - * If the mapping exists but its value is not an array, the existing - * and new values are inserted in order into a new array which is itself - * mapped to {@code name}. In aggregate, this allows values to be added to a - * mapping one at a time. - * - * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, - * Integer, Long, Double, {@link #NULL} or null. May not be {@link - * Double#isNaN() NaNs} or {@link Double#isInfinite() infinities}. - */ - public JSONObject accumulate(String name, Object value) throws JSONException { - Object current = nameValuePairs.get(checkName(name)); - if (current == null) { - return put(name, value); - } + /** + * Equivalent to {@code put(name, value)} when both parameters are non-null; + * does nothing otherwise. + * @param name the name of the property + * @param value the value of the property + * @return this object. + * @throws JSONException if an error occurs + */ + public JSONObject putOpt(String name, Object value) throws JSONException { + if (name == null || value == null) { + return this; + } + return put(name, value); + } - // check in accumulate, since array.put(Object) doesn't do any checking - if (value instanceof Number) { - JSON.checkDouble(((Number) value).doubleValue()); - } + /** + * Appends {@code value} to the array already mapped to {@code name}. If + * this object has no mapping for {@code name}, this inserts a new mapping. + * If the mapping exists but its value is not an array, the existing + * and new values are inserted in order into a new array which is itself + * mapped to {@code name}. In aggregate, this allows values to be added to a + * mapping one at a time. + * + * @param name the name of the property + * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, + * Integer, Long, Double, {@link #NULL} or null. May not be {@link + * Double#isNaN() NaNs} or {@link Double#isInfinite() infinities}. + * @return this object. + * @throws JSONException if an error occurs + */ + public JSONObject accumulate(String name, Object value) throws JSONException { + Object current = this.nameValuePairs.get(checkName(name)); + if (current == null) { + return put(name, value); + } - if (current instanceof JSONArray) { - JSONArray array = (JSONArray) current; - array.put(value); - } else { - JSONArray array = new JSONArray(); - array.put(current); - array.put(value); - nameValuePairs.put(name, array); - } - return this; - } + // check in accumulate, since array.put(Object) doesn't do any checking + if (value instanceof Number) { + JSON.checkDouble(((Number) value).doubleValue()); + } - String checkName(String name) throws JSONException { - if (name == null) { - throw new JSONException("Names must be non-null"); - } - return name; - } + if (current instanceof JSONArray) { + JSONArray array = (JSONArray) current; + array.put(value); + } + else { + JSONArray array = new JSONArray(); + array.put(current); + array.put(value); + this.nameValuePairs.put(name, array); + } + return this; + } - /** - * Removes the named mapping if it exists; does nothing otherwise. - * - * @return the value previously mapped by {@code name}, or null if there was - * no such mapping. - */ - public Object remove(String name) { - return nameValuePairs.remove(name); - } + String checkName(String name) throws JSONException { + if (name == null) { + throw new JSONException("Names must be non-null"); + } + return name; + } - /** - * Returns true if this object has no mapping for {@code name} or if it has - * a mapping whose value is {@link #NULL}. - */ - public boolean isNull(String name) { - Object value = nameValuePairs.get(name); - return value == null || value == NULL; - } + /** + * Removes the named mapping if it exists; does nothing otherwise. + * + * @param name the name of the property + * @return the value previously mapped by {@code name}, or null if there was + * no such mapping. + */ + public Object remove(String name) { + return this.nameValuePairs.remove(name); + } - /** - * Returns true if this object has a mapping for {@code name}. The mapping - * may be {@link #NULL}. - */ - public boolean has(String name) { - return nameValuePairs.containsKey(name); - } + /** + * Returns true if this object has no mapping for {@code name} or if it has + * a mapping whose value is {@link #NULL}. + * @param name the name of the property + * @return true if this object has no mapping for {@code name} + */ + public boolean isNull(String name) { + Object value = this.nameValuePairs.get(name); + return value == null || value == NULL; + } - /** - * Returns the value mapped by {@code name}. - * - * @throws JSONException if no such mapping exists. - */ - public Object get(String name) throws JSONException { - Object result = nameValuePairs.get(name); - if (result == null) { - throw new JSONException("No value for " + name); - } - return result; - } + /** + * Returns true if this object has a mapping for {@code name}. The mapping + * may be {@link #NULL}. + * @param name the name of the property + * @return true if this object has a mapping for {@code name} + */ + public boolean has(String name) { + return this.nameValuePairs.containsKey(name); + } - /** - * Returns the value mapped by {@code name}, or null if no such mapping - * exists. - */ - public Object opt(String name) { - return nameValuePairs.get(name); - } + /** + * Returns the value mapped by {@code name}. + * @param name the name of the property + * @return the value + * @throws JSONException if no such mapping exists. + */ + public Object get(String name) throws JSONException { + Object result = this.nameValuePairs.get(name); + if (result == null) { + throw new JSONException("No value for " + name); + } + return result; + } - /** - * Returns the value mapped by {@code name} if it exists and is a boolean or - * can be coerced to a boolean. - * - * @throws JSONException if the mapping doesn't exist or cannot be coerced - * to a boolean. - */ - public boolean getBoolean(String name) throws JSONException { - Object object = get(name); - Boolean result = JSON.toBoolean(object); - if (result == null) { - throw JSON.typeMismatch(name, object, "boolean"); - } - return result; - } + /** + * Returns the value mapped by {@code name}, or null if no such mapping + * exists. + * @param name the name of the property + * @return the value or {@code null} + */ + public Object opt(String name) { + return this.nameValuePairs.get(name); + } - /** - * Returns the value mapped by {@code name} if it exists and is a boolean or - * can be coerced to a boolean. Returns false otherwise. - */ - public boolean optBoolean(String name) { - return optBoolean(name, false); - } + /** + * Returns the value mapped by {@code name} if it exists and is a boolean or + * can be coerced to a boolean. + * + * @param name the name of the property + * @return the value + * @throws JSONException if the mapping doesn't exist or cannot be coerced + * to a boolean. + */ + public boolean getBoolean(String name) throws JSONException { + Object object = get(name); + Boolean result = JSON.toBoolean(object); + if (result == null) { + throw JSON.typeMismatch(name, object, "boolean"); + } + return result; + } - /** - * Returns the value mapped by {@code name} if it exists and is a boolean or - * can be coerced to a boolean. Returns {@code fallback} otherwise. - */ - public boolean optBoolean(String name, boolean fallback) { - Object object = opt(name); - Boolean result = JSON.toBoolean(object); - return result != null ? result : fallback; - } + /** + * Returns the value mapped by {@code name} if it exists and is a boolean or + * can be coerced to a boolean. Returns false otherwise. + * @param name the name of the property + * @return the value or {@code null} + */ + public boolean optBoolean(String name) { + return optBoolean(name, false); + } - /** - * Returns the value mapped by {@code name} if it exists and is a double or - * can be coerced to a double. - * - * @throws JSONException if the mapping doesn't exist or cannot be coerced - * to a double. - */ - public double getDouble(String name) throws JSONException { - Object object = get(name); - Double result = JSON.toDouble(object); - if (result == null) { - throw JSON.typeMismatch(name, object, "double"); - } - return result; - } + /** + * Returns the value mapped by {@code name} if it exists and is a boolean or + * can be coerced to a boolean. Returns {@code fallback} otherwise. + * @param name the name of the property + * @param fallback a fallback value + * @return the value or {@code fallback} + */ + public boolean optBoolean(String name, boolean fallback) { + Object object = opt(name); + Boolean result = JSON.toBoolean(object); + return result != null ? result : fallback; + } - /** - * Returns the value mapped by {@code name} if it exists and is a double or - * can be coerced to a double. Returns {@code NaN} otherwise. - */ - public double optDouble(String name) { - return optDouble(name, Double.NaN); - } + /** + * Returns the value mapped by {@code name} if it exists and is a double or + * can be coerced to a double. + * + * @param name the name of the property + * @return the value + * @throws JSONException if the mapping doesn't exist or cannot be coerced + * to a double. + */ + public double getDouble(String name) throws JSONException { + Object object = get(name); + Double result = JSON.toDouble(object); + if (result == null) { + throw JSON.typeMismatch(name, object, "double"); + } + return result; + } - /** - * Returns the value mapped by {@code name} if it exists and is a double or - * can be coerced to a double. Returns {@code fallback} otherwise. - */ - public double optDouble(String name, double fallback) { - Object object = opt(name); - Double result = JSON.toDouble(object); - return result != null ? result : fallback; - } + /** + * Returns the value mapped by {@code name} if it exists and is a double or + * can be coerced to a double. Returns {@code NaN} otherwise. + * @param name the name of the property + * @return the value or {@code NaN} + */ + public double optDouble(String name) { + return optDouble(name, Double.NaN); + } - /** - * Returns the value mapped by {@code name} if it exists and is an int or - * can be coerced to an int. - * - * @throws JSONException if the mapping doesn't exist or cannot be coerced - * to an int. - */ - public int getInt(String name) throws JSONException { - Object object = get(name); - Integer result = JSON.toInteger(object); - if (result == null) { - throw JSON.typeMismatch(name, object, "int"); - } - return result; - } + /** + * Returns the value mapped by {@code name} if it exists and is a double or + * can be coerced to a double. Returns {@code fallback} otherwise. + * @param name the name of the property + * @param fallback a fallback value + * @return the value or {@code fallback} + */ + public double optDouble(String name, double fallback) { + Object object = opt(name); + Double result = JSON.toDouble(object); + return result != null ? result : fallback; + } - /** - * Returns the value mapped by {@code name} if it exists and is an int or - * can be coerced to an int. Returns 0 otherwise. - */ - public int optInt(String name) { - return optInt(name, 0); - } + /** + * Returns the value mapped by {@code name} if it exists and is an int or + * can be coerced to an int. + * @param name the name of the property + * @return the value + * @throws JSONException if the mapping doesn't exist or cannot be coerced + * to an int. + */ + public int getInt(String name) throws JSONException { + Object object = get(name); + Integer result = JSON.toInteger(object); + if (result == null) { + throw JSON.typeMismatch(name, object, "int"); + } + return result; + } - /** - * Returns the value mapped by {@code name} if it exists and is an int or - * can be coerced to an int. Returns {@code fallback} otherwise. - */ - public int optInt(String name, int fallback) { - Object object = opt(name); - Integer result = JSON.toInteger(object); - return result != null ? result : fallback; - } + /** + * Returns the value mapped by {@code name} if it exists and is an int or + * can be coerced to an int. Returns 0 otherwise. + * @param name the name of the property + * @return the value of {@code 0} + */ + public int optInt(String name) { + return optInt(name, 0); + } - /** - * Returns the value mapped by {@code name} if it exists and is a long or - * can be coerced to a long. Note that JSON represents numbers as doubles, - * so this is lossy; use strings to transfer numbers via JSON. - * - * @throws JSONException if the mapping doesn't exist or cannot be coerced - * to a long. - */ - public long getLong(String name) throws JSONException { - Object object = get(name); - Long result = JSON.toLong(object); - if (result == null) { - throw JSON.typeMismatch(name, object, "long"); - } - return result; - } + /** + * Returns the value mapped by {@code name} if it exists and is an int or + * can be coerced to an int. Returns {@code fallback} otherwise. + * @param name the name of the property + * @param fallback a fallback value + * @return the value or {@code fallback} + */ + public int optInt(String name, int fallback) { + Object object = opt(name); + Integer result = JSON.toInteger(object); + return result != null ? result : fallback; + } - /** - * Returns the value mapped by {@code name} if it exists and is a long or - * can be coerced to a long. Returns 0 otherwise. Note that JSON represents numbers as doubles, - * so this is lossy; use strings to transfer numbers via JSON. - */ - public long optLong(String name) { - return optLong(name, 0L); - } + /** + * Returns the value mapped by {@code name} if it exists and is a long or + * can be coerced to a long. Note that JSON represents numbers as doubles, + * so this is lossy; use strings to transfer numbers via JSON. + * + * @param name the name of the property + * @return the value + * @throws JSONException if the mapping doesn't exist or cannot be coerced + * to a long. + */ + public long getLong(String name) throws JSONException { + Object object = get(name); + Long result = JSON.toLong(object); + if (result == null) { + throw JSON.typeMismatch(name, object, "long"); + } + return result; + } - /** - * Returns the value mapped by {@code name} if it exists and is a long or - * can be coerced to a long. Returns {@code fallback} otherwise. Note that JSON represents - * numbers as doubles, so this is lossy; use strings to transfer - * numbers via JSON. - */ - public long optLong(String name, long fallback) { - Object object = opt(name); - Long result = JSON.toLong(object); - return result != null ? result : fallback; - } + /** + * Returns the value mapped by {@code name} if it exists and is a long or + * can be coerced to a long. Returns 0 otherwise. Note that JSON represents numbers as doubles, + * so this is lossy; use strings to transfer numbers via JSON. + * @param name the name of the property + * @return the value or {@code 0L} + */ + public long optLong(String name) { + return optLong(name, 0L); + } - /** - * Returns the value mapped by {@code name} if it exists, coercing it if - * necessary. - * - * @throws JSONException if no such mapping exists. - */ - public String getString(String name) throws JSONException { - Object object = get(name); - String result = JSON.toString(object); - if (result == null) { - throw JSON.typeMismatch(name, object, "String"); - } - return result; - } + /** + * Returns the value mapped by {@code name} if it exists and is a long or + * can be coerced to a long. Returns {@code fallback} otherwise. Note that JSON represents + * numbers as doubles, so this is lossy; use strings to transfer + * numbers via JSON. + * @param name the name of the property + * @param fallback a fallback value + * @return the value or {@code fallback} + */ + public long optLong(String name, long fallback) { + Object object = opt(name); + Long result = JSON.toLong(object); + return result != null ? result : fallback; + } - /** - * Returns the value mapped by {@code name} if it exists, coercing it if - * necessary. Returns the empty string if no such mapping exists. - */ - public String optString(String name) { - return optString(name, ""); - } + /** + * Returns the value mapped by {@code name} if it exists, coercing it if + * necessary. + * @param name the name of the property + * @return the value + * @throws JSONException if no such mapping exists. + */ + public String getString(String name) throws JSONException { + Object object = get(name); + String result = JSON.toString(object); + if (result == null) { + throw JSON.typeMismatch(name, object, "String"); + } + return result; + } - /** - * Returns the value mapped by {@code name} if it exists, coercing it if - * necessary. Returns {@code fallback} if no such mapping exists. - */ - public String optString(String name, String fallback) { - Object object = opt(name); - String result = JSON.toString(object); - return result != null ? result : fallback; - } + /** + * Returns the value mapped by {@code name} if it exists, coercing it if + * necessary. Returns the empty string if no such mapping exists. + * @param name the name of the property + * @return the value or an empty string + */ + public String optString(String name) { + return optString(name, ""); + } - /** - * Returns the value mapped by {@code name} if it exists and is a {@code - * JSONArray}. - * - * @throws JSONException if the mapping doesn't exist or is not a {@code - * JSONArray}. - */ - public JSONArray getJSONArray(String name) throws JSONException { - Object object = get(name); - if (object instanceof JSONArray) { - return (JSONArray) object; - } else { - throw JSON.typeMismatch(name, object, "JSONArray"); - } - } + /** + * Returns the value mapped by {@code name} if it exists, coercing it if + * necessary. Returns {@code fallback} if no such mapping exists. + * @param name the name of the property + * @param fallback a fallback value + * @return the value or {@code fallback} + */ + public String optString(String name, String fallback) { + Object object = opt(name); + String result = JSON.toString(object); + return result != null ? result : fallback; + } - /** - * Returns the value mapped by {@code name} if it exists and is a {@code - * JSONArray}. Returns null otherwise. - */ - public JSONArray optJSONArray(String name) { - Object object = opt(name); - return object instanceof JSONArray ? (JSONArray) object : null; - } + /** + * Returns the value mapped by {@code name} if it exists and is a {@code + * JSONArray}. + * @param name the name of the property + * @return the value + * @throws JSONException if the mapping doesn't exist or is not a {@code + * JSONArray}. + */ + public JSONArray getJSONArray(String name) throws JSONException { + Object object = get(name); + if (object instanceof JSONArray) { + return (JSONArray) object; + } + else { + throw JSON.typeMismatch(name, object, "JSONArray"); + } + } - /** - * Returns the value mapped by {@code name} if it exists and is a {@code - * JSONObject}. - * - * @throws JSONException if the mapping doesn't exist or is not a {@code - * JSONObject}. - */ - public JSONObject getJSONObject(String name) throws JSONException { - Object object = get(name); - if (object instanceof JSONObject) { - return (JSONObject) object; - } else { - throw JSON.typeMismatch(name, object, "JSONObject"); - } - } + /** + * Returns the value mapped by {@code name} if it exists and is a {@code + * JSONArray}. Returns null otherwise. + * @param name the name of the property + * @return the value or {@code null} + */ + public JSONArray optJSONArray(String name) { + Object object = opt(name); + return object instanceof JSONArray ? (JSONArray) object : null; + } - /** - * Returns the value mapped by {@code name} if it exists and is a {@code - * JSONObject}. Returns null otherwise. - */ - public JSONObject optJSONObject(String name) { - Object object = opt(name); - return object instanceof JSONObject ? (JSONObject) object : null; - } + /** + * Returns the value mapped by {@code name} if it exists and is a {@code + * JSONObject}. + * @param name the name of the property + * @return the value + * @throws JSONException if the mapping doesn't exist or is not a {@code + * JSONObject}. + */ + public JSONObject getJSONObject(String name) throws JSONException { + Object object = get(name); + if (object instanceof JSONObject) { + return (JSONObject) object; + } + else { + throw JSON.typeMismatch(name, object, "JSONObject"); + } + } - /** - * Returns an array with the values corresponding to {@code names}. The - * array contains null for names that aren't mapped. This method returns - * null if {@code names} is either null or empty. - */ - public JSONArray toJSONArray(JSONArray names) throws JSONException { - JSONArray result = new JSONArray(); - if (names == null) { - return null; - } - int length = names.length(); - if (length == 0) { - return null; - } - for (int i = 0; i < length; i++) { - String name = JSON.toString(names.opt(i)); - result.put(opt(name)); - } - return result; - } + /** + * Returns the value mapped by {@code name} if it exists and is a {@code + * JSONObject}. Returns null otherwise. + * @param name the name of the property + * @return the value or {@code null} + */ + public JSONObject optJSONObject(String name) { + Object object = opt(name); + return object instanceof JSONObject ? (JSONObject) object : null; + } - /** - * Returns an iterator of the {@code String} names in this object. The - * returned iterator supports {@link Iterator#remove() remove}, which will - * remove the corresponding mapping from this object. If this object is - * modified after the iterator is returned, the iterator's behavior is - * undefined. The order of the keys is undefined. - */ - /* Return a raw type for API compatibility */ - public Iterator keys() { - return nameValuePairs.keySet().iterator(); - } + /** + * Returns an array with the values corresponding to {@code names}. The + * array contains null for names that aren't mapped. This method returns + * null if {@code names} is either null or empty. + * @param names the names of the properties + * @return the array + */ + public JSONArray toJSONArray(JSONArray names) { + JSONArray result = new JSONArray(); + if (names == null) { + return null; + } + int length = names.length(); + if (length == 0) { + return null; + } + for (int i = 0; i < length; i++) { + String name = JSON.toString(names.opt(i)); + result.put(opt(name)); + } + return result; + } - /** - * Returns an array containing the string names in this object. This method - * returns null if this object contains no mappings. - */ - public JSONArray names() { - return nameValuePairs.isEmpty() - ? null - : new JSONArray(new ArrayList(nameValuePairs.keySet())); - } + /** + * Returns an iterator of the {@code String} names in this object. The + * returned iterator supports {@link Iterator#remove() remove}, which will + * remove the corresponding mapping from this object. If this object is + * modified after the iterator is returned, the iterator's behavior is + * undefined. The order of the keys is undefined. + * @return the keys + */ + /* Return a raw type for API compatibility */ + public Iterator keys() { + return this.nameValuePairs.keySet().iterator(); + } - /** - * Encodes this object as a compact JSON string, such as: - *

{"query":"Pizza","locations":[94043,90210]}
- */ - @Override public String toString() { - try { - JSONStringer stringer = new JSONStringer(); - writeTo(stringer); - return stringer.toString(); - } catch (JSONException e) { - return null; - } - } + /** + * Returns an array containing the string names in this object. This method + * returns null if this object contains no mappings. + * @return the array + */ + public JSONArray names() { + return this.nameValuePairs.isEmpty() + ? null + : new JSONArray(new ArrayList(this.nameValuePairs.keySet())); + } - /** - * Encodes this object as a human readable JSON string for debugging, such - * as: - *
-     * {
-     *     "query": "Pizza",
-     *     "locations": [
-     *         94043,
-     *         90210
-     *     ]
-     * }
- * - * @param indentSpaces the number of spaces to indent for each level of - * nesting. - */ - public String toString(int indentSpaces) throws JSONException { - JSONStringer stringer = new JSONStringer(indentSpaces); - writeTo(stringer); - return stringer.toString(); - } + /** + * Encodes this object as a compact JSON string, such as: + *
{"query":"Pizza","locations":[94043,90210]}
+ * @return a string representation of the object. + */ + @Override + public String toString() { + try { + JSONStringer stringer = new JSONStringer(); + writeTo(stringer); + return stringer.toString(); + } + catch (JSONException e) { + return null; + } + } - void writeTo(JSONStringer stringer) throws JSONException { - stringer.object(); - for (Map.Entry entry : nameValuePairs.entrySet()) { - stringer.key(entry.getKey()).value(entry.getValue()); - } - stringer.endObject(); - } + /** + * Encodes this object as a human readable JSON string for debugging, such + * as: + *
+	 * {
+	 *     "query": "Pizza",
+	 *     "locations": [
+	 *         94043,
+	 *         90210
+	 *     ]
+	 * }
+ * + * @param indentSpaces the number of spaces to indent for each level of + * nesting. + * @return a string representation of the object. + * @throws JSONException if an error occurs + */ + public String toString(int indentSpaces) throws JSONException { + JSONStringer stringer = new JSONStringer(indentSpaces); + writeTo(stringer); + return stringer.toString(); + } - /** - * Encodes the number as a JSON string. - * - * @param number a finite value. May not be {@link Double#isNaN() NaNs} or - * {@link Double#isInfinite() infinities}. - */ - public static String numberToString(Number number) throws JSONException { - if (number == null) { - throw new JSONException("Number must be non-null"); - } + void writeTo(JSONStringer stringer) throws JSONException { + stringer.object(); + for (Map.Entry entry : this.nameValuePairs.entrySet()) { + stringer.key(entry.getKey()).value(entry.getValue()); + } + stringer.endObject(); + } - double doubleValue = number.doubleValue(); - JSON.checkDouble(doubleValue); + /** + * Encodes the number as a JSON string. + * + * @param number a finite value. May not be {@link Double#isNaN() NaNs} or + * {@link Double#isInfinite() infinities}. + * @return the encoded value + * @throws JSONException if an error occurs + */ + public static String numberToString(Number number) throws JSONException { + if (number == null) { + throw new JSONException("Number must be non-null"); + } - // the original returns "-0" instead of "-0.0" for negative zero - if (number.equals(NEGATIVE_ZERO)) { - return "-0"; - } + double doubleValue = number.doubleValue(); + JSON.checkDouble(doubleValue); - long longValue = number.longValue(); - if (doubleValue == (double) longValue) { - return Long.toString(longValue); - } + // the original returns "-0" instead of "-0.0" for negative zero + if (number.equals(NEGATIVE_ZERO)) { + return "-0"; + } - return number.toString(); - } + long longValue = number.longValue(); + if (doubleValue == (double) longValue) { + return Long.toString(longValue); + } - /** - * Encodes {@code data} as a JSON string. This applies quotes and any - * necessary character escaping. - * - * @param data the string to encode. Null will be interpreted as an empty - * string. - */ - public static String quote(String data) { - if (data == null) { - return "\"\""; - } - try { - JSONStringer stringer = new JSONStringer(); - stringer.open(JSONStringer.Scope.NULL, ""); - stringer.value(data); - stringer.close(JSONStringer.Scope.NULL, JSONStringer.Scope.NULL, ""); - return stringer.toString(); - } catch (JSONException e) { - throw new AssertionError(); - } - } + return number.toString(); + } - /** - * Wraps the given object if necessary. - * - *

If the object is null or , returns {@link #NULL}. - * If the object is a {@code JSONArray} or {@code JSONObject}, no wrapping is necessary. - * If the object is {@code NULL}, no wrapping is necessary. - * If the object is an array or {@code Collection}, returns an equivalent {@code JSONArray}. - * If the object is a {@code Map}, returns an equivalent {@code JSONObject}. - * If the object is a primitive wrapper type or {@code String}, returns the object. - * Otherwise if the object is from a {@code java} package, returns the result of {@code toString}. - * If wrapping fails, returns null. - */ - public static Object wrap(Object o) { - if (o == null) { - return NULL; - } - if (o instanceof JSONArray || o instanceof JSONObject) { - return o; - } - if (o.equals(NULL)) { - return o; - } - try { - if (o instanceof Collection) { - return new JSONArray((Collection) o); - } else if (o.getClass().isArray()) { - return new JSONArray(o); - } - if (o instanceof Map) { - return new JSONObject((Map) o); - } - if (o instanceof Boolean || - o instanceof Byte || - o instanceof Character || - o instanceof Double || - o instanceof Float || - o instanceof Integer || - o instanceof Long || - o instanceof Short || - o instanceof String) { - return o; - } - if (o.getClass().getPackage().getName().startsWith("java.")) { - return o.toString(); - } - } catch (Exception ignored) { - } - return null; - } + /** + * Encodes {@code data} as a JSON string. This applies quotes and any + * necessary character escaping. + * + * @param data the string to encode. Null will be interpreted as an empty + * string. + * @return the quoted value + */ + public static String quote(String data) { + if (data == null) { + return "\"\""; + } + try { + JSONStringer stringer = new JSONStringer(); + stringer.open(JSONStringer.Scope.NULL, ""); + stringer.value(data); + stringer.close(JSONStringer.Scope.NULL, JSONStringer.Scope.NULL, ""); + return stringer.toString(); + } + catch (JSONException e) { + throw new AssertionError(); + } + } + + /** + * Wraps the given object if necessary. + * + *

If the object is null or , returns {@link #NULL}. + * If the object is a {@code JSONArray} or {@code JSONObject}, no wrapping is necessary. + * If the object is {@code NULL}, no wrapping is necessary. + * If the object is an array or {@code Collection}, returns an equivalent {@code JSONArray}. + * If the object is a {@code Map}, returns an equivalent {@code JSONObject}. + * If the object is a primitive wrapper type or {@code String}, returns the object. + * Otherwise if the object is from a {@code java} package, returns the result of {@code toString}. + * If wrapping fails, returns null. + * @param o the object to wrap + * @return the wrapped object + */ + public static Object wrap(Object o) { + if (o == null) { + return NULL; + } + if (o instanceof JSONArray || o instanceof JSONObject) { + return o; + } + if (o.equals(NULL)) { + return o; + } + try { + if (o instanceof Collection) { + return new JSONArray((Collection) o); + } + else if (o.getClass().isArray()) { + return new JSONArray(o); + } + if (o instanceof Map) { + return new JSONObject((Map) o); + } + if (o instanceof Boolean || + o instanceof Byte || + o instanceof Character || + o instanceof Double || + o instanceof Float || + o instanceof Integer || + o instanceof Long || + o instanceof Short || + o instanceof String) { + return o; + } + if (o.getClass().getPackage().getName().startsWith("java.")) { + return o.toString(); + } + } + catch (Exception ignored) { + } + return null; + } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/json/JSONStringer.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/json/JSONStringer.java index 085926b55aa..7269ece1e80 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/json/JSONStringer.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/json/JSONStringer.java @@ -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"); * you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ import java.util.ArrayList; import java.util.Arrays; 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. /** * Implements {@link JSONObject#toString} and {@link JSONArray#toString}. Most @@ -60,373 +60,407 @@ import java.util.List; */ public class JSONStringer { - /** The output data, containing at most one top-level array or object. */ - final StringBuilder out = new StringBuilder(); + /** The output data, containing at most one top-level array or object. */ + final StringBuilder out = new StringBuilder(); - /** - * Lexical scoping elements within this stringer, necessary to insert the - * appropriate separator characters (ie. commas and colons) and to detect - * nesting errors. - */ - enum Scope { + /** + * Lexical scoping elements within this stringer, necessary to insert the + * appropriate separator characters (ie. commas and colons) and to detect + * nesting errors. + */ + enum Scope { - /** - * An array with no elements requires no separators or newlines before - * it is closed. - */ - EMPTY_ARRAY, + /** + * An array with no elements requires no separators or newlines before + * it is closed. + */ + EMPTY_ARRAY, - /** - * A array with at least one value requires a comma and newline before - * the next element. - */ - NONEMPTY_ARRAY, + /** + * A array with at least one value requires a comma and newline before + * the next element. + */ + NONEMPTY_ARRAY, - /** - * An object with no keys or values requires no separators or newlines - * before it is closed. - */ - EMPTY_OBJECT, + /** + * An object with no keys or values requires no separators or newlines + * before it is closed. + */ + EMPTY_OBJECT, - /** - * An object whose most recent element is a key. The next element must - * be a value. - */ - DANGLING_KEY, + /** + * An object whose most recent element is a key. The next element must + * be a value. + */ + DANGLING_KEY, - /** - * An object with at least one name/value pair requires a comma and - * newline before the next element. - */ - NONEMPTY_OBJECT, + /** + * An object with at least one name/value pair requires a comma and + * newline before the next element. + */ + NONEMPTY_OBJECT, - /** - * A special bracketless array needed by JSONStringer.join() and - * JSONObject.quote() only. Not used for JSON encoding. - */ - NULL - } + /** + * A special bracketless array needed by JSONStringer.join() and + * JSONObject.quote() only. Not used for JSON encoding. + */ + NULL, + } - /** - * Unlike the original implementation, this stack isn't limited to 20 - * levels of nesting. - */ - private final List stack = new ArrayList(); + /** + * Unlike the original implementation, this stack isn't limited to 20 + * levels of nesting. + */ + private final List stack = new ArrayList(); - /** - * A string containing a full set of spaces for a single level of - * indentation, or null for no pretty printing. - */ - private final String indent; + /** + * A string containing a full set of spaces for a single level of + * indentation, or null for no pretty printing. + */ + private final String indent; - public JSONStringer() { - indent = null; - } + public JSONStringer() { + this.indent = null; + } - JSONStringer(int indentSpaces) { - char[] indentChars = new char[indentSpaces]; - Arrays.fill(indentChars, ' '); - indent = new String(indentChars); - } + JSONStringer(int indentSpaces) { + char[] indentChars = new char[indentSpaces]; + Arrays.fill(indentChars, ' '); + this.indent = new String(indentChars); + } - /** - * Begins encoding a new array. Each call to this method must be paired with - * a call to {@link #endArray}. - * - * @return this stringer. - */ - public JSONStringer array() throws JSONException { - return open(Scope.EMPTY_ARRAY, "["); - } + /** + * Begins encoding a new array. Each call to this method must be paired with + * a call to {@link #endArray}. + * + * @return this stringer. + * @throws JSONException if processing of json failed + */ + public JSONStringer array() throws JSONException { + return open(Scope.EMPTY_ARRAY, "["); + } - /** - * Ends encoding the current array. - * - * @return this stringer. - */ - public JSONStringer endArray() throws JSONException { - return close(Scope.EMPTY_ARRAY, Scope.NONEMPTY_ARRAY, "]"); - } + /** + * Ends encoding the current array. + * + * @return this stringer. + * @throws JSONException if processing of json failed + */ + public JSONStringer endArray() throws JSONException { + return close(Scope.EMPTY_ARRAY, Scope.NONEMPTY_ARRAY, "]"); + } - /** - * Begins encoding a new object. Each call to this method must be paired - * with a call to {@link #endObject}. - * - * @return this stringer. - */ - public JSONStringer object() throws JSONException { - return open(Scope.EMPTY_OBJECT, "{"); - } + /** + * Begins encoding a new object. Each call to this method must be paired + * with a call to {@link #endObject}. + * + * @return this stringer. + * @throws JSONException if processing of json failed + */ + public JSONStringer object() throws JSONException { + return open(Scope.EMPTY_OBJECT, "{"); + } - /** - * Ends encoding the current object. - * - * @return this stringer. - */ - public JSONStringer endObject() throws JSONException { - return close(Scope.EMPTY_OBJECT, Scope.NONEMPTY_OBJECT, "}"); - } + /** + * Ends encoding the current object. + * + * @return this stringer. + * @throws JSONException if processing of json failed + */ + public JSONStringer endObject() throws JSONException { + return close(Scope.EMPTY_OBJECT, Scope.NONEMPTY_OBJECT, "}"); + } - /** - * Enters a new scope by appending any necessary whitespace and the given - * bracket. - */ - JSONStringer open(Scope empty, String openBracket) throws JSONException { - if (stack.isEmpty() && out.length() > 0) { - throw new JSONException("Nesting problem: multiple top-level roots"); - } - beforeValue(); - stack.add(empty); - out.append(openBracket); - return this; - } + /** + * Enters a new scope by appending any necessary whitespace and the given + * bracket. + * @param empty any necessary whitespace + * @param openBracket the open bracket + * @return this object + * @throws JSONException if processing of json failed + */ + JSONStringer open(Scope empty, String openBracket) throws JSONException { + if (this.stack.isEmpty() && this.out.length() > 0) { + throw new JSONException("Nesting problem: multiple top-level roots"); + } + beforeValue(); + this.stack.add(empty); + this.out.append(openBracket); + return this; + } - /** - * Closes the current scope by appending any necessary whitespace and the - * given bracket. - */ - JSONStringer close(Scope empty, Scope nonempty, String closeBracket) throws JSONException { - Scope context = peek(); - if (context != nonempty && context != empty) { - throw new JSONException("Nesting problem"); - } + /** + * Closes the current scope by appending any necessary whitespace and the + * given bracket. + * @param empty any necessary whitespace + * @param nonempty the current scope + * @param closeBracket the close bracket + * @throws JSONException if processing of json failed + */ + JSONStringer close(Scope empty, Scope nonempty, String closeBracket) throws JSONException { + Scope context = peek(); + if (context != nonempty && context != empty) { + throw new JSONException("Nesting problem"); + } - stack.remove(stack.size() - 1); - if (context == nonempty) { - newline(); - } - out.append(closeBracket); - return this; - } + this.stack.remove(this.stack.size() - 1); + if (context == nonempty) { + newline(); + } + this.out.append(closeBracket); + return this; + } - /** - * Returns the value on the top of the stack. - */ - private Scope peek() throws JSONException { - if (stack.isEmpty()) { - throw new JSONException("Nesting problem"); - } - return stack.get(stack.size() - 1); - } + /** + * Returns the value on the top of the stack. + * @return the scope + * @throws JSONException if processing of json failed + */ + private Scope peek() throws JSONException { + if (this.stack.isEmpty()) { + throw new JSONException("Nesting problem"); + } + return this.stack.get(this.stack.size() - 1); + } - /** - * Replace the value on the top of the stack with the given value. - */ - private void replaceTop(Scope topOfStack) { - stack.set(stack.size() - 1, topOfStack); - } + /** + * Replace the value on the top of the stack with the given value. + * @param topOfStack the scope at the top of the stack + */ + private void replaceTop(Scope topOfStack) { + this.stack.set(this.stack.size() - 1, topOfStack); + } - /** - * Encodes {@code value}. - * - * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, - * Integer, Long, Double or null. May not be {@link Double#isNaN() NaNs} - * or {@link Double#isInfinite() infinities}. - * @return this stringer. - */ - public JSONStringer value(Object value) throws JSONException { - if (stack.isEmpty()) { - throw new JSONException("Nesting problem"); - } + /** + * Encodes {@code value}. + * + * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, + * Integer, Long, Double or null. May not be {@link Double#isNaN() NaNs} + * or {@link Double#isInfinite() infinities}. + * @return this stringer. + * @throws JSONException if processing of json failed + */ + public JSONStringer value(Object value) throws JSONException { + if (this.stack.isEmpty()) { + throw new JSONException("Nesting problem"); + } - if (value instanceof JSONArray) { - ((JSONArray) value).writeTo(this); - return this; + if (value instanceof JSONArray) { + ((JSONArray) value).writeTo(this); + return this; - } else if (value instanceof JSONObject) { - ((JSONObject) value).writeTo(this); - return this; - } + } + else if (value instanceof JSONObject) { + ((JSONObject) value).writeTo(this); + return this; + } - beforeValue(); + beforeValue(); - if (value == null - || value instanceof Boolean - || value == JSONObject.NULL) { - out.append(value); + if (value == null + || value instanceof Boolean + || value == JSONObject.NULL) { + this.out.append(value); - } else if (value instanceof Number) { - out.append(JSONObject.numberToString((Number) value)); + } + else if (value instanceof Number) { + this.out.append(JSONObject.numberToString((Number) value)); - } else { - string(value.toString()); - } + } + else { + string(value.toString()); + } - return this; - } + return this; + } - /** - * Encodes {@code value} to this stringer. - * - * @return this stringer. - */ - public JSONStringer value(boolean value) throws JSONException { - if (stack.isEmpty()) { - throw new JSONException("Nesting problem"); - } - beforeValue(); - out.append(value); - return this; - } + /** + * Encodes {@code value} to this stringer. + * + * @param value the value to encode + * @return this stringer. + * @throws JSONException if processing of json failed + */ + public JSONStringer value(boolean value) throws JSONException { + if (this.stack.isEmpty()) { + throw new JSONException("Nesting problem"); + } + beforeValue(); + this.out.append(value); + return this; + } - /** - * Encodes {@code value} to this stringer. - * - * @param value a finite value. May not be {@link Double#isNaN() NaNs} or - * {@link Double#isInfinite() infinities}. - * @return this stringer. - */ - public JSONStringer value(double value) throws JSONException { - if (stack.isEmpty()) { - throw new JSONException("Nesting problem"); - } - beforeValue(); - out.append(JSONObject.numberToString(value)); - return this; - } + /** + * Encodes {@code value} to this stringer. + * + * @param value a finite value. May not be {@link Double#isNaN() NaNs} or + * {@link Double#isInfinite() infinities}. + * @return this stringer. + * @throws JSONException if processing of json failed + */ + public JSONStringer value(double value) throws JSONException { + if (this.stack.isEmpty()) { + throw new JSONException("Nesting problem"); + } + beforeValue(); + this.out.append(JSONObject.numberToString(value)); + return this; + } - /** - * Encodes {@code value} to this stringer. - * - * @return this stringer. - */ - public JSONStringer value(long value) throws JSONException { - if (stack.isEmpty()) { - throw new JSONException("Nesting problem"); - } - beforeValue(); - out.append(value); - return this; - } + /** + * Encodes {@code value} to this stringer. + * + * @param value the value to encode + * @return this stringer. + * @throws JSONException if processing of json failed + */ + public JSONStringer value(long value) throws JSONException { + if (this.stack.isEmpty()) { + throw new JSONException("Nesting problem"); + } + beforeValue(); + this.out.append(value); + return this; + } - private void string(String value) { - out.append("\""); - for (int i = 0, length = value.length(); i < length; i++) { - char c = value.charAt(i); + private void string(String value) { + this.out.append("\""); + for (int i = 0, length = value.length(); i < length; i++) { + char c = value.charAt(i); - /* - * From RFC 4627, "All Unicode characters may be placed within the - * quotation marks except for the characters that must be escaped: - * quotation mark, reverse solidus, and the control characters - * (U+0000 through U+001F)." - */ - switch (c) { - case '"': - case '\\': - case '/': - out.append('\\').append(c); - break; + /* + * From RFC 4627, "All Unicode characters may be placed within the + * quotation marks except for the characters that must be escaped: + * quotation mark, reverse solidus, and the control characters + * (U+0000 through U+001F)." + */ + switch (c) { + case '"': + case '\\': + case '/': + this.out.append('\\').append(c); + break; - case '\t': - out.append("\\t"); - break; + case '\t': + this.out.append("\\t"); + break; - case '\b': - out.append("\\b"); - break; + case '\b': + this.out.append("\\b"); + break; - case '\n': - out.append("\\n"); - break; + case '\n': + this.out.append("\\n"); + break; - case '\r': - out.append("\\r"); - break; + case '\r': + this.out.append("\\r"); + break; - case '\f': - out.append("\\f"); - break; + case '\f': + this.out.append("\\f"); + break; - default: - if (c <= 0x1F) { - out.append(String.format("\\u%04x", (int) c)); - } else { - out.append(c); - } - break; - } + default: + if (c <= 0x1F) { + this.out.append(String.format("\\u%04x", (int) c)); + } + else { + this.out.append(c); + } + break; + } - } - out.append("\""); - } + } + this.out.append("\""); + } - private void newline() { - if (indent == null) { - return; - } + private void newline() { + if (this.indent == null) { + return; + } - out.append("\n"); - for (int i = 0; i < stack.size(); i++) { - out.append(indent); - } - } + this.out.append("\n"); + for (int i = 0; i < this.stack.size(); i++) { + this.out.append(this.indent); + } + } - /** - * Encodes the key (property name) to this stringer. - * - * @param name the name of the forthcoming value. May not be null. - * @return this stringer. - */ - public JSONStringer key(String name) throws JSONException { - if (name == null) { - throw new JSONException("Names must be non-null"); - } - beforeKey(); - string(name); - return this; - } + /** + * Encodes the key (property name) to this stringer. + * + * @param name the name of the forthcoming value. May not be null. + * @return this stringer. + * @throws JSONException if processing of json failed + */ + public JSONStringer key(String name) throws JSONException { + if (name == null) { + throw new JSONException("Names must be non-null"); + } + beforeKey(); + string(name); + return this; + } - /** - * Inserts any necessary separators and whitespace before a name. Also - * adjusts the stack to expect the key's value. - */ - private void beforeKey() throws JSONException { - Scope context = peek(); - if (context == Scope.NONEMPTY_OBJECT) { // first in object - out.append(','); - } else if (context != Scope.EMPTY_OBJECT) { // not in an object! - throw new JSONException("Nesting problem"); - } - newline(); - replaceTop(Scope.DANGLING_KEY); - } + /** + * Inserts any necessary separators and whitespace before a name. Also + * adjusts the stack to expect the key's value. + * @throws JSONException if processing of json failed + */ + private void beforeKey() throws JSONException { + Scope context = peek(); + if (context == Scope.NONEMPTY_OBJECT) { // first in object + this.out.append(','); + } + else if (context != Scope.EMPTY_OBJECT) { // not in an object! + throw new JSONException("Nesting problem"); + } + newline(); + replaceTop(Scope.DANGLING_KEY); + } - /** - * Inserts any necessary separators and whitespace before a literal value, - * inline array, or inline object. Also adjusts the stack to expect either a - * closing bracket or another element. - */ - private void beforeValue() throws JSONException { - if (stack.isEmpty()) { - return; - } + /** + * Inserts any necessary separators and whitespace before a literal value, + * inline array, or inline object. Also adjusts the stack to expect either a + * closing bracket or another element. + * @throws JSONException if processing of json failed + */ + private void beforeValue() throws JSONException { + if (this.stack.isEmpty()) { + return; + } - Scope context = peek(); - if (context == Scope.EMPTY_ARRAY) { // first in array - replaceTop(Scope.NONEMPTY_ARRAY); - newline(); - } else if (context == Scope.NONEMPTY_ARRAY) { // another in array - out.append(','); - newline(); - } else if (context == Scope.DANGLING_KEY) { // value for key - out.append(indent == null ? ":" : ": "); - replaceTop(Scope.NONEMPTY_OBJECT); - } else if (context != Scope.NULL) { - throw new JSONException("Nesting problem"); - } - } + Scope context = peek(); + if (context == Scope.EMPTY_ARRAY) { // first in array + replaceTop(Scope.NONEMPTY_ARRAY); + newline(); + } + else if (context == Scope.NONEMPTY_ARRAY) { // another in array + this.out.append(','); + newline(); + } + else if (context == Scope.DANGLING_KEY) { // value for key + this.out.append(this.indent == null ? ":" : ": "); + replaceTop(Scope.NONEMPTY_OBJECT); + } + else if (context != Scope.NULL) { + throw new JSONException("Nesting problem"); + } + } - /** - * Returns the encoded JSON string. - * - *

If invoked with unterminated arrays or unclosed objects, this method's - * return value is undefined. - * - *

Warning: although it contradicts the general contract - * of {@link Object#toString}, this method returns null if the stringer - * contains no data. - */ - @Override public String toString() { - return out.length() == 0 ? null : out.toString(); - } + /** + * Returns the encoded JSON string. + * + *

If invoked with unterminated arrays or unclosed objects, this method's + * return value is undefined. + * + *

Warning: although it contradicts the general contract + * of {@link Object#toString}, this method returns null if the stringer + * contains no data. + * @return the encoded JSON string. + */ + @Override + public String toString() { + return this.out.length() == 0 ? null : this.out.toString(); + } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/json/JSONTokener.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/json/JSONTokener.java index 5e026822d17..94448568d7e 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/json/JSONTokener.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/json/JSONTokener.java @@ -61,551 +61,512 @@ package org.springframework.boot.configurationprocessor.json; */ public class JSONTokener { - /** The input JSON. */ - private final String in; + /** The input JSON. */ + private final String in; - /** - * The index of the next character to be returned by {@link #next}. When - * the input is exhausted, this equals the input's length. - */ - private int pos; + /** + * The index of the next character to be returned by {@link #next}. When + * the input is exhausted, this equals the input's length. + */ + private int pos; - /** - * @param in JSON encoded string. Null is not permitted and will yield a - * tokener that throws {@code NullPointerExceptions} when methods are - * called. - */ - public JSONTokener(String in) { - // consume an optional byte order mark (BOM) if it exists - if (in != null && in.startsWith("\ufeff")) { - in = in.substring(1); - } - this.in = in; - } + /** + * @param in JSON encoded string. Null is not permitted and will yield a + * tokener that throws {@code NullPointerExceptions} when methods are + * called. + */ + public JSONTokener(String in) { + // consume an optional byte order mark (BOM) if it exists + if (in != null && in.startsWith("\ufeff")) { + in = in.substring(1); + } + this.in = in; + } - /** - * Returns the next value from the input. - * - * @return a {@link JSONObject}, {@link JSONArray}, String, Boolean, - * Integer, Long, Double or {@link JSONObject#NULL}. - * @throws JSONException if the input is malformed. - */ - public Object nextValue() throws JSONException { - int c = nextCleanInternal(); - switch (c) { - case -1: - throw syntaxError("End of input"); + /** + * Returns the next value from the input. + * + * @return a {@link JSONObject}, {@link JSONArray}, String, Boolean, + * Integer, Long, Double or {@link JSONObject#NULL}. + * @throws JSONException if the input is malformed. + */ + public Object nextValue() throws JSONException { + int c = nextCleanInternal(); + switch (c) { + case -1: + throw syntaxError("End of input"); - case '{': - return readObject(); + case '{': + return readObject(); - case '[': - return readArray(); + case '[': + return readArray(); - case '\'': - case '"': - return nextString((char) c); + case '\'': + case '"': + return nextString((char) c); - default: - pos--; - return readLiteral(); - } - } + default: + this.pos--; + return readLiteral(); + } + } - private int nextCleanInternal() throws JSONException { - while (pos < in.length()) { - int c = in.charAt(pos++); - switch (c) { - case '\t': - case ' ': - case '\n': - case '\r': - continue; + private int nextCleanInternal() throws JSONException { + while (this.pos < this.in.length()) { + int c = this.in.charAt(this.pos++); + switch (c) { + case '\t': + case ' ': + case '\n': + case '\r': + continue; - case '/': - if (pos == in.length()) { - return c; - } + case '/': + if (this.pos == this.in.length()) { + return c; + } - char peek = in.charAt(pos); - switch (peek) { - case '*': - // skip a /* c-style comment */ - pos++; - int commentEnd = in.indexOf("*/", pos); - if (commentEnd == -1) { - throw syntaxError("Unterminated comment"); - } - pos = commentEnd + 2; - continue; + char peek = this.in.charAt(this.pos); + switch (peek) { + case '*': + // skip a /* c-style comment */ + this.pos++; + int commentEnd = this.in.indexOf("*/", this.pos); + if (commentEnd == -1) { + throw syntaxError("Unterminated comment"); + } + this.pos = commentEnd + 2; + continue; - case '/': - // skip a // end-of-line comment - pos++; - skipToEndOfLine(); - continue; + case '/': + // skip a // end-of-line comment + this.pos++; + skipToEndOfLine(); + continue; - default: - return c; - } + default: + 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; + 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; - } - } + default: + return c; + } + } - return -1; - } + return -1; + } - /** - * Advances the position until after the next newline character. If the line - * is terminated by "\r\n", the '\n' must be consumed as whitespace by the - * caller. - */ - private void skipToEndOfLine() { - for (; pos < in.length(); pos++) { - char c = in.charAt(pos); - if (c == '\r' || c == '\n') { - pos++; - break; - } - } - } + /** + * Advances the position until after the next newline character. If the line + * is terminated by "\r\n", the '\n' must be consumed as whitespace by the + * caller. + */ + private void skipToEndOfLine() { + for (; this.pos < this.in.length(); this.pos++) { + char c = this.in.charAt(this.pos); + if (c == '\r' || c == '\n') { + this.pos++; + break; + } + } + } - /** - * Returns the string up to but not including {@code quote}, unescaping any - * character escape sequences encountered along the way. The opening quote - * should have already been read. This consumes the closing quote, but does - * not include it in the returned string. - * - * @param quote either ' or ". - * @throws NumberFormatException if any unicode escape sequences are - * malformed. - */ - public String nextString(char quote) throws JSONException { - /* - * For strings that are free of escape sequences, we can just extract - * the result as a substring of the input. But if we encounter an escape - * sequence, we need to use a StringBuilder to compose the result. - */ - StringBuilder builder = null; + /** + * Returns the string up to but not including {@code quote}, unescaping any + * character escape sequences encountered along the way. The opening quote + * should have already been read. This consumes the closing quote, but does + * not include it in the returned string. + * + * @param quote either ' or ". + * @return the string up to but not including {@code quote} + * @throws NumberFormatException if any unicode escape sequences are + * malformed. + * @throws JSONException if processing of json failed + */ + public String nextString(char quote) throws JSONException { + /* + * For strings that are free of escape sequences, we can just extract + * the result as a substring of the input. But if we encounter an escape + * sequence, we need to use a StringBuilder to compose the result. + */ + StringBuilder builder = null; - /* the index of the first character not yet appended to the builder. */ - int start = pos; + /* the index of the first character not yet appended to the builder. */ + int start = this.pos; - while (pos < in.length()) { - int c = in.charAt(pos++); - if (c == quote) { - if (builder == null) { - // a new string avoids leaking memory - return new String(in.substring(start, pos - 1)); - } else { - builder.append(in, start, pos - 1); - return builder.toString(); - } - } + while (this.pos < this.in.length()) { + int c = this.in.charAt(this.pos++); + if (c == quote) { + if (builder == null) { + // a new string avoids leaking memory + return new String(this.in.substring(start, this.pos - 1)); + } + else { + builder.append(this.in, start, this.pos - 1); + return builder.toString(); + } + } - if (c == '\\') { - if (pos == in.length()) { - throw syntaxError("Unterminated escape sequence"); - } - if (builder == null) { - builder = new StringBuilder(); - } - builder.append(in, start, pos - 1); - builder.append(readEscapeCharacter()); - start = pos; - } - } + if (c == '\\') { + if (this.pos == this.in.length()) { + throw syntaxError("Unterminated escape sequence"); + } + if (builder == null) { + builder = new StringBuilder(); + } + builder.append(this.in, start, this.pos - 1); + builder.append(readEscapeCharacter()); + start = this.pos; + } + } - throw syntaxError("Unterminated string"); - } + throw syntaxError("Unterminated string"); + } - /** - * Unescapes the character identified by the character or characters that - * immediately follow a backslash. The backslash '\' should have already - * been read. This supports both unicode escapes "u000A" and two-character - * escapes "\n". - * - * @throws NumberFormatException if any unicode escape sequences are - * malformed. - */ - private char readEscapeCharacter() throws JSONException { - char escaped = in.charAt(pos++); - switch (escaped) { - case 'u': - if (pos + 4 > in.length()) { - throw syntaxError("Unterminated escape sequence"); - } - String hex = in.substring(pos, pos + 4); - pos += 4; - return (char) Integer.parseInt(hex, 16); + /** + * Unescapes the character identified by the character or characters that + * immediately follow a backslash. The backslash '\' should have already + * been read. This supports both unicode escapes "u000A" and two-character + * escapes "\n". + * + * @return the unescaped char + * @throws NumberFormatException if any unicode escape sequences are + * malformed. + * @throws JSONException if processing of json failed + */ + private char readEscapeCharacter() throws JSONException { + char escaped = this.in.charAt(this.pos++); + switch (escaped) { + case 'u': + if (this.pos + 4 > this.in.length()) { + throw syntaxError("Unterminated escape sequence"); + } + String hex = this.in.substring(this.pos, this.pos + 4); + this.pos += 4; + return (char) Integer.parseInt(hex, 16); - case 't': - return '\t'; + case 't': + return '\t'; - case 'b': - return '\b'; + case 'b': + return '\b'; - case 'n': - return '\n'; + case 'n': + return '\n'; - case 'r': - return '\r'; + case 'r': + return '\r'; - case 'f': - return '\f'; + case 'f': + return '\f'; - case '\'': - case '"': - case '\\': - default: - return escaped; - } - } + case '\'': + case '"': + case '\\': + default: + return escaped; + } + } - /** - * Reads a null, boolean, numeric or unquoted string literal value. Numeric - * values will be returned as an Integer, Long, or Double, in that order of - * preference. - */ - private Object readLiteral() throws JSONException { - String literal = nextToInternal("{}[]/\\:,=;# \t\f"); + /** + * Reads a null, boolean, numeric or unquoted string literal value. Numeric + * values will be returned as an Integer, Long, or Double, in that order of + * preference. + * @return a literal value + * @throws JSONException if processing of json failed + */ + private Object readLiteral() throws JSONException { + String literal = nextToInternal("{}[]/\\:,=;# \t\f"); - if (literal.length() == 0) { - throw syntaxError("Expected literal value"); - } else if ("null".equalsIgnoreCase(literal)) { - return JSONObject.NULL; - } else if ("true".equalsIgnoreCase(literal)) { - return Boolean.TRUE; - } else if ("false".equalsIgnoreCase(literal)) { - return Boolean.FALSE; - } + if (literal.length() == 0) { + throw syntaxError("Expected literal value"); + } + else if ("null".equalsIgnoreCase(literal)) { + return JSONObject.NULL; + } + else if ("true".equalsIgnoreCase(literal)) { + return Boolean.TRUE; + } + else if ("false".equalsIgnoreCase(literal)) { + return Boolean.FALSE; + } - /* try to parse as an integral type... */ - if (literal.indexOf('.') == -1) { - int base = 10; - String number = literal; - if (number.startsWith("0x") || number.startsWith("0X")) { - number = number.substring(2); - base = 16; - } else if (number.startsWith("0") && number.length() > 1) { - number = number.substring(1); - base = 8; - } - try { - long longValue = Long.parseLong(number, base); - if (longValue <= Integer.MAX_VALUE && longValue >= Integer.MIN_VALUE) { - return (int) longValue; - } else { - return longValue; - } - } catch (NumberFormatException e) { - /* - * This only happens for integral numbers greater than - * Long.MAX_VALUE, numbers in exponential form (5e-10) and - * unquoted strings. Fall through to try floating point. - */ - } - } + /* try to parse as an integral type... */ + if (literal.indexOf('.') == -1) { + int base = 10; + String number = literal; + if (number.startsWith("0x") || number.startsWith("0X")) { + number = number.substring(2); + base = 16; + } + else if (number.startsWith("0") && number.length() > 1) { + number = number.substring(1); + base = 8; + } + try { + long longValue = Long.parseLong(number, base); + if (longValue <= Integer.MAX_VALUE && longValue >= Integer.MIN_VALUE) { + return (int) longValue; + } + else { + return longValue; + } + } + catch (NumberFormatException e) { + /* + * This only happens for integral numbers greater than + * Long.MAX_VALUE, numbers in exponential form (5e-10) and + * unquoted strings. Fall through to try floating point. + */ + } + } - /* ...next try to parse as a floating point... */ - try { - return Double.valueOf(literal); - } catch (NumberFormatException ignored) { - } + /* ...next try to parse as a floating point... */ + try { + return Double.valueOf(literal); + } + catch (NumberFormatException ignored) { + } - /* ... finally give up. We have an unquoted string */ - return new String(literal); // a new string avoids leaking memory - } + /* ... finally give up. We have an unquoted string */ + return new String(literal); // a new string avoids leaking memory + } - /** - * Returns the string up to but not including any of the given characters or - * a newline character. This does not consume the excluded character. - */ - private String nextToInternal(String excluded) { - int start = pos; - for (; pos < in.length(); pos++) { - char c = in.charAt(pos); - if (c == '\r' || c == '\n' || excluded.indexOf(c) != -1) { - return in.substring(start, pos); - } - } - return in.substring(start); - } + /** + * Returns the string up to but not including any of the given characters or + * a newline character. This does not consume the excluded character. + * @return the string up to but not including any of the given characters or + * a newline character + */ + private String nextToInternal(String excluded) { + int start = this.pos; + for (; this.pos < this.in.length(); this.pos++) { + char c = this.in.charAt(this.pos); + if (c == '\r' || c == '\n' || excluded.indexOf(c) != -1) { + return this.in.substring(start, this.pos); + } + } + return this.in.substring(start); + } - /** - * Reads a sequence of key/value pairs and the trailing closing brace '}' of - * an object. The opening brace '{' should have already been read. - */ - private JSONObject readObject() throws JSONException { - JSONObject result = new JSONObject(); + /** + * Reads a sequence of key/value pairs and the trailing closing brace '}' of + * an object. The opening brace '{' should have already been read. + * @return an object + * @throws JSONException if processing of json failed + */ + private JSONObject readObject() throws JSONException { + JSONObject result = new JSONObject(); - /* Peek to see if this is the empty object. */ - int first = nextCleanInternal(); - if (first == '}') { - return result; - } else if (first != -1) { - pos--; - } + /* Peek to see if this is the empty object. */ + int first = nextCleanInternal(); + if (first == '}') { + return result; + } + else if (first != -1) { + this.pos--; + } - while (true) { - Object name = nextValue(); - if (!(name instanceof String)) { - if (name == null) { - throw syntaxError("Names cannot be null"); - } else { - throw syntaxError("Names must be strings, but " + name - + " is of type " + name.getClass().getName()); - } - } + while (true) { + Object name = nextValue(); + if (!(name instanceof String)) { + if (name == null) { + throw syntaxError("Names cannot be null"); + } + else { + throw syntaxError("Names must be strings, but " + name + + " is of type " + name.getClass().getName()); + } + } - /* - * Expect the name/value separator to be either a colon ':', an - * equals sign '=', or an arrow "=>". The last two are bogus but we - * include them because that's what the original implementation did. - */ - int separator = nextCleanInternal(); - if (separator != ':' && separator != '=') { - throw syntaxError("Expected ':' after " + name); - } - if (pos < in.length() && in.charAt(pos) == '>') { - pos++; - } + /* + * Expect the name/value separator to be either a colon ':', an + * equals sign '=', or an arrow "=>". The last two are bogus but we + * include them because that's what the original implementation did. + */ + int separator = nextCleanInternal(); + if (separator != ':' && separator != '=') { + throw syntaxError("Expected ':' after " + name); + } + if (this.pos < this.in.length() && this.in.charAt(this.pos) == '>') { + this.pos++; + } - result.put((String) name, nextValue()); + result.put((String) name, nextValue()); - switch (nextCleanInternal()) { - case '}': - return result; - case ';': - case ',': - continue; - default: - throw syntaxError("Unterminated object"); - } - } - } + switch (nextCleanInternal()) { + case '}': + return result; + case ';': + case ',': + continue; + default: + throw syntaxError("Unterminated object"); + } + } + } - /** - * Reads a sequence of values and the trailing closing brace ']' of an - * array. The opening brace '[' should have already been read. Note that - * "[]" yields an empty array, but "[,]" returns a two-element array - * equivalent to "[null,null]". - */ - private JSONArray readArray() throws JSONException { - JSONArray result = new JSONArray(); + /** + * Reads a sequence of values and the trailing closing brace ']' of an + * array. The opening brace '[' should have already been read. Note that + * "[]" yields an empty array, but "[,]" returns a two-element array + * equivalent to "[null,null]". + * @return an array + * @throws JSONException if processing of json failed + */ + private JSONArray readArray() throws JSONException { + JSONArray result = new JSONArray(); - /* to cover input that ends with ",]". */ - boolean hasTrailingSeparator = false; + /* to cover input that ends with ",]". */ + boolean hasTrailingSeparator = false; - while (true) { - switch (nextCleanInternal()) { - case -1: - throw syntaxError("Unterminated array"); - case ']': - if (hasTrailingSeparator) { - result.put(null); - } - return result; - case ',': - case ';': - /* A separator without a value first means "null". */ - result.put(null); - hasTrailingSeparator = true; - continue; - default: - pos--; - } + while (true) { + switch (nextCleanInternal()) { + case -1: + throw syntaxError("Unterminated array"); + case ']': + if (hasTrailingSeparator) { + result.put(null); + } + return result; + case ',': + 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()) { - case ']': - return result; - case ',': - case ';': - hasTrailingSeparator = true; - continue; - default: - throw syntaxError("Unterminated array"); - } - } - } + switch (nextCleanInternal()) { + case ']': + return result; + case ',': + case ';': + hasTrailingSeparator = true; + continue; + default: + throw syntaxError("Unterminated array"); + } + } + } - /** - * Returns an exception containing the given message plus the current - * position and the entire input string. - */ - public JSONException syntaxError(String message) { - return new JSONException(message + this); - } + /** + * Returns an exception containing the given message plus the current + * position and the entire input string. + * @param message the message + * @return an exception + */ + public JSONException syntaxError(String message) { + return new JSONException(message + this); + } - /** - * Returns the current position and the entire input string. - */ - @Override public String toString() { - // consistent with the original implementation - return " at character " + pos + " of " + in; - } + /** + * Returns the current position and the entire input string. + * @return the current position and the entire input string. + */ + @Override + public String toString() { + // consistent with the original implementation + return " at character " + this.pos + " of " + this.in; + } - /* - * Legacy APIs. - * - * None of the methods below are on the critical path of parsing JSON - * documents. They exist only because they were exposed by the original - * implementation and may be used by some clients. - */ + /* + * Legacy APIs. + * + * None of the methods below are on the critical path of parsing JSON + * documents. They exist only because they were exposed by the original + * implementation and may be used by some clients. + */ - /** - * Returns true until the input has been exhausted. - */ - public boolean more() { - return pos < in.length(); - } + public boolean more() { + return this.pos < this.in.length(); + } - /** - * Returns the next available character, or the null character '\0' if all - * input has been exhausted. The return value of this method is ambiguous - * for JSON strings that contain the character '\0'. - */ - public char next() { - return pos < in.length() ? in.charAt(pos++) : '\0'; - } + public char next() { + return this.pos < this.in.length() ? this.in.charAt(this.pos++) : '\0'; + } - /** - * Returns the next available character if it equals {@code c}. Otherwise an - * exception is thrown. - */ - public char next(char c) throws JSONException { - char result = next(); - if (result != c) { - throw syntaxError("Expected " + c + " but was " + result); - } - return result; - } + public char next(char c) throws JSONException { + char result = next(); + if (result != c) { + throw syntaxError("Expected " + c + " but was " + result); + } + return result; + } - /** - * Returns the next character that is not whitespace and does not belong to - * a comment. If the input is exhausted before such a character can be - * found, the null character '\0' is returned. The return value of this - * method is ambiguous for JSON strings that contain the character '\0'. - */ - public char nextClean() throws JSONException { - int nextCleanInt = nextCleanInternal(); - return nextCleanInt == -1 ? '\0' : (char) nextCleanInt; - } + public char nextClean() throws JSONException { + int nextCleanInt = nextCleanInternal(); + return nextCleanInt == -1 ? '\0' : (char) nextCleanInt; + } - /** - * Returns the next {@code length} characters of the input. - * - *

The returned string shares its backing character array with this - * tokener's input string. If a reference to the returned string may be held - * indefinitely, you should use {@code new String(result)} to copy it first - * to avoid memory leaks. - * - * @throws JSONException if the remaining input is not long enough to - * satisfy this request. - */ - public String next(int length) throws JSONException { - if (pos + length > in.length()) { - throw syntaxError(length + " is out of bounds"); - } - String result = in.substring(pos, pos + length); - pos += length; - return result; - } + public String next(int length) throws JSONException { + if (this.pos + length > this.in.length()) { + throw syntaxError(length + " is out of bounds"); + } + String result = this.in.substring(this.pos, this.pos + length); + this.pos += length; + return result; + } - /** - * Returns the {@link String#trim trimmed} string holding the characters up - * to but not including the first of: - *

    - *
  • any character in {@code excluded} - *
  • a newline character '\n' - *
  • a carriage return '\r' - *
- * - *

The returned string shares its backing character array with this - * tokener's input string. If a reference to the returned string may be held - * indefinitely, you should use {@code new String(result)} to copy it first - * to avoid memory leaks. - * - * @return a possibly-empty string - */ - public String nextTo(String excluded) { - if (excluded == null) { - throw new NullPointerException("excluded == null"); - } - return nextToInternal(excluded).trim(); - } + public String nextTo(String excluded) { + if (excluded == null) { + throw new NullPointerException("excluded == null"); + } + return nextToInternal(excluded).trim(); + } - /** - * Equivalent to {@code nextTo(String.valueOf(excluded))}. - */ - public String nextTo(char excluded) { - return nextToInternal(String.valueOf(excluded)).trim(); - } + public String nextTo(char excluded) { + return nextToInternal(String.valueOf(excluded)).trim(); + } - /** - * Advances past all input up to and including the next occurrence of - * {@code thru}. If the remaining input doesn't contain {@code thru}, the - * input is exhausted. - */ - public void skipPast(String thru) { - int thruStart = in.indexOf(thru, pos); - pos = thruStart == -1 ? in.length() : (thruStart + thru.length()); - } + public void skipPast(String thru) { + int thruStart = this.in.indexOf(thru, this.pos); + this.pos = thruStart == -1 ? this.in.length() : (thruStart + thru.length()); + } - /** - * Advances past all input up to but not including the next occurrence of - * {@code to}. If the remaining input doesn't contain {@code to}, the input - * is unchanged. - */ - public char skipTo(char to) { - int index = in.indexOf(to, pos); - if (index != -1) { - pos = index; - return to; - } else { - return '\0'; - } - } + public char skipTo(char to) { + int index = this.in.indexOf(to, this.pos); + if (index != -1) { + this.pos = index; + return to; + } + else { + return '\0'; + } + } - /** - * Unreads the most recent character of input. If no input characters have - * been read, the input is unchanged. - */ - public void back() { - if (--pos == -1) { - pos = 0; - } - } + public void back() { + if (--this.pos == -1) { + this.pos = 0; + } + } - /** - * Returns the integer [0..15] value for the given hex character, or -1 - * for non-hex input. - * - * @param hex a character in the ranges [0-9], [A-F] or [a-f]. Any other - * character will yield a -1 result. - */ - public static int dehexchar(char hex) { - if (hex >= '0' && hex <= '9') { - return hex - '0'; - } else if (hex >= 'A' && hex <= 'F') { - return hex - 'A' + 10; - } else if (hex >= 'a' && hex <= 'f') { - return hex - 'a' + 10; - } else { - return -1; - } - } + public static int dehexchar(char hex) { + if (hex >= '0' && hex <= '9') { + return hex - '0'; + } + else if (hex >= 'A' && hex <= 'F') { + return hex - 'A' + 10; + } + else if (hex >= 'a' && hex <= 'f') { + return hex - 'a' + 10; + } + else { + return -1; + } + } }