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.BaseCloseable; import com.revolsys.io.FileUtil; import com.revolsys.io.map.MapSerializer; import com.revolsys.util.Exceptions; import com.revolsys.util.number.Doubles; public final class JsonWriter implements BaseCloseable { private int depth = 0; private boolean indent; private Writer out; private boolean startAttribute; public JsonWriter(final Writer out) { this(out, true); } public JsonWriter(final Writer out, final boolean indent) { this.out = out; this.indent = indent; } public void charSequence(final CharSequence string) { try { JsonWriterUtil.charSequence(this.out, string); } catch (final Exception e) { throw Exceptions.wrap(e); } } @Override public void close() { FileUtil.closeSilent(this.out); this.out = null; } public void endAttribute() { try { this.out.write(","); newLine(); this.startAttribute = false; } catch (final Exception e) { throw Exceptions.wrap(e); } } public void endList() { try { this.depth--; newLine(); indent(); this.out.write("]"); } catch (final Exception e) { throw Exceptions.wrap(e); } } public void endObject() { try { this.depth--; newLine(); indent(); this.out.write("}"); } catch (final Exception e) { throw Exceptions.wrap(e); } } public void flush() { try { this.out.flush(); } catch (final Exception e) { } } public void indent() { try { if (this.indent) { for (int i = 0; i < this.depth; i++) { this.out.write(" "); } } } catch (final Exception e) { throw Exceptions.wrap(e); } } public void label(final String key) { try { indent(); value(key); this.out.write(": "); this.startAttribute = true; } catch (final Exception e) { throw Exceptions.wrap(e); } } public void list(final Object... values) throws IOException { startList(); final int size = values.length; if (size > 1) { if (this.indent) { { final Object value = values[0]; indent(); value(value); } for (int index = 1; index < size; index++) { endAttribute(); indent(); final Object value = values[index]; value(value); } } else { { final Object value = values[0]; value(value); } for (int index = 1; index < size; index++) { endAttribute(); final Object value = values[index]; value(value); } } } endList(); } public void newLine() { try { if (this.indent) { this.out.write('\n'); } } catch (final Exception e) { throw Exceptions.wrap(e); } } public void print(final char value) { try { this.out.write(value); } catch (final Exception e) { throw Exceptions.wrap(e); } } public void print(final Object value) { if (value != null) { try { this.out.write(value.toString()); } catch (final Exception e) { throw Exceptions.wrap(e); } } } public void setIndent(final boolean indent) { this.indent = indent; } public void startList() { final boolean indent = true; startList(indent); } public void startList(final boolean indent) { try { if (indent && !this.startAttribute) { indent(); } this.out.write('['); newLine(); this.depth++; this.startAttribute = false; } catch (final Exception e) { throw Exceptions.wrap(e); } } public void startObject() { try { if (!this.startAttribute) { indent(); } this.out.write('{'); newLine(); this.depth++; this.startAttribute = false; } catch (final Exception e) { throw Exceptions.wrap(e); } } @SuppressWarnings("unchecked") public void value(final Object value) { try { if (value == null) { this.out.write("null"); } else if (value instanceof Boolean) { if ((Boolean)value) { this.out.write("true"); } else { this.out.write("false"); } } else if (value instanceof Number) { final Number number = (Number)value; final double doubleValue = number.doubleValue(); if (Double.isInfinite(doubleValue) || Double.isNaN(doubleValue)) { this.out.write("null"); } else { this.out.write(Doubles.toString(doubleValue)); } } else if (value instanceof MapSerializer) { final Map<String, ? extends Object> map = ((MapSerializer)value).toMap(); write(map); } else if (value instanceof Collection) { final Collection<? extends Object> list = (Collection<? extends Object>)value; write(list); } else if (value instanceof Map) { final Map<String, ? extends Object> map = (Map<String, ? extends Object>)value; write(map); } else if (value instanceof CharSequence) { final CharSequence string = (CharSequence)value; this.out.write('"'); charSequence(string); this.out.write('"'); } else if (value.getClass().isArray()) { final List<? extends Object> list = Lists.arrayToList(value); write(list); } else { value(DataTypes.toString(value)); } } catch (final Exception e) { throw Exceptions.wrap(e); } } public void write(final Collection<? extends Object> values) throws IOException { startList(); int i = 0; final int size = values.size(); final Iterator<? extends Object> iterator = values.iterator(); if (this.indent) { while (i < size - 1) { final Object value = iterator.next(); indent(); value(value); endAttribute(); i++; } if (iterator.hasNext()) { indent(); final Object value = iterator.next(); value(value); } } else { while (i < size - 1) { final Object value = iterator.next(); value(value); endAttribute(); i++; } if (iterator.hasNext()) { final Object value = iterator.next(); value(value); } } endList(); } public void write(final Map<String, ? extends Object> values) { startObject(); if (values != null) { final Set<String> fields = values.keySet(); int i = 0; final int size = fields.size(); final Iterator<String> iterator = fields.iterator(); while (i < size - 1) { final Object keyObject = iterator.next(); final String key = keyObject.toString(); final Object value = values.get(key); label(key); value(value); endAttribute(); i++; } if (iterator.hasNext()) { final Object keyObject = iterator.next(); final String key = keyObject.toString(); final Object value = values.get(key); label(key); value(value); } } endObject(); } }