blob: dfec390db4cc39c332d61bfd1436389d6c54a06e [file] [log] [blame]
/*
* Copyright 2006- Yonik Seeley
*
* 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.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) {
// NOTE: an instance-of chain was about 50% faster than hashing on the classes, even with perfect hashing.
if (o == null) {
writeNull();
} else if (o instanceof String) {
writeString((String) 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 Boolean) {
write(((Boolean) o).booleanValue());
} else if (o instanceof CharSequence) {
writeString((CharSequence) o);
} else if (o instanceof Writable) {
((Writable) o).write(this);
} else if (o instanceof Object[]) {
write(Arrays.asList((Object[]) o));
} 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(o.toString());
}
public void write(Map<?, ?> val) {
startObject();
int sz = val.size();
boolean first = true;
for (Map.Entry<?, ?> 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(String str) {
JSONUtil.writeString(str, 0, str.length(), 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(':');
}
}