/*
* Copyright 1999-2017 Alibaba Group.
*
* 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.alibaba.fastjson.serializer;
import java.io.IOException;
import java.io.Writer;
import java.lang.reflect.Type;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.IdentityHashMap;
import java.util.Locale;
import java.util.TimeZone;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
/**
* @author wenshao[szujobs@hotmail.com]
*/
public class JSONSerializer extends SerializeFilterable {
protected final SerializeConfig config;
public final SerializeWriter out;
private int indentCount = 0;
private String indent = "\t";
private String dateFormatPattern;
private DateFormat dateFormat;
protected IdentityHashMap<Object, SerialContext> references = null;
protected SerialContext context;
protected TimeZone timeZone = JSON.defaultTimeZone;
protected Locale locale = JSON.defaultLocale;
public JSONSerializer(){
this(new SerializeWriter(), SerializeConfig.getGlobalInstance());
}
public JSONSerializer(SerializeWriter out){
this(out, SerializeConfig.getGlobalInstance());
}
public JSONSerializer(SerializeConfig config){
this(new SerializeWriter(), config);
}
public JSONSerializer(SerializeWriter out, SerializeConfig config){
this.out = out;
this.config = config;
}
public String getDateFormatPattern() {
if (dateFormat instanceof SimpleDateFormat) {
return ((SimpleDateFormat) dateFormat).toPattern();
}
return dateFormatPattern;
}
public DateFormat getDateFormat() {
if (dateFormat == null) {
if (dateFormatPattern != null) {
dateFormat = new SimpleDateFormat(dateFormatPattern, locale);
dateFormat.setTimeZone(timeZone);
}
}
return dateFormat;
}
public void setDateFormat(DateFormat dateFormat) {
this.dateFormat = dateFormat;
if (dateFormatPattern != null) {
dateFormatPattern = null;
}
}
public void setDateFormat(String dateFormat) {
this.dateFormatPattern = dateFormat;
if (this.dateFormat != null) {
this.dateFormat = null;
}
}
public SerialContext getContext() {
return context;
}
public void setContext(SerialContext context) {
this.context = context;
}
public void setContext(SerialContext parent, Object object, Object fieldName, int features) {
this.setContext(parent, object, fieldName, features, 0);
}
public void setContext(SerialContext parent, Object object, Object fieldName, int features, int fieldFeatures) {
if (out.disableCircularReferenceDetect) {
return;
}
this.context = new SerialContext(parent, object, fieldName, features, fieldFeatures);
if (references == null) {
references = new IdentityHashMap<Object, SerialContext>();
}
this.references.put(object, context);
}
public void setContext(Object object, Object fieldName) {
this.setContext(context, object, fieldName, 0);
}
public void popContext() {
if (context != null) {
this.context = this.context.parent;
}
}
public final boolean isWriteClassName(Type fieldType, Object obj) {
return out.isEnabled(SerializerFeature.WriteClassName) //
&& (fieldType != null //
|| (!out.isEnabled(SerializerFeature.NotWriteRootClassName)) //
|| context.parent != null);
}
public boolean containsReference(Object value) {
if (references == null) {
return false;
}
SerialContext refContext = references.get(value);
if (refContext == null) {
return false;
}
Object fieldName = refContext.fieldName;
return fieldName == null || fieldName instanceof Integer || fieldName instanceof String;
}
public void writeReference(Object object) {
SerialContext context = this.context;
Object current = context.object;
if (object == current) {
out.write("{\"$ref\":\"@\"}");
return;
}
SerialContext parentContext = context.parent;
if (parentContext != null) {
if (object == parentContext.object) {
out.write("{\"$ref\":\"..\"}");
return;
}
}
SerialContext rootContext = context;
for (;;) {
if (rootContext.parent == null) {
break;
}
rootContext = rootContext.parent;
}
if (object == rootContext.object) {
out.write("{\"$ref\":\"$\"}");
} else {
out.write("{\"$ref\":\"");
out.write(references.get(object).toString());
out.write("\"}");
}
}
public boolean checkValue(SerializeFilterable filterable) {
return (valueFilters != null && valueFilters.size() > 0) //
|| (contextValueFilters != null && contextValueFilters.size() > 0) //
|| (filterable.valueFilters != null && filterable.valueFilters.size() > 0)
|| (filterable.contextValueFilters != null && filterable.contextValueFilters.size() > 0)
|| out.writeNonStringValueAsString;
}
public boolean hasNameFilters(SerializeFilterable filterable) {
return (nameFilters != null && nameFilters.size() > 0) //
|| (filterable.nameFilters != null && filterable.nameFilters.size() > 0);
}
public int getIndentCount() {
return indentCount;
}
public void incrementIndent() {
indentCount++;
}
public void decrementIdent() {
indentCount--;
}
public void println() {
out.write('\n');
for (int i = 0; i < indentCount; ++i) {
out.write(indent);
}
}
public SerializeWriter getWriter() {
return out;
}
public String toString() {
return out.toString();
}
public void config(SerializerFeature feature, boolean state) {
out.config(feature, state);
}
public boolean isEnabled(SerializerFeature feature) {
return out.isEnabled(feature);
}
public void writeNull() {
this.out.writeNull();
}
public SerializeConfig getMapping() {
return config;
}
public static void write(Writer out, Object object) {
SerializeWriter writer = new SerializeWriter();
try {
JSONSerializer serializer = new JSONSerializer(writer);
serializer.write(object);
writer.writeTo(out);
} catch (IOException ex) {
throw new JSONException(ex.getMessage(), ex);
} finally {
writer.close();
}
}
public static void write(SerializeWriter out, Object object) {
JSONSerializer serializer = new JSONSerializer(out);
serializer.write(object);
}
public final void write(Object object) {
if (object == null) {
out.writeNull();
return;
}
Class<?> clazz = object.getClass();
ObjectSerializer writer = getObjectWriter(clazz);
try {
writer.write(this, object, null, null, 0);
} catch (IOException e) {
throw new JSONException(e.getMessage(), e);
}
}
public final void writeWithFieldName(Object object, Object fieldName) {
writeWithFieldName(object, fieldName, null, 0);
}
protected final void writeKeyValue(char seperator, String key, Object value) {
if (seperator != '\0') {
out.write(seperator);
}
out.writeFieldName(key);
write(value);
}
public final void writeWithFieldName(Object object, Object fieldName, Type fieldType, int fieldFeatures) {
try {
if (object == null) {
out.writeNull();
return;
}
Class<?> clazz = object.getClass();
ObjectSerializer writer = getObjectWriter(clazz);
writer.write(this, object, fieldName, fieldType, fieldFeatures);
} catch (IOException e) {
throw new JSONException(e.getMessage(), e);
}
}
public final void writeWithFormat(Object object, String format) {
if (object instanceof Date) {
DateFormat dateFormat = this.getDateFormat();
if (dateFormat == null) {
dateFormat = new SimpleDateFormat(format, locale);
dateFormat.setTimeZone(timeZone);
}
String text = dateFormat.format((Date) object);
out.writeString(text);
return;
}
write(object);
}
public final void write(String text) {
StringCodec.instance.write(this, text);
}
public ObjectSerializer getObjectWriter(Class<?> clazz) {
return config.getObjectWriter(clazz);
}
public void close() {
this.out.close();
}
}