private String addArrayMarshaller(MetaClass type) {
    String varName = getVarName(type);

    if (!arrayMarshallers.contains(varName)) {
      classStructureBuilder
          .privateField(
              varName, parameterizedAs(Marshaller.class, typeParametersOf(List.class, type)))
          .finish();
      Statement marshaller = generateArrayMarshaller(type);
      constructor.append(loadVariable(varName).assignValue(marshaller));

      constructor.append(
          Stmt.create(classContext)
              .loadVariable(MARSHALLERS_VAR)
              .invoke("put", type.getFullyQualifiedName(), loadVariable(varName)));

      arrayMarshallers.add(varName);
    }

    return varName;
  }
  private String _generate(String packageName, String clazzName) {
    startTime = System.currentTimeMillis();

    classStructureBuilder = implement(MarshallerFactory.class, packageName, clazzName);
    classContext = ((BuildMetaClass) classStructureBuilder.getClassDefinition()).getContext();
    mappingContext =
        new MappingContext(
            classContext,
            classStructureBuilder.getClassDefinition(),
            classStructureBuilder,
            new ArrayMarshallerCallback() {
              @Override
              public Statement marshal(MetaClass type, Statement value) {
                createDemarshallerIfNeeded(type);
                return value;
              }

              @Override
              public Statement demarshall(MetaClass type, Statement value) {
                String variable = createDemarshallerIfNeeded(type);

                value =
                    Stmt.loadVariable(getVarName(List.class))
                        .invoke("demarshall", value, Stmt.loadVariable("a1"));

                return Stmt.loadVariable(variable)
                    .invoke("demarshall", value, Stmt.loadVariable("a1"));
              }

              private String createDemarshallerIfNeeded(MetaClass type) {
                return addArrayMarshaller(type);
              }
            });

    loadMarshallers();

    MetaClass javaUtilMap = MetaClassFactory.get(new TypeLiteral<Map<String, Marshaller>>() {});

    autoInitializedField(classStructureBuilder, javaUtilMap, MARSHALLERS_VAR, HashMap.class);

    constructor = classStructureBuilder.publicConstructor();

    for (Map.Entry<String, Class<? extends Marshaller>> entry :
        mappingContext.getAllMarshallers().entrySet()) {
      String varName = getVarName(entry.getKey());
      String arrayVarName = getArrayVarName(entry.getKey());
      classStructureBuilder.privateField(varName, entry.getValue()).finish();
      classStructureBuilder.privateField(arrayVarName, entry.getValue()).finish();

      constructor.append(
          Stmt.create(classContext)
              .loadVariable(varName)
              .assignValue(Stmt.newObject(entry.getValue())));

      constructor.append(
          Stmt.create(classContext)
              .loadVariable(MARSHALLERS_VAR)
              .invoke("put", entry.getKey(), loadVariable(varName)));

      for (String s : mappingContext.getReverseMappingAliasFor(entry.getKey())) {
        constructor.append(
            Stmt.create(classContext)
                .loadVariable(MARSHALLERS_VAR)
                .invoke("put", s, loadVariable(varName)));
      }
    }

    generateMarshallers();

    classStructureBuilder
        .publicMethod(Marshaller.class, "getMarshaller")
        .parameters(String.class, String.class)
        .body()
        .append(loadVariable(MARSHALLERS_VAR).invoke("get", loadVariable("a1")).returnValue())
        .finish();

    // special support for Object[]
    addArrayMarshaller(MetaClassFactory.get(Object[].class));

    return classStructureBuilder.toJavaString();

    // System.out.println("[Generation Finished in: " + (System.currentTimeMillis() - startTime) +
    // "ms]");

    //  System.out.println(generatedClass);
    // return generatedClass;
  }
  private void generateMarshallers() {
    MetaDataScanner scanner = ScannerSingleton.getOrCreateInstance();

    Set<Class<?>> exposed = new HashSet<Class<?>>(scanner.getTypesAnnotatedWith(Portable.class));
    exposed.addAll(scanner.getTypesAnnotatedWith(ExposeEntity.class));

    // add all GWT JRE  classes

    exposed.add(Throwable.class);
    exposed.add(NullPointerException.class);
    exposed.add(RuntimeException.class);
    exposed.add(Exception.class);
    exposed.add(ArithmeticException.class);
    exposed.add(ArrayStoreException.class);
    exposed.add(AssertionError.class);
    exposed.add(ClassCastException.class);
    exposed.add(IllegalArgumentException.class);
    exposed.add(IndexOutOfBoundsException.class);
    exposed.add(NegativeArraySizeException.class);
    exposed.add(NumberFormatException.class);
    exposed.add(StringIndexOutOfBoundsException.class);
    exposed.add(UnsupportedOperationException.class);
    exposed.add(StackTraceElement.class);

    exposed.add(IOException.class);
    exposed.add(UnsupportedEncodingException.class);
    exposed.add(ConcurrentModificationException.class);
    exposed.add(EmptyStackException.class);
    // exposed.add(MissingResourceException.class);
    // exposed.add(NoSuchMethodException.class);

    for (Class<?> clazz : exposed) {
      mappingContext.registerGeneratedMarshaller(clazz.getName());
    }

    for (Class<?> clazz : exposed) {
      if (clazz.isEnum()) continue;

      MetaClass metaClazz = MetaClassFactory.get(clazz);
      Statement marshaller = marshal(metaClazz);
      MetaClass type = marshaller.getType();
      String varName = getVarName(clazz);

      classStructureBuilder.privateField(varName, type).finish();

      constructor.append(loadVariable(varName).assignValue(marshaller));

      constructor.append(
          Stmt.create(classContext)
              .loadVariable(MARSHALLERS_VAR)
              .invoke("put", clazz.getName(), loadVariable(varName)));

      for (String s : mappingContext.getReverseMappingAliasFor(clazz.getName())) {
        constructor.append(
            Stmt.create(classContext)
                .loadVariable(MARSHALLERS_VAR)
                .invoke("put", s, loadVariable(varName)));
      }
    }

    constructor.finish();
  }