com.aspectran.core.util.json.JsonWriter Maven / Gradle / Ivy
/*
* Copyright (c) 2008-2023 The Aspectran Project
*
* 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.aspectran.core.util.json;
import com.aspectran.core.util.ArrayStack;
import com.aspectran.core.util.BeanUtils;
import com.aspectran.core.util.apon.Parameter;
import com.aspectran.core.util.apon.ParameterValue;
import com.aspectran.core.util.apon.Parameters;
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.Flushable;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collection;
import java.util.Date;
import java.util.Map;
/**
* Converts an object to a JSON formatted string.
* If pretty-printing is enabled, the JsonWriter will add newlines and
* indentation to the written data. Pretty-printing is disabled by default.
*
* Created: 2008. 06. 12 PM 8:20:54
*
* @author Juho Jeong
*/
public class JsonWriter implements Flushable, Closeable {
private static final String DEFAULT_INDENT_STRING = " ";
private final ArrayStack writtenFlags = new ArrayStack<>();
private final Writer out;
private boolean prettyPrint;
private String indentString;
private String dateFormat;
private String dateTimeFormat;
private boolean nullWritable = true;
private int indentDepth;
private String pendedName;
/**
* Instantiates a new JsonWriter.
* Pretty printing is enabled by default, and the indent string is
* set to " " (two spaces).
*/
public JsonWriter() {
this(new StringWriter());
}
/**
* Instantiates a new JsonWriter.
* Pretty printing is enabled by default, and the indent string is
* set to " " (two spaces).
* @param out the character-output stream
*/
public JsonWriter(Writer out) {
this.out = out;
setIndentString(DEFAULT_INDENT_STRING);
writtenFlags.push(false);
}
private void setIndentString(String indentString) {
this.prettyPrint = (indentString != null);
this.indentString = indentString;
}
@SuppressWarnings("unchecked")
public T prettyPrint(boolean prettyPrint) {
if (prettyPrint) {
setIndentString(DEFAULT_INDENT_STRING);
} else {
setIndentString(null);
}
return (T)this;
}
@SuppressWarnings("unchecked")
public T indentString(String indentString) {
setIndentString(indentString);
return (T)this;
}
@SuppressWarnings("unchecked")
public T dateFormat(String dateFormat) {
this.dateFormat = dateFormat;
return (T)this;
}
@SuppressWarnings("unchecked")
public T dateTimeFormat(String dateTimeFormat) {
this.dateTimeFormat = dateTimeFormat;
return (T)this;
}
@SuppressWarnings("unchecked")
public T nullWritable(boolean nullWritable) {
this.nullWritable = nullWritable;
return (T)this;
}
/**
* Writes an object to the writer.
* @param object the object to write to the writer.
* @throws IOException if an I/O error has occurred.
*/
@SuppressWarnings("unchecked")
public T write(Object object) throws IOException {
if (object == null) {
writeNull();
} else if (object instanceof String) {
writeValue(object.toString());
} else if (object instanceof Character) {
writeValue(String.valueOf(((char)object)));
} else if (object instanceof Boolean) {
writeValue((Boolean)object);
} else if (object instanceof Number) {
writeValue((Number)object);
} else if (object instanceof Parameters) {
beginObject();
Map params = ((Parameters)object).getParameterValueMap();
for (Parameter p : params.values()) {
String name = p.getName();
Object value = p.getValue();
checkCircularReference(object, value);
writeName(name);
write(value);
}
endObject();
} else if (object instanceof Map, ?>) {
beginObject();
for (Map.Entry