package com.alibaba.fastjson.parser.deserializer;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.parser.DefaultJSONParser;
import com.alibaba.fastjson.parser.DefaultJSONParser.ResolveTask;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.parser.JSONLexer;
import com.alibaba.fastjson.parser.JSONScanner;
import com.alibaba.fastjson.parser.JSONToken;
import com.alibaba.fastjson.parser.ParseContext;
import com.alibaba.fastjson.util.ASMClassLoader;
import com.alibaba.fastjson.util.TypeUtils;
public class DefaultObjectDeserializer implements ObjectDeserializer {
public final static DefaultObjectDeserializer instance = new DefaultObjectDeserializer();
public DefaultObjectDeserializer(){
}
public Object parseMap(DefaultJSONParser parser, Map<Object, Object> map, Type keyType, Type valueType,
Object fieldName) {
JSONScanner lexer = (JSONScanner) parser.getLexer();
if (lexer.token() != JSONToken.LBRACE && lexer.token() != JSONToken.COMMA) {
throw new JSONException("syntax error, expect {, actual " + lexer.tokenName());
}
ObjectDeserializer keyDeserializer = parser.getConfig().getDeserializer(keyType);
ObjectDeserializer valueDeserializer = parser.getConfig().getDeserializer(valueType);
lexer.nextToken(keyDeserializer.getFastMatchToken());
ParseContext context = parser.getContext();
try {
for (;;) {
if (lexer.token() == JSONToken.RBRACE) {
lexer.nextToken(JSONToken.COMMA);
break;
}
if (lexer.token() == JSONToken.LITERAL_STRING && lexer.isRef()) {
Object object = null;
lexer.nextTokenWithColon(JSONToken.LITERAL_STRING);
if (lexer.token() == JSONToken.LITERAL_STRING) {
String ref = lexer.stringVal();
if ("@".equals(ref)) {
object = context.getObject();
} else if ("..".equals(ref)) {
ParseContext parentContext = context.getParentContext();
if (parentContext.getObject() != null) {
object = parentContext.getObject();
} else {
parser.addResolveTask(new ResolveTask(parentContext, ref));
parser.setResolveStatus(DefaultJSONParser.NeedToResolve);
}
} else if ("$".equals(ref)) {
ParseContext rootContext = context;
while (rootContext.getParentContext() != null) {
rootContext = rootContext.getParentContext();
}
if (rootContext.getObject() != null) {
object = rootContext.getObject();
} else {
parser.addResolveTask(new ResolveTask(rootContext, ref));
parser.setResolveStatus(DefaultJSONParser.NeedToResolve);
}
} else {
parser.addResolveTask(new ResolveTask(context, ref));
parser.setResolveStatus(DefaultJSONParser.NeedToResolve);
}
} else {
throw new JSONException("illegal ref, " + JSONToken.name(lexer.token()));
}
lexer.nextToken(JSONToken.RBRACE);
if (lexer.token() != JSONToken.RBRACE) {
throw new JSONException("illegal ref");
}
lexer.nextToken(JSONToken.COMMA);
//parser.setContext(context, map, fieldName);
//parser.setContext(context);
return object;
}
if (map.size() == 0 && lexer.token() == JSONToken.LITERAL_STRING && "@type".equals(lexer.stringVal())) {
lexer.nextTokenWithColon(JSONToken.LITERAL_STRING);
lexer.nextToken(JSONToken.COMMA);
lexer.nextToken(keyDeserializer.getFastMatchToken());
}
Object key = keyDeserializer.deserialze(parser, keyType, null);
if (lexer.token() != JSONToken.COLON) {
throw new JSONException("syntax error, expect :, actual " + lexer.token());
}
lexer.nextToken(valueDeserializer.getFastMatchToken());
Object value = valueDeserializer.deserialze(parser, valueType, key);
if (map.size() == 0 && context != null && context.getObject() != map) {
parser.setContext(context, map, fieldName);
}
map.put(key, value);
if (lexer.token() == JSONToken.COMMA) {
lexer.nextToken(keyDeserializer.getFastMatchToken());
}
}
} finally {
parser.setContext(context);
}
return map;
}
@SuppressWarnings("rawtypes")
public Map parseMap(DefaultJSONParser parser, Map<String, Object> map, Type valueType, Object fieldName) {
JSONScanner lexer = (JSONScanner) parser.getLexer();
if (lexer.token() != JSONToken.LBRACE) {
throw new JSONException("syntax error, expect {, actual " + lexer.token());
}
ParseContext context = parser.getContext();
try {
for (;;) {
lexer.skipWhitespace();
char ch = lexer.getCurrent();
if (parser.isEnabled(Feature.AllowArbitraryCommas)) {
while (ch == ',') {
lexer.incrementBufferPosition();
lexer.skipWhitespace();
ch = lexer.getCurrent();
}
}
String key;
if (ch == '"') {
key = lexer.scanSymbol(parser.getSymbolTable(), '"');
lexer.skipWhitespace();
ch = lexer.getCurrent();
if (ch != ':') {
throw new JSONException("expect ':' at " + lexer.pos());
}
} else if (ch == '}') {
lexer.incrementBufferPosition();
lexer.resetStringPosition();
lexer.nextToken(JSONToken.COMMA);
return map;
} else if (ch == '\'') {
if (!parser.isEnabled(Feature.AllowSingleQuotes)) {
throw new JSONException("syntax error");
}
key = lexer.scanSymbol(parser.getSymbolTable(), '\'');
lexer.skipWhitespace();
ch = lexer.getCurrent();
if (ch != ':') {
throw new JSONException("expect ':' at " + lexer.pos());
}
} else {
if (!parser.isEnabled(Feature.AllowUnQuotedFieldNames)) {
throw new JSONException("syntax error");
}
key = lexer.scanSymbolUnQuoted(parser.getSymbolTable());
lexer.skipWhitespace();
ch = lexer.getCurrent();
if (ch != ':') {
throw new JSONException("expect ':' at " + lexer.pos() + ", actual " + ch);
}
}
lexer.incrementBufferPosition();
lexer.skipWhitespace();
ch = lexer.getCurrent();
lexer.resetStringPosition();
if (key == "@type") {
String typeName = lexer.scanSymbol(parser.getSymbolTable(), '"');
Class<?> clazz = TypeUtils.loadClass(typeName);
if (clazz == map.getClass()) {
lexer.nextToken(JSONToken.COMMA);
if (lexer.token() == JSONToken.RBRACE) {
lexer.nextToken(JSONToken.COMMA);
return map;
}
continue;
}
ObjectDeserializer deserializer = parser.getConfig().getDeserializer(clazz);
lexer.nextToken(JSONToken.COMMA);
parser.setResolveStatus(DefaultJSONParser.TypeNameRedirect);
return (Map) deserializer.deserialze(parser, clazz, fieldName);
}
Object value;
lexer.nextToken();
if (lexer.token() == JSONToken.NULL) {
value = null;
lexer.nextToken();
} else {
value = parser.parseObject(valueType);
}
map.put(key, value);
parser.setContext(context, value, key);
if (lexer.token() == JSONToken.RBRACE) {
lexer.nextToken();
return map;
}
}
} finally {
parser.setContext(context);
}
}
public void parseObject(DefaultJSONParser parser, Object object) {
Class<?> clazz = object.getClass();
Map<String, FieldDeserializer> setters = parser.getConfig().getFieldDeserializers(clazz);
JSONScanner lexer = (JSONScanner) parser.getLexer(); // xxx
if (lexer.token() == JSONToken.RBRACE) {
lexer.nextToken(JSONToken.COMMA);
return;
}
if (lexer.token() != JSONToken.LBRACE && lexer.token() != JSONToken.COMMA) {
throw new JSONException("syntax error, expect {, actual " + lexer.tokenName());
}
final Object[] args = new Object[1];
for (;;) {
// lexer.scanSymbol
String key = lexer.scanSymbol(parser.getSymbolTable());
if (key == null) {
if (lexer.token() == JSONToken.RBRACE) {
lexer.nextToken(JSONToken.COMMA);
break;
}
if (lexer.token() == JSONToken.COMMA) {
if (parser.isEnabled(Feature.AllowArbitraryCommas)) {
continue;
}
}
}
FieldDeserializer fieldDeser = setters.get(key);
if (fieldDeser == null) {
if (!parser.isEnabled(Feature.IgnoreNotMatch)) {
throw new JSONException("setter not found, class " + clazz.getName() + ", property " + key);
}
lexer.nextTokenWithColon();
parser.parse(); // skip
if (lexer.token() == JSONToken.RBRACE) {
lexer.nextToken();
return;
}
continue;
} else {
Method method = fieldDeser.getMethod();
Class<?> fieldClass = method.getParameterTypes()[0];
Type fieldType = method.getGenericParameterTypes()[0];
if (fieldClass == int.class) {
lexer.nextTokenWithColon(JSONToken.LITERAL_INT);
args[0] = IntegerDeserializer.deserialze(parser);
} else if (fieldClass == String.class) {
lexer.nextTokenWithColon(JSONToken.LITERAL_STRING);
args[0] = StringDeserializer.deserialze(parser);
} else if (fieldClass == long.class) {
lexer.nextTokenWithColon(JSONToken.LITERAL_INT);
args[0] = LongDeserializer.deserialze(parser);
} else if (fieldClass == List.class) {
lexer.nextTokenWithColon(JSONToken.LBRACE);
args[0] = CollectionDeserializer.instance.deserialze(parser, fieldType, null);
} else {
ObjectDeserializer fieldValueDeserializer = parser.getConfig().getDeserializer(fieldClass,
fieldType);
lexer.nextTokenWithColon(fieldValueDeserializer.getFastMatchToken());
args[0] = fieldValueDeserializer.deserialze(parser, fieldType, null);
}
try {
method.invoke(object, args);
} catch (Exception e) {
throw new JSONException("set proprety error, " + method.getName(), e);
}
}
if (lexer.token() == JSONToken.COMMA) {
continue;
}
if (lexer.token() == JSONToken.RBRACE) {
lexer.nextToken(JSONToken.COMMA);
return;
}
}
}
@SuppressWarnings("unchecked")
public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {
if (type instanceof Class<?>) {
return deserialze(parser, (Class<T>) type);
}
if (type instanceof ParameterizedType) {
return (T) deserialze(parser, (ParameterizedType) type, fieldName);
}
if (type instanceof TypeVariable) {
return (T) parser.parse(fieldName);
}
if (type instanceof WildcardType) {
return (T) parser.parse(fieldName);
}
if (type instanceof GenericArrayType) {
Type componentType = ((GenericArrayType) type).getGenericComponentType();
List<Object> list = new ArrayList<Object>();
parser.parseArray(componentType, list);
if (componentType instanceof Class) {
Class<?> componentClass = (Class<?>) componentType;
Object[] array = (Object[]) Array.newInstance(componentClass, list.size());
list.toArray(array);
return (T) array;
}
}
throw new JSONException("not support type : " + type);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public <T> T deserialze(DefaultJSONParser parser, ParameterizedType type, Object fieldName) {
try {
JSONLexer lexer = parser.getLexer();
if (lexer.token() == JSONToken.NULL) {
lexer.nextToken();
return null;
}
Type rawType = type.getRawType();
if (rawType instanceof Class<?>) {
Class<?> rawClass = (Class<?>) rawType;
if (Map.class.isAssignableFrom(rawClass)) {
Map map;
if (Modifier.isAbstract(rawClass.getModifiers())) {
if (rawClass == Map.class) {
map = new HashMap();
} else if (rawClass == SortedMap.class) {
map = new TreeMap();
} else if (rawClass == ConcurrentMap.class) {
map = new ConcurrentHashMap();
} else {
throw new JSONException("can not create instance : " + rawClass);
}
} else {
if (rawClass == HashMap.class) {
map = new HashMap();
} else {
map = (Map) rawClass.newInstance();
}
}
Type keyType = type.getActualTypeArguments()[0];
Type valueType = type.getActualTypeArguments()[1];
if (keyType == String.class) {
return (T) parseMap(parser, map, valueType, fieldName);
} else {
return (T) parseMap(parser, map, keyType, valueType, fieldName);
}
}
}
throw new JSONException("not support type : " + type);
} catch (JSONException e) {
throw e;
} catch (Throwable e) {
throw new JSONException(e.getMessage(), e);
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public <T> T deserialze(DefaultJSONParser parser, Class<T> clazz) {
Object value = null;
if (parser.getLexer().token() == JSONToken.NULL) {
parser.getLexer().nextToken(JSONToken.COMMA);
return null;
}
if (clazz.isAssignableFrom(HashMap.class)) {
value = new HashMap();
} else if (clazz.isAssignableFrom(TreeMap.class)) {
value = new TreeMap();
} else if (clazz.isAssignableFrom(ConcurrentHashMap.class)) {
value = new ConcurrentHashMap();
} else if (clazz.isAssignableFrom(Properties.class)) {
value = new Properties();
} else if (clazz.isAssignableFrom(IdentityHashMap.class)) {
value = new IdentityHashMap();
}
if (clazz == Class.class) {
Object classValue = parser.parse();
if (classValue == null) {
return null;
}
if (classValue instanceof String) {
return (T) ASMClassLoader.forName((String) classValue);
}
} else if (clazz == Serializable.class) {
return (T) parser.parse();
}
if (value == null) {
throw new JSONException("not support type : " + clazz);
}
try {
parseObject(parser, value);
return (T) value;
} catch (JSONException e) {
throw e;
} catch (Throwable e) {
throw new JSONException(e.getMessage(), e);
}
}
public int getFastMatchToken() {
return JSONToken.LBRACE;
}
}