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