/**
* Dianping.com Inc.
* Copyright (c) 2003-2013 All Rights Reserved.
*/
package com.dianping.pigeon.remoting.common.codec.json;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import com.dianping.pigeon.log.Logger;
import com.dianping.pigeon.log.LoggerLoader;
import com.dianping.pigeon.remoting.common.codec.AbstractSerializer;
import com.dianping.pigeon.remoting.common.exception.SerializationException;
import com.dianping.pigeon.remoting.common.util.InvocationUtils;
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JacksonSerializer extends AbstractSerializer {
private static final Logger logger = LoggerLoader.getLogger(JacksonSerializer.class);
static ObjectMapper mapper = new ObjectMapper();
static {
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
mapper.setVisibility(PropertyAccessor.GETTER, Visibility.NONE);
mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
// initialize
JacksonSerializer serializer = new JacksonSerializer();
String content = serializer.serializeObject(InvocationUtils.newRequest());
serializer.deserializeObject(InvocationUtils.getRequestClass(), content);
}
public JacksonSerializer() {
}
public static void registerClass(Class<?>... classes) {
mapper.registerSubtypes(classes);
}
@Override
public Object deserializeRequest(InputStream is) throws SerializationException {
return doDeserialize(is, InvocationUtils.getRequestClass());
}
public Object doDeserialize(InputStream is, Class<?> clazz) throws SerializationException {
ByteArrayOutputStream sw = new ByteArrayOutputStream();
byte[] buf = new byte[512];
int len = -1;
try {
while ((len = is.read(buf)) != -1) {
sw.write(buf, 0, len);
}
if (logger.isDebugEnabled()) {
logger.debug("deserialize:" + new String(sw.toByteArray()));
}
return this.toObject(clazz, new String(sw.toByteArray()));
} catch (Throwable e) {
throw new SerializationException(e);
} finally {
try {
sw.close();
} catch (IOException e) {
}
}
}
public String serializeObject(Object obj) throws SerializationException {
try {
return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
} catch (Throwable e) {
throw new SerializationException(e);
}
}
public <T> T deserializeObject(Class<T> objType, String content) throws SerializationException {
try {
return JacksonObjectMapper.convertObject(mapper.readValue(content, objType));
} catch (Throwable e) {
throw new SerializationException(e);
}
}
public <T> T readObject(Class<T> objType, String content) throws SerializationException {
try {
return mapper.readValue(content, objType);
} catch (Throwable e) {
throw new SerializationException(e);
}
}
public <T> T deserializeCollection(String content, Class<?> collectionClass, Class<?>... componentType)
throws SerializationException {
try {
JavaType javaType = mapper.getTypeFactory().constructParametricType(collectionClass, componentType);
return (T) mapper.readValue(content, javaType);
} catch (Throwable e) {
throw new SerializationException(e);
}
}
public <T> T deserializeArray(String content, Class<?> elementType) throws SerializationException {
try {
JavaType javaType = mapper.getTypeFactory().constructArrayType(elementType);
return (T) mapper.readValue(content, javaType);
} catch (Throwable e) {
throw new SerializationException(e);
}
}
public <T> T deserializeMap(String content, Class<?> mapClass, Class<?> keyClass, Class<?> valueClass)
throws SerializationException {
try {
JavaType javaType = mapper.getTypeFactory().constructMapLikeType(mapClass, keyClass, valueClass);
return (T) mapper.readValue(content, javaType);
} catch (Throwable e) {
throw new SerializationException(e);
}
}
@Override
public void serializeRequest(OutputStream os, Object obj) throws SerializationException {
try {
mapper.writeValue(os, obj);
} catch (Throwable e) {
throw new SerializationException(e);
}
}
@Override
public Object deserializeResponse(InputStream is) throws SerializationException {
return doDeserialize(is, InvocationUtils.getResponseClass());
}
@Override
public void serializeResponse(OutputStream os, Object obj) throws SerializationException {
serializeRequest(os, obj);
}
public Object toObject(Class<?> type, String value) throws SerializationException, ClassNotFoundException {
if (value == null) {
return null;
}
String value_;
if (value.length() == 0) {
value_ = "0";
} else {
value_ = value;
}
Object valueObj = value_;
if (type == int.class || type == Integer.class) {
valueObj = Integer.parseInt(value_);
} else if (type == short.class || type == Short.class) {
valueObj = Short.parseShort(value_);
} else if (type == byte.class || type == Byte.class) {
valueObj = Byte.parseByte(value_);
} else if (type == char.class) {
valueObj = value_;
} else if (type == long.class || type == Long.class) {
valueObj = Long.parseLong(value_);
} else if (type == float.class || type == Float.class) {
valueObj = Float.parseFloat(value_);
} else if (type == double.class || type == Double.class) {
valueObj = Double.parseDouble(value_);
} else if (type == String.class) {
valueObj = String.valueOf(value);
} else {
if (value == null || value.length() == 0) {
valueObj = null;
} else {
valueObj = deserializeObject(type, value);
if (valueObj instanceof Collection) {
Collection valueObjList = (Collection) valueObj;
if (!valueObjList.isEmpty()) {
Object first = valueObjList.iterator().next();
if (first instanceof Map) {
Map valueMap = (Map) first;
String valueClass = (String) valueMap.get("@class");
if (valueClass != null) {
valueObj = deserializeCollection(value, type, Class.forName(valueClass));
}
}
}
} else if (valueObj instanceof Map) {
Map valueObjList = (Map) valueObj;
if (!valueObjList.isEmpty()) {
Map finalMap = new HashMap(valueObjList.size());
valueObj = finalMap;
String keyClass = null;
String valueClass = null;
try {
for (Iterator ir = valueObjList.keySet().iterator(); ir.hasNext();) {
Object k = ir.next();
Object v = valueObjList.get(k);
Object finalKey = k;
Object finalValue = v;
if (k instanceof String) {
try {
finalKey = deserializeObject(Map.class, (String) k);
} catch (Throwable t) {
if (keyClass == null) {
Map firstValueMap = deserializeObject(Map.class, (String) k);
if (firstValueMap != null) {
keyClass = (String) firstValueMap.get("@class");
}
}
if (keyClass != null) {
finalKey = deserializeObject(Class.forName(keyClass), (String) k);
}
}
}
if (v instanceof String) {
try {
finalValue = deserializeObject(Map.class, (String) v);
} catch (Throwable t) {
if (valueClass == null) {
Map firstValueMap = deserializeObject(Map.class, (String) v);
if (firstValueMap != null) {
valueClass = (String) firstValueMap.get("@class");
}
}
if (valueClass != null) {
finalValue = deserializeObject(Class.forName(valueClass), (String) v);
}
}
}
finalMap.put(finalKey, finalValue);
}
} catch (Throwable t) {
valueObj = valueObjList;
}
}
}
}
}
return valueObj;
}
}