boolean needsComma = false;
    NameFactory nameFactory = new NameFactory();
    JParameter[] asyncParams = asyncMethod.getParameters();
    for (int i = 0; i < asyncParams.length; ++i) {
      JParameter param = asyncParams[i];
      if (needsComma) {
        w.print(", ");
      } else {
        needsComma = true;
      }
      /*
       * Ignoring the AsyncCallback parameter, if any method requires a call to
       * SerializationStreamWriter.writeObject we need a try catch block
       */
      JType paramType = param.getType();
      paramType = paramType.getErasedType();
      w.print(paramType.getQualifiedSourceName());
      w.print(" ");
      String paramName = param.getName();
      nameFactory.addName(paramName);
      w.print(paramName);
    }
    w.println(") {");
    w.indent();
    String requestIdName = nameFactory.createName("requestId");
    w.println("int " + requestIdName + " = getNextRequestId();");
    String statsMethodExpr = getProxySimpleName() + "." + syncMethod.getName();
    String tossName = nameFactory.createName("toss");
    w.println("boolean " + tossName + " = isStatsAvailable() && stats("
        + "timeStat(\"" + statsMethodExpr + "\", " + requestIdName
        + ", \"begin\"));");
    w.print(SerializationStreamWriter.class.getSimpleName());
    w.print(" ");
    String streamWriterName = nameFactory.createName("streamWriter");
    w.println(streamWriterName + " = createStreamWriter();");
    w.println("// createStreamWriter() prepared the stream");
    w.println("try {");
    w.indent();
    w.println(streamWriterName + ".writeString(REMOTE_SERVICE_INTERFACE_NAME);");
    // Write the method name
    w.println(streamWriterName + ".writeString(\"" + syncMethod.getName()
        + "\");");
    // Write the parameter count followed by the parameter values
    JParameter[] syncParams = syncMethod.getParameters();
    w.println(streamWriterName + ".writeInt(" + syncParams.length + ");");
    for (JParameter param : syncParams) {
      JType paramType = param.getType().getErasedType();
      String typeNameExpression = computeTypeNameExpression(paramType);
      assert typeNameExpression != null : "Could not compute a type name for "
          + paramType.getQualifiedSourceName();
      w.println(streamWriterName + ".writeString(" + typeNameExpression + ");");
    }
    // Encode all of the arguments to the asynchronous method, but exclude the
    // last argument which is the callback instance.
    //
    for (int i = 0; i < asyncParams.length - 1; ++i) {
      JParameter asyncParam = asyncParams[i];
      w.print(streamWriterName + ".");
      w.print(Shared.getStreamWriteMethodNameFor(asyncParam.getType()));
      w.println("(" + asyncParam.getName() + ");");
    }
    String payloadName = nameFactory.createName("payload");
    w.println("String " + payloadName + " = " + streamWriterName
        + ".toString();");
    w.println(tossName + " = isStatsAvailable() && stats(" + "timeStat(\""
        + statsMethodExpr + "\", " + requestIdName
        + ", \"requestSerialized\"));");
    /*
     * Depending on the return type for the async method, return a
     * RequestBuilder, a Request, or nothing at all.
     */
    if (asyncReturnType == JPrimitiveType.VOID) {
      w.print("doInvoke(");
    } else if (asyncReturnType.getQualifiedSourceName().equals(
        RequestBuilder.class.getName())) {
      w.print("return doPrepareRequestBuilder(");
    } else if (asyncReturnType.getQualifiedSourceName().equals(
        Request.class.getName())) {
      w.print("return doInvoke(");
    } else {
      // This method should have been caught by RemoteServiceAsyncValidator
      throw new RuntimeException("Unhandled return type "
          + asyncReturnType.getQualifiedSourceName());
    }
    JParameter callbackParam = asyncParams[asyncParams.length - 1];
    String callbackName = callbackParam.getName();
    JType returnType = syncMethod.getReturnType();
    w.print("ResponseReader." + getResponseReaderFor(returnType).name());
    w.println(", \"" + getProxySimpleName() + "." + syncMethod.getName()
        + "\", " + requestIdName + ", " + payloadName + ", " + callbackName
        + ");");