Reduce number of codegen'd classes needed for Services

This reduces the number of classes defined, which reduces memory usage.
It also reduces the number of methods defined, which is important
because of the dex limit.

This should have virtually zero performance degradation because the
contiguous switch uses tableswitch bytecode.
diff --git a/benchmarks/src/generated/main/grpc/io/grpc/testing/TestServiceGrpc.java b/benchmarks/src/generated/main/grpc/io/grpc/testing/TestServiceGrpc.java
index 6b9487b..170a631 100644
--- a/benchmarks/src/generated/main/grpc/io/grpc/testing/TestServiceGrpc.java
+++ b/benchmarks/src/generated/main/grpc/io/grpc/testing/TestServiceGrpc.java
@@ -155,33 +155,64 @@
     }
   }
 
+  private static final int METHODID_UNARY_CALL = 0;
+  private static final int METHODID_STREAMING_CALL = 1;
+
+  private static class MethodHandlers<Req, Resp> implements
+      io.grpc.stub.ServerCalls.UnaryMethod<Req, Resp>,
+      io.grpc.stub.ServerCalls.ServerStreamingMethod<Req, Resp>,
+      io.grpc.stub.ServerCalls.ClientStreamingMethod<Req, Resp>,
+      io.grpc.stub.ServerCalls.BidiStreamingMethod<Req, Resp> {
+    private final TestService serviceImpl;
+    private final int methodId;
+
+    public MethodHandlers(TestService serviceImpl, int methodId) {
+      this.serviceImpl = serviceImpl;
+      this.methodId = methodId;
+    }
+
+    @java.lang.SuppressWarnings("unchecked")
+    public void invoke(Req request, io.grpc.stub.StreamObserver<Resp> responseObserver) {
+      switch (methodId) {
+        case METHODID_UNARY_CALL:
+          serviceImpl.unaryCall((io.grpc.testing.SimpleRequest) request,
+              (io.grpc.stub.StreamObserver<io.grpc.testing.SimpleResponse>) responseObserver);
+          break;
+        default:
+          throw new AssertionError();
+      }
+    }
+
+    @java.lang.SuppressWarnings("unchecked")
+    public io.grpc.stub.StreamObserver<Req> invoke(
+        io.grpc.stub.StreamObserver<Resp> responseObserver) {
+      switch (methodId) {
+        case METHODID_STREAMING_CALL:
+          return (io.grpc.stub.StreamObserver<Req>) serviceImpl.streamingCall(
+              (io.grpc.stub.StreamObserver<io.grpc.testing.SimpleResponse>) responseObserver);
+        default:
+          throw new AssertionError();
+      }
+    }
+  }
+
   public static io.grpc.ServerServiceDefinition bindService(
       final TestService serviceImpl) {
     return io.grpc.ServerServiceDefinition.builder(SERVICE_NAME)
-      .addMethod(
-        METHOD_UNARY_CALL,
-        asyncUnaryCall(
-          new io.grpc.stub.ServerCalls.UnaryMethod<
+        .addMethod(
+          METHOD_UNARY_CALL,
+          asyncUnaryCall(
+            new MethodHandlers<
               io.grpc.testing.SimpleRequest,
-              io.grpc.testing.SimpleResponse>() {
-            @java.lang.Override
-            public void invoke(
-                io.grpc.testing.SimpleRequest request,
-                io.grpc.stub.StreamObserver<io.grpc.testing.SimpleResponse> responseObserver) {
-              serviceImpl.unaryCall(request, responseObserver);
-            }
-          }))
-      .addMethod(
-        METHOD_STREAMING_CALL,
-        asyncBidiStreamingCall(
-          new io.grpc.stub.ServerCalls.BidiStreamingMethod<
+              io.grpc.testing.SimpleResponse>(
+                serviceImpl, METHODID_UNARY_CALL)))
+        .addMethod(
+          METHOD_STREAMING_CALL,
+          asyncBidiStreamingCall(
+            new MethodHandlers<
               io.grpc.testing.SimpleRequest,
-              io.grpc.testing.SimpleResponse>() {
-            @java.lang.Override
-            public io.grpc.stub.StreamObserver<io.grpc.testing.SimpleRequest> invoke(
-                io.grpc.stub.StreamObserver<io.grpc.testing.SimpleResponse> responseObserver) {
-              return serviceImpl.streamingCall(responseObserver);
-            }
-          })).build();
+              io.grpc.testing.SimpleResponse>(
+                serviceImpl, METHODID_STREAMING_CALL)))
+        .build();
   }
 }
diff --git a/benchmarks/src/generated/main/grpc/io/grpc/testing/WorkerGrpc.java b/benchmarks/src/generated/main/grpc/io/grpc/testing/WorkerGrpc.java
index 93bfe8b..0fa9d7d 100644
--- a/benchmarks/src/generated/main/grpc/io/grpc/testing/WorkerGrpc.java
+++ b/benchmarks/src/generated/main/grpc/io/grpc/testing/WorkerGrpc.java
@@ -137,32 +137,63 @@
     }
   }
 
+  private static final int METHODID_RUN_TEST = 0;
+  private static final int METHODID_RUN_SERVER = 1;
+
+  private static class MethodHandlers<Req, Resp> implements
+      io.grpc.stub.ServerCalls.UnaryMethod<Req, Resp>,
+      io.grpc.stub.ServerCalls.ServerStreamingMethod<Req, Resp>,
+      io.grpc.stub.ServerCalls.ClientStreamingMethod<Req, Resp>,
+      io.grpc.stub.ServerCalls.BidiStreamingMethod<Req, Resp> {
+    private final Worker serviceImpl;
+    private final int methodId;
+
+    public MethodHandlers(Worker serviceImpl, int methodId) {
+      this.serviceImpl = serviceImpl;
+      this.methodId = methodId;
+    }
+
+    @java.lang.SuppressWarnings("unchecked")
+    public void invoke(Req request, io.grpc.stub.StreamObserver<Resp> responseObserver) {
+      switch (methodId) {
+        default:
+          throw new AssertionError();
+      }
+    }
+
+    @java.lang.SuppressWarnings("unchecked")
+    public io.grpc.stub.StreamObserver<Req> invoke(
+        io.grpc.stub.StreamObserver<Resp> responseObserver) {
+      switch (methodId) {
+        case METHODID_RUN_TEST:
+          return (io.grpc.stub.StreamObserver<Req>) serviceImpl.runTest(
+              (io.grpc.stub.StreamObserver<io.grpc.testing.ClientStatus>) responseObserver);
+        case METHODID_RUN_SERVER:
+          return (io.grpc.stub.StreamObserver<Req>) serviceImpl.runServer(
+              (io.grpc.stub.StreamObserver<io.grpc.testing.ServerStatus>) responseObserver);
+        default:
+          throw new AssertionError();
+      }
+    }
+  }
+
   public static io.grpc.ServerServiceDefinition bindService(
       final Worker serviceImpl) {
     return io.grpc.ServerServiceDefinition.builder(SERVICE_NAME)
-      .addMethod(
-        METHOD_RUN_TEST,
-        asyncBidiStreamingCall(
-          new io.grpc.stub.ServerCalls.BidiStreamingMethod<
+        .addMethod(
+          METHOD_RUN_TEST,
+          asyncBidiStreamingCall(
+            new MethodHandlers<
               io.grpc.testing.ClientArgs,
-              io.grpc.testing.ClientStatus>() {
-            @java.lang.Override
-            public io.grpc.stub.StreamObserver<io.grpc.testing.ClientArgs> invoke(
-                io.grpc.stub.StreamObserver<io.grpc.testing.ClientStatus> responseObserver) {
-              return serviceImpl.runTest(responseObserver);
-            }
-          }))
-      .addMethod(
-        METHOD_RUN_SERVER,
-        asyncBidiStreamingCall(
-          new io.grpc.stub.ServerCalls.BidiStreamingMethod<
+              io.grpc.testing.ClientStatus>(
+                serviceImpl, METHODID_RUN_TEST)))
+        .addMethod(
+          METHOD_RUN_SERVER,
+          asyncBidiStreamingCall(
+            new MethodHandlers<
               io.grpc.testing.ServerArgs,
-              io.grpc.testing.ServerStatus>() {
-            @java.lang.Override
-            public io.grpc.stub.StreamObserver<io.grpc.testing.ServerArgs> invoke(
-                io.grpc.stub.StreamObserver<io.grpc.testing.ServerStatus> responseObserver) {
-              return serviceImpl.runServer(responseObserver);
-            }
-          })).build();
+              io.grpc.testing.ServerStatus>(
+                serviceImpl, METHODID_RUN_SERVER)))
+        .build();
   }
 }
