package com.revolsys.record.io.format.json; import java.io.IOException; import java.io.Writer; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import com.revolsys.collection.list.Lists; import com.revolsys.datatype.DataTypes; import com.revolsys.io.StringPrinter; import com.revolsys.util.MathUtil; import com.revolsys.util.number.Numbers; public final class JsonWriterUtil { public static void charSequence(final Writer out, final CharSequence string) throws IOException { for (int i = 0; i < string.length(); i++) { final char c = string.charAt(i); switch (c) { case '"': out.write("\\\""); break; case '\\': out.write("\\\\"); break; case '\b': out.write("\\b"); break; case '\f': out.write("\\f"); break; case '\n': out.write("\\n"); break; case '\r': out.write("\\r"); break; case '\t': out.write("\\t"); break; default: out.write(c); break; } } } public static void endAttribute(final Writer out, final String indent) throws IOException { out.write(','); newLine(out, indent); } public static void endList(final Writer out) throws IOException { out.write(']'); } public static void endObject(final Writer out) throws IOException { out.write('}'); } public static void label(final Writer out, final String key, final String indent) throws IOException { writeIndent(out, indent); out.write('"'); charSequence(out, key); out.write('"'); out.write(":"); } public static void newLine(final Writer out, final String indent) throws IOException { if (indent != null) { out.write('\n'); } } public static void startList(final Writer out, final String indent) throws IOException { out.write('['); newLine(out, indent); } public static void startObject(final Writer out, final String indent) throws IOException { out.write('{'); newLine(out, indent); } public static void write(final Writer out, final Collection<? extends Object> values, final String indent, final boolean writeNulls) throws IOException { startList(out, indent); String newIndent = indent; if (newIndent != null) { newIndent += " "; } if (values != null) { int i = 0; final int size = values.size(); final Iterator<? extends Object> iterator = values.iterator(); while (i < size - 1) { writeIndent(out, newIndent); final Object value = iterator.next(); write(out, value, newIndent, writeNulls); endAttribute(out, indent); i++; } if (iterator.hasNext()) { writeIndent(out, newIndent); final Object value = iterator.next(); write(out, value, newIndent, writeNulls); newLine(out, indent); } } writeIndent(out, indent); endList(out); } public static void write(final Writer out, final Map<String, ? extends Object> values, final String indent, final boolean writeNulls) throws IOException { startObject(out, indent); if (values != null) { String newIndent = indent; if (newIndent != null) { newIndent += " "; } final Set<String> fields = values.keySet(); boolean hasValue = false; for (final String key : fields) { if (hasValue) { endAttribute(out, indent); } else { hasValue = true; } final Object value = values.get(key); label(out, key, newIndent); write(out, value, newIndent, writeNulls); } if (hasValue) { newLine(out, newIndent); } } writeIndent(out, indent); endObject(out); } @SuppressWarnings("unchecked") public static void write(final Writer out, final Object value, final String indent, final boolean writeNulls) throws IOException { if (value == null) { out.write("null"); } else if (value instanceof StringPrinter) { final StringPrinter printer = (StringPrinter)value; printer.write(out); } else if (value instanceof Boolean) { if ((Boolean)value) { out.write("true"); } else { out.write("false"); } } else if (value instanceof Number) { final Number number = (Number)value; String string = Numbers.toString(number); if ("NaN".equals(string)) { string = "null"; } else if ("Infinity".equals(string)) { string = MathUtil.MAX_DOUBLE_STRING; } else if ("-Infinity".equals(string)) { string = MathUtil.MIN_DOUBLE_STRING; } out.write(string); } else if (value instanceof Collection) { final Collection<? extends Object> list = (Collection<? extends Object>)value; write(out, list, indent, writeNulls); } else if (value instanceof Map) { final Map<String, ? extends Object> map = (Map<String, ? extends Object>)value; write(out, map, indent, false); } else if (value instanceof CharSequence) { final CharSequence string = (CharSequence)value; out.write('"'); charSequence(out, string); out.write('"'); } else if (value.getClass().isArray()) { final List<? extends Object> list = Lists.arrayToList(value); write(out, list, indent, writeNulls); } else { write(out, DataTypes.toString(value), indent, writeNulls); } } protected static void writeIndent(final Writer out, final String indent) throws IOException { if (indent != null) { out.write(indent); } } private JsonWriterUtil() { } }