/*
* Copyright 2004-2010 the original author or authors.
*
* 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 org.slim3.datastore.json;
import java.util.Stack;
import com.google.appengine.repackaged.org.json.JSONObject;
/**
* The JSON Writer.
*
* @author Takao Nakaguchi
*
* @since 1.0.6
*/
public class JsonWriter {
/**
* The constructor.
* @param builder the builder
* @param modelWriter the model writer
*/
public JsonWriter(StringBuilder builder, ModelWriter modelWriter){
this.builder = builder;
this.modelWriter = modelWriter;
}
/**
* Begins the array mode.
*/
public void beginArray(){
checkPropertyName();
writeCammaForValue();
contexts.push(new Context(Context.Mode.ARRAY));
builder.append("[");
}
private void checkPropertyName(){
if(nextPropertyName != null){
writeCammaForPropertyName();
builder.append("\"").append(nextPropertyName).append("\":");
nextPropertyName = null;
}
}
/**
* Ends the array mode.
*/
public void endArray(){
builder.append("]");
contexts.pop();
}
/**
* Begins the object mode.
*/
public void beginObject(){
checkPropertyName();
writeCammaForValue();
contexts.push(new Context(Context.Mode.OBJECT));
builder.append("{");
}
/**
* Ends the object mode.
*/
public void endObject(){
builder.append("}");
contexts.pop();
nextPropertyName = null;
}
/**
* Sets a next property name.
* @param name property name
*/
public void setNextPropertyName(String name){
this.nextPropertyName = name;
}
/**
* Writes a string property
* @param name property name
* @param value value
*/
public void writeStringProperty(String name, String value) {
setNextPropertyName(name);
if(value != null){
writeString(value);
} else{
writeNull();
}
}
/**
* Writes a value property.
* @param name property name
* @param value value
*/
public void writeValueProperty(String name, Object value) {
setNextPropertyName(name);
if(value != null){
writeValue(value);
} else{
writeNull();
}
}
/**
* Writes a string value.
* @param value value
*/
public void writeString(String value){
if(value == null){
writeNull();
return;
}
checkPropertyName();
writeCammaForValue();
builder.append(JSONObject.quote(value));
}
/**
* Writes a value.
* @param value value.
*/
public void writeValue(Object value){
if(value == null){
writeNull();
return;
}
checkPropertyName();
writeCammaForValue();
builder.append(value);
}
/**
* Writes a null.
*/
public void writeNull(){
checkPropertyName();
writeCammaForValue();
builder.append("null");
}
/**
* Writes a model.
* @param model the model
* @param maxDepth the max depth
* @param currentDepth the current depth
*/
public void writeModel(Object model, int maxDepth, int currentDepth){
modelWriter.write(this, model, maxDepth, currentDepth);
}
private void writeCammaForValue(){
if(contexts.size() > 0){
contexts.peek().writeForValue(builder);
}
}
private void writeCammaForPropertyName(){
if(contexts.size() > 0){
contexts.peek().writeForPropertyName(builder);
}
}
private StringBuilder builder;
private ModelWriter modelWriter;
private String nextPropertyName;
private Stack<Context> contexts = new Stack<Context>();
static class Context{
enum Mode{OBJECT, ARRAY}
Mode mode;
boolean first = true;
private Context(Mode mode){
this.mode = mode;
}
private void writeForValue(StringBuilder builder){
if(!mode.equals(Mode.ARRAY)) return;
if(first){
first = false;
} else {
builder.append(",");
}
}
private void writeForPropertyName(StringBuilder builder){
if(!mode.equals(Mode.OBJECT)) return;
if(first){
first = false;
} else {
builder.append(",");
}
}
}
}