diff --git a/compiler/src/java_plugin/cpp/java_generator.cpp b/compiler/src/java_plugin/cpp/java_generator.cpp
index f27463d..49a1f54 100644
--- a/compiler/src/java_plugin/cpp/java_generator.cpp
+++ b/compiler/src/java_plugin/cpp/java_generator.cpp
@@ -1,7 +1,9 @@
 #include "java_generator.h"
 
+#include <algorithm>
 #include <iostream>
 #include <map>
+#include <vector>
 #include <google/protobuf/compiler/java/java_names.h>
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/io/printer.h>
@@ -57,6 +59,10 @@
   return "METHOD_" + ToAllUpperCase(method->name());
 }
 
+static inline string MethodIdFieldName(const MethodDescriptor* method) {
+  return "METHODID_" + ToAllUpperCase(method->name());
+}
+
 static inline string MessageFullJavaName(bool nano, const Descriptor* desc) {
   string name = google::protobuf::compiler::java::ClassName(desc);
   if (nano && !desc->file()->options().javanano_use_deprecated_package()) {
@@ -449,6 +455,123 @@
   p->Print("}\n\n");
 }
 
+static bool CompareMethodClientStreaming(const MethodDescriptor* method1,
+                                         const MethodDescriptor* method2)
+{
+  return method1->client_streaming() < method2->client_streaming();
+}
+
+// Place all method invocations into a single class to reduce memory footprint
+// on Android.
+static void PrintMethodHandlerClass(const ServiceDescriptor* service,
+                                   map<string, string>* vars,
+                                   Printer* p,
+                                   bool generate_nano) {
+  // Sort method ids based on client_streaming() so switch tables are compact.
+  vector<const MethodDescriptor*> sorted_methods(service->method_count());
+  for (int i = 0; i < service->method_count(); ++i) {
+    sorted_methods[i] = service->method(i);
+  }
+  stable_sort(sorted_methods.begin(), sorted_methods.end(),
+              CompareMethodClientStreaming);
+  for (int i = 0; i < sorted_methods.size(); i++) {
+    const MethodDescriptor* method = sorted_methods[i];
+    (*vars)["method_id"] = to_string(i);
+    (*vars)["method_id_name"] = MethodIdFieldName(method);
+    p->Print(
+        *vars,
+        "private static final int $method_id_name$ = $method_id$;\n");
+  }
+  p->Print("\n");
+  (*vars)["service_name"] = service->name();
+  p->Print(
+      *vars,
+      "private static class MethodHandlers<Req, Resp> implements\n"
+      "    io.grpc.stub.ServerCalls.UnaryMethod<Req, Resp>,\n"
+      "    io.grpc.stub.ServerCalls.ServerStreamingMethod<Req, Resp>,\n"
+      "    io.grpc.stub.ServerCalls.ClientStreamingMethod<Req, Resp>,\n"
+      "    io.grpc.stub.ServerCalls.BidiStreamingMethod<Req, Resp> {\n"
+      "  private final $service_name$ serviceImpl;\n"
+      "  private final int methodId;\n"
+      "\n"
+      "  public MethodHandlers($service_name$ serviceImpl, int methodId) {\n"
+      "    this.serviceImpl = serviceImpl;\n"
+      "    this.methodId = methodId;\n"
+      "  }\n\n");
+  p->Indent();
+  p->Print(
+      *vars,
+      "@java.lang.SuppressWarnings(\"unchecked\")\n"
+      "public void invoke(Req request, $StreamObserver$<Resp> responseObserver) {\n"
+      "  switch (methodId) {\n");
+  p->Indent();
+  p->Indent();
+
+  for (int i = 0; i < service->method_count(); ++i) {
+    const MethodDescriptor* method = service->method(i);
+    if (method->client_streaming()) {
+      continue;
+    }
+    (*vars)["method_id_name"] = MethodIdFieldName(method);
+    (*vars)["lower_method_name"] = LowerMethodName(method);
+    (*vars)["input_type"] = MessageFullJavaName(generate_nano,
+                                                method->input_type());
+    (*vars)["output_type"] = MessageFullJavaName(generate_nano,
+                                                 method->output_type());
+    p->Print(
+        *vars,
+        "case $method_id_name$:\n"
+        "  serviceImpl.$lower_method_name$(($input_type$) request,\n"
+        "      ($StreamObserver$<$output_type$>) responseObserver);\n"
+        "  break;\n");
+  }
+  p->Print("default:\n"
+           "  throw new AssertionError();\n");
+
+  p->Outdent();
+  p->Outdent();
+  p->Print("  }\n"
+           "}\n\n");
+
+  p->Print(
+      *vars,
+      "@java.lang.SuppressWarnings(\"unchecked\")\n"
+      "public $StreamObserver$<Req> invoke(\n"
+      "    $StreamObserver$<Resp> responseObserver) {\n"
+      "  switch (methodId) {\n");
+  p->Indent();
+  p->Indent();
+
+  for (int i = 0; i < service->method_count(); ++i) {
+    const MethodDescriptor* method = service->method(i);
+    if (!method->client_streaming()) {
+      continue;
+    }
+    (*vars)["method_id_name"] = MethodIdFieldName(method);
+    (*vars)["lower_method_name"] = LowerMethodName(method);
+    (*vars)["input_type"] = MessageFullJavaName(generate_nano,
+                                                method->input_type());
+    (*vars)["output_type"] = MessageFullJavaName(generate_nano,
+                                                 method->output_type());
+    p->Print(
+        *vars,
+        "case $method_id_name$:\n"
+        "  return ($StreamObserver$<Req>) serviceImpl.$lower_method_name$(\n"
+        "      ($StreamObserver$<$output_type$>) responseObserver);\n");
+  }
+  p->Print("default:\n"
+           "  throw new AssertionError();\n");
+
+  p->Outdent();
+  p->Outdent();
+  p->Print("  }\n"
+           "}\n");
+
+
+  p->Outdent();
+  p->Print("}\n\n");
+}
+
 static void PrintBindServiceMethod(const ServiceDescriptor* service,
                                    map<string, string>* vars,
                                    Printer* p,
@@ -463,6 +586,7 @@
            "return "
            "$ServerServiceDefinition$.builder(SERVICE_NAME)\n");
   p->Indent();
+  p->Indent();
   for (int i = 0; i < service->method_count(); ++i) {
     const MethodDescriptor* method = service->method(i);
     (*vars)["lower_method_name"] = LowerMethodName(method);
@@ -471,27 +595,20 @@
                                                 method->input_type());
     (*vars)["output_type"] = MessageFullJavaName(generate_nano,
                                                  method->output_type());
+    (*vars)["method_id_name"] = MethodIdFieldName(method);
     bool client_streaming = method->client_streaming();
     bool server_streaming = method->server_streaming();
     if (client_streaming) {
       if (server_streaming) {
         (*vars)["calls_method"] = "asyncBidiStreamingCall";
-        (*vars)["invocation_class"] =
-            "io.grpc.stub.ServerCalls.BidiStreamingMethod";
       } else {
         (*vars)["calls_method"] = "asyncClientStreamingCall";
-        (*vars)["invocation_class"] =
-            "io.grpc.stub.ServerCalls.ClientStreamingMethod";
       }
     } else {
       if (server_streaming) {
         (*vars)["calls_method"] = "asyncServerStreamingCall";
-        (*vars)["invocation_class"] =
-            "io.grpc.stub.ServerCalls.ServerStreamingMethod";
       } else {
         (*vars)["calls_method"] = "asyncUnaryCall";
-        (*vars)["invocation_class"] =
-            "io.grpc.stub.ServerCalls.UnaryMethod";
       }
     }
     p->Print(*vars, ".addMethod(\n");
@@ -503,38 +620,15 @@
     p->Indent();
     p->Print(
         *vars,
-        "new $invocation_class$<\n"
-        "    $input_type$,\n"
-        "    $output_type$>() {\n");
-    p->Indent();
-    p->Print(
-        *vars,
-        "@$Override$\n");
-    if (client_streaming) {
-      p->Print(
-          *vars,
-          "public $StreamObserver$<$input_type$> invoke(\n"
-          "    $StreamObserver$<$output_type$> responseObserver) {\n"
-          "  return serviceImpl.$lower_method_name$(responseObserver);\n"
-          "}\n");
-    } else {
-      p->Print(
-          *vars,
-          "public void invoke(\n"
-          "    $input_type$ request,\n"
-          "    $StreamObserver$<$output_type$> responseObserver) {\n"
-          "  serviceImpl.$lower_method_name$(request, responseObserver);\n"
-          "}\n");
-    }
-    p->Outdent();
-    p->Print("}))");
-    if (i == service->method_count() - 1) {
-      p->Print(".build();");
-    }
-    p->Print("\n");
+        "new MethodHandlers<\n"
+        "  $input_type$,\n"
+        "  $output_type$>(\n"
+        "    serviceImpl, $method_id_name$)))\n");
     p->Outdent();
     p->Outdent();
   }
