//
// Copyright 2010 Cinch Logic Pty Ltd.
//
// http://www.chililog.com
//
// 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.chililog.server.data;
import java.lang.reflect.Array;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Map;
import java.util.Set;
import java.util.SimpleTimeZone;
import java.util.regex.Pattern;
import org.bson.types.BSONTimestamp;
import org.bson.types.Binary;
import org.bson.types.Code;
import org.bson.types.CodeWScope;
import org.bson.types.ObjectId;
import com.mongodb.BasicDBObject;
import com.mongodb.Bytes;
import com.mongodb.DBObject;
import com.mongodb.DBRefBase;
/**
* <p>
* Serializer for mongoDB DBObjects into simple JSON
* </p>
* <p>
* Modified from https://github.com/mongodb/mongo-java-driver/blob/master/src/main/com/mongodb/util/JSON.java.
* </p>
* <p>
* Modified to support:
* <ul>
* <li>ObjectId - output as string rather than object like: <code>"_id" : { "$oid" : "4d8002fcf24599f624357467"}</code></li>
* <li>Date - output as string rather than object like:
* <code>"entry_timestamp" : { "$date" : "2011-03-16T00:23:24Z"}</code>.</li>
* </p>
*/
public class MongoJsonSerializer {
/**
* Serializes an object into it's JSON form
*
* @param o
* object to serialize
* @return String containing JSON form of the object
*/
public static String serialize(Object o) {
StringBuilder buf = new StringBuilder();
serialize(o, buf);
return buf.toString();
}
static void string(StringBuilder a, String s) {
a.append("\"");
for (int i = 0; i < s.length(); ++i) {
char c = s.charAt(i);
if (c == '\\')
a.append("\\\\");
else if (c == '"')
a.append("\\\"");
else if (c == '\n')
a.append("\\n");
else if (c == '\r')
a.append("\\r");
else if (c == '\t')
a.append("\\t");
else if (c == '\b')
a.append("\\b");
else if (c < 32)
continue;
else
a.append(c);
}
a.append("\"");
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public static void serialize(Object o, StringBuilder buf) {
o = Bytes.applyEncodingHooks(o);
if (o == null) {
buf.append(" null ");
return;
}
if (o instanceof Number) {
buf.append(o);
return;
}
if (o instanceof String) {
string(buf, o.toString());
return;
}
if (o instanceof Iterable) {
boolean first = true;
buf.append("[ ");
for (Object n : (Iterable) o) {
if (first)
first = false;
else
buf.append(" , ");
serialize(n, buf);
}
buf.append("]");
return;
}
if (o instanceof ObjectId) {
// serialize(new BasicDBObject("$oid", o.toString()), buf);
string(buf, o.toString());
return;
}
if (o instanceof DBObject) {
boolean first = true;
buf.append("{ ");
DBObject dbo = (DBObject) o;
for (String name : dbo.keySet()) {
if (first)
first = false;
else
buf.append(" , ");
string(buf, name);
buf.append(" : ");
serialize(dbo.get(name), buf);
}
buf.append("}");
return;
}
if (o instanceof Map) {
boolean first = true;
buf.append("{ ");
Map m = (Map) o;
for (Map.Entry entry : (Set<Map.Entry>) m.entrySet()) {
if (first)
first = false;
else
buf.append(" , ");
string(buf, entry.getKey().toString());
buf.append(" : ");
serialize(entry.getValue(), buf);
}
buf.append("}");
return;
}
if (o instanceof Date) {
Date d = (Date) o;
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
format.setCalendar(new GregorianCalendar(new SimpleTimeZone(0, "GMT")));
// serialize(new BasicDBObject("$date", format.format(d)), buf);
string(buf, format.format(d));
return;
}
if (o instanceof DBRefBase) {
buf.append(o);
return;
}
if (o instanceof Boolean) {
buf.append(o);
return;
}
if (o instanceof byte[] || o instanceof Binary) {
buf.append("<Binary Data>");
return;
}
if (o instanceof Pattern) {
DBObject externalForm = new BasicDBObject();
externalForm.put("$regex", o.toString());
externalForm.put("$options", Bytes.regexFlags(((Pattern) o).flags()));
serialize(externalForm, buf);
return;
}
if (o.getClass().isArray()) {
buf.append("[ ");
for (int i = 0; i < Array.getLength(o); i++) {
if (i > 0)
buf.append(" , ");
serialize(Array.get(o, i), buf);
}
buf.append("]");
return;
}
if (o instanceof BSONTimestamp) {
BSONTimestamp t = (BSONTimestamp) o;
buf.append(t.getTime()).append("|").append(t.getInc());
return;
}
if (o instanceof CodeWScope) {
CodeWScope c = (CodeWScope) o;
BasicDBObject temp = new BasicDBObject();
temp.put("$code", c.getCode());
temp.put("$scope", c.getScope());
serialize(temp, buf);
return;
}
if (o instanceof Code) {
string(buf, ((Code) o).getCode());
return;
}
throw new RuntimeException("json can't serialize type : " + o.getClass());
}
}