diff --git a/src/compiler/cpp_generator.cc b/src/compiler/cpp_generator.cc
index 08b1123a5121ae226fbe0b34db20d6682cba675b..b1336993067d0b7eb11fe834fa7d8ac4ad1187d6 100644
--- a/src/compiler/cpp_generator.cc
+++ b/src/compiler/cpp_generator.cc
@@ -34,9 +34,6 @@
 #include <map>
 
 #include "src/compiler/cpp_generator.h"
-#include "src/compiler/cpp_generator_helpers.h"
-
-#include "src/compiler/config.h"
 
 #include <sstream>
 
@@ -50,22 +47,6 @@ grpc::string as_string(T x) {
   return out.str();
 }
 
-bool NoStreaming(const grpc::protobuf::MethodDescriptor *method) {
-  return !method->client_streaming() && !method->server_streaming();
-}
-
-bool ClientOnlyStreaming(const grpc::protobuf::MethodDescriptor *method) {
-  return method->client_streaming() && !method->server_streaming();
-}
-
-bool ServerOnlyStreaming(const grpc::protobuf::MethodDescriptor *method) {
-  return !method->client_streaming() && method->server_streaming();
-}
-
-bool BidiStreaming(const grpc::protobuf::MethodDescriptor *method) {
-  return method->client_streaming() && method->server_streaming();
-}
-
 grpc::string FilenameIdentifier(const grpc::string &filename) {
   grpc::string result;
   for (unsigned i = 0; i < filename.size(); i++) {
@@ -86,7 +67,7 @@ grpc::string FilenameIdentifier(const grpc::string &filename) {
 template<class T, size_t N>
 T *array_end(T (&array)[N]) { return array + N; }
 
-void PrintIncludes(grpc::protobuf::io::Printer *printer, const std::vector<grpc::string>& headers, const Parameters &params) {
+void PrintIncludes(Printer *printer, const std::vector<grpc::string>& headers, const Parameters &params) {
   std::map<grpc::string, grpc::string> vars;
 
   vars["l"] = params.use_system_headers ? '<' : '"';
@@ -105,39 +86,36 @@ void PrintIncludes(grpc::protobuf::io::Printer *printer, const std::vector<grpc:
   }
 }
 
-grpc::string GetHeaderPrologue(const grpc::protobuf::FileDescriptor *file,
-                               const Parameters &params) {
+grpc::string GetHeaderPrologue(File *file, const Parameters &params) {
   grpc::string output;
   {
     // Scope the output stream so it closes and finalizes output to the string.
-    grpc::protobuf::io::StringOutputStream output_stream(&output);
-    grpc::protobuf::io::Printer printer(&output_stream, '$');
+    auto printer = file->CreatePrinter(&output);
     std::map<grpc::string, grpc::string> vars;
 
-    vars["filename"] = file->name();
-    vars["filename_identifier"] = FilenameIdentifier(file->name());
-    vars["filename_base"] = grpc_generator::StripProto(file->name());
+    vars["filename"] = file->filename();
+    vars["filename_identifier"] = FilenameIdentifier(file->filename());
+    vars["filename_base"] = file->filename_without_ext();
 
-    printer.Print(vars, "// Generated by the gRPC protobuf plugin.\n");
-    printer.Print(vars,
+    printer->Print(vars, "// Generated by the gRPC protobuf plugin.\n");
+    printer->Print(vars,
                   "// If you make any local change, they will be lost.\n");
-    printer.Print(vars, "// source: $filename$\n");
-    printer.Print(vars, "#ifndef GRPC_$filename_identifier$__INCLUDED\n");
-    printer.Print(vars, "#define GRPC_$filename_identifier$__INCLUDED\n");
-    printer.Print(vars, "\n");
-    printer.Print(vars, "#include \"$filename_base$.pb.h\"\n");
-    printer.Print(vars, "\n");
+    printer->Print(vars, "// source: $filename$\n");
+    printer->Print(vars, "#ifndef GRPC_$filename_identifier$__INCLUDED\n");
+    printer->Print(vars, "#define GRPC_$filename_identifier$__INCLUDED\n");
+    printer->Print(vars, "\n");
+    printer->Print(vars, "#include \"$filename_base$.pb.h\"\n");
+    printer->Print(vars, "\n");
   }
   return output;
 }
 
-grpc::string GetHeaderIncludes(const grpc::protobuf::FileDescriptor *file,
+grpc::string GetHeaderIncludes(File *file,
                                const Parameters &params) {
   grpc::string output;
   {
     // Scope the output stream so it closes and finalizes output to the string.
-    grpc::protobuf::io::StringOutputStream output_stream(&output);
-    grpc::protobuf::io::Printer printer(&output_stream, '$');
+    auto printer = file->CreatePrinter(&output);
     std::map<grpc::string, grpc::string> vars;
 
     static const char *headers_strs[] = {
@@ -151,42 +129,38 @@ grpc::string GetHeaderIncludes(const grpc::protobuf::FileDescriptor *file,
       "grpc++/impl/codegen/sync_stream.h"
     };
     std::vector<grpc::string> headers(headers_strs, array_end(headers_strs));
-    PrintIncludes(&printer, headers, params);
-    printer.Print(vars, "\n");
-    printer.Print(vars, "namespace grpc {\n");
-    printer.Print(vars, "class CompletionQueue;\n");
-    printer.Print(vars, "class Channel;\n");
-    printer.Print(vars, "class RpcService;\n");
-    printer.Print(vars, "class ServerCompletionQueue;\n");
-    printer.Print(vars, "class ServerContext;\n");
-    printer.Print(vars, "}  // namespace grpc\n\n");
+    PrintIncludes(printer.get(), headers, params);
+    printer->Print(vars, "\n");
+    printer->Print(vars, "namespace grpc {\n");
+    printer->Print(vars, "class CompletionQueue;\n");
+    printer->Print(vars, "class Channel;\n");
+    printer->Print(vars, "class RpcService;\n");
+    printer->Print(vars, "class ServerCompletionQueue;\n");
+    printer->Print(vars, "class ServerContext;\n");
+    printer->Print(vars, "}  // namespace grpc\n\n");
 
     if (!file->package().empty()) {
-      std::vector<grpc::string> parts =
-          grpc_generator::tokenize(file->package(), ".");
+      std::vector<grpc::string> parts = file->package_parts();
 
       for (auto part = parts.begin(); part != parts.end(); part++) {
         vars["part"] = *part;
-        printer.Print(vars, "namespace $part$ {\n");
+        printer->Print(vars, "namespace $part$ {\n");
       }
-      printer.Print(vars, "\n");
+      printer->Print(vars, "\n");
     }
   }
   return output;
 }
 
 void PrintHeaderClientMethodInterfaces(
-    grpc::protobuf::io::Printer *printer,
-    const grpc::protobuf::MethodDescriptor *method,
+    Printer *printer, const Method *method,
     std::map<grpc::string, grpc::string> *vars, bool is_public) {
   (*vars)["Method"] = method->name();
-  (*vars)["Request"] =
-      grpc_cpp_generator::ClassName(method->input_type(), true);
-  (*vars)["Response"] =
-      grpc_cpp_generator::ClassName(method->output_type(), true);
+  (*vars)["Request"] = method->input_type_name();
+  (*vars)["Response"] = method->output_type_name();
 
   if (is_public) {
-    if (NoStreaming(method)) {
+    if (method->NoStreaming()) {
       printer->Print(
           *vars,
           "virtual ::grpc::Status $Method$(::grpc::ClientContext* context, "
@@ -204,7 +178,7 @@ void PrintHeaderClientMethodInterfaces(
                      "Async$Method$Raw(context, request, cq));\n");
       printer->Outdent();
       printer->Print("}\n");
-    } else if (ClientOnlyStreaming(method)) {
+    } else if (method->ClientOnlyStreaming()) {
       printer->Print(
           *vars,
           "std::unique_ptr< ::grpc::ClientWriterInterface< $Request$>>"
@@ -230,7 +204,7 @@ void PrintHeaderClientMethodInterfaces(
                      "Async$Method$Raw(context, response, cq, tag));\n");
       printer->Outdent();
       printer->Print("}\n");
-    } else if (ServerOnlyStreaming(method)) {
+    } else if (method->ServerOnlyStreaming()) {
       printer->Print(
           *vars,
           "std::unique_ptr< ::grpc::ClientReaderInterface< $Response$>>"
@@ -256,7 +230,7 @@ void PrintHeaderClientMethodInterfaces(
                      "Async$Method$Raw(context, request, cq, tag));\n");
       printer->Outdent();
       printer->Print("}\n");
-    } else if (BidiStreaming(method)) {
+    } else if (method->BidiStreaming()) {
       printer->Print(*vars,
                      "std::unique_ptr< ::grpc::ClientReaderWriterInterface< "
                      "$Request$, $Response$>> "
@@ -285,14 +259,14 @@ void PrintHeaderClientMethodInterfaces(
       printer->Print("}\n");
     }
   } else {
-    if (NoStreaming(method)) {
+    if (method->NoStreaming()) {
       printer->Print(
           *vars,
           "virtual ::grpc::ClientAsyncResponseReaderInterface< $Response$>* "
           "Async$Method$Raw(::grpc::ClientContext* context, "
           "const $Request$& request, "
           "::grpc::CompletionQueue* cq) = 0;\n");
-    } else if (ClientOnlyStreaming(method)) {
+    } else if (method->ClientOnlyStreaming()) {
       printer->Print(
           *vars,
           "virtual ::grpc::ClientWriterInterface< $Request$>*"
@@ -303,7 +277,7 @@ void PrintHeaderClientMethodInterfaces(
                      " Async$Method$Raw(::grpc::ClientContext* context, "
                      "$Response$* response, "
                      "::grpc::CompletionQueue* cq, void* tag) = 0;\n");
-    } else if (ServerOnlyStreaming(method)) {
+    } else if (method->ServerOnlyStreaming()) {
       printer->Print(
           *vars,
           "virtual ::grpc::ClientReaderInterface< $Response$>* $Method$Raw("
@@ -314,7 +288,7 @@ void PrintHeaderClientMethodInterfaces(
           "Async$Method$Raw("
           "::grpc::ClientContext* context, const $Request$& request, "
           "::grpc::CompletionQueue* cq, void* tag) = 0;\n");
-    } else if (BidiStreaming(method)) {
+    } else if (method->BidiStreaming()) {
       printer->Print(*vars,
                      "virtual ::grpc::ClientReaderWriterInterface< $Request$, "
                      "$Response$>* "
@@ -328,17 +302,15 @@ void PrintHeaderClientMethodInterfaces(
   }
 }
 
-void PrintHeaderClientMethod(grpc::protobuf::io::Printer *printer,
-                             const grpc::protobuf::MethodDescriptor *method,
+void PrintHeaderClientMethod(Printer *printer,
+                             const Method *method,
                              std::map<grpc::string, grpc::string> *vars,
                              bool is_public) {
   (*vars)["Method"] = method->name();
-  (*vars)["Request"] =
-      grpc_cpp_generator::ClassName(method->input_type(), true);
-  (*vars)["Response"] =
-      grpc_cpp_generator::ClassName(method->output_type(), true);
+  (*vars)["Request"] = method->input_type_name();
+  (*vars)["Response"] = method->output_type_name();
   if (is_public) {
-    if (NoStreaming(method)) {
+    if (method->NoStreaming()) {
       printer->Print(
           *vars,
           "::grpc::Status $Method$(::grpc::ClientContext* context, "
@@ -356,7 +328,7 @@ void PrintHeaderClientMethod(grpc::protobuf::io::Printer *printer,
                      "Async$Method$Raw(context, request, cq));\n");
       printer->Outdent();
       printer->Print("}\n");
-    } else if (ClientOnlyStreaming(method)) {
+    } else if (method->ClientOnlyStreaming()) {
       printer->Print(
           *vars,
           "std::unique_ptr< ::grpc::ClientWriter< $Request$>>"
@@ -380,7 +352,7 @@ void PrintHeaderClientMethod(grpc::protobuf::io::Printer *printer,
           "Async$Method$Raw(context, response, cq, tag));\n");
       printer->Outdent();
       printer->Print("}\n");
-    } else if (ServerOnlyStreaming(method)) {
+    } else if (method->ServerOnlyStreaming()) {
       printer->Print(
           *vars,
           "std::unique_ptr< ::grpc::ClientReader< $Response$>>"
@@ -406,7 +378,7 @@ void PrintHeaderClientMethod(grpc::protobuf::io::Printer *printer,
           "Async$Method$Raw(context, request, cq, tag));\n");
       printer->Outdent();
       printer->Print("}\n");
-    } else if (BidiStreaming(method)) {
+    } else if (method->BidiStreaming()) {
       printer->Print(
           *vars,
           "std::unique_ptr< ::grpc::ClientReaderWriter< $Request$, $Response$>>"
@@ -432,13 +404,13 @@ void PrintHeaderClientMethod(grpc::protobuf::io::Printer *printer,
       printer->Print("}\n");
     }
   } else {
-    if (NoStreaming(method)) {
+    if (method->NoStreaming()) {
       printer->Print(*vars,
                      "::grpc::ClientAsyncResponseReader< $Response$>* "
                      "Async$Method$Raw(::grpc::ClientContext* context, "
                      "const $Request$& request, "
                      "::grpc::CompletionQueue* cq) GRPC_OVERRIDE;\n");
-    } else if (ClientOnlyStreaming(method)) {
+    } else if (method->ClientOnlyStreaming()) {
       printer->Print(*vars,
                      "::grpc::ClientWriter< $Request$>* $Method$Raw("
                      "::grpc::ClientContext* context, $Response$* response) "
@@ -448,7 +420,7 @@ void PrintHeaderClientMethod(grpc::protobuf::io::Printer *printer,
           "::grpc::ClientAsyncWriter< $Request$>* Async$Method$Raw("
           "::grpc::ClientContext* context, $Response$* response, "
           "::grpc::CompletionQueue* cq, void* tag) GRPC_OVERRIDE;\n");
-    } else if (ServerOnlyStreaming(method)) {
+    } else if (method->ServerOnlyStreaming()) {
       printer->Print(*vars,
                      "::grpc::ClientReader< $Response$>* $Method$Raw("
                      "::grpc::ClientContext* context, const $Request$& request)"
@@ -458,7 +430,7 @@ void PrintHeaderClientMethod(grpc::protobuf::io::Printer *printer,
           "::grpc::ClientAsyncReader< $Response$>* Async$Method$Raw("
           "::grpc::ClientContext* context, const $Request$& request, "
           "::grpc::CompletionQueue* cq, void* tag) GRPC_OVERRIDE;\n");
-    } else if (BidiStreaming(method)) {
+    } else if (method->BidiStreaming()) {
       printer->Print(
           *vars,
           "::grpc::ClientReaderWriter< $Request$, $Response$>* "
@@ -472,38 +444,34 @@ void PrintHeaderClientMethod(grpc::protobuf::io::Printer *printer,
   }
 }
 
-void PrintHeaderClientMethodData(grpc::protobuf::io::Printer *printer,
-                                 const grpc::protobuf::MethodDescriptor *method,
+void PrintHeaderClientMethodData(Printer *printer, const Method *method,
                                  std::map<grpc::string, grpc::string> *vars) {
   (*vars)["Method"] = method->name();
   printer->Print(*vars, "const ::grpc::RpcMethod rpcmethod_$Method$_;\n");
 }
 
-void PrintHeaderServerMethodSync(grpc::protobuf::io::Printer *printer,
-                                 const grpc::protobuf::MethodDescriptor *method,
+void PrintHeaderServerMethodSync(Printer *printer, const Method *method,
                                  std::map<grpc::string, grpc::string> *vars) {
   (*vars)["Method"] = method->name();
-  (*vars)["Request"] =
-      grpc_cpp_generator::ClassName(method->input_type(), true);
-  (*vars)["Response"] =
-      grpc_cpp_generator::ClassName(method->output_type(), true);
-  if (NoStreaming(method)) {
+  (*vars)["Request"] = method->input_type_name();
+  (*vars)["Response"] = method->output_type_name();
+  if (method->NoStreaming()) {
     printer->Print(*vars,
                    "virtual ::grpc::Status $Method$("
                    "::grpc::ServerContext* context, const $Request$* request, "
                    "$Response$* response);\n");
-  } else if (ClientOnlyStreaming(method)) {
+  } else if (method->ClientOnlyStreaming()) {
     printer->Print(*vars,
                    "virtual ::grpc::Status $Method$("
                    "::grpc::ServerContext* context, "
                    "::grpc::ServerReader< $Request$>* reader, "
                    "$Response$* response);\n");
-  } else if (ServerOnlyStreaming(method)) {
+  } else if (method->ServerOnlyStreaming()) {
     printer->Print(*vars,
                    "virtual ::grpc::Status $Method$("
                    "::grpc::ServerContext* context, const $Request$* request, "
                    "::grpc::ServerWriter< $Response$>* writer);\n");
-  } else if (BidiStreaming(method)) {
+  } else if (method->BidiStreaming()) {
     printer->Print(
         *vars,
         "virtual ::grpc::Status $Method$("
@@ -514,20 +482,18 @@ void PrintHeaderServerMethodSync(grpc::protobuf::io::Printer *printer,
 }
 
 void PrintHeaderServerMethodAsync(
-    grpc::protobuf::io::Printer *printer,
-    const grpc::protobuf::MethodDescriptor *method,
+    Printer *printer,
+    const Method *method,
     std::map<grpc::string, grpc::string> *vars) {
   (*vars)["Method"] = method->name();
-  (*vars)["Request"] =
-      grpc_cpp_generator::ClassName(method->input_type(), true);
-  (*vars)["Response"] =
-      grpc_cpp_generator::ClassName(method->output_type(), true);
+  (*vars)["Request"] = method->input_type_name();
+  (*vars)["Response"] = method->output_type_name();
   printer->Print(*vars, "template <class BaseClass>\n");
   printer->Print(*vars,
                  "class WithAsyncMethod_$Method$ : public BaseClass {\n");
   printer->Print(
       " private:\n"
-      "  void BaseClassMustBeDerivedFromService(Service *service) {}\n");
+      "  void BaseClassMustBeDerivedFromService(const Service *service) {}\n");
   printer->Print(" public:\n");
   printer->Indent();
   printer->Print(*vars,
@@ -538,7 +504,7 @@ void PrintHeaderServerMethodAsync(
                  "~WithAsyncMethod_$Method$() GRPC_OVERRIDE {\n"
                  "  BaseClassMustBeDerivedFromService(this);\n"
                  "}\n");
-  if (NoStreaming(method)) {
+  if (method->NoStreaming()) {
     printer->Print(
         *vars,
         "// disable synchronous version of this method\n"
@@ -559,7 +525,7 @@ void PrintHeaderServerMethodAsync(
                    "  ::grpc::Service::RequestAsyncUnary($Idx$, context, "
                    "request, response, new_call_cq, notification_cq, tag);\n");
     printer->Print("}\n");
-  } else if (ClientOnlyStreaming(method)) {
+  } else if (method->ClientOnlyStreaming()) {
     printer->Print(
         *vars,
         "// disable synchronous version of this method\n"
@@ -581,7 +547,7 @@ void PrintHeaderServerMethodAsync(
                    "  ::grpc::Service::RequestAsyncClientStreaming($Idx$, "
                    "context, reader, new_call_cq, notification_cq, tag);\n");
     printer->Print("}\n");
-  } else if (ServerOnlyStreaming(method)) {
+  } else if (method->ServerOnlyStreaming()) {
     printer->Print(
         *vars,
         "// disable synchronous version of this method\n"
@@ -604,7 +570,7 @@ void PrintHeaderServerMethodAsync(
         "  ::grpc::Service::RequestAsyncServerStreaming($Idx$, "
         "context, request, writer, new_call_cq, notification_cq, tag);\n");
     printer->Print("}\n");
-  } else if (BidiStreaming(method)) {
+  } else if (method->BidiStreaming()) {
     printer->Print(
         *vars,
         "// disable synchronous version of this method\n"
@@ -632,20 +598,18 @@ void PrintHeaderServerMethodAsync(
 }
 
 void PrintHeaderServerMethodGeneric(
-    grpc::protobuf::io::Printer *printer,
-    const grpc::protobuf::MethodDescriptor *method,
+    Printer *printer,
+    const Method *method,
     std::map<grpc::string, grpc::string> *vars) {
   (*vars)["Method"] = method->name();
-  (*vars)["Request"] =
-      grpc_cpp_generator::ClassName(method->input_type(), true);
-  (*vars)["Response"] =
-      grpc_cpp_generator::ClassName(method->output_type(), true);
+  (*vars)["Request"] = method->input_type_name();
+  (*vars)["Response"] = method->output_type_name();
   printer->Print(*vars, "template <class BaseClass>\n");
   printer->Print(*vars,
                  "class WithGenericMethod_$Method$ : public BaseClass {\n");
   printer->Print(
       " private:\n"
-      "  void BaseClassMustBeDerivedFromService(Service *service) {}\n");
+      "  void BaseClassMustBeDerivedFromService(const Service *service) {}\n");
   printer->Print(" public:\n");
   printer->Indent();
   printer->Print(*vars,
@@ -656,7 +620,7 @@ void PrintHeaderServerMethodGeneric(
                  "~WithGenericMethod_$Method$() GRPC_OVERRIDE {\n"
                  "  BaseClassMustBeDerivedFromService(this);\n"
                  "}\n");
-  if (NoStreaming(method)) {
+  if (method->NoStreaming()) {
     printer->Print(
         *vars,
         "// disable synchronous version of this method\n"
@@ -666,7 +630,7 @@ void PrintHeaderServerMethodGeneric(
         "  abort();\n"
         "  return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
         "}\n");
-  } else if (ClientOnlyStreaming(method)) {
+  } else if (method->ClientOnlyStreaming()) {
     printer->Print(
         *vars,
         "// disable synchronous version of this method\n"
@@ -677,7 +641,7 @@ void PrintHeaderServerMethodGeneric(
         "  abort();\n"
         "  return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
         "}\n");
-  } else if (ServerOnlyStreaming(method)) {
+  } else if (method->ServerOnlyStreaming()) {
     printer->Print(
         *vars,
         "// disable synchronous version of this method\n"
@@ -688,7 +652,7 @@ void PrintHeaderServerMethodGeneric(
         "  abort();\n"
         "  return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
         "}\n");
-  } else if (BidiStreaming(method)) {
+  } else if (method->BidiStreaming()) {
     printer->Print(
         *vars,
         "// disable synchronous version of this method\n"
@@ -704,8 +668,8 @@ void PrintHeaderServerMethodGeneric(
   printer->Print(*vars, "};\n");
 }
 
-void PrintHeaderService(grpc::protobuf::io::Printer *printer,
-                        const grpc::protobuf::ServiceDescriptor *service,
+void PrintHeaderService(Printer *printer,
+                        const Service *service,
                         std::map<grpc::string, grpc::string> *vars) {
   (*vars)["Service"] = service->name();
 
@@ -721,13 +685,13 @@ void PrintHeaderService(grpc::protobuf::io::Printer *printer,
   printer->Indent();
   printer->Print("virtual ~StubInterface() {}\n");
   for (int i = 0; i < service->method_count(); ++i) {
-    PrintHeaderClientMethodInterfaces(printer, service->method(i), vars, true);
+    PrintHeaderClientMethodInterfaces(printer, service->method(i).get(), vars, true);
   }
   printer->Outdent();
   printer->Print("private:\n");
   printer->Indent();
   for (int i = 0; i < service->method_count(); ++i) {
-    PrintHeaderClientMethodInterfaces(printer, service->method(i), vars, false);
+    PrintHeaderClientMethodInterfaces(printer, service->method(i).get(), vars, false);
   }
   printer->Outdent();
   printer->Print("};\n");
@@ -737,17 +701,17 @@ void PrintHeaderService(grpc::protobuf::io::Printer *printer,
   printer->Indent();
   printer->Print("Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel);\n");
   for (int i = 0; i < service->method_count(); ++i) {
-    PrintHeaderClientMethod(printer, service->method(i), vars, true);
+    PrintHeaderClientMethod(printer, service->method(i).get(), vars, true);
   }
   printer->Outdent();
   printer->Print("\n private:\n");
   printer->Indent();
   printer->Print("std::shared_ptr< ::grpc::ChannelInterface> channel_;\n");
   for (int i = 0; i < service->method_count(); ++i) {
-    PrintHeaderClientMethod(printer, service->method(i), vars, false);
+    PrintHeaderClientMethod(printer, service->method(i).get(), vars, false);
   }
   for (int i = 0; i < service->method_count(); ++i) {
-    PrintHeaderClientMethodData(printer, service->method(i), vars);
+    PrintHeaderClientMethodData(printer, service->method(i).get(), vars);
   }
   printer->Outdent();
   printer->Print("};\n");
@@ -766,7 +730,7 @@ void PrintHeaderService(grpc::protobuf::io::Printer *printer,
   printer->Print("Service();\n");
   printer->Print("virtual ~Service();\n");
   for (int i = 0; i < service->method_count(); ++i) {
-    PrintHeaderServerMethodSync(printer, service->method(i), vars);
+    PrintHeaderServerMethodSync(printer, service->method(i).get(), vars);
   }
   printer->Outdent();
   printer->Print("};\n");
@@ -774,13 +738,13 @@ void PrintHeaderService(grpc::protobuf::io::Printer *printer,
   // Server side - Asynchronous
   for (int i = 0; i < service->method_count(); ++i) {
     (*vars)["Idx"] = as_string(i);
-    PrintHeaderServerMethodAsync(printer, service->method(i), vars);
+    PrintHeaderServerMethodAsync(printer, service->method(i).get(), vars);
   }
 
   printer->Print("typedef ");
 
   for (int i = 0; i < service->method_count(); ++i) {
-    (*vars)["method_name"] = service->method(i)->name();
+    (*vars)["method_name"] = service->method(i).get()->name();
     printer->Print(*vars, "WithAsyncMethod_$method_name$<");
   }
   printer->Print("Service");
@@ -792,20 +756,19 @@ void PrintHeaderService(grpc::protobuf::io::Printer *printer,
   // Server side - Generic
   for (int i = 0; i < service->method_count(); ++i) {
     (*vars)["Idx"] = as_string(i);
-    PrintHeaderServerMethodGeneric(printer, service->method(i), vars);
+    PrintHeaderServerMethodGeneric(printer, service->method(i).get(), vars);
   }
 
   printer->Outdent();
   printer->Print("};\n");
 }
 
-grpc::string GetHeaderServices(const grpc::protobuf::FileDescriptor *file,
+grpc::string GetHeaderServices(File *file,
                                const Parameters &params) {
   grpc::string output;
   {
     // Scope the output stream so it closes and finalizes output to the string.
-    grpc::protobuf::io::StringOutputStream output_stream(&output);
-    grpc::protobuf::io::Printer printer(&output_stream, '$');
+    auto printer = file->CreatePrinter(&output);
     std::map<grpc::string, grpc::string> vars;
     // Package string is empty or ends with a dot. It is used to fully qualify
     // method names.
@@ -816,80 +779,76 @@ grpc::string GetHeaderServices(const grpc::protobuf::FileDescriptor *file,
 
     if (!params.services_namespace.empty()) {
       vars["services_namespace"] = params.services_namespace;
-      printer.Print(vars, "\nnamespace $services_namespace$ {\n\n");
+      printer->Print(vars, "\nnamespace $services_namespace$ {\n\n");
     }
 
     for (int i = 0; i < file->service_count(); ++i) {
-      PrintHeaderService(&printer, file->service(i), &vars);
-      printer.Print("\n");
+      PrintHeaderService(printer.get(), file->service(i).get(), &vars);
+      printer->Print("\n");
     }
 
     if (!params.services_namespace.empty()) {
-      printer.Print(vars, "}  // namespace $services_namespace$\n\n");
+      printer->Print(vars, "}  // namespace $services_namespace$\n\n");
     }
   }
   return output;
 }
 
-grpc::string GetHeaderEpilogue(const grpc::protobuf::FileDescriptor *file,
+grpc::string GetHeaderEpilogue(File *file,
                                const Parameters &params) {
   grpc::string output;
   {
     // Scope the output stream so it closes and finalizes output to the string.
-    grpc::protobuf::io::StringOutputStream output_stream(&output);
-    grpc::protobuf::io::Printer printer(&output_stream, '$');
+    auto printer = file->CreatePrinter(&output);
     std::map<grpc::string, grpc::string> vars;
 
-    vars["filename"] = file->name();
-    vars["filename_identifier"] = FilenameIdentifier(file->name());
+    vars["filename"] = file->filename();
+    vars["filename_identifier"] = FilenameIdentifier(file->filename());
 
     if (!file->package().empty()) {
-      std::vector<grpc::string> parts =
-          grpc_generator::tokenize(file->package(), ".");
+      std::vector<grpc::string> parts = file->package_parts();
 
       for (auto part = parts.rbegin(); part != parts.rend(); part++) {
         vars["part"] = *part;
-        printer.Print(vars, "}  // namespace $part$\n");
+        printer->Print(vars, "}  // namespace $part$\n");
       }
-      printer.Print(vars, "\n");
+      printer->Print(vars, "\n");
     }
 
-    printer.Print(vars, "\n");
-    printer.Print(vars, "#endif  // GRPC_$filename_identifier$__INCLUDED\n");
+    printer->Print(vars, "\n");
+    printer->Print(vars, "#endif  // GRPC_$filename_identifier$__INCLUDED\n");
   }
   return output;
 }
 
-grpc::string GetSourcePrologue(const grpc::protobuf::FileDescriptor *file,
+grpc::string GetSourcePrologue(File *file,
                                const Parameters &params) {
   grpc::string output;
   {
     // Scope the output stream so it closes and finalizes output to the string.
-    grpc::protobuf::io::StringOutputStream output_stream(&output);
-    grpc::protobuf::io::Printer printer(&output_stream, '$');
+    auto printer = file->CreatePrinter(&output);
     std::map<grpc::string, grpc::string> vars;
 
-    vars["filename"] = file->name();
-    vars["filename_base"] = grpc_generator::StripProto(file->name());
+    vars["filename"] = file->filename();
+    vars["filename_base"] = file->filename_without_ext();
 
-    printer.Print(vars, "// Generated by the gRPC protobuf plugin.\n");
-    printer.Print(vars,
+    printer->Print(vars, "// Generated by the gRPC protobuf plugin.\n");
+    printer->Print(vars,
                   "// If you make any local change, they will be lost.\n");
-    printer.Print(vars, "// source: $filename$\n\n");
-    printer.Print(vars, "#include \"$filename_base$.pb.h\"\n");
-    printer.Print(vars, "#include \"$filename_base$.grpc.pb.h\"\n");
-    printer.Print(vars, "\n");
+    printer->Print(vars, "// source: $filename$\n\n");
+    printer->Print(vars, "#include \"$filename_base$.pb.h\"\n");
+    printer->Print(vars, "#include \"$filename_base$.grpc.pb.h\"\n");
+    printer->Print(vars, "\n");
   }
   return output;
 }
 
-grpc::string GetSourceIncludes(const grpc::protobuf::FileDescriptor *file,
+grpc::string GetSourceIncludes(File *file,
                                const Parameters &params) {
   grpc::string output;
   {
     // Scope the output stream so it closes and finalizes output to the string.
-    grpc::protobuf::io::StringOutputStream output_stream(&output);
-    grpc::protobuf::io::Printer printer(&output_stream, '$');
+    auto printer = file->CreatePrinter(&output);
     std::map<grpc::string, grpc::string> vars;
 
     static const char *headers_strs[] = {
@@ -903,32 +862,29 @@ grpc::string GetSourceIncludes(const grpc::protobuf::FileDescriptor *file,
       "grpc++/impl/codegen/sync_stream.h"
     };
     std::vector<grpc::string> headers(headers_strs, array_end(headers_strs));
-    PrintIncludes(&printer, headers, params);
+    PrintIncludes(printer.get(), headers, params);
 
     if (!file->package().empty()) {
-      std::vector<grpc::string> parts =
-          grpc_generator::tokenize(file->package(), ".");
+      std::vector<grpc::string> parts = file->package_parts();
 
       for (auto part = parts.begin(); part != parts.end(); part++) {
         vars["part"] = *part;
-        printer.Print(vars, "namespace $part$ {\n");
+        printer->Print(vars, "namespace $part$ {\n");
       }
     }
 
-    printer.Print(vars, "\n");
+    printer->Print(vars, "\n");
   }
   return output;
 }
 
-void PrintSourceClientMethod(grpc::protobuf::io::Printer *printer,
-                             const grpc::protobuf::MethodDescriptor *method,
+void PrintSourceClientMethod(Printer *printer,
+                             const Method *method,
                              std::map<grpc::string, grpc::string> *vars) {
   (*vars)["Method"] = method->name();
-  (*vars)["Request"] =
-      grpc_cpp_generator::ClassName(method->input_type(), true);
-  (*vars)["Response"] =
-      grpc_cpp_generator::ClassName(method->output_type(), true);
-  if (NoStreaming(method)) {
+  (*vars)["Request"] = method->input_type_name();
+  (*vars)["Response"] = method->output_type_name();
+  if (method->NoStreaming()) {
     printer->Print(*vars,
                    "::grpc::Status $ns$$Service$::Stub::$Method$("
                    "::grpc::ClientContext* context, "
@@ -951,7 +907,7 @@ void PrintSourceClientMethod(grpc::protobuf::io::Printer *printer,
                    "rpcmethod_$Method$_, "
                    "context, request);\n"
                    "}\n\n");
-  } else if (ClientOnlyStreaming(method)) {
+  } else if (method->ClientOnlyStreaming()) {
     printer->Print(*vars,
                    "::grpc::ClientWriter< $Request$>* "
                    "$ns$$Service$::Stub::$Method$Raw("
@@ -973,7 +929,7 @@ void PrintSourceClientMethod(grpc::protobuf::io::Printer *printer,
                    "rpcmethod_$Method$_, "
                    "context, response, tag);\n"
                    "}\n\n");
-  } else if (ServerOnlyStreaming(method)) {
+  } else if (method->ServerOnlyStreaming()) {
     printer->Print(
         *vars,
         "::grpc::ClientReader< $Response$>* "
@@ -996,7 +952,7 @@ void PrintSourceClientMethod(grpc::protobuf::io::Printer *printer,
                    "rpcmethod_$Method$_, "
                    "context, request, tag);\n"
                    "}\n\n");
-  } else if (BidiStreaming(method)) {
+  } else if (method->BidiStreaming()) {
     printer->Print(
         *vars,
         "::grpc::ClientReaderWriter< $Request$, $Response$>* "
@@ -1023,15 +979,13 @@ void PrintSourceClientMethod(grpc::protobuf::io::Printer *printer,
   }
 }
 
-void PrintSourceServerMethod(grpc::protobuf::io::Printer *printer,
-                             const grpc::protobuf::MethodDescriptor *method,
+void PrintSourceServerMethod(Printer *printer,
+                             const Method *method,
                              std::map<grpc::string, grpc::string> *vars) {
   (*vars)["Method"] = method->name();
-  (*vars)["Request"] =
-      grpc_cpp_generator::ClassName(method->input_type(), true);
-  (*vars)["Response"] =
-      grpc_cpp_generator::ClassName(method->output_type(), true);
-  if (NoStreaming(method)) {
+  (*vars)["Request"] = method->input_type_name();
+  (*vars)["Response"] = method->output_type_name();
+  if (method->NoStreaming()) {
     printer->Print(*vars,
                    "::grpc::Status $ns$$Service$::Service::$Method$("
                    "::grpc::ServerContext* context, "
@@ -1043,7 +997,7 @@ void PrintSourceServerMethod(grpc::protobuf::io::Printer *printer,
         "  return ::grpc::Status("
         "::grpc::StatusCode::UNIMPLEMENTED, \"\");\n");
     printer->Print("}\n\n");
-  } else if (ClientOnlyStreaming(method)) {
+  } else if (method->ClientOnlyStreaming()) {
     printer->Print(*vars,
                    "::grpc::Status $ns$$Service$::Service::$Method$("
                    "::grpc::ServerContext* context, "
@@ -1056,7 +1010,7 @@ void PrintSourceServerMethod(grpc::protobuf::io::Printer *printer,
         "  return ::grpc::Status("
         "::grpc::StatusCode::UNIMPLEMENTED, \"\");\n");
     printer->Print("}\n\n");
-  } else if (ServerOnlyStreaming(method)) {
+  } else if (method->ServerOnlyStreaming()) {
     printer->Print(*vars,
                    "::grpc::Status $ns$$Service$::Service::$Method$("
                    "::grpc::ServerContext* context, "
@@ -1069,7 +1023,7 @@ void PrintSourceServerMethod(grpc::protobuf::io::Printer *printer,
         "  return ::grpc::Status("
         "::grpc::StatusCode::UNIMPLEMENTED, \"\");\n");
     printer->Print("}\n\n");
-  } else if (BidiStreaming(method)) {
+  } else if (method->BidiStreaming()) {
     printer->Print(*vars,
                    "::grpc::Status $ns$$Service$::Service::$Method$("
                    "::grpc::ServerContext* context, "
@@ -1084,15 +1038,15 @@ void PrintSourceServerMethod(grpc::protobuf::io::Printer *printer,
   }
 }
 
-void PrintSourceService(grpc::protobuf::io::Printer *printer,
-                        const grpc::protobuf::ServiceDescriptor *service,
+void PrintSourceService(Printer *printer,
+                        const Service *service,
                         std::map<grpc::string, grpc::string> *vars) {
   (*vars)["Service"] = service->name();
 
   printer->Print(*vars,
                  "static const char* $prefix$$Service$_method_names[] = {\n");
   for (int i = 0; i < service->method_count(); ++i) {
-    (*vars)["Method"] = service->method(i)->name();
+    (*vars)["Method"] = service->method(i).get()->name();
     printer->Print(*vars, "  \"/$Package$$Service$/$Method$\",\n");
   }
   printer->Print(*vars, "};\n\n");
@@ -1111,14 +1065,14 @@ void PrintSourceService(grpc::protobuf::io::Printer *printer,
   printer->Indent();
   printer->Print(": channel_(channel)");
   for (int i = 0; i < service->method_count(); ++i) {
-    const grpc::protobuf::MethodDescriptor *method = service->method(i);
+    auto method = service->method(i);
     (*vars)["Method"] = method->name();
     (*vars)["Idx"] = as_string(i);
-    if (NoStreaming(method)) {
+    if (method->NoStreaming()) {
       (*vars)["StreamingType"] = "NORMAL_RPC";
-    } else if (ClientOnlyStreaming(method)) {
+    } else if (method->ClientOnlyStreaming()) {
       (*vars)["StreamingType"] = "CLIENT_STREAMING";
-    } else if (ServerOnlyStreaming(method)) {
+    } else if (method->ServerOnlyStreaming()) {
       (*vars)["StreamingType"] = "SERVER_STREAMING";
     } else {
       (*vars)["StreamingType"] = "BIDI_STREAMING";
@@ -1135,21 +1089,19 @@ void PrintSourceService(grpc::protobuf::io::Printer *printer,
 
   for (int i = 0; i < service->method_count(); ++i) {
     (*vars)["Idx"] = as_string(i);
-    PrintSourceClientMethod(printer, service->method(i), vars);
+    PrintSourceClientMethod(printer, service->method(i).get(), vars);
   }
 
   printer->Print(*vars, "$ns$$Service$::Service::Service() {\n");
   printer->Indent();
   printer->Print(*vars, "(void)$prefix$$Service$_method_names;\n");
   for (int i = 0; i < service->method_count(); ++i) {
-    const grpc::protobuf::MethodDescriptor *method = service->method(i);
+    auto method = service->method(i);
     (*vars)["Idx"] = as_string(i);
     (*vars)["Method"] = method->name();
-    (*vars)["Request"] =
-        grpc_cpp_generator::ClassName(method->input_type(), true);
-    (*vars)["Response"] =
-        grpc_cpp_generator::ClassName(method->output_type(), true);
-    if (NoStreaming(method)) {
+    (*vars)["Request"] = method->input_type_name();
+    (*vars)["Response"] = method->output_type_name();
+    if (method->NoStreaming()) {
       printer->Print(
           *vars,
           "AddMethod(new ::grpc::RpcServiceMethod(\n"
@@ -1159,7 +1111,7 @@ void PrintSourceService(grpc::protobuf::io::Printer *printer,
           "$Request$, "
           "$Response$>(\n"
           "        std::mem_fn(&$ns$$Service$::Service::$Method$), this)));\n");
-    } else if (ClientOnlyStreaming(method)) {
+    } else if (method->ClientOnlyStreaming()) {
       printer->Print(
           *vars,
           "AddMethod(new ::grpc::RpcServiceMethod(\n"
@@ -1168,7 +1120,7 @@ void PrintSourceService(grpc::protobuf::io::Printer *printer,
           "    new ::grpc::ClientStreamingHandler< "
           "$ns$$Service$::Service, $Request$, $Response$>(\n"
           "        std::mem_fn(&$ns$$Service$::Service::$Method$), this)));\n");
-    } else if (ServerOnlyStreaming(method)) {
+    } else if (method->ServerOnlyStreaming()) {
       printer->Print(
           *vars,
           "AddMethod(new ::grpc::RpcServiceMethod(\n"
@@ -1177,7 +1129,7 @@ void PrintSourceService(grpc::protobuf::io::Printer *printer,
           "    new ::grpc::ServerStreamingHandler< "
           "$ns$$Service$::Service, $Request$, $Response$>(\n"
           "        std::mem_fn(&$ns$$Service$::Service::$Method$), this)));\n");
-    } else if (BidiStreaming(method)) {
+    } else if (method->BidiStreaming()) {
       printer->Print(
           *vars,
           "AddMethod(new ::grpc::RpcServiceMethod(\n"
@@ -1195,17 +1147,16 @@ void PrintSourceService(grpc::protobuf::io::Printer *printer,
                  "}\n\n");
   for (int i = 0; i < service->method_count(); ++i) {
     (*vars)["Idx"] = as_string(i);
-    PrintSourceServerMethod(printer, service->method(i), vars);
+    PrintSourceServerMethod(printer, service->method(i).get(), vars);
   }
 }
 
-grpc::string GetSourceServices(const grpc::protobuf::FileDescriptor *file,
+grpc::string GetSourceServices(File *file,
                                const Parameters &params) {
   grpc::string output;
   {
     // Scope the output stream so it closes and finalizes output to the string.
-    grpc::protobuf::io::StringOutputStream output_stream(&output);
-    grpc::protobuf::io::Printer printer(&output_stream, '$');
+    auto printer = file->CreatePrinter(&output);
     std::map<grpc::string, grpc::string> vars;
     // Package string is empty or ends with a dot. It is used to fully qualify
     // method names.
@@ -1222,20 +1173,19 @@ grpc::string GetSourceServices(const grpc::protobuf::FileDescriptor *file,
     }
 
     for (int i = 0; i < file->service_count(); ++i) {
-      PrintSourceService(&printer, file->service(i), &vars);
-      printer.Print("\n");
+      PrintSourceService(printer.get(), file->service(i).get(), &vars);
+      printer->Print("\n");
     }
   }
   return output;
 }
 
-grpc::string GetSourceEpilogue(const grpc::protobuf::FileDescriptor *file,
+grpc::string GetSourceEpilogue(File *file,
                                const Parameters &params) {
   grpc::string temp;
 
   if (!file->package().empty()) {
-    std::vector<grpc::string> parts =
-        grpc_generator::tokenize(file->package(), ".");
+    std::vector<grpc::string> parts = file->package_parts();
 
     for (auto part = parts.begin(); part != parts.end(); part++) {
       temp.append("}  // namespace ");
diff --git a/src/compiler/cpp_generator.h b/src/compiler/cpp_generator.h
index 03621c8794ce10965629e0e4e7df0cbf176badb1..99a60a2eaec6828a64f8659f11cf36694745041b 100644
--- a/src/compiler/cpp_generator.h
+++ b/src/compiler/cpp_generator.h
@@ -34,7 +34,23 @@
 #ifndef GRPC_INTERNAL_COMPILER_CPP_GENERATOR_H
 #define GRPC_INTERNAL_COMPILER_CPP_GENERATOR_H
 
-#include "src/compiler/config.h"
+// cpp_generator.h/.cc do not directly depend on GRPC/ProtoBuf, such that they
+// can be used to generate code for other serialization systems, such as
+// FlatBuffers.
+
+#include <memory>
+#include <vector>
+
+#ifndef GRPC_CUSTOM_STRING
+#include <string>
+#define GRPC_CUSTOM_STRING std::string
+#endif
+
+namespace grpc {
+
+typedef GRPC_CUSTOM_STRING string;
+
+}  // namespace grpc
 
 namespace grpc_cpp_generator {
 
@@ -48,37 +64,80 @@ struct Parameters {
   grpc::string grpc_search_path;
 };
 
+// An abstract interface representing a method.
+struct Method {
+  virtual ~Method() {}
+
+  virtual grpc::string name() const = 0;
+
+  virtual grpc::string input_type_name() const = 0;
+  virtual grpc::string output_type_name() const = 0;
+
+  virtual bool NoStreaming() const = 0;
+  virtual bool ClientOnlyStreaming() const = 0;
+  virtual bool ServerOnlyStreaming() const = 0;
+  virtual bool BidiStreaming() const = 0;
+};
+
+// An abstract interface representing a service.
+struct Service {
+  virtual ~Service() {}
+
+  virtual grpc::string name() const = 0;
+
+  virtual int method_count() const = 0;
+  virtual std::unique_ptr<const Method> method(int i) const = 0;
+};
+
+struct Printer {
+  virtual ~Printer() {}
+
+  virtual void Print(const std::map<grpc::string, grpc::string> &vars,
+                     const char *template_string) = 0;
+  virtual void Print(const char *string) = 0;
+  virtual void Indent() = 0;
+  virtual void Outdent() = 0;
+};
+
+// An interface that allows the source generated to be output using various
+// libraries/idls/serializers.
+struct File {
+  virtual ~File() {}
+
+  virtual grpc::string filename() const = 0;
+  virtual grpc::string filename_without_ext() const = 0;
+  virtual grpc::string package() const = 0;
+  virtual std::vector<grpc::string> package_parts() const = 0;
+
+  virtual int service_count() const = 0;
+  virtual std::unique_ptr<const Service> service(int i) const = 0;
+
+  virtual std::unique_ptr<Printer> CreatePrinter(grpc::string *str) const = 0;
+};
+
 // Return the prologue of the generated header file.
-grpc::string GetHeaderPrologue(const grpc::protobuf::FileDescriptor *file,
-                               const Parameters &params);
+grpc::string GetHeaderPrologue(File *file, const Parameters &params);
 
 // Return the includes needed for generated header file.
-grpc::string GetHeaderIncludes(const grpc::protobuf::FileDescriptor *file,
-                               const Parameters &params);
+grpc::string GetHeaderIncludes(File *file, const Parameters &params);
 
 // Return the includes needed for generated source file.
-grpc::string GetSourceIncludes(const grpc::protobuf::FileDescriptor *file,
-                               const Parameters &params);
+grpc::string GetSourceIncludes(File *file, const Parameters &params);
 
 // Return the epilogue of the generated header file.
-grpc::string GetHeaderEpilogue(const grpc::protobuf::FileDescriptor *file,
-                               const Parameters &params);
+grpc::string GetHeaderEpilogue(File *file, const Parameters &params);
 
 // Return the prologue of the generated source file.
-grpc::string GetSourcePrologue(const grpc::protobuf::FileDescriptor *file,
-                               const Parameters &params);
+grpc::string GetSourcePrologue(File *file, const Parameters &params);
 
 // Return the services for generated header file.
-grpc::string GetHeaderServices(const grpc::protobuf::FileDescriptor *file,
-                               const Parameters &params);
+grpc::string GetHeaderServices(File *file, const Parameters &params);
 
 // Return the services for generated source file.
-grpc::string GetSourceServices(const grpc::protobuf::FileDescriptor *file,
-                               const Parameters &params);
+grpc::string GetSourceServices(File *file, const Parameters &params);
 
 // Return the epilogue of the generated source file.
-grpc::string GetSourceEpilogue(const grpc::protobuf::FileDescriptor *file,
-                               const Parameters &params);
+grpc::string GetSourceEpilogue(File *file, const Parameters &params);
 
 }  // namespace grpc_cpp_generator
 
diff --git a/src/compiler/cpp_plugin.cc b/src/compiler/cpp_plugin.cc
index 92a9ba754918f894d49e3abc5d9da91657b887d4..f703c6453d5f6d8c54d9c47a11b2a176c98a8102 100644
--- a/src/compiler/cpp_plugin.cc
+++ b/src/compiler/cpp_plugin.cc
@@ -41,6 +41,105 @@
 #include "src/compiler/cpp_generator.h"
 #include "src/compiler/cpp_generator_helpers.h"
 
+class ProtoBufMethod : public grpc_cpp_generator::Method {
+ public:
+  ProtoBufMethod(const grpc::protobuf::MethodDescriptor *method)
+    : method_(method) {}
+
+  grpc::string name() const { return method_->name(); }
+
+  grpc::string input_type_name() const {
+    return grpc_cpp_generator::ClassName(method_->input_type(), true);
+  }
+  grpc::string output_type_name() const {
+    return grpc_cpp_generator::ClassName(method_->output_type(), true);
+  }
+
+  bool NoStreaming() const {
+    return !method_->client_streaming() && !method_->server_streaming();
+  }
+
+  bool ClientOnlyStreaming() const {
+    return method_->client_streaming() && !method_->server_streaming();
+  }
+
+  bool ServerOnlyStreaming() const {
+    return !method_->client_streaming() && method_->server_streaming();
+  }
+
+  bool BidiStreaming() const {
+    return method_->client_streaming() && method_->server_streaming();
+  }
+
+ private:
+  const grpc::protobuf::MethodDescriptor *method_;
+};
+
+class ProtoBufService : public grpc_cpp_generator::Service {
+ public:
+  ProtoBufService(const grpc::protobuf::ServiceDescriptor *service)
+    : service_(service) {}
+
+  grpc::string name() const { return service_->name(); }
+
+  int method_count() const { return service_->method_count(); };
+  std::unique_ptr<const grpc_cpp_generator::Method> method(int i) const {
+    return std::unique_ptr<const grpc_cpp_generator::Method>(
+          new ProtoBufMethod(service_->method(i)));
+  };
+
+ private:
+  const grpc::protobuf::ServiceDescriptor *service_;
+};
+
+class ProtoBufPrinter : public grpc_cpp_generator::Printer {
+ public:
+  ProtoBufPrinter(grpc::string *str)
+    : output_stream_(str), printer_(&output_stream_, '$') {}
+
+  void Print(const std::map<grpc::string, grpc::string> &vars,
+             const char *string_template) {
+    printer_.Print(vars, string_template);
+  }
+
+  void Print(const char *string) { printer_.Print(string); }
+  void Indent() { printer_.Indent(); }
+  void Outdent() { printer_.Outdent(); }
+
+ private:
+  grpc::protobuf::io::StringOutputStream output_stream_;
+  grpc::protobuf::io::Printer printer_;
+};
+
+class ProtoBufFile : public grpc_cpp_generator::File {
+ public:
+  ProtoBufFile(const grpc::protobuf::FileDescriptor *file) : file_(file) {}
+
+  grpc::string filename() const { return file_->name(); }
+  grpc::string filename_without_ext() const {
+    return grpc_generator::StripProto(filename());
+  }
+
+  grpc::string package() const { return file_->package(); }
+  std::vector<grpc::string> package_parts() const {
+    return grpc_generator::tokenize(package(), ".");
+  }
+
+  int service_count() const { return file_->service_count(); };
+  std::unique_ptr<const grpc_cpp_generator::Service> service(int i) const {
+    return std::unique_ptr<const grpc_cpp_generator::Service> (
+          new ProtoBufService(file_->service(i)));
+  }
+
+  std::unique_ptr<grpc_cpp_generator::Printer> CreatePrinter(grpc::string *str) const {
+    return std::unique_ptr<grpc_cpp_generator::Printer>(
+          new ProtoBufPrinter(str));
+  }
+
+ private:
+  const grpc::protobuf::FileDescriptor *file_;
+};
+
 class CppGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
  public:
   CppGrpcGenerator() {}
@@ -61,6 +160,8 @@ class CppGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
     grpc_cpp_generator::Parameters generator_parameters;
     generator_parameters.use_system_headers = true;
 
+    ProtoBufFile pbfile(file);
+
     if (!parameter.empty()) {
       std::vector<grpc::string> parameters_list =
         grpc_generator::tokenize(parameter, ",");
@@ -92,10 +193,10 @@ class CppGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
     grpc::string file_name = grpc_generator::StripProto(file->name());
 
     grpc::string header_code =
-        grpc_cpp_generator::GetHeaderPrologue(file, generator_parameters) +
-        grpc_cpp_generator::GetHeaderIncludes(file, generator_parameters) +
-        grpc_cpp_generator::GetHeaderServices(file, generator_parameters) +
-        grpc_cpp_generator::GetHeaderEpilogue(file, generator_parameters);
+        grpc_cpp_generator::GetHeaderPrologue(&pbfile, generator_parameters) +
+        grpc_cpp_generator::GetHeaderIncludes(&pbfile, generator_parameters) +
+        grpc_cpp_generator::GetHeaderServices(&pbfile, generator_parameters) +
+        grpc_cpp_generator::GetHeaderEpilogue(&pbfile, generator_parameters);
     std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> header_output(
         context->Open(file_name + ".grpc.pb.h"));
     grpc::protobuf::io::CodedOutputStream header_coded_out(
@@ -103,10 +204,10 @@ class CppGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
     header_coded_out.WriteRaw(header_code.data(), header_code.size());
 
     grpc::string source_code =
-        grpc_cpp_generator::GetSourcePrologue(file, generator_parameters) +
-        grpc_cpp_generator::GetSourceIncludes(file, generator_parameters) +
-        grpc_cpp_generator::GetSourceServices(file, generator_parameters) +
-        grpc_cpp_generator::GetSourceEpilogue(file, generator_parameters);
+        grpc_cpp_generator::GetSourcePrologue(&pbfile, generator_parameters) +
+        grpc_cpp_generator::GetSourceIncludes(&pbfile, generator_parameters) +
+        grpc_cpp_generator::GetSourceServices(&pbfile, generator_parameters) +
+        grpc_cpp_generator::GetSourceEpilogue(&pbfile, generator_parameters);
     std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> source_output(
         context->Open(file_name + ".grpc.pb.cc"));
     grpc::protobuf::io::CodedOutputStream source_coded_out(