private static void printJavaNativeStub(
     ProcessingEnvironment env,
     PrintWriter writer,
     ExecutableElement method,
     Mode mode,
     boolean generate_error_checks,
     boolean context_specific) {
   if (Utils.isMethodIndirect(generate_error_checks, context_specific, method)) {
     writer.print("\tstatic native ");
   } else {
     Utils.printDocComment(writer, method, env);
     writer.print("\tpublic static native ");
   }
   writer.print(getResultType(method, true));
   writer.print(
       " " + Utils.getSimpleNativeMethodName(method, generate_error_checks, context_specific));
   if (mode == Mode.BUFFEROBJECT) {
     writer.print(Utils.BUFFER_OBJECT_METHOD_POSTFIX);
   }
   writer.print("(");
   boolean first_parameter =
       generateParametersJava(
           writer, method, TypeInfo.getDefaultTypeInfoMap(method), true, true, mode);
   if (context_specific) {
     if (!first_parameter) {
       writer.print(", ");
     }
     writer.print("long " + Utils.FUNCTION_POINTER_VAR_NAME);
   }
   writer.println(");");
 }
  private static void printMethodWithMultiType(
      ProcessingEnvironment env,
      TypeMap type_map,
      PrintWriter writer,
      TypeElement interface_decl,
      ExecutableElement method,
      Map<VariableElement, TypeInfo> typeinfos_instance,
      Mode mode,
      boolean generate_error_checks,
      boolean context_specific) {
    Utils.printDocComment(writer, method, env);
    if (method.getAnnotation(Deprecated.class) != null) {
      writer.println("\t@Deprecated");
    }
    if (interface_decl.getAnnotation(Private.class) == null
        && method.getAnnotation(Private.class) == null) {
      writer.print("\tpublic static ");
    } else {
      writer.print("\tstatic ");
    }
    writer.print(getResultType(method, false));
    StripPostfix strip_annotation = method.getAnnotation(StripPostfix.class);
    String method_name;
    Alternate alt_annotation = method.getAnnotation(Alternate.class);
    method_name =
        alt_annotation == null || alt_annotation.javaAlt()
            ? method.getSimpleName().toString()
            : alt_annotation.value();
    if (strip_annotation != null && mode == Mode.NORMAL) {
      method_name = getPostfixStrippedName(type_map, interface_decl, method);
    }
    writer.print(" " + method_name + "(");
    generateParametersJava(writer, method, typeinfos_instance, false, true, mode);
    writer.println(") {");

    final TypeMirror result_type = Utils.getMethodReturnType(method);
    boolean has_result = !result_type.equals(env.getTypeUtils().getNoType(TypeKind.VOID));

    final Reuse reuse_annotation = method.getAnnotation(Reuse.class);
    if (reuse_annotation != null) {
      writer.print("\t\t");
      if (has_result || method.getAnnotation(GLreturn.class) != null) {
        writer.print("return ");
      }

      writer.print(
          reuse_annotation.value()
              + "."
              + (reuse_annotation.method().length() > 0 ? reuse_annotation.method() : method_name)
              + "(");
      generateParametersJava(writer, method, typeinfos_instance, false, false, mode);
      writer.println(");\n\t}");
      return;
    }

    if (context_specific) {
      type_map.printCapabilitiesInit(writer);
      writer.print(
          "\t\tlong " + Utils.FUNCTION_POINTER_VAR_NAME + " = " + type_map.getCapabilities() + ".");
      writer.println(Utils.getFunctionAddressName(interface_decl, method, true) + ";");
      writer.print("\t\tBufferChecks.checkFunctionAddress(");
      writer.println(Utils.FUNCTION_POINTER_VAR_NAME + ");");
    }
    final Code code_annotation = method.getAnnotation(Code.class);
    if (code_annotation != null && code_annotation.value().length() > 0) {
      writer.println(code_annotation.value());
    }
    printBufferObjectChecks(writer, method, mode, context_specific);
    printParameterChecks(writer, method, typeinfos_instance, mode, generate_error_checks);
    printParameterCaching(writer, interface_decl, method, mode, context_specific);

    if (code_annotation != null && code_annotation.javaBeforeNative().length() > 0) {
      writer.println(code_annotation.javaBeforeNative());
    }
    writer.print("\t\t");

    final PointerWrapper pointer_wrapper_annotation = method.getAnnotation(PointerWrapper.class);
    if (has_result) {
      writer.print(getResultType(method, false) + " " + Utils.RESULT_VAR_NAME);

      if (code_annotation != null && code_annotation.tryBlock()) {
        writer.print(" = " + getDefaultResultValue(method));
        writer.println(";\n\t\ttry {");
        writer.print("\t\t\t" + Utils.RESULT_VAR_NAME);
      }

      writer.print(" = ");
      if (pointer_wrapper_annotation != null) {
        if (pointer_wrapper_annotation.factory().length() > 0) {
          writer.print(pointer_wrapper_annotation.factory() + "(");
        } else {
          writer.print("new " + getResultType(method, false) + "(");
        }
      }
    } else if (method.getAnnotation(GLreturn.class) != null) {
      has_result = true;
      Utils.printGLReturnPre(writer, method, method.getAnnotation(GLreturn.class), type_map);
    }
    writer.print(Utils.getSimpleNativeMethodName(method, generate_error_checks, context_specific));
    if (mode == Mode.BUFFEROBJECT) {
      writer.print(Utils.BUFFER_OBJECT_METHOD_POSTFIX);
    }
    writer.print("(");
    boolean first_parameter =
        printMethodCallArguments(writer, method, typeinfos_instance, mode, type_map);
    if (context_specific) {
      if (!first_parameter) {
        writer.print(", ");
      }
      writer.print(Utils.FUNCTION_POINTER_VAR_NAME);
    }
    if (has_result && pointer_wrapper_annotation != null) {
      writer.print(")");
      if (pointer_wrapper_annotation.params().length() > 0) {
        writer.print(", " + pointer_wrapper_annotation.params());
      }
    }
    writer.println(");");

    if (code_annotation != null && code_annotation.javaAfterNative().length() > 0) {
      writer.println(code_annotation.javaAfterNative());
    }

    final String tabs = code_annotation != null && code_annotation.tryBlock() ? "\t\t\t" : "\t\t";
    if (generate_error_checks && method.getAnnotation(NoErrorCheck.class) == null) {
      type_map.printErrorCheckMethod(writer, method, tabs);
    }
    // DISABLED: indirect buffer support
    // printNondirectParameterCopies(writer, method, mode);
    if (has_result) {
      if (method.getAnnotation(GLreturn.class) == null) {
        if (ByteBuffer.class.equals(Utils.getJavaType(result_type))) {
          writer.println(
              tabs
                  + "return LWJGLUtil.CHECKS && "
                  + Utils.RESULT_VAR_NAME
                  + " == null ? null : "
                  + Utils.RESULT_VAR_NAME
                  + ".order(ByteOrder.nativeOrder());"); // safeNewBuffer returns a direct
                                                         // ByteBuffer with BIG_ENDIAN order.
        } else {
          writer.println(tabs + "return " + Utils.RESULT_VAR_NAME + ";");
        }
      } else {
        Utils.printGLReturnPost(writer, method, method.getAnnotation(GLreturn.class), type_map);
      }
    }

    if (code_annotation != null && code_annotation.tryBlock()) {
      writer.println("\t\t} finally {");
      writer.println(code_annotation.javaFinally());
      writer.println("\t\t}");
    }
    writer.println("\t}");
  }