package com.alibaba.fastjson.parser.deserializer; import java.lang.reflect.Constructor; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONException; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.parser.*; import com.alibaba.fastjson.parser.DefaultJSONParser.ResolveTask; import com.alibaba.fastjson.serializer.CollectionCodec; import com.alibaba.fastjson.util.TypeUtils; public class MapDeserializer implements ObjectDeserializer { public static MapDeserializer instance = new MapDeserializer(); @SuppressWarnings("unchecked") public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) { if (type == JSONObject.class && parser.getFieldTypeResolver() == null) { return (T) parser.parseObject(); } final JSONLexer lexer = parser.lexer; if (lexer.token() == JSONToken.NULL) { lexer.nextToken(JSONToken.COMMA); return null; } Map<Object, Object> map = createMap(type); ParseContext context = parser.getContext(); try { parser.setContext(context, map, fieldName); return (T) deserialze(parser, type, fieldName, map); } finally { parser.setContext(context); } } @SuppressWarnings({ "rawtypes", "unchecked" }) protected Object deserialze(DefaultJSONParser parser, Type type, Object fieldName, Map map) { if (type instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) type; Type keyType = parameterizedType.getActualTypeArguments()[0]; Type valueType = parameterizedType.getActualTypeArguments()[1]; if (String.class == keyType) { return parseMap(parser, (Map<String, Object>) map, valueType, fieldName); } else { return parseMap(parser, map, keyType, valueType, fieldName); } } else { return parser.parseObject(map, fieldName); } } @SuppressWarnings("rawtypes") public static Map parseMap(DefaultJSONParser parser, Map<String, Object> map, Type valueType, Object fieldName) { JSONLexer lexer = parser.lexer; if (lexer.token() != JSONToken.LBRACE) { String msg = "syntax error, expect {, actual " + lexer.tokenName(); if (fieldName instanceof String) { msg += ", fieldName "; msg += fieldName; } msg += ", "; msg += lexer.info(); JSONArray array = new JSONArray(); parser.parseArray(array, fieldName); if (array.size() == 1) { Object first = array.get(0); if (first instanceof JSONObject) { return (JSONObject) first; } } throw new JSONException(msg); } ParseContext context = parser.getContext(); try { for (int i = 0;;++i) { lexer.skipWhitespace(); char ch = lexer.getCurrent(); if (lexer.isEnabled(Feature.AllowArbitraryCommas)) { while (ch == ',') { lexer.next(); 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.next(); lexer.resetStringPosition(); lexer.nextToken(JSONToken.COMMA); return map; } else if (ch == '\'') { if (!lexer.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 (!lexer.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.next(); lexer.skipWhitespace(); ch = lexer.getCurrent(); lexer.resetStringPosition(); if (key == JSON.DEFAULT_TYPE_KEY && !lexer.isEnabled(Feature.DisableSpecialKeyDetect)) { String typeName = lexer.scanSymbol(parser.getSymbolTable(), '"'); final ParserConfig config = parser.getConfig(); Class<?> clazz = config.checkAutoType(typeName, null); if (Map.class.isAssignableFrom(clazz) ) { lexer.nextToken(JSONToken.COMMA); if (lexer.token() == JSONToken.RBRACE) { lexer.nextToken(JSONToken.COMMA); return map; } continue; } ObjectDeserializer deserializer = config.getDeserializer(clazz); lexer.nextToken(JSONToken.COMMA); parser.setResolveStatus(DefaultJSONParser.TypeNameRedirect); if (context != null && !(fieldName instanceof Integer)) { parser.popContext(); } return (Map) deserializer.deserialze(parser, clazz, fieldName); } Object value; lexer.nextToken(); if (i != 0) { parser.setContext(context); } if (lexer.token() == JSONToken.NULL) { value = null; lexer.nextToken(); } else { value = parser.parseObject(valueType, key); } map.put(key, value); parser.checkMapResolve(map, key); parser.setContext(context, value, key); parser.setContext(context); final int tok = lexer.token(); if (tok == JSONToken.EOF || tok == JSONToken.RBRACKET) { return map; } if (tok == JSONToken.RBRACE) { lexer.nextToken(); return map; } } } finally { parser.setContext(context); } } public static Object parseMap(DefaultJSONParser parser, Map<Object, Object> map, Type keyType, Type valueType, Object fieldName) { JSONLexer lexer = parser.lexer; 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() // && !lexer.isEnabled(Feature.DisableSpecialKeyDetect) // ) { Object object = null; lexer.nextTokenWithColon(JSONToken.LITERAL_STRING); if (lexer.token() == JSONToken.LITERAL_STRING) { String ref = lexer.stringVal(); if ("..".equals(ref)) { ParseContext parentContext = context.parent; object = parentContext.object; } else if ("$".equals(ref)) { ParseContext rootContext = context; while (rootContext.parent != null) { rootContext = rootContext.parent; } object = rootContext.object; } 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 // && JSON.DEFAULT_TYPE_KEY.equals(lexer.stringVal()) // && !lexer.isEnabled(Feature.DisableSpecialKeyDetect)) { lexer.nextTokenWithColon(JSONToken.LITERAL_STRING); lexer.nextToken(JSONToken.COMMA); if (lexer.token() == JSONToken.RBRACE) { lexer.nextToken(); return map; } 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); parser.checkMapResolve(map, key); map.put(key, value); if (lexer.token() == JSONToken.COMMA) { lexer.nextToken(keyDeserializer.getFastMatchToken()); } } } finally { parser.setContext(context); } return map; } @SuppressWarnings({ "unchecked", "rawtypes" }) protected Map<Object, Object> createMap(Type type) { if (type == Properties.class) { return new Properties(); } if (type == Hashtable.class) { return new Hashtable(); } if (type == IdentityHashMap.class) { return new IdentityHashMap(); } if (type == SortedMap.class || type == TreeMap.class) { return new TreeMap(); } if (type == ConcurrentMap.class || type == ConcurrentHashMap.class) { return new ConcurrentHashMap(); } if (type == Map.class || type == HashMap.class) { return new HashMap(); } if (type == LinkedHashMap.class) { return new LinkedHashMap(); } if (type instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) type; Type rawType = parameterizedType.getRawType(); if (EnumMap.class.equals(rawType)) { Type[] actualArgs = parameterizedType.getActualTypeArguments(); return new EnumMap((Class) actualArgs[0]); } return createMap(rawType); } Class<?> clazz = (Class<?>) type; if (clazz.isInterface()) { throw new JSONException("unsupport type " + type); } try { return (Map<Object, Object>) clazz.newInstance(); } catch (Exception e) { throw new JSONException("unsupport type " + type, e); } } public int getFastMatchToken() { return JSONToken.LBRACE; } }