xref: /aosp_15_r20/external/grpc-grpc-java/compiler/src/java_plugin/cpp/java_generator.cpp (revision e07d83d3ffcef9ecfc9f7f475418ec639ff0e5fe)
1 /*
2  * Copyright 2019 The gRPC Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 // gRPC Java code generation
18 //
19 // The generated code should be very light-weight in terms of size. Although
20 // less of a scaling problem than for protobuf messages, additions here are
21 // multiplied many times and could easily bloat binaries if added to without
22 // consideration. This is generally achieved by putting logic in io.grpc.stub
23 // and limiting the generated code to API surface and inputs.
24 //
25 // gRPC is compatible with old versions of the generated code. New versions of
26 // generated code are free to use new APIs, and thus require new gRPC versions.
27 // But this isn't a special rule and is more just that the generated code is
28 // best viewed as a library that depends on gRPC (as it may be used within a
29 // library), and it should adhere to the normal rules of such. Notably, it can
30 // only use stable API. Using experimental API, even if only exposing its own
31 // experimental API, is not safe as libraries do not get to choose the version
32 // of gRPC being used. The rule here is more "everything should behave like
33 // normal to users" or "we don't require users to generate code for their
34 // transitive dependency tree because OSS build tools don't support that."
35 //
36 // Java lite is designed for tools like Proguard to strip unused code. Be
37 // careful not to add new references to methods that would retain them even when
38 // unneeded. In particular, we want uncalled RPC methods to have their
39 // descriptors and code pruned.
40 
41 #include "java_generator.h"
42 
43 #include <algorithm>
44 #include <iostream>
45 #include <iterator>
46 #include <map>
47 #include <set>
48 #include <vector>
49 #include <google/protobuf/descriptor.h>
50 #include <google/protobuf/descriptor.pb.h>
51 #include <google/protobuf/io/printer.h>
52 #include <google/protobuf/io/zero_copy_stream.h>
53 #include <google/protobuf/stubs/common.h>
54 
55 // Protobuf 3.21 changed the name of this file.
56 #if GOOGLE_PROTOBUF_VERSION >= 3021000
57   #include <google/protobuf/compiler/java/names.h>
58 #else
59   #include <google/protobuf/compiler/java/java_names.h>
60 #endif
61 
62 // Stringify helpers used solely to cast GRPC_VERSION
63 #ifndef STR
64 #define STR(s) #s
65 #endif
66 
67 #ifndef XSTR
68 #define XSTR(s) STR(s)
69 #endif
70 
71 #ifdef ABSL_FALLTHROUGH_INTENDED
72 #define FALLTHROUGH ABSL_FALLTHROUGH_INTENDED
73 #else
74 #define FALLTHROUGH
75 #endif
76 
77 namespace java_grpc_generator {
78 
79 namespace protobuf = google::protobuf;
80 
81 using protobuf::Descriptor;
82 using protobuf::FileDescriptor;
83 using protobuf::MethodDescriptor;
84 using protobuf::ServiceDescriptor;
85 using protobuf::SourceLocation;
86 using protobuf::io::Printer;
87 using std::to_string;
88 
89 // java keywords from: https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.9
90 static std::set<std::string> java_keywords = {
91   "abstract",
92   "assert",
93   "boolean",
94   "break",
95   "byte",
96   "case",
97   "catch",
98   "char",
99   "class",
100   "const",
101   "continue",
102   "default",
103   "do",
104   "double",
105   "else",
106   "enum",
107   "extends",
108   "final",
109   "finally",
110   "float",
111   "for",
112   "goto",
113   "if",
114   "implements",
115   "import",
116   "instanceof",
117   "int",
118   "interface",
119   "long",
120   "native",
121   "new",
122   "package",
123   "private",
124   "protected",
125   "public",
126   "return",
127   "short",
128   "static",
129   "strictfp",
130   "super",
131   "switch",
132   "synchronized",
133   "this",
134   "throw",
135   "throws",
136   "transient",
137   "try",
138   "void",
139   "volatile",
140   "while",
141   // additional ones added by us
142   "true",
143   "false",
144 };
145 
146 // Adjust a method name prefix identifier to follow the JavaBean spec:
147 //   - decapitalize the first letter
148 //   - remove embedded underscores & capitalize the following letter
149 //  Finally, if the result is a reserved java keyword, append an underscore.
MixedLower(const std::string & word)150 static std::string MixedLower(const std::string& word) {
151   std::string w;
152   w += tolower(word[0]);
153   bool after_underscore = false;
154   for (size_t i = 1; i < word.length(); ++i) {
155     if (word[i] == '_') {
156       after_underscore = true;
157     } else {
158       w += after_underscore ? toupper(word[i]) : word[i];
159       after_underscore = false;
160     }
161   }
162   if (java_keywords.find(w) != java_keywords.end()) {
163     return w + "_";
164   }
165   return w;
166 }
167 
168 // Converts to the identifier to the ALL_UPPER_CASE format.
169 //   - An underscore is inserted where a lower case letter is followed by an
170 //     upper case letter.
171 //   - All letters are converted to upper case
ToAllUpperCase(const std::string & word)172 static std::string ToAllUpperCase(const std::string& word) {
173   std::string w;
174   for (size_t i = 0; i < word.length(); ++i) {
175     w += toupper(word[i]);
176     if ((i < word.length() - 1) && islower(word[i]) && isupper(word[i + 1])) {
177       w += '_';
178     }
179   }
180   return w;
181 }
182 
LowerMethodName(const MethodDescriptor * method)183 static inline std::string LowerMethodName(const MethodDescriptor* method) {
184   return MixedLower(method->name());
185 }
186 
MethodPropertiesFieldName(const MethodDescriptor * method)187 static inline std::string MethodPropertiesFieldName(const MethodDescriptor* method) {
188   return "METHOD_" + ToAllUpperCase(method->name());
189 }
190 
MethodPropertiesGetterName(const MethodDescriptor * method)191 static inline std::string MethodPropertiesGetterName(const MethodDescriptor* method) {
192   return MixedLower("get_" + method->name() + "_method");
193 }
194 
MethodIdFieldName(const MethodDescriptor * method)195 static inline std::string MethodIdFieldName(const MethodDescriptor* method) {
196   return "METHODID_" + ToAllUpperCase(method->name());
197 }
198 
MessageFullJavaName(const Descriptor * desc)199 static inline std::string MessageFullJavaName(const Descriptor* desc) {
200   return protobuf::compiler::java::ClassName(desc);
201 }
202 
203 // TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
204 template <typename ITR>
GrpcSplitStringToIteratorUsing(const std::string & full,const char * delim,ITR & result)205 static void GrpcSplitStringToIteratorUsing(const std::string& full,
206                                        const char* delim,
207                                        ITR& result) {
208   // Optimize the common case where delim is a single character.
209   if (delim[0] != '\0' && delim[1] == '\0') {
210     char c = delim[0];
211     const char* p = full.data();
212     const char* end = p + full.size();
213     while (p != end) {
214       if (*p == c) {
215         ++p;
216       } else {
217         const char* start = p;
218         while (++p != end && *p != c);
219         *result++ = std::string(start, p - start);
220       }
221     }
222     return;
223   }
224 
225   std::string::size_type begin_index, end_index;
226   begin_index = full.find_first_not_of(delim);
227   while (begin_index != std::string::npos) {
228     end_index = full.find_first_of(delim, begin_index);
229     if (end_index == std::string::npos) {
230       *result++ = full.substr(begin_index);
231       return;
232     }
233     *result++ = full.substr(begin_index, (end_index - begin_index));
234     begin_index = full.find_first_not_of(delim, end_index);
235   }
236 }
237 
238 // TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
GrpcSplitStringUsing(const std::string & full,const char * delim,std::vector<std::string> * result)239 static void GrpcSplitStringUsing(const std::string& full,
240                              const char* delim,
241                              std::vector<std::string>* result) {
242   std::back_insert_iterator< std::vector<std::string> > it(*result);
243   GrpcSplitStringToIteratorUsing(full, delim, it);
244 }
245 
246 // TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
GrpcSplit(const std::string & full,const char * delim)247 static std::vector<std::string> GrpcSplit(const std::string& full, const char* delim) {
248   std::vector<std::string> result;
249   GrpcSplitStringUsing(full, delim, &result);
250   return result;
251 }
252 
253 // TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
GrpcEscapeJavadoc(const std::string & input)254 static std::string GrpcEscapeJavadoc(const std::string& input) {
255   std::string result;
256   result.reserve(input.size() * 2);
257 
258   char prev = '*';
259 
260   for (std::string::size_type i = 0; i < input.size(); i++) {
261     char c = input[i];
262     switch (c) {
263       case '*':
264         // Avoid "/*".
265         if (prev == '/') {
266           result.append("&#42;");
267         } else {
268           result.push_back(c);
269         }
270         break;
271       case '/':
272         // Avoid "*/".
273         if (prev == '*') {
274           result.append("&#47;");
275         } else {
276           result.push_back(c);
277         }
278         break;
279       case '@':
280         // '@' starts javadoc tags including the @deprecated tag, which will
281         // cause a compile-time error if inserted before a declaration that
282         // does not have a corresponding @Deprecated annotation.
283         result.append("&#64;");
284         break;
285       case '<':
286         // Avoid interpretation as HTML.
287         result.append("&lt;");
288         break;
289       case '>':
290         // Avoid interpretation as HTML.
291         result.append("&gt;");
292         break;
293       case '&':
294         // Avoid interpretation as HTML.
295         result.append("&amp;");
296         break;
297       case '\\':
298         // Java interprets Unicode escape sequences anywhere!
299         result.append("&#92;");
300         break;
301       default:
302         result.push_back(c);
303         break;
304     }
305 
306     prev = c;
307   }
308 
309   return result;
310 }
311 
312 // TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
313 template <typename DescriptorType>
GrpcGetCommentsForDescriptor(const DescriptorType * descriptor)314 static std::string GrpcGetCommentsForDescriptor(const DescriptorType* descriptor) {
315   SourceLocation location;
316   if (descriptor->GetSourceLocation(&location)) {
317     return location.leading_comments.empty() ?
318       location.trailing_comments : location.leading_comments;
319   }
320   return std::string();
321 }
322 
323 // TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
GrpcGetDocLines(const std::string & comments)324 static std::vector<std::string> GrpcGetDocLines(const std::string& comments) {
325   if (!comments.empty()) {
326     // TODO(kenton):  Ideally we should parse the comment text as Markdown and
327     //   write it back as HTML, but this requires a Markdown parser.  For now
328     //   we just use <pre> to get fixed-width text formatting.
329 
330     // If the comment itself contains block comment start or end markers,
331     // HTML-escape them so that they don't accidentally close the doc comment.
332     std::string escapedComments = GrpcEscapeJavadoc(comments);
333 
334     std::vector<std::string> lines = GrpcSplit(escapedComments, "\n");
335     while (!lines.empty() && lines.back().empty()) {
336       lines.pop_back();
337     }
338     return lines;
339   }
340   return std::vector<std::string>();
341 }
342 
343 // TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
344 template <typename DescriptorType>
GrpcGetDocLinesForDescriptor(const DescriptorType * descriptor)345 static std::vector<std::string> GrpcGetDocLinesForDescriptor(const DescriptorType* descriptor) {
346   return GrpcGetDocLines(GrpcGetCommentsForDescriptor(descriptor));
347 }
348 
349 enum StubType {
350   ASYNC_INTERFACE = 0,
351   BLOCKING_CLIENT_INTERFACE = 1,
352   FUTURE_CLIENT_INTERFACE = 2,
353   BLOCKING_SERVER_INTERFACE = 3,
354   ASYNC_CLIENT_IMPL = 4,
355   BLOCKING_CLIENT_IMPL = 5,
356   FUTURE_CLIENT_IMPL = 6,
357   ABSTRACT_CLASS = 7,
358   NONE = 8,
359 };
360 
361 enum CallType {
362   ASYNC_CALL = 0,
363   BLOCKING_CALL = 1,
364   FUTURE_CALL = 2
365 };
366 
367 // TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
GrpcWriteDocCommentBody(Printer * printer,const std::vector<std::string> & lines,bool surroundWithPreTag)368 static void GrpcWriteDocCommentBody(Printer* printer,
369                                     const std::vector<std::string>& lines,
370                                     bool surroundWithPreTag) {
371   if (!lines.empty()) {
372     if (surroundWithPreTag) {
373       printer->Print(" * <pre>\n");
374     }
375 
376     for (size_t i = 0; i < lines.size(); i++) {
377       // Most lines should start with a space.  Watch out for lines that start
378       // with a /, since putting that right after the leading asterisk will
379       // close the comment.
380       if (!lines[i].empty() && lines[i][0] == '/') {
381         printer->Print(" * $line$\n", "line", lines[i]);
382       } else {
383         printer->Print(" *$line$\n", "line", lines[i]);
384       }
385     }
386 
387     if (surroundWithPreTag) {
388       printer->Print(" * </pre>\n");
389     }
390   }
391 }
392 
393 // TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
GrpcWriteDocComment(Printer * printer,const std::string & comments)394 static void GrpcWriteDocComment(Printer* printer, const std::string& comments) {
395   printer->Print("/**\n");
396   std::vector<std::string> lines = GrpcGetDocLines(comments);
397   GrpcWriteDocCommentBody(printer, lines, false);
398   printer->Print(" */\n");
399 }
400 
401 // For the non-interface classes add a description of use before the description from proto
GrpcWriteServiceDocComment(Printer * printer,const ServiceDescriptor * service,StubType type)402 static void GrpcWriteServiceDocComment(Printer* printer,
403                                        const ServiceDescriptor* service,
404                                        StubType type) {
405   printer->Print("/**\n");
406 
407   std::map<std::string, std::string> vars = {{"service", service->name()}};
408   switch (type) {
409     case ASYNC_CLIENT_IMPL:
410       printer->Print(vars, " * A stub to allow clients to do asynchronous rpc calls to service $service$.\n");
411       break;
412     case BLOCKING_CLIENT_IMPL:
413       printer->Print(vars, " * A stub to allow clients to do synchronous rpc calls to service $service$.\n");
414       break;
415     case FUTURE_CLIENT_IMPL:
416       printer->Print(vars, " * A stub to allow clients to do ListenableFuture-style rpc calls to service $service$.\n");
417       break;
418     case ABSTRACT_CLASS:
419       printer->Print(vars, " * Base class for the server implementation of the service $service$.\n");
420       break;
421     default: ;
422       // No extra description
423   }
424 
425   std::vector<std::string> lines = GrpcGetDocLinesForDescriptor(service);
426   GrpcWriteDocCommentBody(printer, lines, true);
427   printer->Print(" */\n");
428 }
429 
430 // TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
GrpcWriteMethodDocComment(Printer * printer,const MethodDescriptor * method)431 void GrpcWriteMethodDocComment(Printer* printer,
432                            const MethodDescriptor* method) {
433   // Deviating from protobuf to avoid extraneous docs
434   // (see https://github.com/google/protobuf/issues/1406);
435   printer->Print("/**\n");
436   std::vector<std::string> lines = GrpcGetDocLinesForDescriptor(method);
437   GrpcWriteDocCommentBody(printer, lines, true);
438   printer->Print(" */\n");
439 }
440 
PrintMethodFields(const ServiceDescriptor * service,std::map<std::string,std::string> * vars,Printer * p,ProtoFlavor flavor)441 static void PrintMethodFields(
442     const ServiceDescriptor* service, std::map<std::string, std::string>* vars,
443     Printer* p, ProtoFlavor flavor) {
444   p->Print("// Static method descriptors that strictly reflect the proto.\n");
445   (*vars)["service_name"] = service->name();
446   for (int i = 0; i < service->method_count(); ++i) {
447     const MethodDescriptor* method = service->method(i);
448     (*vars)["arg_in_id"] = to_string(2 * i);
449     (*vars)["arg_out_id"] = to_string(2 * i + 1);
450     (*vars)["method_name"] = method->name();
451     (*vars)["input_type"] = MessageFullJavaName(method->input_type());
452     (*vars)["output_type"] = MessageFullJavaName(method->output_type());
453     (*vars)["method_field_name"] = MethodPropertiesFieldName(method);
454     (*vars)["method_new_field_name"] = MethodPropertiesGetterName(method);
455     (*vars)["method_method_name"] = MethodPropertiesGetterName(method);
456     bool client_streaming = method->client_streaming();
457     bool server_streaming = method->server_streaming();
458     if (client_streaming) {
459       if (server_streaming) {
460         (*vars)["method_type"] = "BIDI_STREAMING";
461       } else {
462         (*vars)["method_type"] = "CLIENT_STREAMING";
463       }
464     } else {
465       if (server_streaming) {
466         (*vars)["method_type"] = "SERVER_STREAMING";
467       } else {
468         (*vars)["method_type"] = "UNARY";
469       }
470     }
471 
472     if (flavor == ProtoFlavor::LITE) {
473       (*vars)["ProtoUtils"] = "io.grpc.protobuf.lite.ProtoLiteUtils";
474     } else {
475       (*vars)["ProtoUtils"] = "io.grpc.protobuf.ProtoUtils";
476     }
477     p->Print(
478         *vars,
479         "private static volatile $MethodDescriptor$<$input_type$,\n"
480         "    $output_type$> $method_new_field_name$;\n"
481         "\n"
482         "@$RpcMethod$(\n"
483         "    fullMethodName = SERVICE_NAME + '/' + \"$method_name$\",\n"
484         "    requestType = $input_type$.class,\n"
485         "    responseType = $output_type$.class,\n"
486         "    methodType = $MethodType$.$method_type$)\n"
487         "public static $MethodDescriptor$<$input_type$,\n"
488         "    $output_type$> $method_method_name$() {\n"
489         "  $MethodDescriptor$<$input_type$, $output_type$> $method_new_field_name$;\n"
490         "  if (($method_new_field_name$ = $service_class_name$.$method_new_field_name$) == null) {\n"
491         "    synchronized ($service_class_name$.class) {\n"
492         "      if (($method_new_field_name$ = $service_class_name$.$method_new_field_name$) == null) {\n"
493         "        $service_class_name$.$method_new_field_name$ = $method_new_field_name$ =\n"
494         "            $MethodDescriptor$.<$input_type$, $output_type$>newBuilder()\n"
495         "            .setType($MethodType$.$method_type$)\n"
496         "            .setFullMethodName(generateFullMethodName(SERVICE_NAME, \"$method_name$\"))\n");
497 
498     bool safe = method->options().idempotency_level()
499         == protobuf::MethodOptions_IdempotencyLevel_NO_SIDE_EFFECTS;
500     if (safe) {
501       p->Print(*vars, "            .setSafe(true)\n");
502     } else {
503       bool idempotent = method->options().idempotency_level()
504           == protobuf::MethodOptions_IdempotencyLevel_IDEMPOTENT;
505       if (idempotent) {
506         p->Print(*vars, "            .setIdempotent(true)\n");
507       }
508     }
509 
510     p->Print(
511         *vars,
512         "            .setSampledToLocalTracing(true)\n"
513         "            .setRequestMarshaller($ProtoUtils$.marshaller(\n"
514         "                $input_type$.getDefaultInstance()))\n"
515         "            .setResponseMarshaller($ProtoUtils$.marshaller(\n"
516         "                $output_type$.getDefaultInstance()))\n");
517 
518     (*vars)["proto_method_descriptor_supplier"] = service->name() + "MethodDescriptorSupplier";
519     if (flavor == ProtoFlavor::NORMAL) {
520       p->Print(
521           *vars,
522         "            .setSchemaDescriptor(new $proto_method_descriptor_supplier$(\"$method_name$\"))\n");
523     }
524 
525     p->Print(
526         *vars,
527         "            .build();\n");
528     p->Print(*vars,
529         "      }\n"
530         "    }\n"
531         "  }\n"
532         "  return $method_new_field_name$;\n"
533         "}\n"
534         "\n");
535   }
536 }
537 
538 static void PrintBindServiceMethod(const ServiceDescriptor* service,
539                                    std::map<std::string, std::string>* vars,
540                                    Printer* p);
541 
542 // Prints a StubFactory for given service / stub type.
PrintStubFactory(const ServiceDescriptor * service,std::map<std::string,std::string> * vars,Printer * p,StubType type)543 static void PrintStubFactory(
544     const ServiceDescriptor* service,
545     std::map<std::string, std::string>* vars,
546     Printer* p, StubType type) {
547   std::string stub_type_name;
548   switch (type) {
549     case ASYNC_CLIENT_IMPL:
550       stub_type_name = "";
551       break;
552     case FUTURE_CLIENT_IMPL:
553       stub_type_name = "Future";
554       break;
555     case BLOCKING_CLIENT_IMPL:
556       stub_type_name = "Blocking";
557       break;
558     default:
559       GRPC_CODEGEN_FAIL << "Cannot generate StubFactory for StubType: " << type;
560   }
561   (*vars)["stub_full_name"] = (*vars)["service_name"] + stub_type_name + "Stub";
562   p->Print(
563     *vars,
564     "$StubFactory$<$stub_full_name$> factory =\n"
565     "  new $StubFactory$<$stub_full_name$>() {\n"
566     "    @$Override$\n"
567     "    public $stub_full_name$ newStub($Channel$ channel, $CallOptions$ callOptions) {\n"
568     "      return new $stub_full_name$(channel, callOptions);\n"
569     "    }\n"
570     "  };\n");
571 }
572 
573 // Prints a client interface or implementation class, or a server interface.
PrintStub(const ServiceDescriptor * service,std::map<std::string,std::string> * vars,Printer * p,StubType type)574 static void PrintStub(
575     const ServiceDescriptor* service,
576     std::map<std::string, std::string>* vars,
577     Printer* p, StubType type) {
578   const std::string service_name = service->name();
579   (*vars)["service_name"] = service_name;
580   std::string stub_name = service_name;
581   std::string stub_base_class_name = "AbstractStub";
582   CallType call_type;
583   bool interface = false;
584   switch (type) {
585     case ASYNC_INTERFACE:
586       call_type = ASYNC_CALL;
587       interface = true;
588       stub_name ="AsyncService";
589       break;
590     case ASYNC_CLIENT_IMPL:
591       call_type = ASYNC_CALL;
592       stub_name += "Stub";
593       stub_base_class_name = "AbstractAsyncStub";
594       break;
595     case BLOCKING_CLIENT_IMPL:
596       call_type = BLOCKING_CALL;
597       stub_name += "BlockingStub";
598       stub_base_class_name = "AbstractBlockingStub";
599       break;
600     case FUTURE_CLIENT_IMPL:
601       call_type = FUTURE_CALL;
602       stub_name += "FutureStub";
603       stub_base_class_name = "AbstractFutureStub";
604       break;
605     case BLOCKING_CLIENT_INTERFACE:
606     case FUTURE_CLIENT_INTERFACE:
607       GRPC_CODEGEN_FAIL << "Intentionally not creating StubType: " << type;
608     case ABSTRACT_CLASS:
609       GRPC_CODEGEN_FAIL << "Call PrintAbstractClassStub for ABSTRACT_CLASS";
610     default:
611       GRPC_CODEGEN_FAIL << "Cannot determine class name for StubType: " << type;
612   }
613   (*vars)["stub_name"] = stub_name;
614   (*vars)["stub_base_class_name"] = (*vars)[stub_base_class_name];
615 
616   // Class head
617   GrpcWriteServiceDocComment(p, service, type);
618 
619   if (service->options().deprecated()) {
620     p->Print(*vars, "@$Deprecated$\n");
621   }
622 
623   if (interface) {
624     p->Print(
625         *vars,
626         "public interface $stub_name$ {\n");
627   } else {
628     p->Print(
629         *vars,
630         "public static final class $stub_name$\n"
631         "    extends $stub_base_class_name$<$stub_name$> {\n");
632   }
633   p->Indent();
634 
635   // Constructor and build() method
636   if (!interface) {
637     p->Print(
638         *vars,
639         "private $stub_name$(\n"
640         "    $Channel$ channel, $CallOptions$ callOptions) {"
641         "\n");
642     p->Indent();
643     p->Print("super(channel, callOptions);\n");
644     p->Outdent();
645     p->Print("}\n\n");
646     p->Print(
647         *vars,
648         "@$Override$\n"
649         "protected $stub_name$ build(\n"
650         "    $Channel$ channel, $CallOptions$ callOptions) {"
651         "\n");
652     p->Indent();
653     p->Print(
654         *vars,
655         "return new $stub_name$(channel, callOptions);\n");
656     p->Outdent();
657     p->Print("}\n");
658   }
659 
660   // RPC methods
661   for (int i = 0; i < service->method_count(); ++i) {
662     const MethodDescriptor* method = service->method(i);
663     (*vars)["input_type"] = MessageFullJavaName(method->input_type());
664     (*vars)["output_type"] = MessageFullJavaName(method->output_type());
665     (*vars)["lower_method_name"] = LowerMethodName(method);
666     (*vars)["method_method_name"] = MethodPropertiesGetterName(method);
667     bool client_streaming = method->client_streaming();
668     bool server_streaming = method->server_streaming();
669 
670     if (call_type == BLOCKING_CALL && client_streaming) {
671       // Blocking client interface with client streaming is not available
672       continue;
673     }
674 
675     if (call_type == FUTURE_CALL && (client_streaming || server_streaming)) {
676       // Future interface doesn't support streaming.
677       continue;
678     }
679 
680     // Method signature
681     p->Print("\n");
682     // TODO(nmittler): Replace with WriteMethodDocComment once included by the protobuf distro.
683     GrpcWriteMethodDocComment(p, method);
684 
685     if (method->options().deprecated()) {
686       p->Print(*vars, "@$Deprecated$\n");
687     }
688 
689     if (!interface) {
690       p->Print("public ");
691     } else {
692       p->Print("default ");
693     }
694     switch (call_type) {
695       case BLOCKING_CALL:
696         GRPC_CODEGEN_CHECK(!client_streaming)
697             << "Blocking client interface with client streaming is unavailable";
698         if (server_streaming) {
699           // Server streaming
700           p->Print(
701               *vars,
702               "$Iterator$<$output_type$> $lower_method_name$(\n"
703               "    $input_type$ request)");
704         } else {
705           // Simple RPC
706           p->Print(
707               *vars,
708               "$output_type$ $lower_method_name$($input_type$ request)");
709         }
710         break;
711       case ASYNC_CALL:
712         if (client_streaming) {
713           // Bidirectional streaming or client streaming
714           p->Print(
715               *vars,
716               "$StreamObserver$<$input_type$> $lower_method_name$(\n"
717               "    $StreamObserver$<$output_type$> responseObserver)");
718         } else {
719           // Server streaming or simple RPC
720           p->Print(
721               *vars,
722               "void $lower_method_name$($input_type$ request,\n"
723               "    $StreamObserver$<$output_type$> responseObserver)");
724         }
725         break;
726       case FUTURE_CALL:
727         GRPC_CODEGEN_CHECK(!client_streaming && !server_streaming)
728             << "Future interface doesn't support streaming. "
729             << "client_streaming=" << client_streaming << ", "
730             << "server_streaming=" << server_streaming;
731         p->Print(
732             *vars,
733             "$ListenableFuture$<$output_type$> $lower_method_name$(\n"
734             "    $input_type$ request)");
735         break;
736     }
737 
738     // Method body.
739     p->Print(" {\n");
740     p->Indent();
741     if (interface && call_type == ASYNC_CALL) {
742       // NB: Skipping validation of service methods. If something is wrong, we wouldn't get to
743       // this point as compiler would return errors when generating service interface.
744       if (client_streaming) {
745         p->Print(
746             *vars,
747             "return io.grpc.stub.ServerCalls.asyncUnimplementedStreamingCall("
748             "$method_method_name$(), responseObserver);\n");
749       } else {
750         p->Print(
751             *vars,
752             "io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall("
753             "$method_method_name$(), responseObserver);\n");
754       }
755     } else if (!interface) {
756       switch (call_type) {
757         case BLOCKING_CALL:
758           GRPC_CODEGEN_CHECK(!client_streaming)
759               << "Blocking client streaming interface is not available";
760           if (server_streaming) {
761             (*vars)["calls_method"] = "io.grpc.stub.ClientCalls.blockingServerStreamingCall";
762             (*vars)["params"] = "request";
763           } else {
764             (*vars)["calls_method"] = "io.grpc.stub.ClientCalls.blockingUnaryCall";
765             (*vars)["params"] = "request";
766           }
767           p->Print(
768               *vars,
769               "return $calls_method$(\n"
770               "    getChannel(), $method_method_name$(), getCallOptions(), $params$);\n");
771           break;
772         case ASYNC_CALL:
773           if (server_streaming) {
774             if (client_streaming) {
775               (*vars)["calls_method"] = "io.grpc.stub.ClientCalls.asyncBidiStreamingCall";
776               (*vars)["params"] = "responseObserver";
777             } else {
778               (*vars)["calls_method"] = "io.grpc.stub.ClientCalls.asyncServerStreamingCall";
779               (*vars)["params"] = "request, responseObserver";
780             }
781           } else {
782             if (client_streaming) {
783               (*vars)["calls_method"] = "io.grpc.stub.ClientCalls.asyncClientStreamingCall";
784               (*vars)["params"] = "responseObserver";
785             } else {
786               (*vars)["calls_method"] = "io.grpc.stub.ClientCalls.asyncUnaryCall";
787               (*vars)["params"] = "request, responseObserver";
788             }
789           }
790           (*vars)["last_line_prefix"] = client_streaming ? "return " : "";
791           p->Print(
792               *vars,
793               "$last_line_prefix$$calls_method$(\n"
794               "    getChannel().newCall($method_method_name$(), getCallOptions()), $params$);\n");
795           break;
796         case FUTURE_CALL:
797           GRPC_CODEGEN_CHECK(!client_streaming && !server_streaming)
798               << "Future interface doesn't support streaming. "
799               << "client_streaming=" << client_streaming << ", "
800               << "server_streaming=" << server_streaming;
801           (*vars)["calls_method"] = "io.grpc.stub.ClientCalls.futureUnaryCall";
802           p->Print(
803               *vars,
804               "return $calls_method$(\n"
805               "    getChannel().newCall($method_method_name$(), getCallOptions()), request);\n");
806           break;
807       }
808     } else {
809       GRPC_CODEGEN_FAIL << "Do not create Stub interfaces";
810     }
811     p->Outdent();
812     p->Print("}\n");
813   }
814 
815   p->Outdent();
816   p->Print("}\n\n");
817 }
818 
819 
PrintAbstractClassStub(const ServiceDescriptor * service,std::map<std::string,std::string> * vars,Printer * p)820 static void PrintAbstractClassStub(
821     const ServiceDescriptor* service,
822     std::map<std::string, std::string>* vars,
823     Printer* p) {
824   const std::string service_name = service->name();
825   (*vars)["service_name"] = service_name;
826 
827   GrpcWriteServiceDocComment(p, service, ABSTRACT_CLASS);
828   if (service->options().deprecated()) {
829     p->Print(*vars, "@$Deprecated$\n");
830   }
831   p->Print(
832       *vars,
833       "public static abstract class $service_name$ImplBase\n"
834       "    implements $BindableService$, AsyncService {\n"
835       "\n"
836       "  @$Override$ public final $ServerServiceDefinition$ bindService() {\n"
837       "    return $service_class_name$.bindService(this);\n"
838       "  }\n"
839       "}\n\n");
840 }
841 
CompareMethodClientStreaming(const MethodDescriptor * method1,const MethodDescriptor * method2)842 static bool CompareMethodClientStreaming(const MethodDescriptor* method1,
843                                          const MethodDescriptor* method2)
844 {
845   return method1->client_streaming() < method2->client_streaming();
846 }
847 
848 // Place all method invocations into a single class to reduce memory footprint
849 // on Android.
PrintMethodHandlerClass(const ServiceDescriptor * service,std::map<std::string,std::string> * vars,Printer * p)850 static void PrintMethodHandlerClass(const ServiceDescriptor* service,
851                                    std::map<std::string, std::string>* vars,
852                                    Printer* p) {
853   // Sort method ids based on client_streaming() so switch tables are compact.
854   std::vector<const MethodDescriptor*> sorted_methods(service->method_count());
855   for (int i = 0; i < service->method_count(); ++i) {
856     sorted_methods[i] = service->method(i);
857   }
858   stable_sort(sorted_methods.begin(), sorted_methods.end(),
859               CompareMethodClientStreaming);
860   for (size_t i = 0; i < sorted_methods.size(); i++) {
861     const MethodDescriptor* method = sorted_methods[i];
862     (*vars)["method_id"] = to_string(i);
863     (*vars)["method_id_name"] = MethodIdFieldName(method);
864     p->Print(
865         *vars,
866         "private static final int $method_id_name$ = $method_id$;\n");
867   }
868   p->Print("\n");
869   p->Print(
870       *vars,
871       "private static final class MethodHandlers<Req, Resp> implements\n"
872       "    io.grpc.stub.ServerCalls.UnaryMethod<Req, Resp>,\n"
873       "    io.grpc.stub.ServerCalls.ServerStreamingMethod<Req, Resp>,\n"
874       "    io.grpc.stub.ServerCalls.ClientStreamingMethod<Req, Resp>,\n"
875       "    io.grpc.stub.ServerCalls.BidiStreamingMethod<Req, Resp> {\n"
876       "  private final AsyncService serviceImpl;\n"
877       "  private final int methodId;\n"
878       "\n"
879       "  MethodHandlers(AsyncService serviceImpl, int methodId) {\n"
880       "    this.serviceImpl = serviceImpl;\n"
881       "    this.methodId = methodId;\n"
882       "  }\n\n");
883   p->Indent();
884   p->Print(
885       *vars,
886       "@$Override$\n"
887       "@java.lang.SuppressWarnings(\"unchecked\")\n"
888       "public void invoke(Req request, $StreamObserver$<Resp> responseObserver) {\n"
889       "  switch (methodId) {\n");
890   p->Indent();
891   p->Indent();
892 
893   for (int i = 0; i < service->method_count(); ++i) {
894     const MethodDescriptor* method = service->method(i);
895     if (method->client_streaming()) {
896       continue;
897     }
898     (*vars)["method_id_name"] = MethodIdFieldName(method);
899     (*vars)["lower_method_name"] = LowerMethodName(method);
900     (*vars)["input_type"] = MessageFullJavaName(method->input_type());
901     (*vars)["output_type"] = MessageFullJavaName(method->output_type());
902     p->Print(
903         *vars,
904         "case $method_id_name$:\n"
905         "  serviceImpl.$lower_method_name$(($input_type$) request,\n"
906         "      ($StreamObserver$<$output_type$>) responseObserver);\n"
907         "  break;\n");
908   }
909   p->Print("default:\n"
910            "  throw new AssertionError();\n");
911 
912   p->Outdent();
913   p->Outdent();
914   p->Print("  }\n"
915            "}\n\n");
916 
917   p->Print(
918       *vars,
919       "@$Override$\n"
920       "@java.lang.SuppressWarnings(\"unchecked\")\n"
921       "public $StreamObserver$<Req> invoke(\n"
922       "    $StreamObserver$<Resp> responseObserver) {\n"
923       "  switch (methodId) {\n");
924   p->Indent();
925   p->Indent();
926 
927   for (int i = 0; i < service->method_count(); ++i) {
928     const MethodDescriptor* method = service->method(i);
929     if (!method->client_streaming()) {
930       continue;
931     }
932     (*vars)["method_id_name"] = MethodIdFieldName(method);
933     (*vars)["lower_method_name"] = LowerMethodName(method);
934     (*vars)["input_type"] = MessageFullJavaName(method->input_type());
935     (*vars)["output_type"] = MessageFullJavaName(method->output_type());
936     p->Print(
937         *vars,
938         "case $method_id_name$:\n"
939         "  return ($StreamObserver$<Req>) serviceImpl.$lower_method_name$(\n"
940         "      ($StreamObserver$<$output_type$>) responseObserver);\n");
941   }
942   p->Print("default:\n"
943            "  throw new AssertionError();\n");
944 
945   p->Outdent();
946   p->Outdent();
947   p->Print("  }\n"
948            "}\n");
949 
950 
951   p->Outdent();
952   p->Print("}\n\n");
953 }
954 
PrintGetServiceDescriptorMethod(const ServiceDescriptor * service,std::map<std::string,std::string> * vars,Printer * p,ProtoFlavor flavor)955 static void PrintGetServiceDescriptorMethod(const ServiceDescriptor* service,
956                                    std::map<std::string, std::string>* vars,
957                                    Printer* p,
958                                    ProtoFlavor flavor) {
959   (*vars)["service_name"] = service->name();
960 
961 
962   if (flavor == ProtoFlavor::NORMAL) {
963     (*vars)["proto_base_descriptor_supplier"] = service->name() + "BaseDescriptorSupplier";
964     (*vars)["proto_file_descriptor_supplier"] = service->name() + "FileDescriptorSupplier";
965     (*vars)["proto_method_descriptor_supplier"] = service->name() + "MethodDescriptorSupplier";
966     (*vars)["proto_class_name"] = protobuf::compiler::java::ClassName(service->file());
967     p->Print(
968         *vars,
969         "private static abstract class $proto_base_descriptor_supplier$\n"
970         "    implements $ProtoFileDescriptorSupplier$, $ProtoServiceDescriptorSupplier$ {\n"
971         "  $proto_base_descriptor_supplier$() {}\n"
972         "\n"
973         "  @$Override$\n"
974         "  public com.google.protobuf.Descriptors.FileDescriptor getFileDescriptor() {\n"
975         "    return $proto_class_name$.getDescriptor();\n"
976         "  }\n"
977         "\n"
978         "  @$Override$\n"
979         "  public com.google.protobuf.Descriptors.ServiceDescriptor getServiceDescriptor() {\n"
980         "    return getFileDescriptor().findServiceByName(\"$service_name$\");\n"
981         "  }\n"
982         "}\n"
983         "\n"
984         "private static final class $proto_file_descriptor_supplier$\n"
985         "    extends $proto_base_descriptor_supplier$ {\n"
986         "  $proto_file_descriptor_supplier$() {}\n"
987         "}\n"
988         "\n"
989         "private static final class $proto_method_descriptor_supplier$\n"
990         "    extends $proto_base_descriptor_supplier$\n"
991         "    implements $ProtoMethodDescriptorSupplier$ {\n"
992         "  private final String methodName;\n"
993         "\n"
994         "  $proto_method_descriptor_supplier$(String methodName) {\n"
995         "    this.methodName = methodName;\n"
996         "  }\n"
997         "\n"
998         "  @$Override$\n"
999         "  public com.google.protobuf.Descriptors.MethodDescriptor getMethodDescriptor() {\n"
1000         "    return getServiceDescriptor().findMethodByName(methodName);\n"
1001         "  }\n"
1002         "}\n\n");
1003   }
1004 
1005   p->Print(
1006       *vars,
1007       "private static volatile $ServiceDescriptor$ serviceDescriptor;\n\n");
1008 
1009   p->Print(
1010       *vars,
1011       "public static $ServiceDescriptor$ getServiceDescriptor() {\n");
1012   p->Indent();
1013   p->Print(
1014       *vars,
1015       "$ServiceDescriptor$ result = serviceDescriptor;\n");
1016   p->Print("if (result == null) {\n");
1017   p->Indent();
1018   p->Print(
1019       *vars,
1020       "synchronized ($service_class_name$.class) {\n");
1021   p->Indent();
1022   p->Print("result = serviceDescriptor;\n");
1023   p->Print("if (result == null) {\n");
1024   p->Indent();
1025 
1026   p->Print(
1027       *vars,
1028       "serviceDescriptor = result = $ServiceDescriptor$.newBuilder(SERVICE_NAME)");
1029   p->Indent();
1030   p->Indent();
1031   if (flavor == ProtoFlavor::NORMAL) {
1032     p->Print(
1033         *vars,
1034         "\n.setSchemaDescriptor(new $proto_file_descriptor_supplier$())");
1035   }
1036   for (int i = 0; i < service->method_count(); ++i) {
1037     const MethodDescriptor* method = service->method(i);
1038     (*vars)["method_method_name"] = MethodPropertiesGetterName(method);
1039     p->Print(*vars, "\n.addMethod($method_method_name$())");
1040   }
1041   p->Print("\n.build();\n");
1042   p->Outdent();
1043   p->Outdent();
1044 
1045   p->Outdent();
1046   p->Print("}\n");
1047   p->Outdent();
1048   p->Print("}\n");
1049   p->Outdent();
1050   p->Print("}\n");
1051   p->Print("return result;\n");
1052   p->Outdent();
1053   p->Print("}\n");
1054 }
1055 
PrintBindServiceMethod(const ServiceDescriptor * service,std::map<std::string,std::string> * vars,Printer * p)1056 static void PrintBindServiceMethod(const ServiceDescriptor* service,
1057                                    std::map<std::string, std::string>* vars,
1058                                    Printer* p) {
1059   (*vars)["service_name"] = service->name();
1060   p->Print(*vars,
1061            "public static final io.grpc.ServerServiceDefinition "
1062            "bindService(AsyncService service) {\n");
1063 
1064   p->Indent();
1065   p->Print(*vars,
1066            "return "
1067            "$ServerServiceDefinition$.builder(getServiceDescriptor())\n");
1068   p->Indent();
1069   p->Indent();
1070   for (int i = 0; i < service->method_count(); ++i) {
1071     const MethodDescriptor* method = service->method(i);
1072     (*vars)["lower_method_name"] = LowerMethodName(method);
1073     (*vars)["method_method_name"] = MethodPropertiesGetterName(method);
1074     (*vars)["input_type"] = MessageFullJavaName(method->input_type());
1075     (*vars)["output_type"] = MessageFullJavaName(method->output_type());
1076     (*vars)["method_id_name"] = MethodIdFieldName(method);
1077     bool client_streaming = method->client_streaming();
1078     bool server_streaming = method->server_streaming();
1079     if (client_streaming) {
1080       if (server_streaming) {
1081         (*vars)["calls_method"] = "io.grpc.stub.ServerCalls.asyncBidiStreamingCall";
1082       } else {
1083         (*vars)["calls_method"] = "io.grpc.stub.ServerCalls.asyncClientStreamingCall";
1084       }
1085     } else {
1086       if (server_streaming) {
1087         (*vars)["calls_method"] = "io.grpc.stub.ServerCalls.asyncServerStreamingCall";
1088       } else {
1089         (*vars)["calls_method"] = "io.grpc.stub.ServerCalls.asyncUnaryCall";
1090       }
1091     }
1092     p->Print(*vars, ".addMethod(\n");
1093     p->Indent();
1094     p->Print(
1095         *vars,
1096         "$method_method_name$(),\n"
1097         "$calls_method$(\n");
1098     p->Indent();
1099     p->Print(
1100         *vars,
1101         "new MethodHandlers<\n"
1102         "  $input_type$,\n"
1103         "  $output_type$>(\n"
1104         "    service, $method_id_name$)))\n");
1105     p->Outdent();
1106     p->Outdent();
1107   }
1108   p->Print(".build();\n");
1109   p->Outdent();
1110   p->Outdent();
1111   p->Outdent();
1112   p->Print("}\n\n");
1113 }
1114 
PrintService(const ServiceDescriptor * service,std::map<std::string,std::string> * vars,Printer * p,ProtoFlavor flavor,bool disable_version)1115 static void PrintService(const ServiceDescriptor* service,
1116                          std::map<std::string, std::string>* vars,
1117                          Printer* p,
1118                          ProtoFlavor flavor,
1119                          bool disable_version) {
1120   (*vars)["service_name"] = service->name();
1121   (*vars)["file_name"] = service->file()->name();
1122   (*vars)["service_class_name"] = ServiceClassName(service);
1123   (*vars)["grpc_version"] = "";
1124   #ifdef GRPC_VERSION
1125   if (!disable_version) {
1126     (*vars)["grpc_version"] = " (version " XSTR(GRPC_VERSION) ")";
1127   }
1128   #endif
1129   // TODO(nmittler): Replace with WriteServiceDocComment once included by protobuf distro.
1130   GrpcWriteServiceDocComment(p, service, NONE);
1131   p->Print(
1132       *vars,
1133       "@$Generated$(\n"
1134       "    value = \"by gRPC proto compiler$grpc_version$\",\n"
1135       "    comments = \"Source: $file_name$\")\n"
1136       "@$GrpcGenerated$\n");
1137 
1138   if (service->options().deprecated()) {
1139     p->Print(*vars, "@$Deprecated$\n");
1140   }
1141 
1142   p->Print(
1143       *vars,
1144       "public final class $service_class_name$ {\n\n");
1145   p->Indent();
1146   p->Print(
1147       *vars,
1148       "private $service_class_name$() {}\n\n");
1149 
1150   p->Print(
1151       *vars,
1152       "public static final String SERVICE_NAME = "
1153       "\"$Package$$service_name$\";\n\n");
1154 
1155   PrintMethodFields(service, vars, p, flavor);
1156 
1157   // TODO(nmittler): Replace with WriteDocComment once included by protobuf distro.
1158   GrpcWriteDocComment(p, " Creates a new async stub that supports all call types for the service");
1159   p->Print(
1160       *vars,
1161       "public static $service_name$Stub newStub($Channel$ channel) {\n");
1162   p->Indent();
1163   PrintStubFactory(service, vars, p, ASYNC_CLIENT_IMPL);
1164   p->Print(*vars, "return $service_name$Stub.newStub(factory, channel);\n");
1165   p->Outdent();
1166   p->Print("}\n\n");
1167 
1168   // TODO(nmittler): Replace with WriteDocComment once included by protobuf distro.
1169   GrpcWriteDocComment(p, " Creates a new blocking-style stub that supports unary and streaming "
1170                          "output calls on the service");
1171   p->Print(
1172       *vars,
1173       "public static $service_name$BlockingStub newBlockingStub(\n"
1174       "    $Channel$ channel) {\n");
1175   p->Indent();
1176   PrintStubFactory(service, vars, p, BLOCKING_CLIENT_IMPL);
1177   p->Print(
1178       *vars,
1179       "return $service_name$BlockingStub.newStub(factory, channel);\n");
1180   p->Outdent();
1181   p->Print("}\n\n");
1182 
1183   // TODO(nmittler): Replace with WriteDocComment once included by protobuf distro.
1184   GrpcWriteDocComment(p, " Creates a new ListenableFuture-style stub that supports unary calls "
1185                          "on the service");
1186   p->Print(
1187       *vars,
1188       "public static $service_name$FutureStub newFutureStub(\n"
1189       "    $Channel$ channel) {\n");
1190   p->Indent();
1191   PrintStubFactory(service, vars, p, FUTURE_CLIENT_IMPL);
1192   p->Print(
1193       *vars,
1194       "return $service_name$FutureStub.newStub(factory, channel);\n");
1195   p->Outdent();
1196   p->Print("}\n\n");
1197 
1198   PrintStub(service, vars, p, ASYNC_INTERFACE);
1199   PrintAbstractClassStub(service, vars, p);
1200   PrintStub(service, vars, p, ASYNC_CLIENT_IMPL);
1201   PrintStub(service, vars, p, BLOCKING_CLIENT_IMPL);
1202   PrintStub(service, vars, p, FUTURE_CLIENT_IMPL);
1203 
1204   PrintMethodHandlerClass(service, vars, p);
1205   PrintBindServiceMethod(service, vars, p);
1206   PrintGetServiceDescriptorMethod(service, vars, p, flavor);
1207   p->Outdent();
1208   p->Print("}\n");
1209 }
1210 
PrintImports(Printer * p)1211 void PrintImports(Printer* p) {
1212   p->Print(
1213       "import static "
1214       "io.grpc.MethodDescriptor.generateFullMethodName;\n\n");
1215 }
1216 
GenerateService(const ServiceDescriptor * service,protobuf::io::ZeroCopyOutputStream * out,ProtoFlavor flavor,bool disable_version)1217 void GenerateService(const ServiceDescriptor* service,
1218                      protobuf::io::ZeroCopyOutputStream* out,
1219                      ProtoFlavor flavor,
1220                      bool disable_version) {
1221   // All non-generated classes must be referred by fully qualified names to
1222   // avoid collision with generated classes.
1223   std::map<std::string, std::string> vars;
1224   vars["String"] = "java.lang.String";
1225   vars["Deprecated"] = "java.lang.Deprecated";
1226   vars["Override"] = "java.lang.Override";
1227   vars["Channel"] = "io.grpc.Channel";
1228   vars["CallOptions"] = "io.grpc.CallOptions";
1229   vars["MethodType"] = "io.grpc.MethodDescriptor.MethodType";
1230   vars["ServerMethodDefinition"] =
1231       "io.grpc.ServerMethodDefinition";
1232   vars["BindableService"] = "io.grpc.BindableService";
1233   vars["ServerServiceDefinition"] =
1234       "io.grpc.ServerServiceDefinition";
1235   vars["ServiceDescriptor"] =
1236       "io.grpc.ServiceDescriptor";
1237   vars["ProtoFileDescriptorSupplier"] =
1238       "io.grpc.protobuf.ProtoFileDescriptorSupplier";
1239   vars["ProtoServiceDescriptorSupplier"] =
1240       "io.grpc.protobuf.ProtoServiceDescriptorSupplier";
1241   vars["ProtoMethodDescriptorSupplier"] =
1242       "io.grpc.protobuf.ProtoMethodDescriptorSupplier";
1243   vars["AbstractStub"] = "io.grpc.stub.AbstractStub";
1244   vars["AbstractAsyncStub"] = "io.grpc.stub.AbstractAsyncStub";
1245   vars["AbstractFutureStub"] = "io.grpc.stub.AbstractFutureStub";
1246   vars["AbstractBlockingStub"] = "io.grpc.stub.AbstractBlockingStub";
1247   vars["StubFactory"] = "io.grpc.stub.AbstractStub.StubFactory";
1248   vars["RpcMethod"] = "io.grpc.stub.annotations.RpcMethod";
1249   vars["MethodDescriptor"] = "io.grpc.MethodDescriptor";
1250   vars["StreamObserver"] = "io.grpc.stub.StreamObserver";
1251   vars["Iterator"] = "java.util.Iterator";
1252   vars["Generated"] = "javax.annotation.Generated";
1253   vars["GrpcGenerated"] = "io.grpc.stub.annotations.GrpcGenerated";
1254   vars["ListenableFuture"] =
1255       "com.google.common.util.concurrent.ListenableFuture";
1256 
1257   Printer printer(out, '$');
1258   std::string package_name = ServiceJavaPackage(service->file());
1259   if (!package_name.empty()) {
1260     printer.Print(
1261         "package $package_name$;\n\n",
1262         "package_name", package_name);
1263   }
1264   PrintImports(&printer);
1265 
1266   // Package string is used to fully qualify method names.
1267   vars["Package"] = service->file()->package();
1268   if (!vars["Package"].empty()) {
1269     vars["Package"].append(".");
1270   }
1271   PrintService(service, &vars, &printer, flavor, disable_version);
1272 }
1273 
ServiceJavaPackage(const FileDescriptor * file)1274 std::string ServiceJavaPackage(const FileDescriptor* file) {
1275   std::string result = protobuf::compiler::java::ClassName(file);
1276   size_t last_dot_pos = result.find_last_of('.');
1277   if (last_dot_pos != std::string::npos) {
1278     result.resize(last_dot_pos);
1279   } else {
1280     result = "";
1281   }
1282   return result;
1283 }
1284 
ServiceClassName(const ServiceDescriptor * service)1285 std::string ServiceClassName(const ServiceDescriptor* service) {
1286   return service->name() + "Grpc";
1287 }
1288 
1289 }  // namespace java_grpc_generator
1290