+  p->Print(".build();\n");
+  p->Outdent();
   p->Outdent();
   p->Outdent();
   p->Print("}\n");
@@ -598,6 +692,7 @@
   PrintStub(service, vars, p, ASYNC_CLIENT_IMPL, generate_nano);
   PrintStub(service, vars, p, BLOCKING_CLIENT_IMPL, generate_nano);
   PrintStub(service, vars, p, FUTURE_CLIENT_IMPL, generate_nano);
+  PrintMethodHandlerClass(service, vars, p, generate_nano);
   PrintBindServiceMethod(service, vars, p, generate_nano);
   p->Outdent();
   p->Print("}\n");
diff --git a/compiler/src/test/golden/TestService.java.txt b/compiler/src/test/golden/TestService.java.txt
index e263f67..77d5bb2 100644
--- a/compiler/src/test/golden/TestService.java.txt
+++ b/compiler/src/test/golden/TestService.java.txt
@@ -222,70 +222,98 @@
     }
   }
 
+  private static final int METHODID_UNARY_CALL = 0;
+  private static final int METHODID_STREAMING_OUTPUT_CALL = 1;
+  private static final int METHODID_STREAMING_INPUT_CALL = 2;
+  private static final int METHODID_FULL_BIDI_CALL = 3;
+  private static final int METHODID_HALF_BIDI_CALL = 4;
+
+  private static class MethodHandlers<Req, Resp> implements
+      io.grpc.stub.ServerCalls.UnaryMethod<Req, Resp>,
+      io.grpc.stub.ServerCalls.ServerStreamingMethod<Req, Resp>,
+      io.grpc.stub.ServerCalls.ClientStreamingMethod<Req, Resp>,
+      io.grpc.stub.ServerCalls.BidiStreamingMethod<Req, Resp> {
+    private final TestService serviceImpl;
+    private final int methodId;
+
+    public MethodHandlers(TestService serviceImpl, int methodId) {
+      this.serviceImpl = serviceImpl;
+      this.methodId = methodId;
+    }
+
+    @java.lang.SuppressWarnings("unchecked")
+    public void invoke(Req request, io.grpc.stub.StreamObserver<Resp> responseObserver) {
+      switch (methodId) {
+        case METHODID_UNARY_CALL:
+          serviceImpl.unaryCall((io.grpc.testing.integration.Test.SimpleRequest) request,
+              (io.grpc.stub.StreamObserver<io.grpc.testing.integration.Test.SimpleResponse>) responseObserver);
+          break;
+        case METHODID_STREAMING_OUTPUT_CALL:
+          serviceImpl.streamingOutputCall((io.grpc.testing.integration.Test.StreamingOutputCallRequest) request,
+              (io.grpc.stub.StreamObserver<io.grpc.testing.integration.Test.StreamingOutputCallResponse>) responseObserver);
+          break;
+        default:
+          throw new AssertionError();
+      }
+    }
+
+    @java.lang.SuppressWarnings("unchecked")
+    public io.grpc.stub.StreamObserver<Req> invoke(
+        io.grpc.stub.StreamObserver<Resp> responseObserver) {
+      switch (methodId) {
+        case METHODID_STREAMING_INPUT_CALL:
+          return (io.grpc.stub.StreamObserver<Req>) serviceImpl.streamingInputCall(
+              (io.grpc.stub.StreamObserver<io.grpc.testing.integration.Test.StreamingInputCallResponse>) responseObserver);
+        case METHODID_FULL_BIDI_CALL:
+          return (io.grpc.stub.StreamObserver<Req>) serviceImpl.fullBidiCall(
+              (io.grpc.stub.StreamObserver<io.grpc.testing.integration.Test.StreamingOutputCallResponse>) responseObserver);
+        case METHODID_HALF_BIDI_CALL:
+          return (io.grpc.stub.StreamObserver<Req>) serviceImpl.halfBidiCall(
+              (io.grpc.stub.StreamObserver<io.grpc.testing.integration.Test.StreamingOutputCallResponse>) responseObserver);
+        default:
+          throw new AssertionError();
+      }
+    }
+  }
+
   public static io.grpc.ServerServiceDefinition bindService(
       final TestService serviceImpl) {
     return io.grpc.ServerServiceDefinition.builder(SERVICE_NAME)
-      .addMethod(
-        METHOD_UNARY_CALL,
-        asyncUnaryCall(
-          new io.grpc.stub.ServerCalls.UnaryMethod<
+        .addMethod(
+          METHOD_UNARY_CALL,
+          asyncUnaryCall(
+            new MethodHandlers<
               io.grpc.testing.integration.Test.SimpleRequest,
-              io.grpc.testing.integration.Test.SimpleResponse>() {
-            @java.lang.Override
-            public void invoke(
-                io.grpc.testing.integration.Test.SimpleRequest request,
-                io.grpc.stub.StreamObserver<io.grpc.testing.integration.Test.SimpleResponse> responseObserver) {
-              serviceImpl.unaryCall(request, responseObserver);
-            }
-          }))
-      .addMethod(
-        METHOD_STREAMING_OUTPUT_CALL,
-        asyncServerStreamingCall(
-          new io.grpc.stub.ServerCalls.ServerStreamingMethod<
+              io.grpc.testing.integration.Test.SimpleResponse>(
+                serviceImpl, METHODID_UNARY_CALL)))
+        .addMethod(
+          METHOD_STREAMING_OUTPUT_CALL,
+          asyncServerStreamingCall(
+            new MethodHandlers<
               io.grpc.testing.integration.Test.StreamingOutputCallRequest,
-              io.grpc.testing.integration.Test.StreamingOutputCallResponse>() {
-            @java.lang.Override
-            public void invoke(
-                io.grpc.testing.integration.Test.StreamingOutputCallRequest request,
-                io.grpc.stub.StreamObserver<io.grpc.testing.integration.Test.StreamingOutputCallResponse> responseObserver) {
-              serviceImpl.streamingOutputCall(request, responseObserver);
-            }
-          }))
-      .addMethod(
-        METHOD_STREAMING_INPUT_CALL,
-        asyncClientStreamingCall(
-          new io.grpc.stub.ServerCalls.ClientStreamingMethod<
+              io.grpc.testing.integration.Test.StreamingOutputCallResponse>(
+                serviceImpl, METHODID_STREAMING_OUTPUT_CALL)))
+        .addMethod(
+          METHOD_STREAMING_INPUT_CALL,
+          asyncClientStreamingCall(
+            new MethodHandlers<
               io.grpc.testing.integration.Test.StreamingInputCallRequest,
-              io.grpc.testing.integration.Test.StreamingInputCallResponse>() {
-            @java.lang.Override
-            public io.grpc.stub.StreamObserver<io.grpc.testing.integration.Test.StreamingInputCallRequest> invoke(
-                io.grpc.stub.StreamObserver<io.grpc.testing.integration.Test.StreamingInputCallResponse> responseObserver) {
-              return serviceImpl.streamingInputCall(responseObserver);
-            }
-          }))
-      .addMethod(
-        METHOD_FULL_BIDI_CALL,
-        asyncBidiStreamingCall(
-          new io.grpc.stub.ServerCalls.BidiStreamingMethod<
+              io.grpc.testing.integration.Test.StreamingInputCallResponse>(
+                serviceImpl, METHODID_STREAMING_INPUT_CALL)))
+        .addMethod(
+          METHOD_FULL_BIDI_CALL,
+          asyncBidiStreamingCall(
+            new MethodHandlers<
               io.grpc.testing.integration.Test.StreamingOutputCallRequest,
-              io.grpc.testing.integration.Test.StreamingOutputCallResponse>() {
-            @java.lang.Override
-            public io.grpc.stub.StreamObserver<io.grpc.testing.integration.Test.StreamingOutputCallRequest> invoke(
-                io.grpc.stub.StreamObserver<io.grpc.testing.integration.Test.StreamingOutputCallResponse> responseObserver) {
-              return serviceImpl.fullBidiCall(responseObserver);
-            }
-          }))
-      .addMethod(
-        METHOD_HALF_BIDI_CALL,
-        asyncBidiStreamingCall(
-          new io.grpc.stub.ServerCalls.BidiStreamingMethod<
+              io.grpc.testing.integration.Test.StreamingOutputCallResponse>(
+                serviceImpl, METHODID_FULL_BIDI_CALL)))
+        .addMethod(
+          METHOD_HALF_BIDI_CALL,
+          asyncBidiStreamingCall(
+            new MethodHandlers<
               io.grpc.testing.integration.Test.StreamingOutputCallRequest,
-              io.grpc.testing.integration.Test.StreamingOutputCallResponse>() {
-            @java.lang.Override
-            public io.grpc.stub.StreamObserver<io.grpc.testing.integration.Test.StreamingOutputCallRequest> invoke(
-                io.grpc.stub.StreamObserver<io.grpc.testing.integration.Test.StreamingOutputCallResponse> responseObserver) {
-              return serviceImpl.halfBidiCall(responseObserver);
-            }
-          })).build();
+              io.grpc.testing.integration.Test.StreamingOutputCallResponse>(
+                serviceImpl, METHODID_HALF_BIDI_CALL)))
+        .build();
   }
 }
