/******************************************************************************* * Copyright 2013 SAP AG * * Licensed 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 com.sap.core.odata.core.ep.util; import java.io.IOException; import java.io.Writer; /** * Writes JSON output. * @author SAP AG */ public class JsonStreamWriter { private final Writer writer; public JsonStreamWriter(final Writer writer) { this.writer = writer; } public JsonStreamWriter beginObject() throws IOException { writer.append('{'); return this; } public JsonStreamWriter endObject() throws IOException { writer.append('}'); return this; } public JsonStreamWriter beginArray() throws IOException { writer.append('['); return this; } public JsonStreamWriter endArray() throws IOException { writer.append(']'); return this; } public JsonStreamWriter name(final String name) throws IOException { writer.append('"').append(name).append('"').append(':'); return this; } public JsonStreamWriter unquotedValue(final String value) throws IOException { writer.append(value == null ? FormatJson.NULL : value); return this; } public JsonStreamWriter stringValueRaw(final String value) throws IOException { if (value == null) { writer.append(FormatJson.NULL); } else { writer.append('"').append(value).append('"'); } return this; } public JsonStreamWriter stringValue(final String value) throws IOException { if (value == null) { writer.append(FormatJson.NULL); } else { writer.append('"'); escape(value); writer.append('"'); } return this; } public JsonStreamWriter namedStringValueRaw(final String name, final String value) throws IOException { name(name); stringValueRaw(value); return this; } public JsonStreamWriter namedStringValue(final String name, final String value) throws IOException { name(name); stringValue(value); return this; } public JsonStreamWriter separator() throws IOException { writer.append(','); return this; } /** * Writes the JSON-escaped form of a Java String value according to RFC 4627. * @param value the Java String * @throws IOException if an I/O error occurs */ protected void escape(final String value) throws IOException { // RFC 4627 says: "All Unicode characters may be placed within the // quotation marks except for the characters that must be escaped: // quotation mark, reverse solidus, and the control characters // (U+0000 through U+001F)." // All output here is done on character basis which should be faster // than writing Strings. for (int i = 0; i < value.length(); i++) { final char c = value.charAt(i); switch (c) { case '\\': writer.append('\\').append(c); break; case '"': writer.append('\\').append(c); break; case '\b': writer.append('\\').append('b'); break; case '\t': writer.append('\\').append('t'); break; case '\n': writer.append('\\').append('n'); break; case '\f': writer.append('\\').append('f'); break; case '\r': writer.append('\\').append('r'); break; case '\u0000': case '\u0001': case '\u0002': case '\u0003': case '\u0004': case '\u0005': case '\u0006': case '\u0007': case '\u000B': case '\u000E': case '\u000F': case '\u0010': case '\u0011': case '\u0012': case '\u0013': case '\u0014': case '\u0015': case '\u0016': case '\u0017': case '\u0018': case '\u0019': case '\u001A': case '\u001B': case '\u001C': case '\u001D': case '\u001E': case '\u001F': final int lastHexDigit = c % 0x10; writer.append('\\').append('u').append('0').append('0') .append(c >= '\u0010' ? '1' : '0') .append((char) ((lastHexDigit > 9 ? 'A' : '0') + lastHexDigit % 10)); break; default: writer.append(c); } } } }