jsimple.json.text.Serializer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jsimple-json Show documentation
Show all versions of jsimple-json Show documentation
JSimple cross platform friendly library
The newest version!
/*
* Copyright (c) 2012-2015, Microsoft Mobile
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package jsimple.json.text;
import jsimple.io.Writer;
import jsimple.json.JsonException;
import jsimple.json.objectmodel.JsonArray;
import jsimple.json.objectmodel.JsonNull;
import jsimple.json.objectmodel.JsonObject;
/**
* @author Bret Johnson
* @since 7/8/12 3:46 AM
*/
public final class Serializer {
private Writer writer;
private char[] buffer = new char[BUFFER_SIZE];
private int currIndex; // Next character to be processed
int indent;
private static final int BUFFER_SIZE = 256;
public Serializer(Writer writer) {
this.writer = writer;
currIndex = 0;
indent = 0;
}
public void writeValue(Object obj) {
if (obj instanceof String)
writeString((String) obj);
else if (obj instanceof Integer || obj instanceof Long)
write(obj.toString());
else if (obj instanceof Float || obj instanceof Double)
write(obj.toString());
else if (obj instanceof Boolean) {
write((boolean) (Boolean) obj ? "true" : "false");
} else if (obj instanceof JsonObject)
writeJsonObject((JsonObject) obj);
else if (obj instanceof JsonArray)
writeJsonArray((JsonArray) obj);
else if (obj instanceof JsonNull)
write("null");
else throw new JsonException("Unexpected JSON object type: {}", obj);
}
/**
* Write a JSON object. Each name/value pair is output on a separate line, indented by two spaces. If the object
* is empty, just "{}" is appended.
*
* @param jsonObject object to append
*/
public void writeJsonObject(JsonObject jsonObject) {
int size = jsonObject.size();
if (size == 0)
write("{}");
else {
write("{\n");
indent += 2;
for (int i = 0; i < size; ++i) {
writeIndent();
writeString(jsonObject.getName(i));
write(": ");
writeValue(jsonObject.getValue(i));
if (i < size - 1)
write(",\n");
else write("\n");
}
indent -= 2;
writeIndent();
write("}");
}
}
/**
* Append a JSON array. If the array is empty or its elements are all simple objects (that is, literals or embedded
* objects/arrays that are empty), then output it all on one line. Otherwise, each array element is on a separate
* line.
*
* @param array array to append
*/
public void writeJsonArray(JsonArray array) {
int size = array.size();
if (size == 0)
write("[]");
else {
boolean allSimpleObjects = true;
for (int i = 0; i < size; ++i) {
Object item = array.get(i);
if (item instanceof JsonObject && ((JsonObject) item).size() > 0) {
allSimpleObjects = false;
break;
} else if (item instanceof JsonArray && ((JsonArray) item).size() > 0) {
allSimpleObjects = false;
break;
}
}
boolean useMultipleLines = !allSimpleObjects;
write("[");
if (useMultipleLines) {
write("\n");
indent += 2;
for (int i = 0; i < size; ++i) {
writeIndent();
writeValue(array.get(i));
if (i < size - 1)
write(",\n");
else write("\n");
}
indent -= 2;
writeIndent();
} else {
for (int i = 0; i < size; ++i) {
writeValue(array.get(i));
if (i < size - 1)
write(", ");
}
}
write(']');
}
}
/**
* Append spaces for the current indent.
*/
public void writeIndent() {
for (int i = 0; i < indent; ++i)
write(' ');
}
public void writeString(String string) {
write('\"');
int length = string.length();
for (int i = 0; i < length; ++i) {
char c = string.charAt(i);
// Check for characters that need to be escaped
switch (c) {
case '\"':
write("\\\"");
break;
case '\\':
write("\\\\");
break;
case '\b':
write("\\b");
break;
case '\f':
write("\\f");
break;
case '\n':
write("\\n");
break;
case '\r':
write("\\r");
break;
case '\t':
write("\\t");
break;
default:
if (Token.isControlCharacter(c))
writeUnicodeEscape(c);
else write(c);
}
}
write("\"");
}
public void writeUnicodeEscape(char c) {
write("\\u");
writeHexDigit((c & 0xF000) >>> 12);
writeHexDigit((c & 0x0F00) >>> 8);
writeHexDigit((c & 0x00F0) >>> 4);
writeHexDigit(c & 0x000F);
}
public void writeHexDigit(int hexDigit) {
if (hexDigit <= 9)
write((char) ('0' + hexDigit));
else if (hexDigit <= 15)
write((char) ('A' + (hexDigit - 10)));
else throw new JsonException("Hex digit out of range: {}", hexDigit);
}
public void write(String s) {
int length = s.length();
for (int i = 0; i < length; i++)
write(s.charAt(i));
}
private void write(char c) {
if (currIndex >= BUFFER_SIZE)
flush();
buffer[currIndex++] = c;
}
public void flush() {
writer.write(buffer, 0, currIndex);
currIndex = 0;
}
/**
* Increment (or decrement if negative) the prevailing indent by the specified amount.
*
* @param amount amount to change indent
*/
public void addToIndent(int amount) {
indent += amount;
}
}