diff --git a/compiler/src/test/golden/TestServiceNano.java.txt b/compiler/src/test/golden/TestServiceNano.java.txt
index 7fd611f..f8c1ff3 100644
--- a/compiler/src/test/golden/TestServiceNano.java.txt
+++ b/compiler/src/test/golden/TestServiceNano.java.txt
@@ -300,70 +300,98 @@
     }
   }
 
+  private static final int METHODID_UNARY_CALL = 0;
+  private static final int METHODID_STREAMING_OUTPUT_CALL = 1;
+  private static final int METHODID_STREAMING_INPUT_CALL = 2;
+  private static final int METHODID_FULL_BIDI_CALL = 3;
+  private static final int METHODID_HALF_BIDI_CALL = 4;
+
+  private static class MethodHandlers<Req, Resp> implements
+      io.grpc.stub.ServerCalls.UnaryMethod<Req, Resp>,
+      io.grpc.stub.ServerCalls.ServerStreamingMethod<Req, Resp>,
+      io.grpc.stub.ServerCalls.ClientStreamingMethod<Req, Resp>,
+      io.grpc.stub.ServerCalls.BidiStreamingMethod<Req, Resp> {
+    private final TestService serviceImpl;
+    private final int methodId;
+
+    public MethodHandlers(TestService serviceImpl, int methodId) {
+      this.serviceImpl = serviceImpl;
+      this.methodId = methodId;
+    }
+
+    @java.lang.SuppressWarnings("unchecked")
+    public void invoke(Req request, io.grpc.stub.StreamObserver<Resp> responseObserver) {
+      switch (methodId) {
+        case METHODID_UNARY_CALL:
+          serviceImpl.unaryCall((io.grpc.testing.integration.nano.Test.SimpleRequest) request,
+              (io.grpc.stub.StreamObserver<io.grpc.testing.integration.nano.Test.SimpleResponse>) responseObserver);
+          break;
+        case METHODID_STREAMING_OUTPUT_CALL:
+          serviceImpl.streamingOutputCall((io.grpc.testing.integration.nano.Test.StreamingOutputCallRequest) request,
+              (io.grpc.stub.StreamObserver<io.grpc.testing.integration.nano.Test.StreamingOutputCallResponse>) responseObserver);
+          break;
+        default:
+          throw new AssertionError();
+      }
+    }
+
+    @java.lang.SuppressWarnings("unchecked")
+    public io.grpc.stub.StreamObserver<Req> invoke(
+        io.grpc.stub.StreamObserver<Resp> responseObserver) {
+      switch (methodId) {
+        case METHODID_STREAMING_INPUT_CALL:
+          return (io.grpc.stub.StreamObserver<Req>) serviceImpl.streamingInputCall(
+              (io.grpc.stub.StreamObserver<io.grpc.testing.integration.nano.Test.StreamingInputCallResponse>) responseObserver);
+        case METHODID_FULL_BIDI_CALL:
+          return (io.grpc.stub.StreamObserver<Req>) serviceImpl.fullBidiCall(
+              (io.grpc.stub.StreamObserver<io.grpc.testing.integration.nano.Test.StreamingOutputCallResponse>) responseObserver);
+        case METHODID_HALF_BIDI_CALL:
+          return (io.grpc.stub.StreamObserver<Req>) serviceImpl.halfBidiCall(
+              (io.grpc.stub.StreamObserver<io.grpc.testing.integration.nano.Test.StreamingOutputCallResponse>) responseObserver);
+        default:
+          throw new AssertionError();
+      }
+    }
+  }
+
   public static io.grpc.ServerServiceDefinition bindService(
       final TestService serviceImpl) {
     return io.grpc.ServerServiceDefinition.builder(SERVICE_NAME)
-      .addMethod(
-        METHOD_UNARY_CALL,
-        asyncUnaryCall(
-          new io.grpc.stub.ServerCalls.UnaryMethod<
+        .addMethod(
+          METHOD_UNARY_CALL,
+          asyncUnaryCall(
+            new MethodHandlers<
               io.grpc.testing.integration.nano.Test.SimpleRequest,
-              io.grpc.testing.integration.nano.Test.SimpleResponse>() {
-            @java.lang.Override
-            public void invoke(
-                io.grpc.testing.integration.nano.Test.SimpleRequest request,
-                io.grpc.stub.StreamObserver<io.grpc.testing.integration.nano.Test.SimpleResponse> responseObserver) {
-              serviceImpl.unaryCall(request, responseObserver);
-            }
-          }))
-      .addMethod(
-        METHOD_STREAMING_OUTPUT_CALL,
-        asyncServerStreamingCall(
-          new io.grpc.stub.ServerCalls.ServerStreamingMethod<
+              io.grpc.testing.integration.nano.Test.SimpleResponse>(
+                serviceImpl, METHODID_UNARY_CALL)))
+        .addMethod(
+          METHOD_STREAMING_OUTPUT_CALL,
+          asyncServerStreamingCall(
+            new MethodHandlers<
               io.grpc.testing.integration.nano.Test.StreamingOutputCallRequest,
-              io.grpc.testing.integration.nano.Test.StreamingOutputCallResponse>() {
-            @java.lang.Override
-            public void invoke(
-                io.grpc.testing.integration.nano.Test.StreamingOutputCallRequest request,
-                io.grpc.stub.StreamObserver<io.grpc.testing.integration.nano.Test.StreamingOutputCallResponse> responseObserver) {
-              serviceImpl.streamingOutputCall(request, responseObserver);
-            }
-          }))
-      .addMethod(
-        METHOD_STREAMING_INPUT_CALL,
-        asyncClientStreamingCall(
-          new io.grpc.stub.ServerCalls.ClientStreamingMethod<
+              io.grpc.testing.integration.nano.Test.StreamingOutputCallResponse>(
+                serviceImpl, METHODID_STREAMING_OUTPUT_CALL)))
+        .addMethod(
+          METHOD_STREAMING_INPUT_CALL,
+          asyncClientStreamingCall(
+            new MethodHandlers<
               io.grpc.testing.integration.nano.Test.StreamingInputCallRequest,
-              io.grpc.testing.integration.nano.Test.StreamingInputCallResponse>() {
-            @java.lang.Override
-            public io.grpc.stub.StreamObserver<io.grpc.testing.integration.nano.Test.StreamingInputCallRequest> invoke(
-                io.grpc.stub.StreamObserver<io.grpc.testing.integration.nano.Test.StreamingInputCallResponse> responseObserver) {
-              return serviceImpl.streamingInputCall(responseObserver);
-            }
-          }))
-      .addMethod(
-        METHOD_FULL_BIDI_CALL,
-        asyncBidiStreamingCall(
-          new io.grpc.stub.ServerCalls.BidiStreamingMethod<
+              io.grpc.testing.integration.nano.Test.StreamingInputCallResponse>(
+                serviceImpl, METHODID_STREAMING_INPUT_CALL)))
+        .addMethod(
+          METHOD_FULL_BIDI_CALL,
+          asyncBidiStreamingCall(
+            new MethodHandlers<
               io.grpc.testing.integration.nano.Test.StreamingOutputCallRequest,
-              io.grpc.testing.integration.nano.Test.StreamingOutputCallResponse>() {
-            @java.lang.Override
-            public io.grpc.stub.StreamObserver<io.grpc.testing.integration.nano.Test.StreamingOutputCallRequest> invoke(
-                io.grpc.stub.StreamObserver<io.grpc.testing.integration.nano.Test.StreamingOutputCallResponse> responseObserver) {
-              return serviceImpl.fullBidiCall(responseObserver);
-            }
-          }))
-      .addMethod(
-        METHOD_HALF_BIDI_CALL,
-        asyncBidiStreamingCall(
-          new io.grpc.stub.ServerCalls.BidiStreamingMethod<
+              io.grpc.testing.integration.nano.Test.StreamingOutputCallResponse>(
+                serviceImpl, METHODID_FULL_BIDI_CALL)))
+        .addMethod(
+          METHOD_HALF_BIDI_CALL,
+          asyncBidiStreamingCall(
+            new MethodHandlers<
               io.grpc.testing.integration.nano.Test.StreamingOutputCallRequest,
-              io.grpc.testing.integration.nano.Test.StreamingOutputCallResponse>() {
-            @java.lang.Override
-            public io.grpc.stub.StreamObserver<io.grpc.testing.integration.nano.Test.StreamingOutputCallRequest> invoke(
-                io.grpc.stub.StreamObserver<io.grpc.testing.integration.nano.Test.StreamingOutputCallResponse> responseObserver) {
-              return serviceImpl.halfBidiCall(responseObserver);
-            }
-          })).build();
+              io.grpc.testing.integration.nano.Test.StreamingOutputCallResponse>(
+                serviceImpl, METHODID_HALF_BIDI_CALL)))
+        .build();
   }
 }
