public ClassReference14Processor() {

    InvocationExprent invfor = new InvocationExprent();
    invfor.setName("forName");
    invfor.setClassname("java/lang/Class");
    invfor.setStringDescriptor("(Ljava/lang/String;)Ljava/lang/Class;");
    invfor.setDescriptor(MethodDescriptor.parseDescriptor("(Ljava/lang/String;)Ljava/lang/Class;"));
    invfor.setStatic(true);
    invfor.setLstParameters(
        Arrays.asList(new Exprent[] {new VarExprent(0, VarType.VARTYPE_STRING, null)}));

    bodyexprent = new ExitExprent(ExitExprent.EXIT_RETURN, invfor, VarType.VARTYPE_CLASS, null);

    InvocationExprent constr = new InvocationExprent();
    constr.setName("<init>");
    constr.setClassname("java/lang/NoClassDefFoundError");
    constr.setStringDescriptor("()V");
    constr.setFunctype(InvocationExprent.TYP_INIT);
    constr.setDescriptor(MethodDescriptor.parseDescriptor("()V"));

    NewExprent newexpr =
        new NewExprent(
            new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/NoClassDefFoundError"),
            new ArrayList<Exprent>(),
            null);
    newexpr.setConstructor(constr);

    InvocationExprent invcause = new InvocationExprent();
    invcause.setName("initCause");
    invcause.setClassname("java/lang/NoClassDefFoundError");
    invcause.setStringDescriptor("(Ljava/lang/Throwable;)Ljava/lang/Throwable;");
    invcause.setDescriptor(
        MethodDescriptor.parseDescriptor("(Ljava/lang/Throwable;)Ljava/lang/Throwable;"));
    invcause.setInstance(newexpr);
    invcause.setLstParameters(
        Arrays.asList(
            new Exprent[] {
              new VarExprent(
                  2,
                  new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/ClassNotFoundException"),
                  null)
            }));

    handlerexprent = new ExitExprent(ExitExprent.EXIT_THROW, invcause, null, null);
  }
  public static Exprent parseAnnotationElement(DataInputStream data, ConstantPool pool)
      throws IOException {
    int tag = data.readUnsignedByte();

    switch (tag) {
      case 'e': // enum constant
        String className = pool.getPrimitiveConstant(data.readUnsignedShort()).getString();
        String constName = pool.getPrimitiveConstant(data.readUnsignedShort()).getString();
        FieldDescriptor descr = FieldDescriptor.parseDescriptor(className);
        return new FieldExprent(constName, descr.type.value, true, null, descr, null);

      case 'c': // class
        String descriptor = pool.getPrimitiveConstant(data.readUnsignedShort()).getString();
        VarType type = FieldDescriptor.parseDescriptor(descriptor).type;

        String value;
        switch (type.type) {
          case CodeConstants.TYPE_OBJECT:
            value = type.value;
            break;
          case CodeConstants.TYPE_BYTE:
            value = byte.class.getName();
            break;
          case CodeConstants.TYPE_CHAR:
            value = char.class.getName();
            break;
          case CodeConstants.TYPE_DOUBLE:
            value = double.class.getName();
            break;
          case CodeConstants.TYPE_FLOAT:
            value = float.class.getName();
            break;
          case CodeConstants.TYPE_INT:
            value = int.class.getName();
            break;
          case CodeConstants.TYPE_LONG:
            value = long.class.getName();
            break;
          case CodeConstants.TYPE_SHORT:
            value = short.class.getName();
            break;
          case CodeConstants.TYPE_BOOLEAN:
            value = boolean.class.getName();
            break;
          case CodeConstants.TYPE_VOID:
            value = void.class.getName();
            break;
          default:
            throw new RuntimeException("invalid class type: " + type.type);
        }
        return new ConstExprent(VarType.VARTYPE_CLASS, value, null);

      case '[': // array
        List<Exprent> elements = Collections.emptyList();
        int len = data.readUnsignedShort();
        if (len > 0) {
          elements = new ArrayList<Exprent>(len);
          for (int i = 0; i < len; i++) {
            elements.add(parseAnnotationElement(data, pool));
          }
        }

        VarType newType;
        if (elements.isEmpty()) {
          newType = new VarType(CodeConstants.TYPE_OBJECT, 1, "java/lang/Object");
        } else {
          VarType elementType = elements.get(0).getExprType();
          newType = new VarType(elementType.type, 1, elementType.value);
        }

        NewExprent newExpr = new NewExprent(newType, Collections.emptyList(), null);
        newExpr.setDirectArrayInit(true);
        newExpr.setLstArrayElements(elements);
        return newExpr;

      case '@': // annotation
        return parseAnnotation(data, pool);

      default:
        PrimitiveConstant cn = pool.getPrimitiveConstant(data.readUnsignedShort());
        switch (tag) {
          case 'B':
            return new ConstExprent(VarType.VARTYPE_BYTE, cn.value, null);
          case 'C':
            return new ConstExprent(VarType.VARTYPE_CHAR, cn.value, null);
          case 'D':
            return new ConstExprent(VarType.VARTYPE_DOUBLE, cn.value, null);
          case 'F':
            return new ConstExprent(VarType.VARTYPE_FLOAT, cn.value, null);
          case 'I':
            return new ConstExprent(VarType.VARTYPE_INT, cn.value, null);
          case 'J':
            return new ConstExprent(VarType.VARTYPE_LONG, cn.value, null);
          case 'S':
            return new ConstExprent(VarType.VARTYPE_SHORT, cn.value, null);
          case 'Z':
            return new ConstExprent(VarType.VARTYPE_BOOLEAN, cn.value, null);
          case 's':
            return new ConstExprent(VarType.VARTYPE_STRING, cn.value, null);
          default:
            throw new RuntimeException("invalid element type!");
        }
    }
  }
  private void fieldToJava(
      ClassWrapper wrapper,
      StructClass cl,
      StructField fd,
      TextBuffer buffer,
      int indent,
      BytecodeMappingTracer tracer) {
    int start = buffer.length();
    boolean isInterface = cl.hasModifier(CodeConstants.ACC_INTERFACE);
    boolean isDeprecated = fd.getAttributes().containsKey("Deprecated");
    boolean isEnum =
        fd.hasModifier(CodeConstants.ACC_ENUM)
            && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM);

    if (isDeprecated) {
      appendDeprecation(buffer, indent);
    }

    if (interceptor != null) {
      String oldName =
          interceptor.getOldName(cl.qualifiedName + " " + fd.getName() + " " + fd.getDescriptor());
      appendRenameComment(buffer, oldName, MType.FIELD, indent);
    }

    if (fd.isSynthetic()) {
      appendComment(buffer, "synthetic field", indent);
    }

    appendAnnotations(buffer, fd, indent);

    buffer.appendIndent(indent);

    if (!isEnum) {
      appendModifiers(buffer, fd.getAccessFlags(), FIELD_ALLOWED, isInterface, FIELD_EXCLUDED);
    }

    VarType fieldType = new VarType(fd.getDescriptor(), false);

    GenericFieldDescriptor descriptor = null;
    if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) {
      StructGenericSignatureAttribute attr =
          (StructGenericSignatureAttribute) fd.getAttributes().getWithKey("Signature");
      if (attr != null) {
        descriptor = GenericMain.parseFieldSignature(attr.getSignature());
      }
    }

    if (!isEnum) {
      if (descriptor != null) {
        buffer.append(GenericMain.getGenericCastTypeName(descriptor.type));
      } else {
        buffer.append(ExprProcessor.getCastTypeName(fieldType));
      }
      buffer.append(' ');
    }

    buffer.append(fd.getName());

    tracer.incrementCurrentSourceLine(buffer.countLines(start));

    Exprent initializer;
    if (fd.hasModifier(CodeConstants.ACC_STATIC)) {
      initializer =
          wrapper
              .getStaticFieldInitializers()
              .getWithKey(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor()));
    } else {
      initializer =
          wrapper
              .getDynamicFieldInitializers()
              .getWithKey(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor()));
    }
    if (initializer != null) {
      if (isEnum && initializer.type == Exprent.EXPRENT_NEW) {
        NewExprent nexpr = (NewExprent) initializer;
        nexpr.setEnumConst(true);
        buffer.append(nexpr.toJava(indent, tracer));
      } else {
        buffer.append(" = ");
        // FIXME: special case field initializer. Can map to more than one method (constructor) and
        // bytecode intruction.
        buffer.append(initializer.toJava(indent, tracer));
      }
    } else if (fd.hasModifier(CodeConstants.ACC_FINAL)
        && fd.hasModifier(CodeConstants.ACC_STATIC)) {
      StructConstantValueAttribute attr =
          (StructConstantValueAttribute)
              fd.getAttributes().getWithKey(StructGeneralAttribute.ATTRIBUTE_CONSTANT_VALUE);
      if (attr != null) {
        PrimitiveConstant constant = cl.getPool().getPrimitiveConstant(attr.getIndex());
        buffer.append(" = ");
        buffer.append(new ConstExprent(fieldType, constant.value, null).toJava(indent, tracer));
      }
    }

    if (!isEnum) {
      buffer.append(";").appendLineSeparator();
      tracer.incrementCurrentSourceLine();
    }
  }