Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
292 changes: 171 additions & 121 deletions src/main/java/org/json/JSONArray.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,13 @@
* @author JSON.org
* @version 2016-08/15
*/
public class JSONArray implements Iterable<Object> {
public class JSONArray implements Iterable<Object>, JSONSimilar {

/**
* The constants used for the method toString to eliminate magic number code smell.
*/
private static final int commaMultiplier = 2; // Each value requires a comma in output
private static final int minimumBufferSize = 16; // Minimum reasonable buffer size for small arrays

/**
* The arrayList where the JSONArray's properties are kept.
Expand Down Expand Up @@ -325,27 +331,46 @@ public Object get(int index) throws JSONException {
* Get the boolean value associated with an index. The string values "true"
* and "false" are converted to boolean.
*
* @param index
* The index must be between 0 and length() - 1.
* @param index The index must be between 0 and length() - 1.
* @return The truth.
* @throws JSONException
* If there is no value for the index or if the value is not
* convertible to boolean.
* @throws JSONException If there is no value for the index or if the value is not
* convertible to boolean.
*/
public boolean getBoolean(int index) throws JSONException {
Object object = this.get(index);
if (object.equals(Boolean.FALSE)
|| (object instanceof String && ((String) object)
.equalsIgnoreCase("false"))) {

if (isFalse(object)) {
return false;
} else if (object.equals(Boolean.TRUE)
|| (object instanceof String && ((String) object)
.equalsIgnoreCase("true"))) {
}
if (isTrue(object)) {
return true;
}

throw wrongValueFormatException(index, "boolean", object, null);
}

/**
* Checks if the object represents a false value
* @param object The object to check
* @return true if the object represents false
*/
private boolean isFalse(Object object) {
if (object.equals(Boolean.FALSE)) return true;
if (!(object instanceof String)) return false;
return ((String) object).equalsIgnoreCase("false");
}

/**
* Checks if the object represents a true value
* @param object The object to check
* @return true if the object represents true
*/
private boolean isTrue(Object object) {
if (object.equals(Boolean.TRUE)) return true;
if (!(object instanceof String)) return false;
return ((String) object).equalsIgnoreCase("true");
}

/**
* Get the double value associated with an index.
*
Expand Down Expand Up @@ -1624,44 +1649,21 @@ public Object remove(int index) {
/**
* Determine if two JSONArrays are similar.
* They must contain similar sequences.
*
* @param other The other JSONArray
* @return true if they are equal
*/
@Override
public boolean similar(Object other) {
if (!(other instanceof JSONArray)) {
return false;
}
JSONArray otherArray = (JSONArray)other;
int len = this.length();
if (len != ((JSONArray)other).length()) {
if (len != otherArray.length()) {
return false;
}
for (int i = 0; i < len; i += 1) {
Object valueThis = this.myArrayList.get(i);
Object valueOther = ((JSONArray)other).myArrayList.get(i);
if(valueThis == valueOther) {
continue;
}
if(valueThis == null) {
return false;
}
if (valueThis instanceof JSONObject) {
if (!((JSONObject)valueThis).similar(valueOther)) {
return false;
}
} else if (valueThis instanceof JSONArray) {
if (!((JSONArray)valueThis).similar(valueOther)) {
return false;
}
} else if (valueThis instanceof Number && valueOther instanceof Number) {
if (!JSONObject.isNumberSimilar((Number)valueThis, (Number)valueOther)) {
return false;
}
} else if (valueThis instanceof JSONString && valueOther instanceof JSONString) {
if (!((JSONString) valueThis).toJSONString().equals(((JSONString) valueOther).toJSONString())) {
return false;
}
} else if (!valueThis.equals(valueOther)) {
if (!JSONSimilar.compare(this.myArrayList.get(i), otherArray.myArrayList.get(i))) {
return false;
}
}
Expand Down Expand Up @@ -1714,11 +1716,11 @@ public String toString() {

/**
* Make a pretty-printed JSON text of this JSONArray.
*
*
* <p>If <pre> {@code indentFactor > 0}</pre> and the {@link JSONArray} has only
* one element, then the array will be output on a single line:
* <pre>{@code [1]}</pre>
*
*
* <p>If an array has 2 or more elements, then it will be output across
* multiple lines: <pre>{@code
* [
Expand All @@ -1730,9 +1732,8 @@ public String toString() {
* <p><b>
* Warning: This method assumes that the data structure is acyclical.
* </b>
*
* @param indentFactor
* The number of spaces to add to each level of indentation.
*
* @param indentFactor The number of spaces to add to each level of indentation.
* @return a printable, displayable, transmittable representation of the
* object, beginning with <code>[</code>&nbsp;<small>(left
* bracket)</small> and ending with <code>]</code>
Expand All @@ -1741,101 +1742,150 @@ public String toString() {
*/
@SuppressWarnings("resource")
public String toString(int indentFactor) throws JSONException {
// each value requires a comma, so multiply the count by 2
// We don't want to oversize the initial capacity
int initialSize = myArrayList.size() * 2;
Writer sw = new StringBuilderWriter(Math.max(initialSize, 16));
return this.write(sw, indentFactor, 0).toString();
int initialSize = calculateInitialBufferSize(commaMultiplier);
Writer stringWriter = new StringBuilderWriter(Math.max(initialSize, minimumBufferSize));
return this.write(stringWriter, indentFactor, 0).toString();
}

/**
* Write the contents of the JSONArray as JSON text to a writer. For
* compactness, no whitespace is added.
* <p><b>
* Warning: This method assumes that the data structure is acyclical.
*</b>
* @param writer the writer object
* @return The writer.
* @throws JSONException if a called function fails
* Calculates the initial buffer size needed for JSON string representation.
* @param elementsPerItem Multiplier accounting for commas between elements
* @return Calculated initial size based on array contents
*/
public Writer write(Writer writer) throws JSONException {
return this.write(writer, 0, 0);
private int calculateInitialBufferSize(int elementsPerItem) {
return myArrayList.size() * elementsPerItem;
}

/**
* Write the contents of the JSONArray as JSON text to a writer.
*
* <p>If <pre>{@code indentFactor > 0}</pre> and the {@link JSONArray} has only
* one element, then the array will be output on a single line:
* <pre>{@code [1]}</pre>
*
* <p>If an array has 2 or more elements, then it will be output across
* multiple lines: <pre>{@code
* [
* 1,
* "value 2",
* 3
* ]
* }</pre>
* <p><b>
* Warning: This method assumes that the data structure is acyclical.
* </b>
* Writes the contents of the JSONArray as JSON text to a writer.
*
* <p>If {@code indentFactor > 0} and the JSONArray has only one element,
* the array will be output on a single line (e.g., {@code [1]}). If the array
* has 2 or more elements, it will be output across multiple lines with proper
* indentation.</p>
*
* <p><b>Warning:</b> This method assumes that the data structure is acyclical.</p>
*
* @param writer
* Writes the serialized JSON
* @param indentFactor
* The number of spaces to add to each level of indentation.
* @param indent
* The indentation of the top level.
* @param writer The writer to which the JSON text is written.
* @param indentFactor The number of spaces to add to each level of indentation.
* @param indent The indentation level of the top level.
* @return The writer.
* @throws JSONException if a called function fails or unable to write
* @throws JSONException If an error occurs while writing the JSON text.
*/
@SuppressWarnings("resource")
public Writer write(Writer writer, int indentFactor, int indent)
throws JSONException {
public Writer write(Writer writer, int indentFactor, int indent) throws JSONException {
try {
boolean needsComma = false;
int length = this.length();
writer.write('[');

if (length == 1) {
try {
JSONObject.writeValue(writer, this.myArrayList.get(0),
indentFactor, indent);
} catch (Exception e) {
throw new JSONException("Unable to write JSONArray value at index: 0", e);
}
} else if (length != 0) {
final int newIndent = indent + indentFactor;

for (int i = 0; i < length; i += 1) {
if (needsComma) {
writer.write(',');
}
if (indentFactor > 0) {
writer.write('\n');
}
JSONObject.indent(writer, newIndent);
try {
JSONObject.writeValue(writer, this.myArrayList.get(i),
indentFactor, newIndent);
} catch (Exception e) {
throw new JSONException("Unable to write JSONArray value at index: " + i, e);
}
needsComma = true;
}
if (indentFactor > 0) {
writer.write('\n');
}
JSONObject.indent(writer, indent);
}
writer.write(']');
writeArrayStart(writer);
writeArrayContents(writer, indentFactor, indent);
writeArrayEnd(writer);
return writer;
} catch (IOException e) {
throw new JSONException(e);
}
}

/**
* Writes the opening bracket '[' of the JSONArray to the writer.
*
* @param writer The writer to which the opening bracket is written.
* @throws IOException If an I/O error occurs while writing.
*/
private void writeArrayStart(Writer writer) throws IOException {
writer.write('[');
}

/**
* Writes the contents of the JSONArray to the writer, handling single and multiple elements.
*
* @param writer The writer to which the contents are written.
* @param indentFactor The number of spaces to add to each level of indentation.
* @param indent The indentation level of the top level.
* @throws JSONException If an error occurs while writing the contents.
* @throws IOException If an I/O error occurs while writing.
*/
private void writeArrayContents(Writer writer, int indentFactor, int indent) throws JSONException, IOException {
int length = this.length();
if (length == 1) {
writeSingleElement(writer, indentFactor, indent);
} else if (length != 0) {
writeMultipleElements(writer, indentFactor, indent);
}
}

/**
* Writes a single element of the JSONArray to the writer.
*
* @param writer The writer to which the element is written.
* @param indentFactor The number of spaces to add to each level of indentation.
* @param indent The indentation level of the top level.
* @throws JSONException If an error occurs while writing the element.
*/
private void writeSingleElement(Writer writer, int indentFactor, int indent) throws JSONException {
try {
JSONObject.writeValue(writer, this.myArrayList.get(0), indentFactor, indent);
} catch (Exception e) {
throw new JSONException("Unable to write JSONArray value at index: 0", e);
}
}

/**
* Writes multiple elements of the JSONArray to the writer, formatting them with proper indentation.
*
* @param writer The writer to which the elements are written.
* @param indentFactor The number of spaces to add to each level of indentation.
* @param indent The indentation level of the top level.
* @throws JSONException If an error occurs while writing the elements.
* @throws IOException If an I/O error occurs while writing.
*/
private void writeMultipleElements(Writer writer, int indentFactor, int indent) throws JSONException, IOException {
final int newIndent = indent + indentFactor;
boolean needsComma = false;

for (int i = 0; i < this.length(); i += 1) {
if (needsComma) {
writer.write(',');
}
if (indentFactor > 0) {
writer.write('\n');
}
JSONObject.indent(writer, newIndent);
writeElement(writer, i, indentFactor, newIndent);
needsComma = true;
}

if (indentFactor > 0) {
writer.write('\n');
}
JSONObject.indent(writer, indent);
}

/**
* Writes a specific element of the JSONArray to the writer.
*
* @param writer The writer to which the element is written.
* @param index The index of the element to write.
* @param indentFactor The number of spaces to add to each level of indentation.
* @param indent The indentation level of the top level.
* @throws JSONException If an error occurs while writing the element.
*/
private void writeElement(Writer writer, int index, int indentFactor, int indent) throws JSONException {
try {
JSONObject.writeValue(writer, this.myArrayList.get(index), indentFactor, indent);
} catch (Exception e) {
throw new JSONException("Unable to write JSONArray value at index: " + index, e);
}
}

/**
* Writes the closing bracket ']' of the JSONArray to the writer.
*
* @param writer The writer to which the closing bracket is written.
* @throws IOException If an I/O error occurs while writing.
*/
private void writeArrayEnd(Writer writer) throws IOException {
writer.write(']');
}

/**
* Returns a java.util.List containing all of the elements in this array.
* If an element in the array is a JSONArray or JSONObject it will also
Expand Down
Loading
Loading