diff --git a/examples/src/generated/main/grpc/io/grpc/examples/helloworld/GreeterGrpc.java b/examples/src/generated/main/grpc/io/grpc/examples/helloworld/GreeterGrpc.java
index 31968eb..ac400a5 100644
--- a/examples/src/generated/main/grpc/io/grpc/examples/helloworld/GreeterGrpc.java
+++ b/examples/src/generated/main/grpc/io/grpc/examples/helloworld/GreeterGrpc.java
@@ -136,21 +136,53 @@
     }
   }
 
+  private static final int METHODID_SAY_HELLO = 0;
+
+  private static class MethodHandlers<Req, Resp> implements
+      io.grpc.stub.ServerCalls.UnaryMethod<Req, Resp>,
+      io.grpc.stub.ServerCalls.ServerStreamingMethod<Req, Resp>,
+      io.grpc.stub.ServerCalls.ClientStreamingMethod<Req, Resp>,
+      io.grpc.stub.ServerCalls.BidiStreamingMethod<Req, Resp> {
+    private final Greeter serviceImpl;
+    private final int methodId;
+
+    public MethodHandlers(Greeter serviceImpl, int methodId) {
+      this.serviceImpl = serviceImpl;
+      this.methodId = methodId;
+    }
+
+    @java.lang.SuppressWarnings("unchecked")
+    public void invoke(Req request, io.grpc.stub.StreamObserver<Resp> responseObserver) {
+      switch (methodId) {
+        case METHODID_SAY_HELLO:
+          serviceImpl.sayHello((io.grpc.examples.helloworld.HelloRequest) request,
+              (io.grpc.stub.StreamObserver<io.grpc.examples.helloworld.HelloResponse>) responseObserver);
+          break;
+        default:
+          throw new AssertionError();
+      }
+    }
+
+    @java.lang.SuppressWarnings("unchecked")
+    public io.grpc.stub.StreamObserver<Req> invoke(
+        io.grpc.stub.StreamObserver<Resp> responseObserver) {
+      switch (methodId) {
+        default:
+          throw new AssertionError();
+      }
+    }
+  }
+
   public static io.grpc.ServerServiceDefinition bindService(
       final Greeter serviceImpl) {
     return io.grpc.ServerServiceDefinition.builder(SERVICE_NAME)
-      .addMethod(
-        METHOD_SAY_HELLO,
-        asyncUnaryCall(
-          new io.grpc.stub.ServerCalls.UnaryMethod<
+        .addMethod(
+          METHOD_SAY_HELLO,
+          asyncUnaryCall(
+            new MethodHandlers<
               io.grpc.examples.helloworld.HelloRequest,
-              io.grpc.examples.helloworld.HelloResponse>() {
-            @java.lang.Override
-            public void invoke(
-                io.grpc.examples.helloworld.HelloRequest request,
-                io.grpc.stub.StreamObserver<io.grpc.examples.helloworld.HelloResponse> responseObserver) {
-              serviceImpl.sayHello(request, responseObserver);
-            }
-          })).build();
+              io.grpc.examples.helloworld.HelloResponse>(
+                serviceImpl, METHODID_SAY_HELLO)))
+        .build();
   }
 }
diff --git a/examples/src/generated/main/grpc/io/grpc/examples/routeguide/RouteGuideGrpc.java b/examples/src/generated/main/grpc/io/grpc/examples/routeguide/RouteGuideGrpc.java
index 740ea59..6fe7108 100644
--- a/examples/src/generated/main/grpc/io/grpc/examples/routeguide/RouteGuideGrpc.java
+++ b/examples/src/generated/main/grpc/io/grpc/examples/routeguide/RouteGuideGrpc.java
@@ -203,58 +203,87 @@
     }
   }
 
