private void generateProxyClass(
     ClassWriter visitor,
     StructSchema<?> viewSchema,
     StructSchema<?> delegateSchema,
     Collection<String> interfacesToImplement,
     Set<Class<?>> typesToDelegate,
     Type generatedType,
     Type superclassType) {
   ModelType<?> viewType = viewSchema.getType();
   Class<?> viewClass = viewType.getConcreteClass();
   declareClass(visitor, interfacesToImplement, generatedType, superclassType);
   declareStateField(visitor);
   declareTypeConverterField(visitor);
   declareManagedTypeField(visitor);
   declareCanCallSettersField(visitor);
   writeStaticConstructor(visitor, generatedType, viewClass);
   writeConstructor(visitor, generatedType, superclassType, delegateSchema);
   writeToString(visitor, generatedType, viewClass, delegateSchema);
   writeManagedInstanceMethods(visitor, generatedType);
   if (delegateSchema != null) {
     declareDelegateField(visitor, delegateSchema);
     writeDelegateMethods(visitor, generatedType, delegateSchema, typesToDelegate);
   }
   writeGroovyMethods(visitor, viewClass);
   writePropertyMethods(visitor, generatedType, viewSchema, delegateSchema);
   writeHashCodeMethod(visitor, generatedType);
   writeEqualsMethod(visitor, generatedType);
   visitor.visitEnd();
 }
  @Override
  public FieldAccessor build(ClassLoader classLoader) {
    String targetClassType = getInternalName(this.getTarget().getName());

    ClassWriter classWriter = this.getClassWriter();

    injectFieldTable(classWriter);
    injectConstructor(classWriter);
    injectGetTargetClass(classWriter, this.getTarget());

    List<Field> fields = new ArrayList<>();
    Class<?> current = this.getTarget();
    while (current != Object.class) {
      for (Field field : current.getDeclaredFields()) {
        fields.add(field);
      }
      current = current.getSuperclass();
    }

    injectGetByIndex(classWriter, targetClassType, fields);
    injectSetByIndex(classWriter, targetClassType, fields);

    injectGetByName(classWriter);
    injectSetByName(classWriter);

    injectGetFieldTable(classWriter);
    injectGetIndex(classWriter);

    classWriter.visitEnd();

    Class<?> result =
        CompilerService.create(classLoader)
            .defineClass(
                getExternalName(
                    getAccessorNameInternal(
                        this.getTarget(),
                        this
                            .getAccessorType())), // this is somewhat redundant but maybe in the
                                                  // future the class-name-format changes
                this.getClassWriter().toByteArray());

    return (FieldAccessor) instantiate(result);
  }
  public static byte[] createTargetSetterFactory(String factoryName, String className, Type target)
      throws Exception {

    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
    MethodVisitor mv;

    String factoryType = AsmUtils.toType(factoryName);
    String classType = AsmUtils.toType(className);
    String targetType = AsmUtils.toType(target);

    cw.visit(
        V1_6,
        ACC_FINAL + ACC_PUBLIC + ACC_SUPER,
        factoryType,
        "L" + CELL_HANDLER_FACTORY_TYPE + "<L" + targetType + ";>;",
        CELL_HANDLER_FACTORY_TYPE,
        null);

    {
      mv =
          cw.visitMethod(
              ACC_PUBLIC,
              "<init>",
              "("
                  + AsmUtils.toDeclaredLType(Instantiator.class)
                  + AsmUtils.toDeclaredLType(CsvColumnKey[].class)
                  + AsmUtils.toDeclaredLType(ParsingContextFactory.class)
                  + AsmUtils.toDeclaredLType(FieldMapperErrorHandler.class)
                  + ")V",
              "("
                  + "L"
                  + AsmUtils.toType(Instantiator.class)
                  + "<L"
                  + AsmUtils.toType(CsvMapperCellHandler.class)
                  + "<L"
                  + targetType
                  + ";>;L"
                  + targetType
                  + ";>;"
                  + AsmUtils.toDeclaredLType(CsvColumnKey[].class)
                  + AsmUtils.toDeclaredLType(ParsingContextFactory.class)
                  + "L"
                  + AsmUtils.toType(FieldMapperErrorHandler.class)
                  + "<L"
                  + AsmUtils.toType(CsvColumnKey.class)
                  + ";>;"
                  + ")V",
              null);

      mv.visitCode();
      mv.visitVarInsn(ALOAD, 0);
      mv.visitVarInsn(ALOAD, 1);
      mv.visitVarInsn(ALOAD, 2);
      mv.visitVarInsn(ALOAD, 3);
      mv.visitVarInsn(ALOAD, 4);
      mv.visitMethodInsn(
          INVOKESPECIAL,
          CELL_HANDLER_FACTORY_TYPE,
          "<init>",
          "("
              + AsmUtils.toDeclaredLType(Instantiator.class)
              + AsmUtils.toDeclaredLType(CsvColumnKey[].class)
              + AsmUtils.toDeclaredLType(ParsingContextFactory.class)
              + AsmUtils.toDeclaredLType(FieldMapperErrorHandler.class)
              + ")V",
          false);
      mv.visitInsn(RETURN);
      mv.visitMaxs(5, 5);
      mv.visitEnd();
    }
    {
      mv =
          cw.visitMethod(
              ACC_PUBLIC,
              "newInstance",
              "("
                  + AsmUtils.toDeclaredLType(DelayedCellSetter[].class)
                  + AsmUtils.toDeclaredLType(CellSetter[].class)
                  + ")"
                  + AsmUtils.toDeclaredLType(CsvMapperCellHandler.class),
              "("
                  + "[L"
                  + DELAYED_CELL_SETTER_TYPE
                  + "<L"
                  + targetType
                  + ";*>;"
                  + "[L"
                  + CELL_SETTER_TYPE
                  + "<L"
                  + targetType
                  + ";>;"
                  + ")"
                  + "L"
                  + AsmUtils.toType(CsvMapperCellHandler.class)
                  + "<L"
                  + targetType
                  + ";>;",
              null);
      mv.visitCode();
      mv.visitTypeInsn(NEW, classType);
      mv.visitInsn(DUP);
      mv.visitVarInsn(ALOAD, 0);
      mv.visitFieldInsn(
          GETFIELD, factoryType, "instantiator", AsmUtils.toDeclaredLType(Instantiator.class));
      mv.visitVarInsn(ALOAD, 1);
      mv.visitVarInsn(ALOAD, 2);
      mv.visitVarInsn(ALOAD, 0);
      mv.visitFieldInsn(
          GETFIELD, factoryType, "keys", AsmUtils.toDeclaredLType(CsvColumnKey[].class));
      mv.visitVarInsn(ALOAD, 0);
      mv.visitFieldInsn(
          GETFIELD,
          factoryType,
          "parsingContextFactory",
          AsmUtils.toDeclaredLType(ParsingContextFactory.class));
      mv.visitMethodInsn(
          INVOKEVIRTUAL,
          AsmUtils.toType(ParsingContextFactory.class),
          "newContext",
          "()" + AsmUtils.toDeclaredLType(ParsingContext.class),
          false);
      mv.visitVarInsn(ALOAD, 0);
      mv.visitFieldInsn(
          GETFIELD,
          factoryType,
          "fieldErrorHandler",
          AsmUtils.toDeclaredLType(FieldMapperErrorHandler.class));
      mv.visitMethodInsn(
          INVOKESPECIAL,
          classType,
          "<init>",
          "("
              + AsmUtils.toDeclaredLType(Instantiator.class)
              + AsmUtils.toDeclaredLType(DelayedCellSetter[].class)
              + AsmUtils.toDeclaredLType(CellSetter[].class)
              + AsmUtils.toDeclaredLType(CsvColumnKey[].class)
              + AsmUtils.toDeclaredLType(ParsingContext.class)
              + AsmUtils.toDeclaredLType(FieldMapperErrorHandler.class)
              + ")V",
          false);
      mv.visitInsn(ARETURN);
      mv.visitMaxs(8, 3);
      mv.visitEnd();
    }
    cw.visitEnd();

    return cw.toByteArray();
  }
  public static <T> byte[] createTargetSetterClass(
      String className,
      DelayedCellSetterFactory<T, ?>[] delayedCellSetters,
      CellSetter<T>[] setters,
      Type type,
      boolean ignoreException,
      int maxMethodSize)
      throws Exception {

    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);

    FieldVisitor fv;
    MethodVisitor mv;

    final String targetType = AsmUtils.toType(type);
    final String classType = AsmUtils.toType(className);

    cw.visit(
        V1_6,
        ACC_FINAL + ACC_PUBLIC + ACC_SUPER,
        classType,
        "L" + CSV_CELL_MAPPER_TYPE + "<L" + targetType + ";>;",
        CSV_CELL_MAPPER_TYPE,
        null);

    // declare fields
    for (int i = 0; i < delayedCellSetters.length; i++) {
      if (delayedCellSetters[i] != null) {
        fv =
            cw.visitField(
                ACC_PROTECTED + ACC_FINAL,
                "delayedCellSetter" + i,
                AsmUtils.toDeclaredLType(DELAYED_CELL_SETTER_TYPE),
                "L" + DELAYED_CELL_SETTER_TYPE + "<L" + targetType + ";*>;",
                null);
        fv.visitEnd();
      }
    }

    for (int i = 0; i < setters.length; i++) {
      if (setters[i] != null) {
        fv =
            cw.visitField(
                ACC_PROTECTED + ACC_FINAL,
                "setter" + i,
                AsmUtils.toDeclaredLType(CELL_SETTER_TYPE),
                "L" + CELL_SETTER_TYPE + "<L" + targetType + ";>;",
                null);
        fv.visitEnd();
      }
    }
    appendInit(delayedCellSetters, setters, cw, targetType, classType, maxMethodSize);

    appendDelayedCellValue(delayedCellSetters, ignoreException, cw, classType);
    append_delayedCellValue(delayedCellSetters, cw, classType, maxMethodSize);

    appendCellValue(setters, ignoreException, cw, classType);
    append_cellValue(delayedCellSetters, setters, cw, classType, maxMethodSize);

    appendApplyDelayedSetter(delayedCellSetters, ignoreException, cw, classType, maxMethodSize);
    appendApplyDelayedCellSetterN(delayedCellSetters, cw, classType);

    appendGetDelayedCellSetter(delayedCellSetters, cw, targetType, classType, maxMethodSize);
    appendPeekDelayedCellSetterValue(delayedCellSetters, cw, classType, maxMethodSize);

    cw.visitEnd();

    return AsmUtils.writeClassToFile(className, cw.toByteArray());
  }