blob: 98f8788d83fa3fe5bcde939f9f07e52240388134 [file] [log] [blame]
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001/*
2 * Copyright 2016 Google Inc. All rights reserved.
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
Austin Schuh272c6132020-11-14 16:37:52 -080017#include "src/compiler/java_generator.h"
Austin Schuhe89fa2d2019-08-14 20:24:23 -070018
19#include <algorithm>
20#include <iostream>
21#include <iterator>
22#include <map>
23#include <utility>
24#include <vector>
25
James Kuszmaul8e62b022022-03-22 09:33:25 -070026#include "flatbuffers/util.h"
Austin Schuhe89fa2d2019-08-14 20:24:23 -070027#define to_string flatbuffers::NumToString
28
29// Stringify helpers used solely to cast GRPC_VERSION
30#ifndef STR
James Kuszmaul8e62b022022-03-22 09:33:25 -070031# define STR(s) # s
Austin Schuhe89fa2d2019-08-14 20:24:23 -070032#endif
33
34#ifndef XSTR
James Kuszmaul8e62b022022-03-22 09:33:25 -070035# define XSTR(s) STR(s)
Austin Schuhe89fa2d2019-08-14 20:24:23 -070036#endif
37
Austin Schuhe89fa2d2019-08-14 20:24:23 -070038typedef grpc_generator::Printer Printer;
39typedef std::map<grpc::string, grpc::string> VARS;
40typedef grpc_generator::Service ServiceDescriptor;
41typedef grpc_generator::CommentHolder
42 DescriptorType; // base class of all 'descriptors'
43typedef grpc_generator::Method MethodDescriptor;
44
45namespace grpc_java_generator {
46typedef std::string string;
47// Generates imports for the service
James Kuszmaul8e62b022022-03-22 09:33:25 -070048void GenerateImports(grpc_generator::File *file,
49 grpc_generator::Printer *printer, VARS &vars) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -070050 vars["filename"] = file->filename();
James Kuszmaul8e62b022022-03-22 09:33:25 -070051 printer->Print(vars,
52 "//Generated by flatc compiler (version $flatc_version$)\n");
Austin Schuhe89fa2d2019-08-14 20:24:23 -070053 printer->Print("//If you make any local changes, they will be lost\n");
54 printer->Print(vars, "//source: $filename$.fbs\n\n");
55 printer->Print(vars, "package $Package$;\n\n");
56 vars["Package"] = vars["Package"] + ".";
57 if (!file->additional_headers().empty()) {
58 printer->Print(file->additional_headers().c_str());
59 printer->Print("\n\n");
60 }
61}
62
63// Adjust a method name prefix identifier to follow the JavaBean spec:
64// - decapitalize the first letter
65// - remove embedded underscores & capitalize the following letter
James Kuszmaul8e62b022022-03-22 09:33:25 -070066static string MixedLower(const string &word) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -070067 string w;
68 w += static_cast<string::value_type>(tolower(word[0]));
69 bool after_underscore = false;
70 for (size_t i = 1; i < word.length(); ++i) {
71 if (word[i] == '_') {
72 after_underscore = true;
73 } else {
74 w += after_underscore ? static_cast<string::value_type>(toupper(word[i]))
75 : word[i];
76 after_underscore = false;
77 }
78 }
79 return w;
80}
81
82// Converts to the identifier to the ALL_UPPER_CASE format.
83// - An underscore is inserted where a lower case letter is followed by an
84// upper case letter.
85// - All letters are converted to upper case
James Kuszmaul8e62b022022-03-22 09:33:25 -070086static string ToAllUpperCase(const string &word) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -070087 string w;
88 for (size_t i = 0; i < word.length(); ++i) {
89 w += static_cast<string::value_type>(toupper(word[i]));
90 if ((i < word.length() - 1) && islower(word[i]) && isupper(word[i + 1])) {
91 w += '_';
92 }
93 }
94 return w;
95}
96
James Kuszmaul8e62b022022-03-22 09:33:25 -070097static inline string LowerMethodName(const MethodDescriptor *method) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -070098 return MixedLower(method->name());
99}
100
James Kuszmaul8e62b022022-03-22 09:33:25 -0700101static inline string MethodPropertiesFieldName(const MethodDescriptor *method) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700102 return "METHOD_" + ToAllUpperCase(method->name());
103}
104
105static inline string MethodPropertiesGetterName(
James Kuszmaul8e62b022022-03-22 09:33:25 -0700106 const MethodDescriptor *method) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700107 return MixedLower("get_" + method->name() + "_method");
108}
109
James Kuszmaul8e62b022022-03-22 09:33:25 -0700110static inline string MethodIdFieldName(const MethodDescriptor *method) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700111 return "METHODID_" + ToAllUpperCase(method->name());
112}
113
James Kuszmaul8e62b022022-03-22 09:33:25 -0700114static inline string JavaClassName(VARS &vars, const string &name) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700115 // string name = google::protobuf::compiler::java::ClassName(desc);
116 return vars["Package"] + name;
117}
118
James Kuszmaul8e62b022022-03-22 09:33:25 -0700119static inline string ServiceClassName(const string &service_name) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700120 return service_name + "Grpc";
121}
122
123// TODO(nmittler): Remove once protobuf includes javadoc methods in
124// distribution.
James Kuszmaul8e62b022022-03-22 09:33:25 -0700125template<typename ITR>
126static void GrpcSplitStringToIteratorUsing(const string &full,
127 const char *delim, ITR &result) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700128 // Optimize the common case where delim is a single character.
129 if (delim[0] != '\0' && delim[1] == '\0') {
130 char c = delim[0];
James Kuszmaul8e62b022022-03-22 09:33:25 -0700131 const char *p = full.data();
132 const char *end = p + full.size();
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700133 while (p != end) {
134 if (*p == c) {
135 ++p;
136 } else {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700137 const char *start = p;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700138 while (++p != end && *p != c)
139 ;
140 *result++ = string(start, p - start);
141 }
142 }
143 return;
144 }
145
146 string::size_type begin_index, end_index;
147 begin_index = full.find_first_not_of(delim);
148 while (begin_index != string::npos) {
149 end_index = full.find_first_of(delim, begin_index);
150 if (end_index == string::npos) {
151 *result++ = full.substr(begin_index);
152 return;
153 }
154 *result++ = full.substr(begin_index, (end_index - begin_index));
155 begin_index = full.find_first_not_of(delim, end_index);
156 }
157}
158
James Kuszmaul8e62b022022-03-22 09:33:25 -0700159static void GrpcSplitStringUsing(const string &full, const char *delim,
160 std::vector<string> *result) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700161 std::back_insert_iterator<std::vector<string>> it(*result);
162 GrpcSplitStringToIteratorUsing(full, delim, it);
163}
164
James Kuszmaul8e62b022022-03-22 09:33:25 -0700165static std::vector<string> GrpcSplit(const string &full, const char *delim) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700166 std::vector<string> result;
167 GrpcSplitStringUsing(full, delim, &result);
168 return result;
169}
170
171// TODO(nmittler): Remove once protobuf includes javadoc methods in
172// distribution.
James Kuszmaul8e62b022022-03-22 09:33:25 -0700173static string GrpcEscapeJavadoc(const string &input) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700174 string result;
175 result.reserve(input.size() * 2);
176
177 char prev = '*';
178
179 for (string::size_type i = 0; i < input.size(); i++) {
180 char c = input[i];
181 switch (c) {
182 case '*':
183 // Avoid "/*".
184 if (prev == '/') {
185 result.append("&#42;");
186 } else {
187 result.push_back(c);
188 }
189 break;
190 case '/':
191 // Avoid "*/".
192 if (prev == '*') {
193 result.append("&#47;");
194 } else {
195 result.push_back(c);
196 }
197 break;
198 case '@':
199 // '@' starts javadoc tags including the @deprecated tag, which will
200 // cause a compile-time error if inserted before a declaration that
201 // does not have a corresponding @Deprecated annotation.
202 result.append("&#64;");
203 break;
204 case '<':
205 // Avoid interpretation as HTML.
206 result.append("&lt;");
207 break;
208 case '>':
209 // Avoid interpretation as HTML.
210 result.append("&gt;");
211 break;
212 case '&':
213 // Avoid interpretation as HTML.
214 result.append("&amp;");
215 break;
216 case '\\':
217 // Java interprets Unicode escape sequences anywhere!
218 result.append("&#92;");
219 break;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700220 default: result.push_back(c); break;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700221 }
222
223 prev = c;
224 }
225
226 return result;
227}
228
James Kuszmaul8e62b022022-03-22 09:33:25 -0700229static std::vector<string> GrpcGetDocLines(const string &comments) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700230 if (!comments.empty()) {
231 // TODO(kenton): Ideally we should parse the comment text as Markdown and
232 // write it back as HTML, but this requires a Markdown parser. For now
233 // we just use <pre> to get fixed-width text formatting.
234
235 // If the comment itself contains block comment start or end markers,
236 // HTML-escape them so that they don't accidentally close the doc comment.
237 string escapedComments = GrpcEscapeJavadoc(comments);
238
239 std::vector<string> lines = GrpcSplit(escapedComments, "\n");
James Kuszmaul8e62b022022-03-22 09:33:25 -0700240 while (!lines.empty() && lines.back().empty()) { lines.pop_back(); }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700241 return lines;
242 }
243 return std::vector<string>();
244}
245
246static std::vector<string> GrpcGetDocLinesForDescriptor(
James Kuszmaul8e62b022022-03-22 09:33:25 -0700247 const DescriptorType *descriptor) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700248 return descriptor->GetAllComments();
249 // return GrpcGetDocLines(descriptor->GetLeadingComments("///"));
250}
251
James Kuszmaul8e62b022022-03-22 09:33:25 -0700252static void GrpcWriteDocCommentBody(Printer *printer, VARS &vars,
253 const std::vector<string> &lines,
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700254 bool surroundWithPreTag) {
255 if (!lines.empty()) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700256 if (surroundWithPreTag) { printer->Print(" * <pre>\n"); }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700257
258 for (size_t i = 0; i < lines.size(); i++) {
259 // Most lines should start with a space. Watch out for lines that start
260 // with a /, since putting that right after the leading asterisk will
261 // close the comment.
262 vars["line"] = lines[i];
263 if (!lines[i].empty() && lines[i][0] == '/') {
264 printer->Print(vars, " * $line$\n");
265 } else {
266 printer->Print(vars, " *$line$\n");
267 }
268 }
269
James Kuszmaul8e62b022022-03-22 09:33:25 -0700270 if (surroundWithPreTag) { printer->Print(" * </pre>\n"); }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700271 }
272}
273
James Kuszmaul8e62b022022-03-22 09:33:25 -0700274static void GrpcWriteDocComment(Printer *printer, VARS &vars,
275 const string &comments) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700276 printer->Print("/**\n");
277 std::vector<string> lines = GrpcGetDocLines(comments);
278 GrpcWriteDocCommentBody(printer, vars, lines, false);
279 printer->Print(" */\n");
280}
281
James Kuszmaul8e62b022022-03-22 09:33:25 -0700282static void GrpcWriteServiceDocComment(Printer *printer, VARS &vars,
283 const ServiceDescriptor *service) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700284 printer->Print("/**\n");
285 std::vector<string> lines = GrpcGetDocLinesForDescriptor(service);
286 GrpcWriteDocCommentBody(printer, vars, lines, true);
287 printer->Print(" */\n");
288}
289
James Kuszmaul8e62b022022-03-22 09:33:25 -0700290void GrpcWriteMethodDocComment(Printer *printer, VARS &vars,
291 const MethodDescriptor *method) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700292 printer->Print("/**\n");
293 std::vector<string> lines = GrpcGetDocLinesForDescriptor(method);
294 GrpcWriteDocCommentBody(printer, vars, lines, true);
295 printer->Print(" */\n");
296}
297
James Kuszmaul8e62b022022-03-22 09:33:25 -0700298// outputs static singleton extractor for type stored in "extr_type" and
299// "extr_type_name" vars
300static void PrintTypeExtractor(Printer *p, VARS &vars) {
301 p->Print(vars,
302 "private static volatile FlatbuffersUtils.FBExtactor<$extr_type$> "
303 "extractorOf$extr_type_name$;\n"
304 "private static FlatbuffersUtils.FBExtactor<$extr_type$> "
305 "getExtractorOf$extr_type_name$() {\n"
306 " if (extractorOf$extr_type_name$ != null) return "
307 "extractorOf$extr_type_name$;\n"
308 " synchronized ($service_class_name$.class) {\n"
309 " if (extractorOf$extr_type_name$ != null) return "
310 "extractorOf$extr_type_name$;\n"
311 " extractorOf$extr_type_name$ = new "
312 "FlatbuffersUtils.FBExtactor<$extr_type$>() {\n"
313 " public $extr_type$ extract (ByteBuffer buffer) {\n"
314 " return "
315 "$extr_type$.getRootAs$extr_type_name$(buffer);\n"
316 " }\n"
317 " };\n"
318 " return extractorOf$extr_type_name$;\n"
319 " }\n"
320 "}\n\n");
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700321}
James Kuszmaul8e62b022022-03-22 09:33:25 -0700322static void PrintMethodFields(Printer *p, VARS &vars,
323 const ServiceDescriptor *service) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700324 p->Print("// Static method descriptors that strictly reflect the proto.\n");
325 vars["service_name"] = service->name();
326
James Kuszmaul8e62b022022-03-22 09:33:25 -0700327 // set of names of rpc input- and output- types that were already encountered.
328 // this is needed to avoid duplicating type extractor since it's possible that
329 // the same type is used as an input or output type of more than a single RPC
330 // method
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700331 std::set<std::string> encounteredTypes;
332
333 for (int i = 0; i < service->method_count(); ++i) {
334 auto method = service->method(i);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700335 vars["arg_in_id"] = to_string(2L * i); // trying to make msvc 10 happy
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700336 vars["arg_out_id"] = to_string(2L * i + 1);
337 vars["method_name"] = method->name();
338 vars["input_type_name"] = method->get_input_type_name();
339 vars["output_type_name"] = method->get_output_type_name();
340 vars["input_type"] = JavaClassName(vars, method->get_input_type_name());
341 vars["output_type"] = JavaClassName(vars, method->get_output_type_name());
342 vars["method_field_name"] = MethodPropertiesFieldName(method.get());
343 vars["method_new_field_name"] = MethodPropertiesGetterName(method.get());
344 vars["method_method_name"] = MethodPropertiesGetterName(method.get());
James Kuszmaul8e62b022022-03-22 09:33:25 -0700345 bool client_streaming =
346 method->ClientStreaming() || method->BidiStreaming();
347 bool server_streaming =
348 method->ServerStreaming() || method->BidiStreaming();
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700349 if (client_streaming) {
350 if (server_streaming) {
351 vars["method_type"] = "BIDI_STREAMING";
352 } else {
353 vars["method_type"] = "CLIENT_STREAMING";
354 }
355 } else {
356 if (server_streaming) {
357 vars["method_type"] = "SERVER_STREAMING";
358 } else {
359 vars["method_type"] = "UNARY";
360 }
361 }
362
363 p->Print(
364 vars,
365 "@$ExperimentalApi$(\"https://github.com/grpc/grpc-java/issues/"
366 "1901\")\n"
367 "@$Deprecated$ // Use {@link #$method_method_name$()} instead. \n"
368 "public static final $MethodDescriptor$<$input_type$,\n"
369 " $output_type$> $method_field_name$ = $method_method_name$();\n"
370 "\n"
371 "private static volatile $MethodDescriptor$<$input_type$,\n"
372 " $output_type$> $method_new_field_name$;\n"
373 "\n");
374
375 if (encounteredTypes.insert(vars["input_type_name"]).second) {
376 vars["extr_type"] = vars["input_type"];
377 vars["extr_type_name"] = vars["input_type_name"];
378 PrintTypeExtractor(p, vars);
379 }
380
381 if (encounteredTypes.insert(vars["output_type_name"]).second) {
382 vars["extr_type"] = vars["output_type"];
383 vars["extr_type_name"] = vars["output_type_name"];
384 PrintTypeExtractor(p, vars);
385 }
386
387 p->Print(
James Kuszmaul8e62b022022-03-22 09:33:25 -0700388 vars,
389 "@$ExperimentalApi$(\"https://github.com/grpc/grpc-java/issues/"
390 "1901\")\n"
391 "public static $MethodDescriptor$<$input_type$,\n"
392 " $output_type$> $method_method_name$() {\n"
393 " $MethodDescriptor$<$input_type$, $output_type$> "
394 "$method_new_field_name$;\n"
395 " if (($method_new_field_name$ = "
396 "$service_class_name$.$method_new_field_name$) == null) {\n"
397 " synchronized ($service_class_name$.class) {\n"
398 " if (($method_new_field_name$ = "
399 "$service_class_name$.$method_new_field_name$) == null) {\n"
400 " $service_class_name$.$method_new_field_name$ = "
401 "$method_new_field_name$ = \n"
402 " $MethodDescriptor$.<$input_type$, "
403 "$output_type$>newBuilder()\n"
404 " .setType($MethodType$.$method_type$)\n"
405 " .setFullMethodName(generateFullMethodName(\n"
406 " \"$Package$$service_name$\", \"$method_name$\"))\n"
407 " .setSampledToLocalTracing(true)\n"
408 " .setRequestMarshaller(FlatbuffersUtils.marshaller(\n"
409 " $input_type$.class, "
410 "getExtractorOf$input_type_name$()))\n"
411 " .setResponseMarshaller(FlatbuffersUtils.marshaller(\n"
412 " $output_type$.class, "
413 "getExtractorOf$output_type_name$()))\n");
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700414
415 // vars["proto_method_descriptor_supplier"] = service->name() +
416 // "MethodDescriptorSupplier";
417 p->Print(vars, " .setSchemaDescriptor(null)\n");
418 //" .setSchemaDescriptor(new
419 //$proto_method_descriptor_supplier$(\"$method_name$\"))\n");
420
421 p->Print(vars, " .build();\n");
422 p->Print(vars,
423 " }\n"
424 " }\n"
425 " }\n"
426 " return $method_new_field_name$;\n"
427 "}\n");
428
429 p->Print("\n");
430 }
431}
432enum StubType {
433 ASYNC_INTERFACE = 0,
434 BLOCKING_CLIENT_INTERFACE = 1,
435 FUTURE_CLIENT_INTERFACE = 2,
436 BLOCKING_SERVER_INTERFACE = 3,
437 ASYNC_CLIENT_IMPL = 4,
438 BLOCKING_CLIENT_IMPL = 5,
439 FUTURE_CLIENT_IMPL = 6,
440 ABSTRACT_CLASS = 7,
441};
442
443enum CallType { ASYNC_CALL = 0, BLOCKING_CALL = 1, FUTURE_CALL = 2 };
444
James Kuszmaul8e62b022022-03-22 09:33:25 -0700445static void PrintBindServiceMethodBody(Printer *p, VARS &vars,
446 const ServiceDescriptor *service);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700447
448// Prints a client interface or implementation class, or a server interface.
James Kuszmaul8e62b022022-03-22 09:33:25 -0700449static void PrintStub(Printer *p, VARS &vars, const ServiceDescriptor *service,
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700450 StubType type) {
451 const string service_name = service->name();
452 vars["service_name"] = service_name;
453 vars["abstract_name"] = service_name + "ImplBase";
454 string stub_name = service_name;
455 string client_name = service_name;
456 CallType call_type = ASYNC_CALL;
457 bool impl_base = false;
458 bool interface = false;
459 switch (type) {
460 case ABSTRACT_CLASS:
461 call_type = ASYNC_CALL;
462 impl_base = true;
463 break;
464 case ASYNC_CLIENT_IMPL:
465 call_type = ASYNC_CALL;
466 stub_name += "Stub";
467 break;
468 case BLOCKING_CLIENT_INTERFACE:
469 interface = true;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700470 FLATBUFFERS_FALLTHROUGH(); // fall thru
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700471 case BLOCKING_CLIENT_IMPL:
472 call_type = BLOCKING_CALL;
473 stub_name += "BlockingStub";
474 client_name += "BlockingClient";
475 break;
476 case FUTURE_CLIENT_INTERFACE:
477 interface = true;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700478 FLATBUFFERS_FALLTHROUGH(); // fall thru
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700479 case FUTURE_CLIENT_IMPL:
480 call_type = FUTURE_CALL;
481 stub_name += "FutureStub";
482 client_name += "FutureClient";
483 break;
484 case ASYNC_INTERFACE:
485 call_type = ASYNC_CALL;
486 interface = true;
487 break;
488 default:
489 GRPC_CODEGEN_FAIL << "Cannot determine class name for StubType: " << type;
490 }
491 vars["stub_name"] = stub_name;
492 vars["client_name"] = client_name;
493
494 // Class head
James Kuszmaul8e62b022022-03-22 09:33:25 -0700495 if (!interface) { GrpcWriteServiceDocComment(p, vars, service); }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700496 if (impl_base) {
497 p->Print(vars,
498 "public static abstract class $abstract_name$ implements "
499 "$BindableService$ {\n");
500 } else {
501 p->Print(vars,
502 "public static final class $stub_name$ extends "
503 "$AbstractStub$<$stub_name$> {\n");
504 }
505 p->Indent();
506
507 // Constructor and build() method
508 if (!impl_base && !interface) {
509 p->Print(vars, "private $stub_name$($Channel$ channel) {\n");
510 p->Indent();
511 p->Print("super(channel);\n");
512 p->Outdent();
513 p->Print("}\n\n");
514 p->Print(vars,
515 "private $stub_name$($Channel$ channel,\n"
516 " $CallOptions$ callOptions) {\n");
517 p->Indent();
518 p->Print("super(channel, callOptions);\n");
519 p->Outdent();
520 p->Print("}\n\n");
521 p->Print(vars,
522 "@$Override$\n"
523 "protected $stub_name$ build($Channel$ channel,\n"
524 " $CallOptions$ callOptions) {\n");
525 p->Indent();
526 p->Print(vars, "return new $stub_name$(channel, callOptions);\n");
527 p->Outdent();
528 p->Print("}\n");
529 }
530
531 // RPC methods
532 for (int i = 0; i < service->method_count(); ++i) {
533 auto method = service->method(i);
534 vars["input_type"] = JavaClassName(vars, method->get_input_type_name());
535 vars["output_type"] = JavaClassName(vars, method->get_output_type_name());
536 vars["lower_method_name"] = LowerMethodName(&*method);
537 vars["method_method_name"] = MethodPropertiesGetterName(&*method);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700538 bool client_streaming =
539 method->ClientStreaming() || method->BidiStreaming();
540 bool server_streaming =
541 method->ServerStreaming() || method->BidiStreaming();
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700542
543 if (call_type == BLOCKING_CALL && client_streaming) {
544 // Blocking client interface with client streaming is not available
545 continue;
546 }
547
548 if (call_type == FUTURE_CALL && (client_streaming || server_streaming)) {
549 // Future interface doesn't support streaming.
550 continue;
551 }
552
553 // Method signature
554 p->Print("\n");
555 // TODO(nmittler): Replace with WriteMethodDocComment once included by the
556 // protobuf distro.
James Kuszmaul8e62b022022-03-22 09:33:25 -0700557 if (!interface) { GrpcWriteMethodDocComment(p, vars, &*method); }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700558 p->Print("public ");
559 switch (call_type) {
560 case BLOCKING_CALL:
561 GRPC_CODEGEN_CHECK(!client_streaming)
562 << "Blocking client interface with client streaming is unavailable";
563 if (server_streaming) {
564 // Server streaming
565 p->Print(vars,
566 "$Iterator$<$output_type$> $lower_method_name$(\n"
567 " $input_type$ request)");
568 } else {
569 // Simple RPC
570 p->Print(vars,
571 "$output_type$ $lower_method_name$($input_type$ request)");
572 }
573 break;
574 case ASYNC_CALL:
575 if (client_streaming) {
576 // Bidirectional streaming or client streaming
577 p->Print(vars,
578 "$StreamObserver$<$input_type$> $lower_method_name$(\n"
579 " $StreamObserver$<$output_type$> responseObserver)");
580 } else {
581 // Server streaming or simple RPC
582 p->Print(vars,
583 "void $lower_method_name$($input_type$ request,\n"
584 " $StreamObserver$<$output_type$> responseObserver)");
585 }
586 break;
587 case FUTURE_CALL:
588 GRPC_CODEGEN_CHECK(!client_streaming && !server_streaming)
589 << "Future interface doesn't support streaming. "
590 << "client_streaming=" << client_streaming << ", "
591 << "server_streaming=" << server_streaming;
592 p->Print(vars,
593 "$ListenableFuture$<$output_type$> $lower_method_name$(\n"
594 " $input_type$ request)");
595 break;
596 }
597
598 if (interface) {
599 p->Print(";\n");
600 continue;
601 }
602 // Method body.
603 p->Print(" {\n");
604 p->Indent();
605 if (impl_base) {
606 switch (call_type) {
607 // NB: Skipping validation of service methods. If something is wrong,
608 // we wouldn't get to this point as compiler would return errors when
609 // generating service interface.
610 case ASYNC_CALL:
611 if (client_streaming) {
612 p->Print(vars,
613 "return "
614 "asyncUnimplementedStreamingCall($method_method_name$(), "
615 "responseObserver);\n");
616 } else {
617 p->Print(vars,
618 "asyncUnimplementedUnaryCall($method_method_name$(), "
619 "responseObserver);\n");
620 }
621 break;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700622 default: break;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700623 }
624 } else if (!interface) {
625 switch (call_type) {
626 case BLOCKING_CALL:
627 GRPC_CODEGEN_CHECK(!client_streaming)
628 << "Blocking client streaming interface is not available";
629 if (server_streaming) {
630 vars["calls_method"] = "blockingServerStreamingCall";
631 vars["params"] = "request";
632 } else {
633 vars["calls_method"] = "blockingUnaryCall";
634 vars["params"] = "request";
635 }
636 p->Print(vars,
637 "return $calls_method$(\n"
638 " getChannel(), $method_method_name$(), "
639 "getCallOptions(), $params$);\n");
640 break;
641 case ASYNC_CALL:
642 if (server_streaming) {
643 if (client_streaming) {
644 vars["calls_method"] = "asyncBidiStreamingCall";
645 vars["params"] = "responseObserver";
646 } else {
647 vars["calls_method"] = "asyncServerStreamingCall";
648 vars["params"] = "request, responseObserver";
649 }
650 } else {
651 if (client_streaming) {
652 vars["calls_method"] = "asyncClientStreamingCall";
653 vars["params"] = "responseObserver";
654 } else {
655 vars["calls_method"] = "asyncUnaryCall";
656 vars["params"] = "request, responseObserver";
657 }
658 }
659 vars["last_line_prefix"] = client_streaming ? "return " : "";
660 p->Print(vars,
661 "$last_line_prefix$$calls_method$(\n"
662 " getChannel().newCall($method_method_name$(), "
663 "getCallOptions()), $params$);\n");
664 break;
665 case FUTURE_CALL:
666 GRPC_CODEGEN_CHECK(!client_streaming && !server_streaming)
667 << "Future interface doesn't support streaming. "
668 << "client_streaming=" << client_streaming << ", "
669 << "server_streaming=" << server_streaming;
670 vars["calls_method"] = "futureUnaryCall";
671 p->Print(vars,
672 "return $calls_method$(\n"
673 " getChannel().newCall($method_method_name$(), "
674 "getCallOptions()), request);\n");
675 break;
676 }
677 }
678 p->Outdent();
679 p->Print("}\n");
680 }
681
682 if (impl_base) {
683 p->Print("\n");
684 p->Print(
685 vars,
686 "@$Override$ public final $ServerServiceDefinition$ bindService() {\n");
687 vars["instance"] = "this";
688 PrintBindServiceMethodBody(p, vars, service);
689 p->Print("}\n");
690 }
691
692 p->Outdent();
693 p->Print("}\n\n");
694}
695
696static bool CompareMethodClientStreaming(
James Kuszmaul8e62b022022-03-22 09:33:25 -0700697 const std::unique_ptr<const grpc_generator::Method> &method1,
698 const std::unique_ptr<const grpc_generator::Method> &method2) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700699 return method1->ClientStreaming() < method2->ClientStreaming();
700}
701
702// Place all method invocations into a single class to reduce memory footprint
703// on Android.
James Kuszmaul8e62b022022-03-22 09:33:25 -0700704static void PrintMethodHandlerClass(Printer *p, VARS &vars,
705 const ServiceDescriptor *service) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700706 // Sort method ids based on ClientStreaming() so switch tables are compact.
707 std::vector<std::unique_ptr<const grpc_generator::Method>> sorted_methods(
708 service->method_count());
709 for (int i = 0; i < service->method_count(); ++i) {
710 sorted_methods[i] = service->method(i);
711 }
712 stable_sort(sorted_methods.begin(), sorted_methods.end(),
713 CompareMethodClientStreaming);
714 for (size_t i = 0; i < sorted_methods.size(); i++) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700715 auto &method = sorted_methods[i];
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700716 vars["method_id"] = to_string(i);
717 vars["method_id_name"] = MethodIdFieldName(&*method);
718 p->Print(vars,
719 "private static final int $method_id_name$ = $method_id$;\n");
720 }
721 p->Print("\n");
722 vars["service_name"] = service->name() + "ImplBase";
723 p->Print(vars,
724 "private static final class MethodHandlers<Req, Resp> implements\n"
725 " io.grpc.stub.ServerCalls.UnaryMethod<Req, Resp>,\n"
726 " io.grpc.stub.ServerCalls.ServerStreamingMethod<Req, Resp>,\n"
727 " io.grpc.stub.ServerCalls.ClientStreamingMethod<Req, Resp>,\n"
728 " io.grpc.stub.ServerCalls.BidiStreamingMethod<Req, Resp> {\n"
729 " private final $service_name$ serviceImpl;\n"
730 " private final int methodId;\n"
731 "\n"
732 " MethodHandlers($service_name$ serviceImpl, int methodId) {\n"
733 " this.serviceImpl = serviceImpl;\n"
734 " this.methodId = methodId;\n"
735 " }\n\n");
736 p->Indent();
737 p->Print(vars,
738 "@$Override$\n"
739 "@java.lang.SuppressWarnings(\"unchecked\")\n"
740 "public void invoke(Req request, $StreamObserver$<Resp> "
741 "responseObserver) {\n"
742 " switch (methodId) {\n");
743 p->Indent();
744 p->Indent();
745
746 for (int i = 0; i < service->method_count(); ++i) {
747 auto method = service->method(i);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700748 if (method->ClientStreaming() || method->BidiStreaming()) { continue; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700749 vars["method_id_name"] = MethodIdFieldName(&*method);
750 vars["lower_method_name"] = LowerMethodName(&*method);
751 vars["input_type"] = JavaClassName(vars, method->get_input_type_name());
752 vars["output_type"] = JavaClassName(vars, method->get_output_type_name());
753 p->Print(vars,
754 "case $method_id_name$:\n"
755 " serviceImpl.$lower_method_name$(($input_type$) request,\n"
756 " ($StreamObserver$<$output_type$>) responseObserver);\n"
757 " break;\n");
758 }
759 p->Print(
760 "default:\n"
761 " throw new AssertionError();\n");
762
763 p->Outdent();
764 p->Outdent();
765 p->Print(
766 " }\n"
767 "}\n\n");
768
769 p->Print(vars,
770 "@$Override$\n"
771 "@java.lang.SuppressWarnings(\"unchecked\")\n"
772 "public $StreamObserver$<Req> invoke(\n"
773 " $StreamObserver$<Resp> responseObserver) {\n"
774 " switch (methodId) {\n");
775 p->Indent();
776 p->Indent();
777
778 for (int i = 0; i < service->method_count(); ++i) {
779 auto method = service->method(i);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700780 if (!(method->ClientStreaming() || method->BidiStreaming())) { continue; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700781 vars["method_id_name"] = MethodIdFieldName(&*method);
782 vars["lower_method_name"] = LowerMethodName(&*method);
783 vars["input_type"] = JavaClassName(vars, method->get_input_type_name());
784 vars["output_type"] = JavaClassName(vars, method->get_output_type_name());
785 p->Print(
786 vars,
787 "case $method_id_name$:\n"
788 " return ($StreamObserver$<Req>) serviceImpl.$lower_method_name$(\n"
789 " ($StreamObserver$<$output_type$>) responseObserver);\n");
790 }
791 p->Print(
792 "default:\n"
793 " throw new AssertionError();\n");
794
795 p->Outdent();
796 p->Outdent();
797 p->Print(
798 " }\n"
799 "}\n");
800
801 p->Outdent();
802 p->Print("}\n\n");
803}
804
James Kuszmaul8e62b022022-03-22 09:33:25 -0700805static void PrintGetServiceDescriptorMethod(Printer *p, VARS &vars,
806 const ServiceDescriptor *service) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700807 vars["service_name"] = service->name();
808 // vars["proto_base_descriptor_supplier"] = service->name() +
809 // "BaseDescriptorSupplier"; vars["proto_file_descriptor_supplier"] =
810 // service->name() + "FileDescriptorSupplier";
811 // vars["proto_method_descriptor_supplier"] = service->name() +
812 // "MethodDescriptorSupplier"; vars["proto_class_name"] =
813 // google::protobuf::compiler::java::ClassName(service->file());
814 // p->Print(
815 // vars,
816 // "private static abstract class
817 // $proto_base_descriptor_supplier$\n" " implements
818 // $ProtoFileDescriptorSupplier$,
819 // $ProtoServiceDescriptorSupplier$ {\n" "
820 // $proto_base_descriptor_supplier$() {}\n"
821 // "\n"
822 // " @$Override$\n"
823 // " public com.google.protobuf.Descriptors.FileDescriptor
824 // getFileDescriptor() {\n" " return
825 // $proto_class_name$.getDescriptor();\n" " }\n"
826 // "\n"
827 // " @$Override$\n"
828 // " public com.google.protobuf.Descriptors.ServiceDescriptor
829 // getServiceDescriptor() {\n" " return
830 // getFileDescriptor().findServiceByName(\"$service_name$\");\n"
831 // " }\n"
832 // "}\n"
833 // "\n"
834 // "private static final class
835 // $proto_file_descriptor_supplier$\n" " extends
836 // $proto_base_descriptor_supplier$ {\n" "
837 // $proto_file_descriptor_supplier$() {}\n"
838 // "}\n"
839 // "\n"
840 // "private static final class
841 // $proto_method_descriptor_supplier$\n" " extends
842 // $proto_base_descriptor_supplier$\n" " implements
843 // $ProtoMethodDescriptorSupplier$ {\n" " private final
844 // String methodName;\n"
845 // "\n"
846 // " $proto_method_descriptor_supplier$(String methodName)
847 // {\n" " this.methodName = methodName;\n" " }\n"
848 // "\n"
849 // " @$Override$\n"
850 // " public com.google.protobuf.Descriptors.MethodDescriptor
851 // getMethodDescriptor() {\n" " return
852 // getServiceDescriptor().findMethodByName(methodName);\n" "
853 // }\n"
854 // "}\n\n");
855
856 p->Print(
857 vars,
858 "private static volatile $ServiceDescriptor$ serviceDescriptor;\n\n");
859
860 p->Print(vars,
861 "public static $ServiceDescriptor$ getServiceDescriptor() {\n");
862 p->Indent();
863 p->Print(vars, "$ServiceDescriptor$ result = serviceDescriptor;\n");
864 p->Print("if (result == null) {\n");
865 p->Indent();
866 p->Print(vars, "synchronized ($service_class_name$.class) {\n");
867 p->Indent();
868 p->Print("result = serviceDescriptor;\n");
869 p->Print("if (result == null) {\n");
870 p->Indent();
871
872 p->Print(vars,
873 "serviceDescriptor = result = "
874 "$ServiceDescriptor$.newBuilder(SERVICE_NAME)");
875 p->Indent();
876 p->Indent();
877 p->Print(vars, "\n.setSchemaDescriptor(null)");
878 for (int i = 0; i < service->method_count(); ++i) {
879 auto method = service->method(i);
880 vars["method_method_name"] = MethodPropertiesGetterName(&*method);
881 p->Print(vars, "\n.addMethod($method_method_name$())");
882 }
883 p->Print("\n.build();\n");
884 p->Outdent();
885 p->Outdent();
886
887 p->Outdent();
888 p->Print("}\n");
889 p->Outdent();
890 p->Print("}\n");
891 p->Outdent();
892 p->Print("}\n");
893 p->Print("return result;\n");
894 p->Outdent();
895 p->Print("}\n");
896}
897
James Kuszmaul8e62b022022-03-22 09:33:25 -0700898static void PrintBindServiceMethodBody(Printer *p, VARS &vars,
899 const ServiceDescriptor *service) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700900 vars["service_name"] = service->name();
901 p->Indent();
902 p->Print(vars,
903 "return "
904 "$ServerServiceDefinition$.builder(getServiceDescriptor())\n");
905 p->Indent();
906 p->Indent();
907 for (int i = 0; i < service->method_count(); ++i) {
908 auto method = service->method(i);
909 vars["lower_method_name"] = LowerMethodName(&*method);
910 vars["method_method_name"] = MethodPropertiesGetterName(&*method);
911 vars["input_type"] = JavaClassName(vars, method->get_input_type_name());
912 vars["output_type"] = JavaClassName(vars, method->get_output_type_name());
913 vars["method_id_name"] = MethodIdFieldName(&*method);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700914 bool client_streaming =
915 method->ClientStreaming() || method->BidiStreaming();
916 bool server_streaming =
917 method->ServerStreaming() || method->BidiStreaming();
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700918 if (client_streaming) {
919 if (server_streaming) {
920 vars["calls_method"] = "asyncBidiStreamingCall";
921 } else {
922 vars["calls_method"] = "asyncClientStreamingCall";
923 }
924 } else {
925 if (server_streaming) {
926 vars["calls_method"] = "asyncServerStreamingCall";
927 } else {
928 vars["calls_method"] = "asyncUnaryCall";
929 }
930 }
931 p->Print(vars, ".addMethod(\n");
932 p->Indent();
933 p->Print(vars,
934 "$method_method_name$(),\n"
935 "$calls_method$(\n");
936 p->Indent();
937 p->Print(vars,
938 "new MethodHandlers<\n"
939 " $input_type$,\n"
940 " $output_type$>(\n"
941 " $instance$, $method_id_name$)))\n");
942 p->Outdent();
943 p->Outdent();
944 }
945 p->Print(".build();\n");
946 p->Outdent();
947 p->Outdent();
948 p->Outdent();
949}
950
James Kuszmaul8e62b022022-03-22 09:33:25 -0700951static void PrintService(Printer *p, VARS &vars,
952 const ServiceDescriptor *service,
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700953 bool disable_version) {
954 vars["service_name"] = service->name();
955 vars["service_class_name"] = ServiceClassName(service->name());
956 vars["grpc_version"] = "";
957#ifdef GRPC_VERSION
958 if (!disable_version) {
959 vars["grpc_version"] = " (version " XSTR(GRPC_VERSION) ")";
960 }
961#else
962 (void)disable_version;
963#endif
964 // TODO(nmittler): Replace with WriteServiceDocComment once included by
965 // protobuf distro.
966 GrpcWriteServiceDocComment(p, vars, service);
967 p->Print(vars,
968 "@$Generated$(\n"
969 " value = \"by gRPC proto compiler$grpc_version$\",\n"
970 " comments = \"Source: $file_name$.fbs\")\n"
971 "public final class $service_class_name$ {\n\n");
972 p->Indent();
973 p->Print(vars, "private $service_class_name$() {}\n\n");
974
975 p->Print(vars,
976 "public static final String SERVICE_NAME = "
977 "\"$Package$$service_name$\";\n\n");
978
979 PrintMethodFields(p, vars, service);
980
981 // TODO(nmittler): Replace with WriteDocComment once included by protobuf
982 // distro.
983 GrpcWriteDocComment(
984 p, vars,
985 " Creates a new async stub that supports all call types for the service");
986 p->Print(vars,
987 "public static $service_name$Stub newStub($Channel$ channel) {\n");
988 p->Indent();
989 p->Print(vars, "return new $service_name$Stub(channel);\n");
990 p->Outdent();
991 p->Print("}\n\n");
992
993 // TODO(nmittler): Replace with WriteDocComment once included by protobuf
994 // distro.
995 GrpcWriteDocComment(
996 p, vars,
997 " Creates a new blocking-style stub that supports unary and streaming "
998 "output calls on the service");
999 p->Print(vars,
1000 "public static $service_name$BlockingStub newBlockingStub(\n"
1001 " $Channel$ channel) {\n");
1002 p->Indent();
1003 p->Print(vars, "return new $service_name$BlockingStub(channel);\n");
1004 p->Outdent();
1005 p->Print("}\n\n");
1006
1007 // TODO(nmittler): Replace with WriteDocComment once included by protobuf
1008 // distro.
1009 GrpcWriteDocComment(
1010 p, vars,
1011 " Creates a new ListenableFuture-style stub that supports unary calls "
1012 "on the service");
1013 p->Print(vars,
1014 "public static $service_name$FutureStub newFutureStub(\n"
1015 " $Channel$ channel) {\n");
1016 p->Indent();
1017 p->Print(vars, "return new $service_name$FutureStub(channel);\n");
1018 p->Outdent();
1019 p->Print("}\n\n");
1020
1021 PrintStub(p, vars, service, ABSTRACT_CLASS);
1022 PrintStub(p, vars, service, ASYNC_CLIENT_IMPL);
1023 PrintStub(p, vars, service, BLOCKING_CLIENT_IMPL);
1024 PrintStub(p, vars, service, FUTURE_CLIENT_IMPL);
1025
1026 PrintMethodHandlerClass(p, vars, service);
1027 PrintGetServiceDescriptorMethod(p, vars, service);
1028 p->Outdent();
1029 p->Print("}\n");
1030}
1031
James Kuszmaul8e62b022022-03-22 09:33:25 -07001032void PrintStaticImports(Printer *p) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001033 p->Print(
1034 "import java.nio.ByteBuffer;\n"
1035 "import static "
1036 "io.grpc.MethodDescriptor.generateFullMethodName;\n"
1037 "import static "
1038 "io.grpc.stub.ClientCalls.asyncBidiStreamingCall;\n"
1039 "import static "
1040 "io.grpc.stub.ClientCalls.asyncClientStreamingCall;\n"
1041 "import static "
1042 "io.grpc.stub.ClientCalls.asyncServerStreamingCall;\n"
1043 "import static "
1044 "io.grpc.stub.ClientCalls.asyncUnaryCall;\n"
1045 "import static "
1046 "io.grpc.stub.ClientCalls.blockingServerStreamingCall;\n"
1047 "import static "
1048 "io.grpc.stub.ClientCalls.blockingUnaryCall;\n"
1049 "import static "
1050 "io.grpc.stub.ClientCalls.futureUnaryCall;\n"
1051 "import static "
1052 "io.grpc.stub.ServerCalls.asyncBidiStreamingCall;\n"
1053 "import static "
1054 "io.grpc.stub.ServerCalls.asyncClientStreamingCall;\n"
1055 "import static "
1056 "io.grpc.stub.ServerCalls.asyncServerStreamingCall;\n"
1057 "import static "
1058 "io.grpc.stub.ServerCalls.asyncUnaryCall;\n"
1059 "import static "
1060 "io.grpc.stub.ServerCalls.asyncUnimplementedStreamingCall;\n"
1061 "import static "
1062 "io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall;\n\n");
1063}
1064
James Kuszmaul8e62b022022-03-22 09:33:25 -07001065void GenerateService(const grpc_generator::Service *service,
1066 grpc_generator::Printer *printer, VARS &vars,
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001067 bool disable_version) {
1068 // All non-generated classes must be referred by fully qualified names to
1069 // avoid collision with generated classes.
1070 vars["String"] = "java.lang.String";
1071 vars["Deprecated"] = "java.lang.Deprecated";
1072 vars["Override"] = "java.lang.Override";
1073 vars["Channel"] = "io.grpc.Channel";
1074 vars["CallOptions"] = "io.grpc.CallOptions";
1075 vars["MethodType"] = "io.grpc.MethodDescriptor.MethodType";
1076 vars["ServerMethodDefinition"] = "io.grpc.ServerMethodDefinition";
1077 vars["BindableService"] = "io.grpc.BindableService";
1078 vars["ServerServiceDefinition"] = "io.grpc.ServerServiceDefinition";
1079 vars["ServiceDescriptor"] = "io.grpc.ServiceDescriptor";
1080 vars["ProtoFileDescriptorSupplier"] =
1081 "io.grpc.protobuf.ProtoFileDescriptorSupplier";
1082 vars["ProtoServiceDescriptorSupplier"] =
1083 "io.grpc.protobuf.ProtoServiceDescriptorSupplier";
1084 vars["ProtoMethodDescriptorSupplier"] =
1085 "io.grpc.protobuf.ProtoMethodDescriptorSupplier";
1086 vars["AbstractStub"] = "io.grpc.stub.AbstractStub";
1087 vars["MethodDescriptor"] = "io.grpc.MethodDescriptor";
1088 vars["NanoUtils"] = "io.grpc.protobuf.nano.NanoUtils";
1089 vars["StreamObserver"] = "io.grpc.stub.StreamObserver";
1090 vars["Iterator"] = "java.util.Iterator";
1091 vars["Generated"] = "javax.annotation.Generated";
1092 vars["ListenableFuture"] =
1093 "com.google.common.util.concurrent.ListenableFuture";
1094 vars["ExperimentalApi"] = "io.grpc.ExperimentalApi";
1095
1096 PrintStaticImports(printer);
1097
1098 PrintService(printer, vars, service, disable_version);
1099}
1100
1101grpc::string GenerateServiceSource(
James Kuszmaul8e62b022022-03-22 09:33:25 -07001102 grpc_generator::File *file, const grpc_generator::Service *service,
1103 grpc_java_generator::Parameters *parameters) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001104 grpc::string out;
1105 auto printer = file->CreatePrinter(&out);
1106 VARS vars;
1107 vars["flatc_version"] = grpc::string(
1108 FLATBUFFERS_STRING(FLATBUFFERS_VERSION_MAJOR) "." FLATBUFFERS_STRING(
1109 FLATBUFFERS_VERSION_MINOR) "." FLATBUFFERS_STRING(FLATBUFFERS_VERSION_REVISION));
1110
1111 vars["file_name"] = file->filename();
1112
1113 if (!parameters->package_name.empty()) {
1114 vars["Package"] = parameters->package_name; // ServiceJavaPackage(service);
1115 }
1116 GenerateImports(file, &*printer, vars);
1117 GenerateService(service, &*printer, vars, false);
1118 return out;
1119}
1120
1121} // namespace grpc_java_generator