+  private static final int METHODID_GET_FEATURE = 0;
+  private static final int METHODID_LIST_FEATURES = 1;
+  private static final int METHODID_RECORD_ROUTE = 2;
+  private static final int METHODID_ROUTE_CHAT = 3;
+
+  private static class MethodHandlers<Req, Resp> implements
+      io.grpc.stub.ServerCalls.UnaryMethod<Req, Resp>,
+      io.grpc.stub.ServerCalls.ServerStreamingMethod<Req, Resp>,
+      io.grpc.stub.ServerCalls.ClientStreamingMethod<Req, Resp>,
+      io.grpc.stub.ServerCalls.BidiStreamingMethod<Req, Resp> {
+    private final RouteGuide serviceImpl;
+    private final int methodId;
+
+    public MethodHandlers(RouteGuide serviceImpl, int methodId) {
+      this.serviceImpl = serviceImpl;
+      this.methodId = methodId;
+    }
+
+    @java.lang.SuppressWarnings("unchecked")
+    public void invoke(Req request, io.grpc.stub.StreamObserver<Resp> responseObserver) {
+      switch (methodId) {
+        case METHODID_GET_FEATURE:
+          serviceImpl.getFeature((io.grpc.examples.routeguide.Point) request,
+              (io.grpc.stub.StreamObserver<io.grpc.examples.routeguide.Feature>) responseObserver);
+          break;
+        case METHODID_LIST_FEATURES:
+          serviceImpl.listFeatures((io.grpc.examples.routeguide.Rectangle) request,
+              (io.grpc.stub.StreamObserver<io.grpc.examples.routeguide.Feature>) responseObserver);
+          break;
+        default:
+          throw new AssertionError();
+      }
+    }
+
+    @java.lang.SuppressWarnings("unchecked")
+    public io.grpc.stub.StreamObserver<Req> invoke(
+        io.grpc.stub.StreamObserver<Resp> responseObserver) {
+      switch (methodId) {
+        case METHODID_RECORD_ROUTE:
+          return (io.grpc.stub.StreamObserver<Req>) serviceImpl.recordRoute(
+              (io.grpc.stub.StreamObserver<io.grpc.examples.routeguide.RouteSummary>) responseObserver);
+        case METHODID_ROUTE_CHAT:
+          return (io.grpc.stub.StreamObserver<Req>) serviceImpl.routeChat(
+              (io.grpc.stub.StreamObserver<io.grpc.examples.routeguide.RouteNote>) responseObserver);
+        default:
+          throw new AssertionError();
+      }
+    }
+  }
+
   public static io.grpc.ServerServiceDefinition bindService(
       final RouteGuide serviceImpl) {
     return io.grpc.ServerServiceDefinition.builder(SERVICE_NAME)
-      .addMethod(
-        METHOD_GET_FEATURE,
-        asyncUnaryCall(
-          new io.grpc.stub.ServerCalls.UnaryMethod<
+        .addMethod(
+          METHOD_GET_FEATURE,
+          asyncUnaryCall(
+            new MethodHandlers<
               io.grpc.examples.routeguide.Point,
-              io.grpc.examples.routeguide.Feature>() {
-            @java.lang.Override
-            public void invoke(
-                io.grpc.examples.routeguide.Point request,
-                io.grpc.stub.StreamObserver<io.grpc.examples.routeguide.Feature> responseObserver) {
-              serviceImpl.getFeature(request, responseObserver);
-            }
-          }))
-      .addMethod(
-        METHOD_LIST_FEATURES,
-        asyncServerStreamingCall(
-          new io.grpc.stub.ServerCalls.ServerStreamingMethod<
+              io.grpc.examples.routeguide.Feature>(
+                serviceImpl, METHODID_GET_FEATURE)))
+        .addMethod(
+          METHOD_LIST_FEATURES,
+          asyncServerStreamingCall(
+            new MethodHandlers<
               io.grpc.examples.routeguide.Rectangle,
-              io.grpc.examples.routeguide.Feature>() {
-            @java.lang.Override
-            public void invoke(
-                io.grpc.examples.routeguide.Rectangle request,
-                io.grpc.stub.StreamObserver<io.grpc.examples.routeguide.Feature> responseObserver) {
-              serviceImpl.listFeatures(request, responseObserver);
-            }
-          }))
-      .addMethod(
-        METHOD_RECORD_ROUTE,
-        asyncClientStreamingCall(
-          new io.grpc.stub.ServerCalls.ClientStreamingMethod<
+              io.grpc.examples.routeguide.Feature>(
+                serviceImpl, METHODID_LIST_FEATURES)))
+        .addMethod(
+          METHOD_RECORD_ROUTE,
+          asyncClientStreamingCall(
+            new MethodHandlers<
               io.grpc.examples.routeguide.Point,
-              io.grpc.examples.routeguide.RouteSummary>() {
-            @java.lang.Override
-            public io.grpc.stub.StreamObserver<io.grpc.examples.routeguide.Point> invoke(
-                io.grpc.stub.StreamObserver<io.grpc.examples.routeguide.RouteSummary> responseObserver) {
-              return serviceImpl.recordRoute(responseObserver);
-            }
-          }))
-      .addMethod(
-        METHOD_ROUTE_CHAT,
-        asyncBidiStreamingCall(
-          new io.grpc.stub.ServerCalls.BidiStreamingMethod<
+              io.grpc.examples.routeguide.RouteSummary>(
+                serviceImpl, METHODID_RECORD_ROUTE)))
+        .addMethod(
+          METHOD_ROUTE_CHAT,
+          asyncBidiStreamingCall(
+            new MethodHandlers<
               io.grpc.examples.routeguide.RouteNote,
-              io.grpc.examples.routeguide.RouteNote>() {
-            @java.lang.Override
-            public io.grpc.stub.StreamObserver<io.grpc.examples.routeguide.RouteNote> invoke(
-                io.grpc.stub.StreamObserver<io.grpc.examples.routeguide.RouteNote> responseObserver) {
-              return serviceImpl.routeChat(responseObserver);
-            }
-          })).build();
+              io.grpc.examples.routeguide.RouteNote>(
+                serviceImpl, METHODID_ROUTE_CHAT)))
+        .build();
   }
 }
diff --git a/grpclb/src/generated/main/grpc/io/grpc/grpclb/LoadBalancerGrpc.java b/grpclb/src/generated/main/grpc/io/grpc/grpclb/LoadBalancerGrpc.java
index 555902c..57d2982 100644
--- a/grpclb/src/generated/main/grpc/io/grpc/grpclb/LoadBalancerGrpc.java
+++ b/grpclb/src/generated/main/grpc/io/grpc/grpclb/LoadBalancerGrpc.java
@@ -118,20 +118,52 @@
     }
   }
 
+  private static final int METHODID_BALANCE_LOAD = 0;
+
+  private static class MethodHandlers<Req, Resp> implements
+      io.grpc.stub.ServerCalls.UnaryMethod<Req, Resp>,
+      io.grpc.stub.ServerCalls.ServerStreamingMethod<Req, Resp>,
+      io.grpc.stub.ServerCalls.ClientStreamingMethod<Req, Resp>,
+      io.grpc.stub.ServerCalls.BidiStreamingMethod<Req, Resp> {
+    private final LoadBalancer serviceImpl;
+    private final int methodId;
+
+    public MethodHandlers(LoadBalancer serviceImpl, int methodId) {
+      this.serviceImpl = serviceImpl;
+      this.methodId = methodId;
+    }
+
+    @java.lang.SuppressWarnings("unchecked")
+    public void invoke(Req request, io.grpc.stub.StreamObserver<Resp> responseObserver) {
+      switch (methodId) {
+        default:
+          throw new AssertionError();
+      }
+    }
+
+    @java.lang.SuppressWarnings("unchecked")
+    public io.grpc.stub.StreamObserver<Req> invoke(
+        io.grpc.stub.StreamObserver<Resp> responseObserver) {
+      switch (methodId) {
+        case METHODID_BALANCE_LOAD:
+          return (io.grpc.stub.StreamObserver<Req>) serviceImpl.balanceLoad(
+              (io.grpc.stub.StreamObserver<io.grpc.grpclb.LoadBalanceResponse>) responseObserver);
+        default:
+          throw new AssertionError();
+      }
+    }
+  }
+
   public static io.grpc.ServerServiceDefinition bindService(
       final LoadBalancer serviceImpl) {
     return io.grpc.ServerServiceDefinition.builder(SERVICE_NAME)
-      .addMethod(
-        METHOD_BALANCE_LOAD,
-        asyncBidiStreamingCall(
-          new io.grpc.stub.ServerCalls.BidiStreamingMethod<
+        .addMethod(
+          METHOD_BALANCE_LOAD,
+          asyncBidiStreamingCall(
+            new MethodHandlers<
               io.grpc.grpclb.LoadBalanceRequest,
-              io.grpc.grpclb.LoadBalanceResponse>() {
-            @java.lang.Override
-            public io.grpc.stub.StreamObserver<io.grpc.grpclb.LoadBalanceRequest> invoke(
-                io.grpc.stub.StreamObserver<io.grpc.grpclb.LoadBalanceResponse> responseObserver) {
-              return serviceImpl.balanceLoad(responseObserver);
-            }
-          })).build();
+              io.grpc.grpclb.LoadBalanceResponse>(
+                serviceImpl, METHODID_BALANCE_LOAD)))
+        .build();
   }
 }
diff --git a/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/ReconnectServiceGrpc.java b/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/ReconnectServiceGrpc.java
index 28505c0..6a573ad 100644
--- a/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/ReconnectServiceGrpc.java
+++ b/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/ReconnectServiceGrpc.java
@@ -173,34 +173,65 @@
     }
   }
 
