content: 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);
                      
                      if (context != null && !(fieldName instanceof Integer)) {
                          parser.popContext();
                      }
                      
                      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.checkMapResolve(map, key);
                  
                  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;
      }
  }
  