/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.noggit; import java.util.*; /** */ public class JSONWriter { /** Implement this interface on your class to support serialization */ public static interface Writable { public void write(JSONWriter writer); } protected int level; protected int indent; protected final CharArr out; /** * @param out the CharArr to write the output to. * @param indentSize The number of space characters to use as an indent (default 2). 0=newlines but no spaces, -1=no indent at all. */ public JSONWriter(CharArr out, int indentSize) { this.out = out; this.indent = indentSize; } public JSONWriter(CharArr out) { this(out, 2); } public void setIndentSize(int indentSize) { this.indent = indentSize; } public void indent() { if (indent >= 0) { out.write('\n'); if (indent > 0) { int spaces = level*indent; out.reserve(spaces); for (int i=0; i<spaces; i++) { out.unsafeWrite(' '); } } } } public void write(Object o) { if (o == null) { writeNull(); } else if (o instanceof CharSequence) { writeString((CharSequence)o); } else if (o instanceof Number) { if (o instanceof Integer || o instanceof Long) { write(((Number)o).longValue()); } else if (o instanceof Float || o instanceof Double) { write(((Number)o).doubleValue()); } else { CharArr arr = new CharArr(); arr.write(o.toString()); writeNumber(arr); } } else if (o instanceof Map) { write((Map)o); } else if (o instanceof Collection) { write((Collection)o); } else if (o instanceof Object[]) { write(Arrays.asList((Object[])o)); } else if (o instanceof Boolean) { write(((Boolean)o).booleanValue()); } else if (o instanceof Writable) { ((Writable) o).write(this); } else if (o instanceof int[]) { write((int[])o); } else if (o instanceof float[]) { write((float[])o); } else if (o instanceof long[]) { write((long[])o); } else if (o instanceof double[]) { write((double[])o); } else if (o instanceof short[]) { write((short[])o); } else if (o instanceof boolean[]) { write((boolean[])o); } else if (o instanceof char[]) { write((char[])o); } else if (o instanceof byte[]) { write((byte[])o); } else { handleUnknownClass(o); } } /** Override this method for custom handling of unknown classes. Also see the Writable interface. */ public void handleUnknownClass(Object o) { writeString(out.toString()); } public void write(Map val) { startObject(); int sz = val.size(); boolean first = true; for (Map.Entry entry : (Set<Map.Entry>)val.entrySet()) { if (first) { first = false; } else { writeValueSeparator(); } if (sz>1) indent(); writeString(entry.getKey().toString()); writeNameSeparator(); write(entry.getValue()); } endObject(); } public void write(Collection val) { startArray(); int sz = val.size(); boolean first = true; for (Object o : val) { if (first) { first = false; } else { writeValueSeparator(); } if (sz>1) indent(); write(o); } endArray(); } /** A byte[] may be either a single logical value, or a list of small integers. * It's up to the implementation to decide. */ public void write(byte[] val) { startArray(); boolean first = true; for (short v : val) { if (first) { first = false; } else { writeValueSeparator(); } write(v); } endArray(); } public void write(short[] val) { startArray(); boolean first = true; for (short v : val) { if (first) { first = false; } else { writeValueSeparator(); } write(v); } endArray(); } public void write(int[] val) { startArray(); boolean first = true; for (int v : val) { if (first) { first = false; } else { writeValueSeparator(); } write(v); } endArray(); } public void write(long[] val) { startArray(); boolean first = true; for (long v : val) { if (first) { first = false; } else { writeValueSeparator(); } write(v); } endArray(); } public void write(float[] val) { startArray(); boolean first = true; for (float v : val) { if (first) { first = false; } else { writeValueSeparator(); } write(v); } endArray(); } public void write(double[] val) { startArray(); boolean first = true; for (double v : val) { if (first) { first = false; } else { writeValueSeparator(); } write(v); } endArray(); } public void write(boolean[] val) { startArray(); boolean first = true; for (boolean v : val) { if (first) { first = false; } else { writeValueSeparator(); } write(v); } endArray(); } public void write(short number) { write ((int)number); } public void write(byte number) { write((int)number); } public void writeNull() { JSONUtil.writeNull(out); } public void writeString(CharSequence str) { JSONUtil.writeString(str,0,str.length(),out); } public void writeString(CharArr str) { JSONUtil.writeString(str,out); } public void writeStringStart() { out.write('"'); } public void writeStringChars(CharArr partialStr) { JSONUtil.writeStringPart(partialStr.getArray(), partialStr.getStart(), partialStr.getEnd(), out); } public void writeStringEnd() { out.write('"'); } public void write(long number) { JSONUtil.writeNumber(number,out); } public void write(int number) { JSONUtil.writeNumber(number,out); } public void write(double number) { JSONUtil.writeNumber(number,out); } public void write(float number) { JSONUtil.writeNumber(number,out); } public void write(boolean bool) { JSONUtil.writeBoolean(bool,out); } public void write(char[] val) { JSONUtil.writeString(val, 0, val.length, out); } public void writeNumber(CharArr digits) { out.write(digits); } public void writePartialNumber(CharArr digits) { out.write(digits); } public void startObject() { out.write('{'); level++; } public void endObject() { out.write('}'); level--; } public void startArray() { out.write('['); level++; } public void endArray() { out.write(']'); level--; } public void writeValueSeparator() { out.write(','); } public void writeNameSeparator() { out.write(':'); } }