+  private static final int METHODID_START = 0;
+  private static final int METHODID_STOP = 1;
+
+  private static class MethodHandlers<Req, Resp> implements
+      io.grpc.stub.ServerCalls.UnaryMethod<Req, Resp>,
+      io.grpc.stub.ServerCalls.ServerStreamingMethod<Req, Resp>,
+      io.grpc.stub.ServerCalls.ClientStreamingMethod<Req, Resp>,
+      io.grpc.stub.ServerCalls.BidiStreamingMethod<Req, Resp> {
+    private final ReconnectService serviceImpl;
+    private final int methodId;
+
+    public MethodHandlers(ReconnectService serviceImpl, int methodId) {
+      this.serviceImpl = serviceImpl;
+      this.methodId = methodId;
+    }
+
+    @java.lang.SuppressWarnings("unchecked")
+    public void invoke(Req request, io.grpc.stub.StreamObserver<Resp> responseObserver) {
+      switch (methodId) {
+        case METHODID_START:
+          serviceImpl.start((com.google.protobuf.EmptyProtos.Empty) request,
+              (io.grpc.stub.StreamObserver<com.google.protobuf.EmptyProtos.Empty>) responseObserver);
+          break;
+        case METHODID_STOP:
+          serviceImpl.stop((com.google.protobuf.EmptyProtos.Empty) request,
+              (io.grpc.stub.StreamObserver<io.grpc.testing.integration.Messages.ReconnectInfo>) responseObserver);
+          break;
+        default:
+          throw new AssertionError();
+      }
+    }
+
+    @java.lang.SuppressWarnings("unchecked")
+    public io.grpc.stub.StreamObserver<Req> invoke(
+        io.grpc.stub.StreamObserver<Resp> responseObserver) {
+      switch (methodId) {
+        default:
+          throw new AssertionError();
+      }
+    }
+  }
+
   public static io.grpc.ServerServiceDefinition bindService(
       final ReconnectService serviceImpl) {
     return io.grpc.ServerServiceDefinition.builder(SERVICE_NAME)
-      .addMethod(
-        METHOD_START,
-        asyncUnaryCall(
-          new io.grpc.stub.ServerCalls.UnaryMethod<
+        .addMethod(
+          METHOD_START,
+          asyncUnaryCall(
+            new MethodHandlers<
               com.google.protobuf.EmptyProtos.Empty,
-              com.google.protobuf.EmptyProtos.Empty>() {
-            @java.lang.Override
-            public void invoke(
-                com.google.protobuf.EmptyProtos.Empty request,
-                io.grpc.stub.StreamObserver<com.google.protobuf.EmptyProtos.Empty> responseObserver) {
-              serviceImpl.start(request, responseObserver);
-            }
-          }))
-      .addMethod(
-        METHOD_STOP,
-        asyncUnaryCall(
-          new io.grpc.stub.ServerCalls.UnaryMethod<
+              com.google.protobuf.EmptyProtos.Empty>(
+                serviceImpl, METHODID_START)))
+        .addMethod(
+          METHOD_STOP,
+          asyncUnaryCall(
+            new MethodHandlers<
               com.google.protobuf.EmptyProtos.Empty,
-              io.grpc.testing.integration.Messages.ReconnectInfo>() {
-            @java.lang.Override
-            public void invoke(
-                com.google.protobuf.EmptyProtos.Empty request,
-                io.grpc.stub.StreamObserver<io.grpc.testing.integration.Messages.ReconnectInfo> responseObserver) {
-              serviceImpl.stop(request, responseObserver);
-            }
-          })).build();
+              io.grpc.testing.integration.Messages.ReconnectInfo>(
+                serviceImpl, METHODID_STOP)))
+        .build();
   }
 }
diff --git a/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/TestServiceGrpc.java b/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/TestServiceGrpc.java
index 35b474d..c06c7b5 100644
--- a/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/TestServiceGrpc.java
+++ b/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/TestServiceGrpc.java
@@ -259,83 +259,110 @@
     }
   }
 
