public void appendToSignature(
     int iParam,
     ValueType type,
     Class<?> parameterType,
     Type genericParameterType,
     StringBuilder javaSig,
     StringBuilder dcSig,
     StringBuilder asmSig) {
   char dcChar;
   String javaChar, asmChar = null;
   switch (type) {
     case eVoidValue:
       dcChar = DC_SIGCHAR_VOID;
       javaChar = "V";
       break;
     case eIntValue:
       dcChar = DC_SIGCHAR_INT;
       javaChar = "I";
       break;
     case eLongValue:
       dcChar = DC_SIGCHAR_LONGLONG;
       javaChar = "J";
       break;
     case eSizeTValue:
       javaChar = "J";
       if (Platform.SIZE_T_SIZE == 8) {
         dcChar = DC_SIGCHAR_LONGLONG;
       } else {
         dcChar = DC_SIGCHAR_INT;
         direct = false;
       }
       break;
     case eShortValue:
       dcChar = DC_SIGCHAR_SHORT;
       javaChar = "S";
       break;
     case eDoubleValue:
       dcChar = DC_SIGCHAR_DOUBLE;
       javaChar = "D";
       break;
     case eFloatValue:
       dcChar = DC_SIGCHAR_FLOAT;
       javaChar = "F";
       break;
     case eByteValue:
       dcChar = DC_SIGCHAR_CHAR;
       javaChar = "B";
       break;
     case eBooleanValue:
       dcChar = DC_SIGCHAR_BOOL;
       javaChar = "Z";
       break;
     case eWCharValue:
       switch (Platform.WCHAR_T_SIZE) {
         case 1:
           dcChar = DC_SIGCHAR_CHAR;
           direct = false;
           break;
         case 2:
           dcChar = DC_SIGCHAR_SHORT;
           break;
         case 4:
           dcChar = DC_SIGCHAR_INT;
           direct = false;
           break;
         default:
           throw new RuntimeException(
               "Unhandled sizeof(wchar_t) in GetJavaTypeSignature: " + Platform.WCHAR_T_SIZE);
       }
       javaChar = "C";
       break;
     case eIntFlagSet:
       dcChar = DC_SIGCHAR_INT;
       javaChar =
           "L" + parameterType.getName().replace('.', '/') + ";"; // "Lorg/bridj/ValuedEnum;";
       direct = false;
       break;
     case eCLongObjectValue:
       dcChar = DC_SIGCHAR_POINTER;
       javaChar = "Lorg/bridj/CLong;";
       direct = false;
       break;
     case eSizeTObjectValue:
       dcChar = DC_SIGCHAR_POINTER;
       javaChar = "Lorg/bridj/SizeT;";
       direct = false;
       break;
     case eTimeTObjectValue:
       dcChar = DC_SIGCHAR_POINTER;
       javaChar = "Lorg/bridj/TimeT;";
       direct = false;
       break;
     case ePointerValue:
       dcChar = DC_SIGCHAR_POINTER;
       javaChar = "L" + parameterType.getName().replace('.', '/') + ";";
       //                javaChar = "Lorg/bridj/Pointer;";
       direct = false;
       break;
     case eNativeObjectValue:
       dcChar = DC_SIGCHAR_STRUCT; // TODO : unroll struct signature ?
       javaChar = "L" + parameterType.getName().replace('.', '/') + ";";
       direct = false;
       //              if (parameterType.equals(declaringClass)) {
       //                    // special case of self-returning pointers
       //                    dcChar = DC_SIGCHAR_POINTER;
       break;
     case eEllipsis:
       javaChar = "[Ljava/lang/Object;";
       dcChar = '?';
       break;
     default:
       direct = false;
       throw new RuntimeException("Unhandled " + ValueType.class.getSimpleName() + ": " + type);
   }
   if (genericParameterType instanceof ParameterizedType && iParam < 0) {
     ParameterizedType pt = (ParameterizedType) genericParameterType;
     // TODO handle all cases !!!
     Type[] ts = pt.getActualTypeArguments();
     if (ts != null && ts.length == 1) {
       Type t = ts[0];
       if (t instanceof ParameterizedType) t = ((ParameterizedType) t).getRawType();
       if (t instanceof Class) {
         Class c = (Class) t;
         if (javaChar.endsWith(";")) {
           asmChar =
               javaChar.substring(0, javaChar.length() - 1)
                   + "<*L"
                   + c.getName().replace('.', '/')
                   + ";>";
           // asmChar += ";";
         }
       }
     }
   }
   if (javaSig != null) javaSig.append(javaChar);
   if (asmChar == null) asmChar = javaChar;
   if (asmSig != null) asmSig.append(asmChar);
   if (dcSig != null) dcSig.append(dcChar);
 }
  protected void init(
      AnnotatedElement annotatedElement,
      Class returnType,
      Type genericReturnType,
      Annotation[] returnAnnotations,
      Class[] parameterTypes,
      Type[] genericParameterTypes,
      Annotation[][] paramsAnnotations,
      boolean prependJNIPointers,
      boolean isVirtual,
      boolean isDirectModeAllowed) {
    assert returnType != null;
    assert genericReturnType != null;
    assert parameterTypes != null;
    assert genericParameterTypes != null;
    assert returnAnnotations != null;
    assert parameterTypes.length == genericParameterTypes.length;
    assert paramsAnnotations.length == genericParameterTypes.length;

    int nParams = genericParameterTypes.length;
    paramsValueTypes = new int[nParams];

    direct =
        isDirectModeAllowed; // TODO on native side : test number of parameters (on 64 bits win :
                             // must be <= 4)

    StringBuilder javaSig = new StringBuilder(64),
        asmSig = new StringBuilder(64),
        dcSig = new StringBuilder(16);
    javaSig.append('(');
    asmSig.append('(');
    if (prependJNIPointers) // !isCPlusPlus)
    dcSig
          .append(DC_SIGCHAR_POINTER)
          .append(DC_SIGCHAR_POINTER); // JNIEnv*, jobject: always present in native-bound functions

    if (BridJ.debug)
      BridJ.info(
          "Analyzing "
              + (declaringClass == null
                  ? "anonymous method"
                  : declaringClass.getName() + "." + methodName));

    if (isObjCBlock)
      appendToSignature(
          0, ValueType.ePointerValue, Pointer.class, Pointer.class, null, dcSig, null);

    for (int iParam = 0; iParam < nParams; iParam++) {
      //            Options paramOptions = paramsOptions[iParam] = new Options();
      Type genericParameterType = genericParameterTypes[iParam];
      Class<?> parameterType = parameterTypes[iParam];

      ValueType paramValueType =
          getValueType(
              iParam,
              nParams,
              parameterType,
              genericParameterType,
              null,
              paramsAnnotations[iParam]);
      if (BridJ.veryVerbose) BridJ.info("\tparam " + paramValueType);
      paramsValueTypes[iParam] = paramValueType.ordinal();

      appendToSignature(
          iParam, paramValueType, parameterType, genericParameterType, javaSig, dcSig, asmSig);
    }
    javaSig.append(')');
    asmSig.append(')');
    dcSig.append(')');

    ValueType retType =
        getValueType(
            -1, nParams, returnType, genericReturnType, annotatedElement, returnAnnotations);
    if (BridJ.veryVerbose) BridJ.info("\treturns " + retType);
    appendToSignature(-1, retType, returnType, genericReturnType, javaSig, dcSig, asmSig);
    returnValueType = retType.ordinal();

    javaSignature = javaSig.toString();
    asmSignature = asmSig.toString();
    dcSignature = dcSig.toString();

    isCPlusPlus = isCPlusPlus || isVirtual;

    if (isCPlusPlus && !isStatic) {
      if (!startsWithThis) direct = false;
      bNeedsThisPointer = true;
      if (Platform.isWindows()) {
        if (!Platform.is64Bits()) setDcCallingConvention(DC_CALL_C_X86_WIN32_THIS_MS);
      } else {
        // if (!Platform.is64Bits())
        //	setDcCallingConvention(DC_CALL_C_X86_WIN32_THIS_GNU);
      }
    }

    if (nParams > Platform.getMaxDirectMappingArgCount()) this.direct = false;

    if (BridJ.veryVerbose) {
      BridJ.info("\t-> direct " + direct);
      BridJ.info("\t-> javaSignature " + javaSignature);
      BridJ.info("\t-> callIOs " + callIOs);
      BridJ.info("\t-> asmSignature " + asmSignature);
      BridJ.info("\t-> dcSignature " + dcSignature);
    }

    if (BridJ.veryVerbose)
      BridJ.info((direct ? "[mappable as direct] " : "[not mappable as direct] ") + method);
  }