content: package com.alibaba.fastjson.parser.deserializer;
  
  import java.lang.reflect.Constructor;
  import java.lang.reflect.Proxy;
  import java.lang.reflect.Type;
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.IdentityHashMap;
  import java.util.List;
  import java.util.Map;
  
  import com.alibaba.fastjson.JSONException;
  import com.alibaba.fastjson.JSONObject;
  import com.alibaba.fastjson.parser.DefaultJSONParser;
  import com.alibaba.fastjson.parser.DefaultJSONParser.ResolveTask;
  import com.alibaba.fastjson.parser.Feature;
  import com.alibaba.fastjson.parser.JSONScanner;
  import com.alibaba.fastjson.parser.JSONToken;
  import com.alibaba.fastjson.parser.ParseContext;
  import com.alibaba.fastjson.parser.ParserConfig;
  import com.alibaba.fastjson.util.DeserializeBeanInfo;
  import com.alibaba.fastjson.util.FieldInfo;
  import com.alibaba.fastjson.util.TypeUtils;
  
  public class JavaBeanDeserializer implements ObjectDeserializer {
  
      private final Map<String, FieldDeserializer> feildDeserializerMap = new IdentityHashMap<String, FieldDeserializer>();
  
      private final List<FieldDeserializer>        fieldDeserializers   = new ArrayList<FieldDeserializer>();
  
      private final Class<?>                       clazz;
      private final Type                           type;
  
      private DeserializeBeanInfo                  beanInfo;
  
      public JavaBeanDeserializer(DeserializeBeanInfo beanInfo){
          this.beanInfo = beanInfo;
          this.clazz = beanInfo.getClazz();
          this.type = beanInfo.getType();
      }
  
      public JavaBeanDeserializer(ParserConfig config, Class<?> clazz){
          this(config, clazz, clazz);
      }
  
      public JavaBeanDeserializer(ParserConfig config, Class<?> clazz, Type type){
          this.clazz = clazz;
          this.type = type;
  
          beanInfo = DeserializeBeanInfo.computeSetters(clazz, type);
  
          for (FieldInfo fieldInfo : beanInfo.getFieldList()) {
              addFieldDeserializer(config, clazz, fieldInfo);
          }
      }
  
      public Map<String, FieldDeserializer> getFieldDeserializerMap() {
          return feildDeserializerMap;
      }
  
      public Class<?> getClazz() {
          return clazz;
      }
  
      public Type getType() {
          return type;
      }
  
      private void addFieldDeserializer(ParserConfig mapping, Class<?> clazz, FieldInfo fieldInfo) {
          FieldDeserializer fieldDeserializer = createFieldDeserializer(mapping, clazz, fieldInfo);
  
          feildDeserializerMap.put(fieldInfo.getName().intern(), fieldDeserializer);
          fieldDeserializers.add(fieldDeserializer);
      }
  
      public FieldDeserializer createFieldDeserializer(ParserConfig mapping, Class<?> clazz, FieldInfo fieldInfo) {
          return mapping.createFieldDeserializer(mapping, clazz, fieldInfo);
      }
  
      public Object createInstance(DefaultJSONParser parser, Type type) {
          if (type instanceof Class) {
              if (clazz.isInterface()) {
                  Class<?> clazz = (Class<?>) type;
                  ClassLoader loader = Thread.currentThread().getContextClassLoader();
                  final JSONObject obj = new JSONObject();
                  Object proxy = Proxy.newProxyInstance(loader, new Class<?>[] { clazz }, obj);
                  return proxy;
              }
          }
  
          if (beanInfo.getDefaultConstructor() == null) {
              return null;
          }
  
          Object object;
          try {
              Constructor<?> constructor = beanInfo.getDefaultConstructor();
              if (constructor.getParameterTypes().length == 0) {
                  object = constructor.newInstance();
              } else {
                  object = constructor.newInstance(parser.getContext().getObject());
              }
          } catch (Exception e) {
              throw new JSONException("create instance error, class " + clazz.getName(), e);
          }
  
          if (parser.isEnabled(Feature.InitStringFieldAsEmpty)) {
              for (FieldInfo fieldInfo : beanInfo.getFieldList()) {
                  if (fieldInfo.getFieldClass() == String.class) {
                      try {
                          fieldInfo.set(object, "");
                      } catch (Exception e) {
                          throw new JSONException("create instance error, class " + clazz.getName(), e);
                      }
                  }
              }
          }
  
          return object;
      }
  
      @SuppressWarnings("unchecked")
      public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {
          JSONScanner lexer = (JSONScanner) parser.getLexer(); // xxx
  
          if (lexer.token() == JSONToken.NULL) {
              lexer.nextToken(JSONToken.COMMA);
              return null;
          }
  
          ParseContext context = parser.getContext();
          ParseContext childContext = null;
          Object object = null;
  
          try {
              Map<String, Object> fieldValues = null;
  
              if (lexer.token() == JSONToken.RBRACE) {
                  lexer.nextToken(JSONToken.COMMA);
                  return (T) createInstance(parser, type);
              }
  
              if (lexer.token() != JSONToken.LBRACE && lexer.token() != JSONToken.COMMA) {
              	StringBuffer buf = (new StringBuffer()) //
              			.append("syntax error, expect {, actual ") //
              			.append(lexer.tokenName()) //
              			.append(", pos ") //
              			.append(lexer.pos()) //
              			;
              	if (fieldName instanceof String) {
              		buf //
              		.append(", fieldName ") //
              		.append(fieldName);
              	}
                  throw new JSONException(buf.toString());
              }
  
              if (parser.getResolveStatus() == DefaultJSONParser.TypeNameRedirect) {
                  parser.setResolveStatus(DefaultJSONParser.NONE);
              }
  
              for (;;) {
  
                  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;
                          }
                      }
                  }
  
                  if ("$ref" == key) {
                      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);
  
                      childContext = parser.setContext(context, object, fieldName);
  
                      return (T) object;
                  }
  
                  if ("@type" == key) {
                      lexer.nextTokenWithColon(JSONToken.LITERAL_STRING);
                      if (lexer.token() == JSONToken.LITERAL_STRING) {
                          String typeName = lexer.stringVal();
                          lexer.nextToken(JSONToken.COMMA);
  
                          if (type instanceof Class && typeName.equals(((Class<?>) type).getName())) {
                              if (lexer.token() == JSONToken.RBRACE) {
                                  lexer.nextToken();
                                  break;
                              }
                              continue;
                          }
  
                          Class<?> userType = TypeUtils.loadClass(typeName);
                          ObjectDeserializer deserizer = parser.getConfig().getDeserializer(userType);
                          return (T) deserizer.deserialze(parser, userType, fieldName);
                      } else {
                          throw new JSONException("syntax error");
                      }
                  }
  
                  if (object == null && fieldValues == null) {
                      object = createInstance(parser, type);
                      if (object == null) {
                          fieldValues = new HashMap<String, Object>(this.fieldDeserializers.size());
                      }
                      childContext = parser.setContext(context, object, fieldName);
                  }
  
                  boolean match = parseField(parser, key, object, type, fieldValues);
                  if (!match) {
                      if (lexer.token() == JSONToken.RBRACE) {
                          lexer.nextToken();
                          break;
                      }
  
                      continue;
                  }
  
                  if (lexer.token() == JSONToken.COMMA) {
                      continue;
                  }
  
                  if (lexer.token() == JSONToken.RBRACE) {
                      lexer.nextToken(JSONToken.COMMA);
                      break;
                  }
  
                  if (lexer.token() == JSONToken.IDENTIFIER || lexer.token() == JSONToken.ERROR) {
                      throw new JSONException("syntax error, unexpect token " + JSONToken.name(lexer.token()));
                  }
              }
  
              if (object == null) {
                  if (fieldValues == null) {
                      object = createInstance(parser, type);
                      return (T) object;
                  }
  
                  List<FieldInfo> fieldInfoList = beanInfo.getFieldList();
                  int size = fieldInfoList.size();
                  Object[] params = new Object[size];
                  for (int i = 0; i < size; ++i) {
                      FieldInfo fieldInfo = fieldInfoList.get(i);
                      params[i] = fieldValues.get(fieldInfo.getName());
                  }
  
                  if (beanInfo.getCreatorConstructor() != null) {
                      try {
                          object = beanInfo.getCreatorConstructor().newInstance(params);
                      } catch (Exception e) {
                          throw new JSONException("create instance error, "
                                                  + beanInfo.getCreatorConstructor().toGenericString(), e);
                      }
                  } else if (beanInfo.getFactoryMethod() != null) {
                      try {
                          object = beanInfo.getFactoryMethod().invoke(null, params);
                      } catch (Exception e) {
                          throw new JSONException("create factory method error, "
                                                  + beanInfo.getFactoryMethod().toString(), e);
                      }
                  }
              }
  
              return (T) object;
          } finally {
              if (childContext != null) {
                  childContext.setObject(object);
              }
              parser.setContext(context);
          }
      }
  
      public boolean parseField(DefaultJSONParser parser, String key, Object object, Type objectType,
                                Map<String, Object> fieldValues) {
          JSONScanner lexer = (JSONScanner) parser.getLexer(); // xxx
  
          FieldDeserializer fieldDeserializer = feildDeserializerMap.get(key);
  
          if (fieldDeserializer == null) {
              for (Map.Entry<String, FieldDeserializer> entry : feildDeserializerMap.entrySet()) {
                  if (entry.getKey().equalsIgnoreCase(key)) {
                      fieldDeserializer = entry.getValue();
                      break;
                  }
              }
          }
  
          if (fieldDeserializer == null) {
              if (!parser.isEnabled(Feature.IgnoreNotMatch)) {
                  throw new JSONException("setter not found, class " + clazz.getName() + ", property " + key);
              }
  
              lexer.nextTokenWithColon();
              parser.parse(); // skip
  
              return false;
          }
  
          lexer.nextTokenWithColon(fieldDeserializer.getFastMatchToken());
  
          fieldDeserializer.parseField(parser, object, objectType, fieldValues);
  
          return true;
      }
  
      public int getFastMatchToken() {
          return JSONToken.LBRACE;
      }
  
  }
  