+  private static final int METHODID_EMPTY_CALL = 0;
+  private static final int METHODID_UNARY_CALL = 1;
+  private static final int METHODID_STREAMING_OUTPUT_CALL = 2;
+  private static final int METHODID_STREAMING_INPUT_CALL = 3;
+  private static final int METHODID_FULL_DUPLEX_CALL = 4;
+  private static final int METHODID_HALF_DUPLEX_CALL = 5;
+
+  private static class MethodHandlers<Req, Resp> implements
+      io.grpc.stub.ServerCalls.UnaryMethod<Req, Resp>,
+      io.grpc.stub.ServerCalls.ServerStreamingMethod<Req, Resp>,
+      io.grpc.stub.ServerCalls.ClientStreamingMethod<Req, Resp>,
+      io.grpc.stub.ServerCalls.BidiStreamingMethod<Req, Resp> {
+    private final TestService serviceImpl;
+    private final int methodId;
+
+    public MethodHandlers(TestService serviceImpl, int methodId) {
+      this.serviceImpl = serviceImpl;
+      this.methodId = methodId;
+    }
+
+    @java.lang.SuppressWarnings("unchecked")
+    public void invoke(Req request, io.grpc.stub.StreamObserver<Resp> responseObserver) {
+      switch (methodId) {
+        case METHODID_EMPTY_CALL:
+          serviceImpl.emptyCall((com.google.protobuf.EmptyProtos.Empty) request,
+              (io.grpc.stub.StreamObserver<com.google.protobuf.EmptyProtos.Empty>) responseObserver);
+          break;
+        case METHODID_UNARY_CALL:
+          serviceImpl.unaryCall((io.grpc.testing.integration.Messages.SimpleRequest) request,
+              (io.grpc.stub.StreamObserver<io.grpc.testing.integration.Messages.SimpleResponse>) responseObserver);
+          break;
+        case METHODID_STREAMING_OUTPUT_CALL:
+          serviceImpl.streamingOutputCall((io.grpc.testing.integration.Messages.StreamingOutputCallRequest) request,
+              (io.grpc.stub.StreamObserver<io.grpc.testing.integration.Messages.StreamingOutputCallResponse>) responseObserver);
+          break;
+        default:
+          throw new AssertionError();
+      }
+    }
+
+    @java.lang.SuppressWarnings("unchecked")
+    public io.grpc.stub.StreamObserver<Req> invoke(
+        io.grpc.stub.StreamObserver<Resp> responseObserver) {
+      switch (methodId) {
+        case METHODID_STREAMING_INPUT_CALL:
+          return (io.grpc.stub.StreamObserver<Req>) serviceImpl.streamingInputCall(
+              (io.grpc.stub.StreamObserver<io.grpc.testing.integration.Messages.StreamingInputCallResponse>) responseObserver);
+        case METHODID_FULL_DUPLEX_CALL:
+          return (io.grpc.stub.StreamObserver<Req>) serviceImpl.fullDuplexCall(
+              (io.grpc.stub.StreamObserver<io.grpc.testing.integration.Messages.StreamingOutputCallResponse>) responseObserver);
+        case METHODID_HALF_DUPLEX_CALL:
+          return (io.grpc.stub.StreamObserver<Req>) serviceImpl.halfDuplexCall(
+              (io.grpc.stub.StreamObserver<io.grpc.testing.integration.Messages.StreamingOutputCallResponse>) responseObserver);
+        default:
+          throw new AssertionError();
+      }
+    }
+  }
+
   public static io.grpc.ServerServiceDefinition bindService(
       final TestService serviceImpl) {
     return io.grpc.ServerServiceDefinition.builder(SERVICE_NAME)
-      .addMethod(
-        METHOD_EMPTY_CALL,
-        asyncUnaryCall(
-          new io.grpc.stub.ServerCalls.UnaryMethod<
+        .addMethod(
+          METHOD_EMPTY_CALL,
+          asyncUnaryCall(
+            new MethodHandlers<
               com.google.protobuf.EmptyProtos.Empty,
-              com.google.protobuf.EmptyProtos.Empty>() {
-            @java.lang.Override
-            public void invoke(
-                com.google.protobuf.EmptyProtos.Empty request,
-                io.grpc.stub.StreamObserver<com.google.protobuf.EmptyProtos.Empty> responseObserver) {
-              serviceImpl.emptyCall(request, responseObserver);
-            }
-          }))
-      .addMethod(
-        METHOD_UNARY_CALL,
-        asyncUnaryCall(
-          new io.grpc.stub.ServerCalls.UnaryMethod<
+              com.google.protobuf.EmptyProtos.Empty>(
+                serviceImpl, METHODID_EMPTY_CALL)))
+        .addMethod(
+          METHOD_UNARY_CALL,
+          asyncUnaryCall(
+            new MethodHandlers<
               io.grpc.testing.integration.Messages.SimpleRequest,
-              io.grpc.testing.integration.Messages.SimpleResponse>() {
-            @java.lang.Override
-            public void invoke(
-                io.grpc.testing.integration.Messages.SimpleRequest request,
-                io.grpc.stub.StreamObserver<io.grpc.testing.integration.Messages.SimpleResponse> responseObserver) {
-              serviceImpl.unaryCall(request, responseObserver);
-            }
-          }))
-      .addMethod(
-        METHOD_STREAMING_OUTPUT_CALL,
-        asyncServerStreamingCall(
-          new io.grpc.stub.ServerCalls.ServerStreamingMethod<
+              io.grpc.testing.integration.Messages.SimpleResponse>(
+                serviceImpl, METHODID_UNARY_CALL)))
+        .addMethod(
+          METHOD_STREAMING_OUTPUT_CALL,
+          asyncServerStreamingCall(
+            new MethodHandlers<
               io.grpc.testing.integration.Messages.StreamingOutputCallRequest,
-              io.grpc.testing.integration.Messages.StreamingOutputCallResponse>() {
-            @java.lang.Override
-            public void invoke(
-                io.grpc.testing.integration.Messages.StreamingOutputCallRequest request,
-                io.grpc.stub.StreamObserver<io.grpc.testing.integration.Messages.StreamingOutputCallResponse> responseObserver) {
-              serviceImpl.streamingOutputCall(request, responseObserver);
-            }
-          }))
-      .addMethod(
-        METHOD_STREAMING_INPUT_CALL,
-        asyncClientStreamingCall(
-          new io.grpc.stub.ServerCalls.ClientStreamingMethod<
+              io.grpc.testing.integration.Messages.StreamingOutputCallResponse>(
+                serviceImpl, METHODID_STREAMING_OUTPUT_CALL)))
+        .addMethod(
+          METHOD_STREAMING_INPUT_CALL,
+          asyncClientStreamingCall(
+            new MethodHandlers<
               io.grpc.testing.integration.Messages.StreamingInputCallRequest,
-              io.grpc.testing.integration.Messages.StreamingInputCallResponse>() {
-            @java.lang.Override
-            public io.grpc.stub.StreamObserver<io.grpc.testing.integration.Messages.StreamingInputCallRequest> invoke(
-                io.grpc.stub.StreamObserver<io.grpc.testing.integration.Messages.StreamingInputCallResponse> responseObserver) {
-              return serviceImpl.streamingInputCall(responseObserver);
-            }
-          }))
-      .addMethod(
-        METHOD_FULL_DUPLEX_CALL,
-        asyncBidiStreamingCall(
-          new io.grpc.stub.ServerCalls.BidiStreamingMethod<
+              io.grpc.testing.integration.Messages.StreamingInputCallResponse>(
+                serviceImpl, METHODID_STREAMING_INPUT_CALL)))
+        .addMethod(
+          METHOD_FULL_DUPLEX_CALL,
+          asyncBidiStreamingCall(
+            new MethodHandlers<
               io.grpc.testing.integration.Messages.StreamingOutputCallRequest,
-              io.grpc.testing.integration.Messages.StreamingOutputCallResponse>() {
-            @java.lang.Override
-            public io.grpc.stub.StreamObserver<io.grpc.testing.integration.Messages.StreamingOutputCallRequest> invoke(
-                io.grpc.stub.StreamObserver<io.grpc.testing.integration.Messages.StreamingOutputCallResponse> responseObserver) {
-              return serviceImpl.fullDuplexCall(responseObserver);
-            }
-          }))
-      .addMethod(
-        METHOD_HALF_DUPLEX_CALL,
-        asyncBidiStreamingCall(
-          new io.grpc.stub.ServerCalls.BidiStreamingMethod<
+              io.grpc.testing.integration.Messages.StreamingOutputCallResponse>(
+                serviceImpl, METHODID_FULL_DUPLEX_CALL)))
+        .addMethod(
+          METHOD_HALF_DUPLEX_CALL,
+          asyncBidiStreamingCall(
+            new MethodHandlers<
               io.grpc.testing.integration.Messages.StreamingOutputCallRequest,
-              io.grpc.testing.integration.Messages.StreamingOutputCallResponse>() {
-            @java.lang.Override
-            public io.grpc.stub.StreamObserver<io.grpc.testing.integration.Messages.StreamingOutputCallRequest> invoke(
-                io.grpc.stub.StreamObserver<io.grpc.testing.integration.Messages.StreamingOutputCallResponse> responseObserver) {
-              return serviceImpl.halfDuplexCall(responseObserver);
-            }
-          })).build();
+              io.grpc.testing.integration.Messages.StreamingOutputCallResponse>(
+                serviceImpl, METHODID_HALF_DUPLEX_CALL)))
+        .build();
   }
 }
diff --git a/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/UnimplementedServiceGrpc.java b/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/UnimplementedServiceGrpc.java
index febad9d..2436c26 100644
--- a/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/UnimplementedServiceGrpc.java
+++ b/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/UnimplementedServiceGrpc.java
@@ -136,21 +136,53 @@
     }
   }
 
+  private static final int METHODID_UNIMPLEMENTED_CALL = 0;
+
+  private static class MethodHandlers<Req, Resp> implements
+      io.grpc.stub.ServerCalls.UnaryMethod<Req, Resp>,
+      io.grpc.stub.ServerCalls.ServerStreamingMethod<Req, Resp>,
+      io.grpc.stub.ServerCalls.ClientStreamingMethod<Req, Resp>,
+      io.grpc.stub.ServerCalls.BidiStreamingMethod<Req, Resp> {
+    private final UnimplementedService serviceImpl;
+    private final int methodId;
+
+    public MethodHandlers(UnimplementedService serviceImpl, int methodId) {
+      this.serviceImpl = serviceImpl;
+      this.methodId = methodId;
+    }
+
+    @java.lang.SuppressWarnings("unchecked")
+    public void invoke(Req request, io.grpc.stub.StreamObserver<Resp> responseObserver) {
+      switch (methodId) {
+        case METHODID_UNIMPLEMENTED_CALL:
+          serviceImpl.unimplementedCall((com.google.protobuf.EmptyProtos.Empty) request,
+              (io.grpc.stub.StreamObserver<com.google.protobuf.EmptyProtos.Empty>) responseObserver);
+          break;
+        default:
+          throw new AssertionError();
+      }
+    }
+
+    @java.lang.SuppressWarnings("unchecked")
+    public io.grpc.stub.StreamObserver<Req> invoke(
+        io.grpc.stub.StreamObserver<Resp> responseObserver) {
+      switch (methodId) {
+        default:
+          throw new AssertionError();
+      }
+    }
+  }
+
   public static io.grpc.ServerServiceDefinition bindService(
       final UnimplementedService serviceImpl) {
     return io.grpc.ServerServiceDefinition.builder(SERVICE_NAME)
-      .addMethod(
-        METHOD_UNIMPLEMENTED_CALL,
-        asyncUnaryCall(
-          new io.grpc.stub.ServerCalls.UnaryMethod<
+        .addMethod(
+          METHOD_UNIMPLEMENTED_CALL,
+          asyncUnaryCall(
+            new MethodHandlers<
               com.google.protobuf.EmptyProtos.Empty,
-              com.google.protobuf.EmptyProtos.Empty>() {
-            @java.lang.Override
-            public void invoke(
-                com.google.protobuf.EmptyProtos.Empty request,
-                io.grpc.stub.StreamObserver<com.google.protobuf.EmptyProtos.Empty> responseObserver) {
-              serviceImpl.unimplementedCall(request, responseObserver);
-            }
-          })).build();
+              com.google.protobuf.EmptyProtos.Empty>(
+                serviceImpl, METHODID_UNIMPLEMENTED_CALL)))
+        .build();
   }
 }