Java tutorial
/******************************************************************************* * Copyright 2011 See AUTHORS file. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package com.badlogic.gdx.utils; import com.badlogic.gdx.utils.JsonWriter.OutputType; import java.util.Iterator; import java.util.NoSuchElementException; /** Container for a JSON object, array, string, double, long, boolean, or null. * <p> * JsonValue children are a linked list. Iteration of arrays or objects is easily done using a for loop, either with the enhanced * for loop syntactic sugar or like the example below. This is much more efficient than accessing children by index when there are * many children.<br> * * <pre> * JsonValue map = ...; * for (JsonValue entry = map.child; entry != null; entry = entry.next) * System.out.println(entry.name + " = " + entry.asString()); * </pre> * @author Nathan Sweet */ public class JsonValue implements Iterable<JsonValue> { private ValueType type; private String stringValue; private double doubleValue; private long longValue; public String name; /** May be null. */ public JsonValue child, next, prev; public int size; public JsonValue(ValueType type) { this.type = type; } /** @param value May be null. */ public JsonValue(String value) { set(value); } public JsonValue(double value) { set(value); } public JsonValue(long value) { set(value); } public JsonValue(boolean value) { set(value); } /** Returns the child at the specified index. This requires walking the linked list to the specified entry, see * {@link JsonValue} for how to iterate efficiently. * @return May be null. */ public JsonValue get(int index) { JsonValue current = child; while (current != null && index > 0) { index--; current = current.next; } return current; } /** Returns the child with the specified name. * @return May be null. */ public JsonValue get(String name) { JsonValue current = child; while (current != null && !current.name.equalsIgnoreCase(name)) current = current.next; return current; } /** Returns true if a child with the specified name exists. */ public boolean has(String name) { return get(name) != null; } /** Returns the child at the specified index. This requires walking the linked list to the specified entry, see * {@link JsonValue} for how to iterate efficiently. * @throws IllegalArgumentException if the child was not found. */ public JsonValue require(int index) { JsonValue current = child; while (current != null && index > 0) { index--; current = current.next; } if (current == null) throw new IllegalArgumentException("Child not found with index: " + index); return current; } /** Returns the child with the specified name. * @throws IllegalArgumentException if the child was not found. */ public JsonValue require(String name) { JsonValue current = child; while (current != null && !current.name.equalsIgnoreCase(name)) current = current.next; if (current == null) throw new IllegalArgumentException("Child not found with name: " + name); return current; } /** Removes the child with the specified index. This requires walking the linked list to the specified entry, see * {@link JsonValue} for how to iterate efficiently. * @return May be null. */ public JsonValue remove(int index) { JsonValue child = get(index); if (child == null) return null; if (child.prev == null) { this.child = child.next; if (this.child != null) this.child.prev = null; } else { child.prev.next = child.next; if (child.next != null) child.next.prev = child.prev; } size--; return child; } /** Removes the child with the specified name. * @return May be null. */ public JsonValue remove(String name) { JsonValue child = get(name); if (child == null) return null; if (child.prev == null) { this.child = child.next; if (this.child != null) this.child.prev = null; } else { child.prev.next = child.next; if (child.next != null) child.next.prev = child.prev; } size--; return child; } /** @deprecated Use the size property instead. Returns this number of children in the array or object. */ @Deprecated public int size() { return size; } /** Returns this value as a string. * @return May be null if this value is null. * @throws IllegalStateException if this an array or object. */ public String asString() { switch (type) { case stringValue: return stringValue; case doubleValue: return Double.toString(doubleValue); case longValue: return Long.toString(longValue); case booleanValue: return longValue != 0 ? "true" : "false"; case nullValue: return null; } throw new IllegalStateException("Value cannot be converted to string: " + type); } /** Returns this value as a float. * @throws IllegalStateException if this an array or object. */ public float asFloat() { switch (type) { case stringValue: return Float.parseFloat(stringValue); case doubleValue: return (float) doubleValue; case longValue: return (float) longValue; case booleanValue: return longValue != 0 ? 1 : 0; } throw new IllegalStateException("Value cannot be converted to float: " + type); } /** Returns this value as a double. * @throws IllegalStateException if this an array or object. */ public double asDouble() { switch (type) { case stringValue: return Double.parseDouble(stringValue); case doubleValue: return doubleValue; case longValue: return (double) longValue; case booleanValue: return longValue != 0 ? 1 : 0; } throw new IllegalStateException("Value cannot be converted to double: " + type); } /** Returns this value as a long. * @throws IllegalStateException if this an array or object. */ public long asLong() { switch (type) { case stringValue: return Long.parseLong(stringValue); case doubleValue: return (long) doubleValue; case longValue: return longValue; case booleanValue: return longValue != 0 ? 1 : 0; } throw new IllegalStateException("Value cannot be converted to long: " + type); } /** Returns this value as an int. * @throws IllegalStateException if this an array or object. */ public int asInt() { switch (type) { case stringValue: return Integer.parseInt(stringValue); case doubleValue: return (int) doubleValue; case longValue: return (int) longValue; case booleanValue: return longValue != 0 ? 1 : 0; } throw new IllegalStateException("Value cannot be converted to int: " + type); } /** Returns this value as a boolean. * @throws IllegalStateException if this an array or object. */ public boolean asBoolean() { switch (type) { case stringValue: return stringValue.equalsIgnoreCase("true"); case doubleValue: return doubleValue != 0; case longValue: return longValue != 0; case booleanValue: return longValue != 0; } throw new IllegalStateException("Value cannot be converted to boolean: " + type); } /** Returns this value as a byte. * @throws IllegalStateException if this an array or object. */ public byte asByte() { switch (type) { case stringValue: return Byte.parseByte(stringValue); case doubleValue: return (byte) doubleValue; case longValue: return (byte) longValue; case booleanValue: return longValue != 0 ? (byte) 1 : 0; } throw new IllegalStateException("Value cannot be converted to byte: " + type); } /** Returns this value as a short. * @throws IllegalStateException if this an array or object. */ public short asShort() { switch (type) { case stringValue: return Short.parseShort(stringValue); case doubleValue: return (short) doubleValue; case longValue: return (short) longValue; case booleanValue: return longValue != 0 ? (short) 1 : 0; } throw new IllegalStateException("Value cannot be converted to short: " + type); } /** Returns this value as a char. * @throws IllegalStateException if this an array or object. */ public char asChar() { switch (type) { case stringValue: return stringValue.length() == 0 ? 0 : stringValue.charAt(0); case doubleValue: return (char) doubleValue; case longValue: return (char) longValue; case booleanValue: return longValue != 0 ? (char) 1 : 0; } throw new IllegalStateException("Value cannot be converted to char: " + type); } /** Returns the children of this value as a newly allocated String array. * @throws IllegalStateException if this is not an array. */ public String[] asStringArray() { if (type != ValueType.array) throw new IllegalStateException("Value is not an array: " + type); String[] array = new String[size]; int i = 0; for (JsonValue value = child; value != null; value = value.next, i++) { String v; switch (value.type) { case stringValue: v = value.stringValue; break; case doubleValue: v = Double.toString(value.doubleValue); break; case longValue: v = Long.toString(value.longValue); break; case booleanValue: v = value.longValue != 0 ? "true" : "false"; break; case nullValue: v = null; break; default: throw new IllegalStateException("Value cannot be converted to string: " + value.type); } array[i] = v; } return array; } /** Returns the children of this value as a newly allocated float array. * @throws IllegalStateException if this is not an array. */ public float[] asFloatArray() { if (type != ValueType.array) throw new IllegalStateException("Value is not an array: " + type); float[] array = new float[size]; int i = 0; for (JsonValue value = child; value != null; value = value.next, i++) { float v; switch (value.type) { case stringValue: v = Float.parseFloat(value.stringValue); break; case doubleValue: v = (float) value.doubleValue; break; case longValue: v = (float) value.longValue; break; case booleanValue: v = value.longValue != 0 ? 1 : 0; break; default: throw new IllegalStateException("Value cannot be converted to float: " + value.type); } array[i] = v; } return array; } /** Returns the children of this value as a newly allocated double array. * @throws IllegalStateException if this is not an array. */ public double[] asDoubleArray() { if (type != ValueType.array) throw new IllegalStateException("Value is not an array: " + type); double[] array = new double[size]; int i = 0; for (JsonValue value = child; value != null; value = value.next, i++) { double v; switch (value.type) { case stringValue: v = Double.parseDouble(value.stringValue); break; case doubleValue: v = value.doubleValue; break; case longValue: v = (double) value.longValue; break; case booleanValue: v = value.longValue != 0 ? 1 : 0; break; default: throw new IllegalStateException("Value cannot be converted to double: " + value.type); } array[i] = v; } return array; } /** Returns the children of this value as a newly allocated long array. * @throws IllegalStateException if this is not an array. */ public long[] asLongArray() { if (type != ValueType.array) throw new IllegalStateException("Value is not an array: " + type); long[] array = new long[size]; int i = 0; for (JsonValue value = child; value != null; value = value.next, i++) { long v; switch (value.type) { case stringValue: v = Long.parseLong(value.stringValue); break; case doubleValue: v = (long) value.doubleValue; break; case longValue: v = value.longValue; break; case booleanValue: v = value.longValue != 0 ? 1 : 0; break; default: throw new IllegalStateException("Value cannot be converted to long: " + value.type); } array[i] = v; } return array; } /** Returns the children of this value as a newly allocated int array. * @throws IllegalStateException if this is not an array. */ public int[] asIntArray() { if (type != ValueType.array) throw new IllegalStateException("Value is not an array: " + type); int[] array = new int[size]; int i = 0; for (JsonValue value = child; value != null; value = value.next, i++) { int v; switch (value.type) { case stringValue: v = Integer.parseInt(value.stringValue); break; case doubleValue: v = (int) value.doubleValue; break; case longValue: v = (int) value.longValue; break; case booleanValue: v = value.longValue != 0 ? 1 : 0; break; default: throw new IllegalStateException("Value cannot be converted to int: " + value.type); } array[i] = v; } return array; } /** Returns the children of this value as a newly allocated boolean array. * @throws IllegalStateException if this is not an array. */ public boolean[] asBooleanArray() { if (type != ValueType.array) throw new IllegalStateException("Value is not an array: " + type); boolean[] array = new boolean[size]; int i = 0; for (JsonValue value = child; value != null; value = value.next, i++) { boolean v; switch (value.type) { case stringValue: v = Boolean.parseBoolean(value.stringValue); break; case doubleValue: v = value.doubleValue == 0; break; case longValue: v = value.longValue == 0; break; case booleanValue: v = value.longValue != 0; break; default: throw new IllegalStateException("Value cannot be converted to boolean: " + value.type); } array[i] = v; } return array; } /** Returns the children of this value as a newly allocated byte array. * @throws IllegalStateException if this is not an array. */ public byte[] asByteArray() { if (type != ValueType.array) throw new IllegalStateException("Value is not an array: " + type); byte[] array = new byte[size]; int i = 0; for (JsonValue value = child; value != null; value = value.next, i++) { byte v; switch (value.type) { case stringValue: v = Byte.parseByte(value.stringValue); break; case doubleValue: v = (byte) value.doubleValue; break; case longValue: v = (byte) value.longValue; break; case booleanValue: v = value.longValue != 0 ? (byte) 1 : 0; break; default: throw new IllegalStateException("Value cannot be converted to byte: " + value.type); } array[i] = v; } return array; } /** Returns the children of this value as a newly allocated short array. * @throws IllegalStateException if this is not an array. */ public short[] asShortArray() { if (type != ValueType.array) throw new IllegalStateException("Value is not an array: " + type); short[] array = new short[size]; int i = 0; for (JsonValue value = child; value != null; value = value.next, i++) { short v; switch (value.type) { case stringValue: v = Short.parseShort(value.stringValue); break; case doubleValue: v = (short) value.doubleValue; break; case longValue: v = (short) value.longValue; break; case booleanValue: v = value.longValue != 0 ? (short) 1 : 0; break; default: throw new IllegalStateException("Value cannot be converted to short: " + value.type); } array[i] = v; } return array; } /** Returns the children of this value as a newly allocated char array. * @throws IllegalStateException if this is not an array. */ public char[] asCharArray() { if (type != ValueType.array) throw new IllegalStateException("Value is not an array: " + type); char[] array = new char[size]; int i = 0; for (JsonValue value = child; value != null; value = value.next, i++) { char v; switch (value.type) { case stringValue: v = value.stringValue.length() == 0 ? 0 : value.stringValue.charAt(0); break; case doubleValue: v = (char) value.doubleValue; break; case longValue: v = (char) value.longValue; break; case booleanValue: v = value.longValue != 0 ? (char) 1 : 0; break; default: throw new IllegalStateException("Value cannot be converted to char: " + value.type); } array[i] = v; } return array; } /** Returns true if a child with the specified name exists and has a child. */ public boolean hasChild(String name) { return getChild(name) != null; } /** Finds the child with the specified name and returns its first child. * @return May be null. */ public JsonValue getChild(String name) { JsonValue child = get(name); return child == null ? null : child.child; } /** Finds the child with the specified name and returns it as a string. Returns defaultValue if not found. * @param defaultValue May be null. */ public String getString(String name, String defaultValue) { JsonValue child = get(name); return (child == null || !child.isValue() || child.isNull()) ? defaultValue : child.asString(); } /** Finds the child with the specified name and returns it as a float. Returns defaultValue if not found. */ public float getFloat(String name, float defaultValue) { JsonValue child = get(name); return (child == null || !child.isValue()) ? defaultValue : child.asFloat(); } /** Finds the child with the specified name and returns it as a double. Returns defaultValue if not found. */ public double getDouble(String name, double defaultValue) { JsonValue child = get(name); return (child == null || !child.isValue()) ? defaultValue : child.asDouble(); } /** Finds the child with the specified name and returns it as a long. Returns defaultValue if not found. */ public long getLong(String name, long defaultValue) { JsonValue child = get(name); return (child == null || !child.isValue()) ? defaultValue : child.asLong(); } /** Finds the child with the specified name and returns it as an int. Returns defaultValue if not found. */ public int getInt(String name, int defaultValue) { JsonValue child = get(name); return (child == null || !child.isValue()) ? defaultValue : child.asInt(); } /** Finds the child with the specified name and returns it as a boolean. Returns defaultValue if not found. */ public boolean getBoolean(String name, boolean defaultValue) { JsonValue child = get(name); return (child == null || !child.isValue()) ? defaultValue : child.asBoolean(); } /** Finds the child with the specified name and returns it as a byte. Returns defaultValue if not found. */ public byte getByte(String name, byte defaultValue) { JsonValue child = get(name); return (child == null || !child.isValue()) ? defaultValue : child.asByte(); } /** Finds the child with the specified name and returns it as a short. Returns defaultValue if not found. */ public short getShort(String name, short defaultValue) { JsonValue child = get(name); return (child == null || !child.isValue()) ? defaultValue : child.asShort(); } /** Finds the child with the specified name and returns it as a char. Returns defaultValue if not found. */ public char getChar(String name, char defaultValue) { JsonValue child = get(name); return (child == null || !child.isValue()) ? defaultValue : child.asChar(); } /** Finds the child with the specified name and returns it as a string. * @throws IllegalArgumentException if the child was not found. */ public String getString(String name) { JsonValue child = get(name); if (child == null) throw new IllegalArgumentException("Named value not found: " + name); return child.asString(); } /** Finds the child with the specified name and returns it as a float. * @throws IllegalArgumentException if the child was not found. */ public float getFloat(String name) { JsonValue child = get(name); if (child == null) throw new IllegalArgumentException("Named value not found: " + name); return child.asFloat(); } /** Finds the child with the specified name and returns it as a double. * @throws IllegalArgumentException if the child was not found. */ public double getDouble(String name) { JsonValue child = get(name); if (child == null) throw new IllegalArgumentException("Named value not found: " + name); return child.asDouble(); } /** Finds the child with the specified name and returns it as a long. * @throws IllegalArgumentException if the child was not found. */ public long getLong(String name) { JsonValue child = get(name); if (child == null) throw new IllegalArgumentException("Named value not found: " + name); return child.asLong(); } /** Finds the child with the specified name and returns it as an int. * @throws IllegalArgumentException if the child was not found. */ public int getInt(String name) { JsonValue child = get(name); if (child == null) throw new IllegalArgumentException("Named value not found: " + name); return child.asInt(); } /** Finds the child with the specified name and returns it as a boolean. * @throws IllegalArgumentException if the child was not found. */ public boolean getBoolean(String name) { JsonValue child = get(name); if (child == null) throw new IllegalArgumentException("Named value not found: " + name); return child.asBoolean(); } /** Finds the child with the specified name and returns it as a byte. * @throws IllegalArgumentException if the child was not found. */ public byte getByte(String name) { JsonValue child = get(name); if (child == null) throw new IllegalArgumentException("Named value not found: " + name); return child.asByte(); } /** Finds the child with the specified name and returns it as a short. * @throws IllegalArgumentException if the child was not found. */ public short getShort(String name) { JsonValue child = get(name); if (child == null) throw new IllegalArgumentException("Named value not found: " + name); return child.asShort(); } /** Finds the child with the specified name and returns it as a char. * @throws IllegalArgumentException if the child was not found. */ public char getChar(String name) { JsonValue child = get(name); if (child == null) throw new IllegalArgumentException("Named value not found: " + name); return child.asChar(); } /** Finds the child with the specified index and returns it as a string. * @throws IllegalArgumentException if the child was not found. */ public String getString(int index) { JsonValue child = get(index); if (child == null) throw new IllegalArgumentException("Indexed value not found: " + name); return child.asString(); } /** Finds the child with the specified index and returns it as a float. * @throws IllegalArgumentException if the child was not found. */ public float getFloat(int index) { JsonValue child = get(index); if (child == null) throw new IllegalArgumentException("Indexed value not found: " + name); return child.asFloat(); } /** Finds the child with the specified index and returns it as a double. * @throws IllegalArgumentException if the child was not found. */ public double getDouble(int index) { JsonValue child = get(index); if (child == null) throw new IllegalArgumentException("Indexed value not found: " + name); return child.asDouble(); } /** Finds the child with the specified index and returns it as a long. * @throws IllegalArgumentException if the child was not found. */ public long getLong(int index) { JsonValue child = get(index); if (child == null) throw new IllegalArgumentException("Indexed value not found: " + name); return child.asLong(); } /** Finds the child with the specified index and returns it as an int. * @throws IllegalArgumentException if the child was not found. */ public int getInt(int index) { JsonValue child = get(index); if (child == null) throw new IllegalArgumentException("Indexed value not found: " + name); return child.asInt(); } /** Finds the child with the specified index and returns it as a boolean. * @throws IllegalArgumentException if the child was not found. */ public boolean getBoolean(int index) { JsonValue child = get(index); if (child == null) throw new IllegalArgumentException("Indexed value not found: " + name); return child.asBoolean(); } /** Finds the child with the specified index and returns it as a byte. * @throws IllegalArgumentException if the child was not found. */ public byte getByte(int index) { JsonValue child = get(index); if (child == null) throw new IllegalArgumentException("Indexed value not found: " + name); return child.asByte(); } /** Finds the child with the specified index and returns it as a short. * @throws IllegalArgumentException if the child was not found. */ public short getShort(int index) { JsonValue child = get(index); if (child == null) throw new IllegalArgumentException("Indexed value not found: " + name); return child.asShort(); } /** Finds the child with the specified index and returns it as a char. * @throws IllegalArgumentException if the child was not found. */ public char getChar(int index) { JsonValue child = get(index); if (child == null) throw new IllegalArgumentException("Indexed value not found: " + name); return child.asChar(); } public ValueType type() { return type; } public void setType(ValueType type) { if (type == null) throw new IllegalArgumentException("type cannot be null."); this.type = type; } public boolean isArray() { return type == ValueType.array; } public boolean isObject() { return type == ValueType.object; } public boolean isString() { return type == ValueType.stringValue; } /** Returns true if this is a double or long value. */ public boolean isNumber() { return type == ValueType.doubleValue || type == ValueType.longValue; } public boolean isDouble() { return type == ValueType.doubleValue; } public boolean isLong() { return type == ValueType.longValue; } public boolean isBoolean() { return type == ValueType.booleanValue; } public boolean isNull() { return type == ValueType.nullValue; } /** Returns true if this is not an array or object. */ public boolean isValue() { switch (type) { case stringValue: case doubleValue: case longValue: case booleanValue: case nullValue: return true; } return false; } /** Returns the name for this object value. * @return May be null. */ public String name() { return name; } public void setName(String name) { this.name = name; } /** Returns the first child for this object or array. * @return May be null. */ public JsonValue child() { return child; } /** Returns the next sibling of this value. * @return May be null. */ public JsonValue next() { return next; } public void setNext(JsonValue next) { this.next = next; } /** Returns the previous sibling of this value. * @return May be null. */ public JsonValue prev() { return prev; } public void setPrev(JsonValue prev) { this.prev = prev; } /** @param value May be null. */ public void set(String value) { stringValue = value; type = value == null ? ValueType.nullValue : ValueType.stringValue; } public void set(double value) { doubleValue = value; longValue = (long) value; type = ValueType.doubleValue; } public void set(long value) { longValue = value; doubleValue = (double) value; type = ValueType.longValue; } public void set(boolean value) { longValue = value ? 1 : 0; type = ValueType.booleanValue; } public String toString() { if (isValue()) return name == null ? asString() : name + ": " + asString(); else return prettyPrint(OutputType.minimal, 0); } public String prettyPrint(OutputType outputType, int singleLineColumns) { PrettyPrintSettings settings = new PrettyPrintSettings(); settings.outputType = outputType; settings.singleLineColumns = singleLineColumns; return prettyPrint(settings); } public String prettyPrint(PrettyPrintSettings settings) { StringBuilder buffer = new StringBuilder(512); prettyPrint(this, buffer, 0, settings); return buffer.toString(); } private void prettyPrint(JsonValue object, StringBuilder buffer, int indent, PrettyPrintSettings settings) { if (object.isObject()) { if (object.child() == null) { buffer.append("{}"); } else { boolean newLines = !isFlat(object); int start = buffer.length(); outer: while (true) { buffer.append(newLines ? "{\n" : "{ "); int i = 0; for (JsonValue child = object.child(); child != null; child = child.next()) { if (newLines) indent(indent, buffer); buffer.append(settings.outputType.quoteName(child.name())); buffer.append(": "); prettyPrint(child, buffer, indent + 1, settings); if (child.next() != null) buffer.append(","); buffer.append(newLines ? '\n' : ' '); if (!newLines && buffer.length() - start > settings.singleLineColumns) { buffer.setLength(start); newLines = true; continue outer; } } break; } if (newLines) indent(indent - 1, buffer); buffer.append('}'); } } else if (object.isArray()) { if (object.child() == null) { buffer.append("[]"); } else { boolean newLines = !isFlat(object); boolean wrap = settings.wrapNumericArrays || !isNumeric(object); int start = buffer.length(); outer: while (true) { buffer.append(newLines ? "[\n" : "[ "); for (JsonValue child = object.child(); child != null; child = child.next()) { if (newLines) indent(indent, buffer); prettyPrint(child, buffer, indent + 1, settings); if (child.next() != null) buffer.append(","); buffer.append(newLines ? '\n' : ' '); if (wrap && !newLines && buffer.length() - start > settings.singleLineColumns) { buffer.setLength(start); newLines = true; continue outer; } } break; } if (newLines) indent(indent - 1, buffer); buffer.append(']'); } } else if (object.isString()) { buffer.append(settings.outputType.quoteValue(object.asString())); } else if (object.isDouble()) { double doubleValue = object.asDouble(); long longValue = object.asLong(); buffer.append(doubleValue == longValue ? longValue : doubleValue); } else if (object.isLong()) { buffer.append(object.asLong()); } else if (object.isBoolean()) { buffer.append(object.asBoolean()); } else if (object.isNull()) { buffer.append("null"); } else throw new SerializationException("Unknown object type: " + object); } static private boolean isFlat(JsonValue object) { for (JsonValue child = object.child(); child != null; child = child.next()) if (child.isObject() || child.isArray()) return false; return true; } static private boolean isNumeric(JsonValue object) { for (JsonValue child = object.child(); child != null; child = child.next()) if (!child.isNumber()) return false; return true; } static private void indent(int count, StringBuilder buffer) { for (int i = 0; i < count; i++) buffer.append('\t'); } public enum ValueType { object, array, stringValue, doubleValue, longValue, booleanValue, nullValue } public JsonIterator iterator() { return new JsonIterator(); } public class JsonIterator implements Iterator<JsonValue>, Iterable<JsonValue> { JsonValue entry = child; JsonValue current; public boolean hasNext() { return entry != null; } public JsonValue next() { current = entry; if (current == null) throw new NoSuchElementException(); entry = current.next; return current; } public void remove() { if (current.prev == null) { child = current.next; if (child != null) child.prev = null; } else { current.prev.next = current.next; if (current.next != null) current.next.prev = current.prev; } size--; } public Iterator<JsonValue> iterator() { return this; } } static public class PrettyPrintSettings { public OutputType outputType; /** If an object on a single line fits this many columns, it won't wrap. */ public int singleLineColumns; /** Arrays of floats won't wrap. */ public boolean wrapNumericArrays; } }