content: package com.alibaba.fastjson.codegen;
  
  import java.io.IOException;
  import java.lang.reflect.Constructor;
  import java.lang.reflect.Modifier;
  import java.lang.reflect.ParameterizedType;
  import java.lang.reflect.Type;
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.Collections;
  import java.util.HashSet;
  import java.util.LinkedList;
  import java.util.List;
  import java.util.TreeSet;
  
  import com.alibaba.fastjson.util.JavaBeanInfo;
  import com.alibaba.fastjson.util.FieldInfo;
  import com.alibaba.fastjson.util.TypeUtils;
  
  public class DeserializerGen extends ClassGen {
  
      private JavaBeanInfo beanInfo;
      private String              genClassName;
  
      public DeserializerGen(Class<?> clazz, Appendable out){
          super(clazz, out);
      }
  
      @Override
      public void gen() throws IOException {
          beanInfo = JavaBeanInfo.build(clazz, type, null);
          genClassName = clazz.getSimpleName() + "GenDecoder";
  
          print("package ");
          print(clazz.getPackage().getName());
          println(";");
          println();
  
          println("import java.lang.reflect.Type;");
          println();
  
          println("import com.alibaba.fastjson.parser.DefaultJSONParser;");
          println("import com.alibaba.fastjson.parser.DefaultJSONParser.ResolveTask;");
          println("import com.alibaba.fastjson.parser.ParserConfig;");
          println("import com.alibaba.fastjson.parser.Feature;");
          println("import com.alibaba.fastjson.parser.JSONLexerBase;");
          println("import com.alibaba.fastjson.parser.JSONToken;");
          println("import com.alibaba.fastjson.parser.ParseContext;");
          println("import com.alibaba.fastjson.parser.deserializer.ASMJavaBeanDeserializer;");
          println("import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer;");
          println();
  
          print("public class ");
          print(genClassName);
          print(" extends ASMJavaBeanDeserializer implements ObjectDeserializer {");
          incrementIndent();
          println();
  
          genConstructor();
  
          genCreateInstance();
  
          genDeserialze();
  
          endClass();
      }
  
      protected void genCreateInstance() throws IOException {
          println();
          print("public Object createInstance(DefaultJSONParser parser, Type type) {");
          incrementIndent();
          println();
  
          print("return new ");
          print(clazz.getSimpleName());
          print("();");
          println();
  
          decrementIndent();
          println();
          print("}");
      }
  
      protected void genDeserialze() throws IOException {
          if (beanInfo.fields.length == 0) {
              return;
          }
  
          for (FieldInfo fieldInfo : beanInfo.fields) {
              Class<?> fieldClass = fieldInfo.fieldClass;
              Type fieldType = fieldInfo.fieldType;
  
              if (fieldClass == char.class) {
                  return;
              }
  
              if (Collection.class.isAssignableFrom(fieldClass)) {
                  if (fieldType instanceof ParameterizedType) {
                      Type itemType = ((ParameterizedType) fieldType).getActualTypeArguments()[0];
                      if (itemType instanceof Class) {
                          continue;
                      } else {
                          return;
                      }
                  } else {
                      return;
                  }
              }
          }
  
          FieldInfo[] fieldList = beanInfo.sortedFields;
  
          println();
          print("public Object deserialze(DefaultJSONParser parser, Type type, Object fieldName) {");
          incrementIndent();
          println();
  
          println("JSONLexerBase lexer = (JSONLexerBase) parser.getLexer();");
          println();
  
          println("if (!lexer.isEnabled(Feature.SortFeidFastMatch)) {");
          println("\treturn super.deserialze(parser, type, fieldName);");
          println("}");
  
          println();
  
          println("if (isSupportArrayToBean(lexer)) {");
          println("\t// deserialzeArrayMapping");
          println("}");
  
          println();
          println("if (lexer.scanType(\"Department\") == JSONLexerBase.NOT_MATCH) {");
          println("\treturn super.deserialze(parser, type, fieldName);");
          println("}");
  
          println();
  
          println("ParseContext mark_context = parser.getContext();");
          println("int matchedCount = 0;");
  
          print(clazz.getSimpleName());
          print(" instance = ");
          Constructor<?> defaultConstructor = beanInfo.defaultConstructor;
          if (Modifier.isPublic(defaultConstructor.getModifiers())) {
              print("new ");
              print(clazz.getSimpleName());
              println("();");
          } else {
              print("(");
              print(clazz.getSimpleName());
              print(") createInstance(parser);");
          }
  
          println();
  
          println("ParseContext context = parser.getContext();");
          println("ParseContext childContext = parser.setContext(context, instance, fieldName);");
  
          println();
  
          println("if (lexer.matchStat == JSONLexerBase.END) {");
          println("\treturn instance;");
          println("}");
  
          println();
  
          println("int matchStat = 0;");
  
          int fieldListSize = fieldList.length;
          for (int i = 0; i < fieldListSize; i += 32) {
              print("int _asm_flag_");
              print(Integer.toString(i / 32));
              println(" = 0;");
          }
  
          for (int i = 0; i < fieldListSize; ++i) {
              FieldInfo fieldInfo = fieldList[i];
              Class<?> fieldClass = fieldInfo.fieldClass;
  
              if (fieldClass == boolean.class) {
                  print("boolean ");
                  printFieldVarName(fieldInfo);
                  println(" = false;");
              } else if (fieldClass == byte.class //
                         || fieldClass == short.class //
                         || fieldClass == int.class //
                         || fieldClass == long.class //
                         || fieldClass == float.class //
                         || fieldClass == double.class //
              ) {
                  print(fieldClass.getSimpleName());
                  print(" ");
                  printFieldVarName(fieldInfo);
                  println(" = 0;");
              } else {
                  if (fieldClass == String.class) {
                      print("String ");
                      printFieldVarName(fieldInfo);
                      println(";");
  
                      println("if (lexer.isEnabled(Feature.InitStringFieldAsEmpty)) {");
                      print("\t");
                      printFieldVarName(fieldInfo);
                      println(" = lexer.stringDefaultValue();");
                      print("\t");
                      genSetFlag(i);
                      println("} else {");
                      print("\t");
                      printFieldVarName(fieldInfo);
                      println(" = null;");
                      println("}");
                  } else {
                      printClassName(fieldClass);
                      print(" ");
                      printFieldVarName(fieldInfo);
                      print(" = null;");
                      println();
                  }
              }
          }
  
          println("boolean endFlag = false, restFlag = false;");
          println();
  
          for (int i = 0; i < fieldListSize; ++i) {
              print("if ((!endFlag) && (!restFlag)) {");
              incrementIndent();
              println();
  
              FieldInfo fieldInfo = fieldList[i];
              Class<?> fieldClass = fieldInfo.fieldClass;
              Type fieldType = fieldInfo.fieldType;
  
              if (fieldClass == boolean.class) {
                  printFieldVarName(fieldInfo);
                  print(" = lexer.scanFieldBoolean(");
                  printFieldPrefix(fieldInfo);
                  println(");");
              } else if (fieldClass == byte.class || fieldClass == short.class || fieldClass == int.class) {
                  printFieldVarName(fieldInfo);
                  print(" = lexer.scanFieldInt(");
                  printFieldPrefix(fieldInfo);
                  println(");");
              } else if (fieldClass == long.class) {
                  printFieldVarName(fieldInfo);
                  print(" = lexer.scanFieldLong(");
                  printFieldPrefix(fieldInfo);
                  println(");");
              } else if (fieldClass == float.class) {
                  printFieldVarName(fieldInfo);
                  print(" = lexer.scanFieldFloat(");
                  printFieldPrefix(fieldInfo);
                  println(");");
              } else if (fieldClass == double.class) {
                  printFieldVarName(fieldInfo);
                  print(" = lexer.scanFieldDouble(");
                  printFieldPrefix(fieldInfo);
                  println(");");
              } else if (fieldClass == String.class) {
                  printFieldVarName(fieldInfo);
                  print(" = lexer.scanFieldString(");
                  printFieldPrefix(fieldInfo);
                  println(");");
              } else if (fieldClass.isEnum()) {
                  print("String ");
                  printFieldVarEnumName(fieldInfo);
  
                  print(" = lexer.scanFieldSymbol(");
                  printFieldPrefix(fieldInfo);
                  println(", parser.getSymbolTable());");
  
                  print("if (");
                  printFieldVarEnumName(fieldInfo);
                  println(" == null) {");
                  print("\t");
                  printFieldVarName(fieldInfo);
                  print(" = ");
                  printClassName(fieldClass);
                  print(".valueOf(");
                  printFieldVarEnumName(fieldInfo);
                  println(");");
                  println("}");
              } else if (Collection.class.isAssignableFrom(fieldClass)) {
                  Class<?> itemClass = TypeUtils.getCollectionItemClass(fieldType);
  
                  if (itemClass == String.class) {
                      printFieldVarName(fieldInfo);
                      print(" = (");
                      printClassName(fieldClass);
                      print(") lexer.scanFieldStringArray(");
                      printFieldPrefix(fieldInfo);
                      print(", ");
                      printClassName(fieldClass);
                      print(".class);");
                      println();
                  } else {
                      genDeserialzeList(fieldInfo, i, itemClass);
                      if (i == fieldListSize - 1) {
                          genEndCheck();
                      }
                  }
              } else {
                  genDeserialzeObject(fieldInfo, i);
  
                  if (i == fieldListSize - 1) {
                      genEndCheck();
                  }
              }
  
              println("if(lexer.matchStat > 0) {");
              print("\t");
              genSetFlag(i);
              println("\tmatchedCount++;");
              println("}");
  
              println("if(lexer.matchStat == JSONLexerBase.NOT_MATCH) {");
              println("\trestFlag = true;");
              println("}");
  
    
              println("if(lexer.matchStat != JSONLexerBase.END) {");
              println("\tendFlag = true;");
              println("}");
              
  
              decrementIndent();
              println();
              println("}");
          }
  
          genBatchSet(fieldList, true);
  
          println();
          println("if (restFlag) {");
          println("\treturn super.parseRest(parser, type, fieldName, instance);");
          println("}");
  
          println();
          print("return instance;");
          println();
  
          decrementIndent();
          println();
          print("}");
      }
  
      private void genBatchSet(FieldInfo[] fieldList, boolean flag) throws IOException {
          for (int i = 0, size = fieldList.length; i < size; ++i) {
              FieldInfo fieldInfo = fieldList[i];
              
              String varName = "_asm_flag_" + (i / 32);
              if (flag) {
                  print("if ((");
                  print(varName);
                  print(" & ");
                  print(Integer.toString(1 << i));
                  print(") != 0) {");
                  println();
                  incrementIndent();
              }
              
              if (fieldInfo.method != null) {
                  print("\tinstance.");
                  print(fieldInfo.method.getName());
                  print("(");
                  printFieldVarName(fieldInfo);
                  println(");");
              } else {
                  print("\tinstance.");
                  print(fieldInfo.field.getName());
                  print(" = ");
                  printFieldVarName(fieldInfo);
                  println(";");
              }
  
              if (flag) {
                  decrementIndent();
                  println();
                  println("}");
              }
          }
      }
  
      private void genEndCheck() throws IOException {
          println("if (matchedCount <= 0 || lexer.token() != JSONToken.RBRACE) {");
          println("\trestFlag = true;");
          println("} else if (lexer.token() == JSONToken.COMMA) {");
          println("\tlexer.nextToken();");
          println("}");
      }
  
      protected void genDeserialzeList(FieldInfo fieldInfo, int i, Class<?> itemClass) throws IOException {
          print("if (lexer.matchField(");
          printFieldPrefix(fieldInfo);
          print(")) {");
          println();
          print("\t");
          genSetFlag(i);
          println("\tif (lexer.token() == JSONToken.NULL) {");
          println("\t\tlexer.nextToken(JSONToken.COMMA);");
          println("\t} else {");
          println("\t\tif (lexer.token() == JSONToken.LBRACKET) {");
          print("\t\t\tif(");
          printListFieldItemDeser(fieldInfo);
          print(" == null) {");
          println();
  
          print("\t\t\t\t");
          printListFieldItemDeser(fieldInfo);
          print(" = parser.getConfig().getDeserializer(");
          printClassName(itemClass);
          print(".class);");
          println();
  
          print("\t\t\t}");
          println();
  
          print("\t\t\tfinal int fastMatchToken = ");
          printListFieldItemDeser(fieldInfo);
          print(".getFastMatchToken();");
          println();
          println("\t\t\tlexer.nextToken(fastMatchToken);");
  
          // _newCollection
          print("\t\t\t");
          printFieldVarName(fieldInfo);
          print(" = ");
          Class<?> fieldClass = fieldInfo.fieldClass;
          if (fieldClass.isAssignableFrom(ArrayList.class)) {
              print("new java.util.ArrayList();");
          } else if (fieldClass.isAssignableFrom(LinkedList.class)) {
              print("new java.util.LinkedList();");
          } else if (fieldClass.isAssignableFrom(HashSet.class)) {
              print("new java.util.HashSet();");
          } else if (fieldClass.isAssignableFrom(TreeSet.class)) {
              print("new java.util.TreeSet();");
          } else {
              print("new ");
              printClassName(fieldClass);
              print("();");
          }
          println();
  
          println("\t\t\tParseContext listContext = parser.getContext();");
          print("\t\t\tparser.setContext(");
          printFieldVarName(fieldInfo);
          print(", \"");
          print(fieldInfo.name);
          print("\");");
          println();
  
          println();
          println("\t\t\tfor(int i = 0; ;++i) {");
  
          println("\t\t\t\tif (lexer.token() == JSONToken.RBRACKET) {");
          println("\t\t\t\t\tbreak;");
          println("\t\t\t\t}");
          print("\t\t\t\t");
          printClassName(itemClass);
          print(" itemValue = ");
          printListFieldItemDeser(fieldInfo);
          print(".deserialze(parser, ");
          printListFieldItemType(fieldInfo);
          println(", i);");
  
          print("\t\t\t\t");
          printFieldVarName(fieldInfo);
          println(".add(itemValue);");
  
          print("\t\t\t\tparser.checkListResolve(");
          printFieldVarName(fieldInfo);
          println(");");
  
          println("\t\t\t\tif (lexer.token() == JSONToken.COMMA) {");
          println("\t\t\t\t\tlexer.nextToken(fastMatchToken);");
          println("\t\t\t\t}");
  
          // end for
          println("\t\t\t}");
  
          println("\t\t\tparser.setContext(listContext);");
  
          println("\t\t\tif (lexer.token() != JSONToken.RBRACKET) {");
          println("\t\t\t\trestFlag = true;");
          println("\t\t\t}");
          println("\t\t\tlexer.nextToken(JSONToken.COMMA);");
  
          println();
          println("\t\t} else {");
          println("\t\t\trestFlag = true;");
          println("\t\t}");
          println("\t}");
          println("}");
      }
  
      protected void genDeserialzeObject(FieldInfo fieldInfo, int i) throws IOException {
          print("if (lexer.matchField(");
          printFieldPrefix(fieldInfo);
          print(")) {");
          println();
          print("\t");
          genSetFlag(i);
          println("\tmatchedCount++;");
  
          // _deserObject
          print("if (");
          printFieldDeser(fieldInfo);
          print(" == null) {");
          println();
  
          print("\t");
          printFieldDeser(fieldInfo);
          print(" = parser.getConfig().getDeserializer(");
          printClassName(fieldInfo.fieldClass);
          println(".class);");
          println("}");
  
          print("\t");
          printFieldDeser(fieldInfo);
          print(".deserialze(parser, ");
          if (fieldInfo.fieldType instanceof Class) {
              printClassName(fieldInfo.fieldClass);
              print(".class");
          } else {
              print("getFieldType(\"");
              println(fieldInfo.name);
              print("\")");
          }
          print(",\"");
          print(fieldInfo.name);
          println("\");");
  
          println("\tif(parser.getResolveStatus() == DefaultJSONParser.NeedToResolve) {");
          println("\t\tResolveTask resolveTask = parser.getLastResolveTask();");
          println("\t\tresolveTask.setOwnerContext(parser.getContext());");
          print("\t\tresolveTask.setFieldDeserializer(this.getFieldDeserializer(\"");
          print(fieldInfo.name);
          println("\"));");
          println("\t\tparser.setResolveStatus(DefaultJSONParser.NONE);");
          println("\t}");
          println("}");
      }
  
      private void printFieldVarName(FieldInfo fieldInfo) throws IOException {
          print(fieldInfo.name);
          print("_gen");
      }
  
      private void printFieldVarEnumName(FieldInfo fieldInfo) throws IOException {
          print(fieldInfo.name);
          print("_gen_enum_name");
      }
  
      private void printFieldPrefix(FieldInfo fieldInfo) throws IOException {
          print(fieldInfo.name);
          print("_gen_prefix__");
      }
  
      private void printListFieldItemDeser(FieldInfo fieldInfo) throws IOException {
          print(fieldInfo.name);
          print("_gen_list_item_deser__");
      }
  
      private void printFieldDeser(FieldInfo fieldInfo) throws IOException {
          print(fieldInfo.name);
          print("_gen_deser__");
      }
  
      private void printListFieldItemType(FieldInfo fieldInfo) throws IOException {
          print(fieldInfo.name);
          print("_gen_list_item_type__");
      }
  
      private void genSetFlag(int flag) throws IOException {
          String varName = "_asm_flag_" + (flag / 32);
          print(varName);
          print(" |= ");
          print(Integer.toString(1 << flag));
          print(";");
          println();
      }
  
      protected void genConstructor() throws IOException {
          for (int i = 0, size = beanInfo.fields.length; i < size; ++i) {
              FieldInfo fieldInfo = beanInfo.fields[i];
              print("private char[] ");
              printFieldPrefix(fieldInfo);
              print(" = \"\\\"");
              print(fieldInfo.name);
              print("\\\":\".toCharArray();");
              println();
          }
  
          println();
  
          boolean fieldDeserFlag = false;
          for (int i = 0, size = beanInfo.fields.length; i < size; ++i) {
              FieldInfo fieldInfo = beanInfo.fields[i];
              Class<?> fieldClass = fieldInfo.fieldClass;
  
              if (fieldClass.isPrimitive()) {
                  continue;
              }
  
              if (fieldClass.isEnum()) {
                  continue;
              }
  
              print("private ObjectDeserializer ");
  
              if (Collection.class.isAssignableFrom(fieldClass)) {
                  printListFieldItemDeser(fieldInfo);
              } else {
                  printFieldDeser(fieldInfo);
              }
              println(";");
              fieldDeserFlag = true;
  
              if (Collection.class.isAssignableFrom(fieldClass)) {
                  print("private Type ");
                  printListFieldItemType(fieldInfo);
                  print(" = ");
                  Class<?> fieldItemClass = TypeUtils.getCollectionItemClass(fieldInfo.fieldType);
                  printClassName(fieldItemClass);
                  println(".class;");
              }
          }
  
          if (fieldDeserFlag) {
              println();
          }
  
          // constructor
          print("public ");
          print(genClassName);
          print(" (ParserConfig config, Class clazz) {");
          incrementIndent();
          println();
  
          println("super(config, clazz);");
  
          decrementIndent();
          println();
          print("}");
          println();
      }
  
  }
  