/* Copyright (c) 2011 Danish Maritime Authority.
*
* 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 net.maritimecloud.internal.message.text.json;
import static java.util.Objects.requireNonNull;
import java.io.Closeable;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.List;
import java.util.Map;
import net.maritimecloud.internal.message.TaggableMessageWriter;
import net.maritimecloud.internal.message.TaggableValueWriter;
import net.maritimecloud.internal.message.text.AbstractTextValueWriter;
import net.maritimecloud.message.Message;
import net.maritimecloud.message.MessageSerializer;
import net.maritimecloud.message.MessageWriter;
import net.maritimecloud.message.ValueSerializer;
public class JsonValueWriter extends AbstractTextValueWriter implements TaggableValueWriter, Closeable {
/** The Unix line separator. */
static final String LS = "\n";
private int indent;
private boolean isFirst = true;
private final Writer pw;
private final MessageWriter w = new TaggableMessageWriter(this);
public JsonValueWriter(Writer w) {
this(w, 0);
}
public JsonValueWriter(Writer w, int indent) {
this.pw = requireNonNull(w);
this.indent = indent;
}
/**
* {@inheritDoc}
*
* @throws IOException
*/
@Override
public void close() throws IOException {
pw.close();
}
protected String escape(String string) {
StringBuilder sb = new StringBuilder();
int len = string.length();
for (int i = 0; i < len; i++) {
char ch = string.charAt(i);
switch (ch) {
case '"':
sb.append("\\\"");
break;
case '\\':
sb.append("\\\\");
break;
case '/':
sb.append("\\/");
break;
case '\b':
sb.append("\\b");
break;
case '\f':
sb.append("\\f");
break;
case '\n':
sb.append("\\n");
break;
case '\r':
sb.append("\\r");
break;
case '\t':
sb.append("\\t");
break;
default:
if (ch >= '\u0000' && ch <= '\u001F' || ch >= '\u007F' && ch <= '\u009F' || ch >= '\u2000'
&& ch <= '\u20FF') {
String ss = Integer.toHexString(ch);
sb.append("\\u");
for (int k = 0; k < 4 - ss.length(); k++) {
sb.append('0');
}
sb.append(ss.toUpperCase());
} else {
sb.append(ch);
}
}
}
return sb.toString();
}
/**
* Adds the specified count of spaces to the specified string builder.
*
* @throws IOException
*/
private void indent() throws IOException {
for (int i = 0; i < indent; i++) {
pw.append(" ");
}
}
/** {@inheritDoc} */
@Override
public void writeBoolean(Boolean value) throws IOException {
pw.write(value.toString());
}
@Override
protected void writeEscapedString(String value) throws IOException {
pw.append("\"").append(value).append("\"");
}
public <T> void writeList(List<T> list, ValueSerializer<T> serializer) throws IOException {
pw.write("[");
indent++;
boolean isFirst = true;
for (T o : list) {
if (!isFirst) {
pw.write(",");
}
pw.write(LS);
indent();
serializer.write(o, this);
// writeElement(o);
isFirst = false;
}
pw.write(LS);
indent--;
indent();
pw.append("]");
}
/** {@inheritDoc} */
@Override
public <K, V> void writeMap(Map<K, V> map, ValueSerializer<K> keySerializer, ValueSerializer<V> valueSerializer)
throws IOException {
pw.write("{}");
}
/** {@inheritDoc} */
@Override
public <T extends Message> void writeMessage(T message, MessageSerializer<T> serializer) throws IOException {
if (message != null) {
pw.write("{");
indent++;
boolean isFirst = this.isFirst;
this.isFirst = true;
serializer.write(message, w);
this.isFirst = isFirst;
indent--;
pw.write(LS);
indent();
pw.write("}");
}
}
@Override
protected void writeNumber(String value) throws IOException {
pw.write(value);
}
public JsonValueWriter writeTag(int tag, String name) throws IOException {
if (!isFirst) {
pw.write(",");
}
isFirst = false;
pw.write(LS);
indent();
pw.write("\"" + name + "\": ");
return this;
}
public static <T extends Message> String writeMessageTo(int indent, T message, MessageSerializer<T> serializer)
throws IOException {
StringWriter sw = new StringWriter();
try (JsonValueWriter jvv = new JsonValueWriter(sw, indent)) {
jvv.writeMessage(message, serializer);
}
return sw.toString();
}
public static <T> String writeValueTo(int indent, T message, ValueSerializer<T> serializer) throws IOException {
StringWriter sw = new StringWriter();
try (JsonValueWriter jvv = new JsonValueWriter(sw, indent)) {
serializer.write(message, jvv);
}
return sw.toString();
}
}