blob: ea0bca7651d0ce96f519256d4a7ceeb6933e0fad [file] [log] [blame]
/*
* 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 com.alibaba.dubbo.common.json;
import com.alibaba.dubbo.common.utils.Stack;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
/**
* JSON Writer.
* <p>
* w.objectBegin().objectItem("name").valueString("qianlei").objectEnd() = {name:"qianlei"}.
*/
@Deprecated
public class JSONWriter {
private static final byte UNKNOWN = 0, ARRAY = 1, OBJECT = 2, OBJECT_VALUE = 3;
private static final String[] CONTROL_CHAR_MAP = new String[]{
"\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005", "\\u0006", "\\u0007",
"\\b", "\\t", "\\n", "\\u000b", "\\f", "\\r", "\\u000e", "\\u000f",
"\\u0010", "\\u0011", "\\u0012", "\\u0013", "\\u0014", "\\u0015", "\\u0016", "\\u0017",
"\\u0018", "\\u0019", "\\u001a", "\\u001b", "\\u001c", "\\u001d", "\\u001e", "\\u001f"
};
private Writer mWriter;
private State mState = new State(UNKNOWN);
private Stack<State> mStack = new Stack<State>();
public JSONWriter(Writer writer) {
mWriter = writer;
}
public JSONWriter(OutputStream is, String charset) throws UnsupportedEncodingException {
mWriter = new OutputStreamWriter(is, charset);
}
private static String escape(String str) {
if (str == null)
return str;
int len = str.length();
if (len == 0)
return str;
char c;
StringBuilder sb = null;
for (int i = 0; i < len; i++) {
c = str.charAt(i);
if (c < ' ') // control char.
{
if (sb == null) {
sb = new StringBuilder(len << 1);
sb.append(str, 0, i);
}
sb.append(CONTROL_CHAR_MAP[c]);
} else {
switch (c) {
case '\\':
case '/':
case '"':
if (sb == null) {
sb = new StringBuilder(len << 1);
sb.append(str, 0, i);
}
sb.append('\\').append(c);
break;
default:
if (sb != null)
sb.append(c);
}
}
}
return sb == null ? str : sb.toString();
}
/**
* object begin.
*
* @return this.
* @throws IOException
*/
public JSONWriter objectBegin() throws IOException {
beforeValue();
mWriter.write(JSON.LBRACE);
mStack.push(mState);
mState = new State(OBJECT);
return this;
}
/**
* object end.
*
* @return this.
* @throws IOException
*/
public JSONWriter objectEnd() throws IOException {
mWriter.write(JSON.RBRACE);
mState = mStack.pop();
return this;
}
/**
* object item.
*
* @param name name.
* @return this.
* @throws IOException
*/
public JSONWriter objectItem(String name) throws IOException {
beforeObjectItem();
mWriter.write(JSON.QUOTE);
mWriter.write(escape(name));
mWriter.write(JSON.QUOTE);
mWriter.write(JSON.COLON);
return this;
}
/**
* array begin.
*
* @return this.
* @throws IOException
*/
public JSONWriter arrayBegin() throws IOException {
beforeValue();
mWriter.write(JSON.LSQUARE);
mStack.push(mState);
mState = new State(ARRAY);
return this;
}
/**
* array end, return array value.
*
* @return this.
* @throws IOException
*/
public JSONWriter arrayEnd() throws IOException {
mWriter.write(JSON.RSQUARE);
mState = mStack.pop();
return this;
}
/**
* value.
*
* @return this.
* @throws IOException
*/
public JSONWriter valueNull() throws IOException {
beforeValue();
mWriter.write(JSON.NULL);
return this;
}
/**
* value.
*
* @param value value.
* @return this.
* @throws IOException
*/
public JSONWriter valueString(String value) throws IOException {
beforeValue();
mWriter.write(JSON.QUOTE);
mWriter.write(escape(value));
mWriter.write(JSON.QUOTE);
return this;
}
/**
* value.
*
* @param value value.
* @return this.
* @throws IOException
*/
public JSONWriter valueBoolean(boolean value) throws IOException {
beforeValue();
mWriter.write(value ? "true" : "false");
return this;
}
/**
* value.
*
* @param value value.
* @return this.
* @throws IOException
*/
public JSONWriter valueInt(int value) throws IOException {
beforeValue();
mWriter.write(String.valueOf(value));
return this;
}
/**
* value.
*
* @param value value.
* @return this.
* @throws IOException
*/
public JSONWriter valueLong(long value) throws IOException {
beforeValue();
mWriter.write(String.valueOf(value));
return this;
}
/**
* value.
*
* @param value value.
* @return this.
* @throws IOException
*/
public JSONWriter valueFloat(float value) throws IOException {
beforeValue();
mWriter.write(String.valueOf(value));
return this;
}
/**
* value.
*
* @param value value.
* @return this.
* @throws IOException
*/
public JSONWriter valueDouble(double value) throws IOException {
beforeValue();
mWriter.write(String.valueOf(value));
return this;
}
private void beforeValue() throws IOException {
switch (mState.type) {
case ARRAY:
if (mState.itemCount++ > 0)
mWriter.write(JSON.COMMA);
return;
case OBJECT:
throw new IOException("Must call objectItem first.");
case OBJECT_VALUE:
mState.type = OBJECT;
return;
}
}
private void beforeObjectItem() throws IOException {
switch (mState.type) {
case OBJECT_VALUE:
mWriter.write(JSON.NULL);
case OBJECT:
mState.type = OBJECT_VALUE;
if (mState.itemCount++ > 0)
mWriter.write(JSON.COMMA);
return;
default:
throw new IOException("Must call objectBegin first.");
}
}
private static class State {
private byte type;
private int itemCount = 0;
State(byte t) {
type = t;
}
}
}