1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 #include <cassert>
21 #include <ctime>
22
23 #include <cctype>
24 #include <fstream>
25 #include <iomanip>
26 #include <iostream>
27 #include <limits>
28 #include <sstream>
29 #include <string>
30 #include <vector>
31
32 #include <stdexcept>
33 #include <sys/stat.h>
34
35 #include "thrift/generate/t_oop_generator.h"
36 #include "thrift/platform.h"
37
38 using std::map;
39 using std::ostream;
40 using std::ostringstream;
41 using std::setfill;
42 using std::set;
43 using std::setw;
44 using std::string;
45 using std::stringstream;
46 using std::vector;
47
48 static const string endl = "\n"; // avoid ostream << std::endl flushes
49
50 static const string thrift_option_class = "org.apache.thrift.Option";
51 static const string jdk_option_class = "java.util.Optional";
52
53 /**
54 * Java code generator.
55 *
56 */
57 class t_java_generator : public t_oop_generator {
58 public:
t_java_generator(t_program * program,const std::map<std::string,std::string> & parsed_options,const std::string & option_string)59 t_java_generator(t_program* program,
60 const std::map<std::string, std::string>& parsed_options,
61 const std::string& option_string)
62 : t_oop_generator(program) {
63 (void)option_string;
64 std::map<std::string, std::string>::const_iterator iter;
65
66 bean_style_ = false;
67 android_style_ = false;
68 private_members_ = false;
69 nocamel_style_ = false;
70 fullcamel_style_ = false;
71 android_legacy_ = false;
72 sorted_containers_ = false;
73 java5_ = false;
74 reuse_objects_ = false;
75 use_option_type_ = false;
76 generate_future_iface_ = false;
77 use_jdk8_option_type_ = false;
78 undated_generated_annotations_ = false;
79 suppress_generated_annotations_ = false;
80 rethrow_unhandled_exceptions_ = false;
81 unsafe_binaries_ = false;
82 annotations_as_metadata_ = false;
83 for (iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
84 if (iter->first.compare("beans") == 0) {
85 bean_style_ = true;
86 } else if (iter->first.compare("android") == 0) {
87 android_style_ = true;
88 } else if (iter->first.compare("private_members") == 0
89 || iter->first.compare("private-members") == 0) {
90 // keep both private_members and private-members (legacy) for backwards compatibility
91 private_members_ = true;
92 } else if (iter->first.compare("nocamel") == 0) {
93 nocamel_style_ = true;
94 } else if (iter->first.compare("fullcamel") == 0) {
95 fullcamel_style_ = true;
96 } else if (iter->first.compare("android_legacy") == 0) {
97 android_legacy_ = true;
98 } else if (iter->first.compare("sorted_containers") == 0) {
99 sorted_containers_ = true;
100 } else if (iter->first.compare("java5") == 0) {
101 java5_ = true;
102 } else if (iter->first.compare("future_iface") == 0) {
103 generate_future_iface_ = true;
104 } else if (iter->first.compare("reuse_objects") == 0
105 || iter->first.compare("reuse-objects") == 0) {
106 // keep both reuse_objects and reuse-objects (legacy) for backwards compatibility
107 reuse_objects_ = true;
108 } else if (iter->first.compare("option_type") == 0) {
109 use_option_type_ = true;
110 if (iter->second.compare("jdk8") == 0) {
111 use_jdk8_option_type_ = true;
112 } else if (iter->second.compare("thrift") == 0 || iter->second.compare("") == 0) {
113 use_jdk8_option_type_ = false;
114 } else {
115 throw "option_type must be 'jdk8' or 'thrift'";
116 }
117 } else if (iter->first.compare("rethrow_unhandled_exceptions") == 0) {
118 rethrow_unhandled_exceptions_ = true;
119 } else if (iter->first.compare("generated_annotations") == 0) {
120 if (iter->second.compare("undated") == 0) {
121 undated_generated_annotations_ = true;
122 } else if (iter->second.compare("suppress") == 0) {
123 suppress_generated_annotations_ = true;
124 } else {
125 throw "unknown option java:" + iter->first + "=" + iter->second;
126 }
127 } else if (iter->first.compare("unsafe_binaries") == 0) {
128 unsafe_binaries_ = true;
129 } else if (iter->first.compare("annotations_as_metadata") == 0) {
130 annotations_as_metadata_ = true;
131 } else {
132 throw "unknown option java:" + iter->first;
133 }
134 }
135
136 if (java5_) {
137 android_legacy_ = true;
138 }
139
140 out_dir_base_ = (bean_style_ ? "gen-javabean" : "gen-java");
141 }
142
143 /**
144 * Init and close methods
145 */
146
147 void init_generator() override;
148 void close_generator() override;
149 std::string display_name() const override;
150
151 void generate_consts(std::vector<t_const*> consts) override;
152
153 /**
154 * Program-level generation functions
155 */
156
157 void generate_typedef(t_typedef* ttypedef) override;
158 void generate_enum(t_enum* tenum) override;
159 void generate_struct(t_struct* tstruct) override;
160 void generate_union(t_struct* tunion);
161 void generate_xception(t_struct* txception) override;
162 void generate_service(t_service* tservice) override;
163
164 void print_const_value(std::ostream& out,
165 std::string name,
166 t_type* type,
167 t_const_value* value,
168 bool in_static,
169 bool defval = false);
170 std::string render_const_value(std::ostream& out, t_type* type, t_const_value* value);
171
172 /**
173 * Service-level generation functions
174 */
175
176 void generate_java_struct(t_struct* tstruct, bool is_exception);
177
178 void generate_java_struct_definition(std::ostream& out,
179 t_struct* tstruct,
180 bool is_xception = false,
181 bool in_class = false,
182 bool is_result = false);
183 void generate_java_struct_parcelable(std::ostream& out, t_struct* tstruct);
184 void generate_java_struct_equality(std::ostream& out, t_struct* tstruct);
185 void generate_java_struct_compare_to(std::ostream& out, t_struct* tstruct);
186 void generate_java_struct_reader(std::ostream& out, t_struct* tstruct);
187 void generate_java_validator(std::ostream& out, t_struct* tstruct);
188 void generate_java_struct_result_writer(std::ostream& out, t_struct* tstruct);
189 void generate_java_struct_writer(std::ostream& out, t_struct* tstruct);
190 void generate_java_struct_tostring(std::ostream& out, t_struct* tstruct);
191 void generate_java_struct_clear(std::ostream& out, t_struct* tstruct);
192 void generate_java_struct_write_object(std::ostream& out, t_struct* tstruct);
193 void generate_java_struct_read_object(std::ostream& out, t_struct* tstruct);
194 void generate_java_meta_data_map(std::ostream& out, t_struct* tstruct);
195 void generate_field_value_meta_data(std::ostream& out, t_type* type);
196 void generate_metadata_for_field_annotations(std::ostream& out, t_field* field);
197 std::string get_java_type_string(t_type* type);
198 void generate_java_struct_field_by_id(ostream& out, t_struct* tstruct);
199 void generate_reflection_setters(std::ostringstream& out,
200 t_type* type,
201 std::string field_name,
202 std::string cap_name);
203 void generate_reflection_getters(std::ostringstream& out,
204 t_type* type,
205 std::string field_name,
206 std::string cap_name);
207 void generate_generic_field_getters_setters(std::ostream& out, t_struct* tstruct);
208 void generate_generic_isset_method(std::ostream& out, t_struct* tstruct);
209 void generate_java_bean_boilerplate(std::ostream& out, t_struct* tstruct);
210
211 void generate_function_helpers(t_function* tfunction);
212 std::string as_camel_case(std::string name, bool ucfirst = true);
213 std::string get_rpc_method_name(std::string name);
214 std::string get_cap_name(std::string name);
215 std::string generate_isset_check(t_field* field);
216 std::string generate_isset_check(std::string field);
217 void generate_isset_set(ostream& out, t_field* field, std::string prefix);
218 std::string isset_field_id(t_field* field);
219
220 void generate_service_interface(t_service* tservice);
221 void generate_service_async_interface(t_service* tservice);
222 void generate_service_future_interface(t_service* tservice);
223 void generate_service_helpers(t_service* tservice);
224 void generate_service_client(t_service* tservice);
225 void generate_service_async_client(t_service* tservice);
226 void generate_service_future_client(t_service* tservice);
227 void generate_service_server(t_service* tservice);
228 void generate_service_async_server(t_service* tservice);
229 void generate_process_function(t_service* tservice, t_function* tfunction);
230 void generate_process_async_function(t_service* tservice, t_function* tfunction);
231
232 void generate_java_union(t_struct* tstruct);
233 void generate_union_constructor(ostream& out, t_struct* tstruct);
234 void generate_union_getters_and_setters(ostream& out, t_struct* tstruct);
235 void generate_union_is_set_methods(ostream& out, t_struct* tstruct);
236 void generate_union_abstract_methods(ostream& out, t_struct* tstruct);
237 void generate_check_type(ostream& out, t_struct* tstruct);
238 void generate_standard_scheme_read_value(ostream& out, t_struct* tstruct);
239 void generate_standard_scheme_write_value(ostream& out, t_struct* tstruct);
240 void generate_tuple_scheme_read_value(ostream& out, t_struct* tstruct);
241 void generate_tuple_scheme_write_value(ostream& out, t_struct* tstruct);
242 void generate_get_field_desc(ostream& out, t_struct* tstruct);
243 void generate_get_struct_desc(ostream& out, t_struct* tstruct);
244 void generate_get_field_name(ostream& out, t_struct* tstruct);
245
246 void generate_union_comparisons(ostream& out, t_struct* tstruct);
247 void generate_union_hashcode(ostream& out, t_struct* tstruct);
248
249 void generate_scheme_map(ostream& out, t_struct* tstruct);
250 void generate_standard_writer(ostream& out, t_struct* tstruct, bool is_result);
251 void generate_standard_reader(ostream& out, t_struct* tstruct);
252 void generate_java_struct_standard_scheme(ostream& out, t_struct* tstruct, bool is_result);
253
254 void generate_java_struct_tuple_scheme(ostream& out, t_struct* tstruct);
255 void generate_java_struct_tuple_reader(ostream& out, t_struct* tstruct);
256 void generate_java_struct_tuple_writer(ostream& out, t_struct* tstruct);
257
258 void generate_java_scheme_lookup(ostream& out);
259
260 void generate_javax_generated_annotation(ostream& out);
261 /**
262 * Serialization constructs
263 */
264
265 void generate_deserialize_field(std::ostream& out,
266 t_field* tfield,
267 std::string prefix = "",
268 bool has_metadata = true);
269
270 void generate_deserialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
271
272 void generate_deserialize_container(std::ostream& out,
273 t_type* ttype,
274 std::string prefix = "",
275 bool has_metadata = true);
276
277 void generate_deserialize_set_element(std::ostream& out,
278 t_set* tset,
279 std::string prefix = "",
280 std::string obj = "",
281 bool has_metadata = true);
282
283 void generate_deserialize_map_element(std::ostream& out,
284 t_map* tmap,
285 std::string prefix = "",
286 std::string obj = "",
287 bool has_metadata = true);
288
289 void generate_deserialize_list_element(std::ostream& out,
290 t_list* tlist,
291 std::string prefix = "",
292 std::string obj = "",
293 bool has_metadata = true);
294
295 void generate_serialize_field(std::ostream& out,
296 t_field* tfield,
297 std::string prefix = "",
298 std::string postfix = "",
299 bool has_metadata = true);
300
301 void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
302
303 void generate_serialize_container(std::ostream& out,
304 t_type* ttype,
305 std::string prefix = "",
306 bool has_metadata = true);
307
308 void generate_serialize_map_element(std::ostream& out,
309 t_map* tmap,
310 std::string iter,
311 std::string map,
312 bool has_metadata = true);
313
314 void generate_serialize_set_element(std::ostream& out,
315 t_set* tmap,
316 std::string iter,
317 bool has_metadata = true);
318
319 void generate_serialize_list_element(std::ostream& out,
320 t_list* tlist,
321 std::string iter,
322 bool has_metadata = true);
323
324 void generate_deep_copy_container(std::ostream& out,
325 std::string source_name_p1,
326 std::string source_name_p2,
327 std::string result_name,
328 t_type* type);
329 void generate_deep_copy_non_container(std::ostream& out,
330 std::string source_name,
331 std::string dest_name,
332 t_type* type);
333
334 enum isset_type { ISSET_NONE, ISSET_PRIMITIVE, ISSET_BITSET };
335 isset_type needs_isset(t_struct* tstruct, std::string* outPrimitiveType = nullptr);
336
337 /**
338 * Helper rendering functions
339 */
340
341 std::string java_package();
342 std::string java_suppressions();
343 std::string java_nullable_annotation();
344 std::string java_override_annotation();
345 std::string type_name(t_type* ttype,
346 bool in_container = false,
347 bool in_init = false,
348 bool skip_generic = false,
349 bool force_namespace = false);
350 std::string base_type_name(t_base_type* tbase, bool in_container = false);
351 std::string declare_field(t_field* tfield, bool init = false, bool comment = false);
352 std::string function_signature(t_function* tfunction, std::string prefix = "");
353 std::string function_signature_async(t_function* tfunction,
354 bool use_base_method = false,
355 std::string prefix = "");
356 std::string function_signature_future(t_function* tfunction, std::string prefix = "");
357 std::string argument_list(t_struct* tstruct, bool include_types = true);
358 std::string async_function_call_arglist(t_function* tfunc,
359 bool use_base_method = true,
360 bool include_types = true);
361 std::string async_argument_list(t_function* tfunct,
362 t_struct* tstruct,
363 t_type* ttype,
364 bool include_types = false);
365 std::string type_to_enum(t_type* ttype);
366 void generate_struct_desc(ostream& out, t_struct* tstruct);
367 void generate_field_descs(ostream& out, t_struct* tstruct);
368 void generate_field_name_constants(ostream& out, t_struct* tstruct);
369
370 std::string make_valid_java_filename(std::string const& fromName);
371 std::string make_valid_java_identifier(std::string const& fromName);
372
373 string normalize_name(string name);
374
type_can_be_null(t_type * ttype)375 bool type_can_be_null(t_type* ttype) {
376 ttype = get_true_type(ttype);
377
378 return ttype->is_container() || ttype->is_struct() || ttype->is_xception() || ttype->is_string()
379 || ttype->is_uuid() || ttype->is_enum();
380 }
381
is_deprecated(const std::map<std::string,std::vector<std::string>> & annotations)382 bool is_deprecated(const std::map<std::string, std::vector<std::string>>& annotations) {
383 return annotations.find("deprecated") != annotations.end();
384 }
385
is_deprecated(const std::map<std::string,std::string> & annotations)386 bool is_deprecated(const std::map<std::string, std::string>& annotations) {
387 return annotations.find("deprecated") != annotations.end();
388 }
389
is_enum_set(t_type * ttype)390 bool is_enum_set(t_type* ttype) {
391 if (!sorted_containers_) {
392 ttype = get_true_type(ttype);
393 if (ttype->is_set()) {
394 t_set* tset = (t_set*)ttype;
395 t_type* elem_type = get_true_type(tset->get_elem_type());
396 return elem_type->is_enum();
397 }
398 }
399 return false;
400 }
401
is_enum_map(t_type * ttype)402 bool is_enum_map(t_type* ttype) {
403 if (!sorted_containers_) {
404 ttype = get_true_type(ttype);
405 if (ttype->is_map()) {
406 t_map* tmap = (t_map*)ttype;
407 t_type* key_type = get_true_type(tmap->get_key_type());
408 return key_type->is_enum();
409 }
410 }
411 return false;
412 }
413
inner_enum_type_name(t_type * ttype)414 std::string inner_enum_type_name(t_type* ttype) {
415 ttype = get_true_type(ttype);
416 if (ttype->is_map()) {
417 t_map* tmap = (t_map*)ttype;
418 t_type* key_type = get_true_type(tmap->get_key_type());
419 return type_name(key_type, true) + ".class";
420 } else if (ttype->is_set()) {
421 t_set* tset = (t_set*)ttype;
422 t_type* elem_type = get_true_type(tset->get_elem_type());
423 return type_name(elem_type, true) + ".class";
424 }
425 return "";
426 }
427
428 std::string constant_name(std::string name);
429
430 private:
431 /**
432 * File streams
433 */
434
435 std::string package_name_;
436 ofstream_with_content_based_conditional_update f_service_;
437 std::string package_dir_;
438
439 // keywords (according to Oracle docs)
440 // true, false, and null might seem like keywords, but they are actually literals;
441 // you cannot use them as identifiers in your programs.
442 const std::string JAVA_KEYWORDS[53] = {
443 "abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class", "const", "continue",
444 "default", "do", "double", "else", "enum", "extends", "final", "finally", "float", "for", "goto", "if",
445 "implements", "import", "instanceof", "int", "interface", "long", "native", "new", "package", "private",
446 "protected", "public", "return", "short", "static", "strictfp", "super", "switch", "synchronized", "this",
447 "throw", "throws", "transient", "try", "void", "volatile", "while", "true", "false", "null"
448 };
449 std::set<string> java_keywords = std::set<string>(JAVA_KEYWORDS, JAVA_KEYWORDS + sizeof(JAVA_KEYWORDS) / sizeof(JAVA_KEYWORDS[0]));
450
451 bool bean_style_;
452 bool android_style_;
453 bool private_members_;
454 bool nocamel_style_;
455 bool fullcamel_style_;
456 bool android_legacy_;
457 bool java5_;
458 bool sorted_containers_;
459 bool reuse_objects_;
460 bool generate_future_iface_;
461 bool use_option_type_;
462 bool use_jdk8_option_type_;
463 bool undated_generated_annotations_;
464 bool suppress_generated_annotations_;
465 bool rethrow_unhandled_exceptions_;
466 bool unsafe_binaries_;
467 bool annotations_as_metadata_;
468 };
469
470 /**
471 * Prepares for file generation by opening up the necessary file output
472 * streams.
473 *
474 * @param tprogram The program to generate
475 */
init_generator()476 void t_java_generator::init_generator() {
477 // Make output directory
478 MKDIR(get_out_dir().c_str());
479 package_name_ = program_->get_namespace("java");
480
481 string dir = package_name_;
482 string subdir = get_out_dir();
483 string::size_type loc;
484 while ((loc = dir.find(".")) != string::npos) {
485 subdir = subdir + "/" + dir.substr(0, loc);
486 MKDIR(subdir.c_str());
487 dir = dir.substr(loc + 1);
488 }
489 if (dir.size() > 0) {
490 subdir = subdir + "/" + dir;
491 MKDIR(subdir.c_str());
492 }
493
494 package_dir_ = subdir;
495 }
496
497 /**
498 * Packages the generated file
499 *
500 * @return String of the package, i.e. "package org.apache.thriftdemo;"
501 */
java_package()502 string t_java_generator::java_package() {
503 if (!package_name_.empty()) {
504 return string("package ") + package_name_ + ";\n\n";
505 }
506 return "";
507 }
508
java_suppressions()509 string t_java_generator::java_suppressions() {
510 return "@SuppressWarnings({\"cast\", \"rawtypes\", \"serial\", \"unchecked\", \"unused\"})"
511 + endl;
512 }
513
java_nullable_annotation()514 string t_java_generator::java_nullable_annotation() {
515 return "@org.apache.thrift.annotation.Nullable";
516 }
517
java_override_annotation()518 string t_java_generator::java_override_annotation() {
519 return "@Override";
520 }
521
normalize_name(string name)522 string t_java_generator::normalize_name(string name)
523 {
524 string tmp(name);
525 //transform(tmp.begin(), tmp.end(), tmp.begin(), static_cast<int(*)(int)>(tolower));
526
527 // un-conflict keywords by prefixing with "$"
528 if (java_keywords.find(tmp) != java_keywords.end())
529 {
530 return "$" + name;
531 }
532
533 // no changes necessary
534 return name;
535 }
536
537 /**
538 * Nothing in Java
539 */
close_generator()540 void t_java_generator::close_generator() {}
541
542 /**
543 * Generates a typedef. This is not done in Java, since it does
544 * not support arbitrary name replacements, and it'd be a wacky waste
545 * of overhead to make wrapper classes.
546 *
547 * @param ttypedef The type definition
548 */
generate_typedef(t_typedef * ttypedef)549 void t_java_generator::generate_typedef(t_typedef* ttypedef) {
550 (void)ttypedef;
551 }
552
553 /**
554 * Enums are a class with a set of static constants.
555 *
556 * @param tenum The enumeration
557 */
generate_enum(t_enum * tenum)558 void t_java_generator::generate_enum(t_enum* tenum) {
559 bool is_deprecated = this->is_deprecated(tenum->annotations_);
560 // Make output file
561 string f_enum_name = package_dir_ + "/" + make_valid_java_filename(tenum->get_name()) + ".java";
562 ofstream_with_content_based_conditional_update f_enum;
563 f_enum.open(f_enum_name.c_str());
564
565 // Comment and package it
566 f_enum << autogen_comment() << java_package() << endl;
567
568 generate_java_doc(f_enum, tenum);
569
570 if (!suppress_generated_annotations_) {
571 generate_javax_generated_annotation(f_enum);
572 }
573
574 if (is_deprecated) {
575 indent(f_enum) << "@Deprecated" << endl;
576 }
577 indent(f_enum) << "public enum " << tenum->get_name() << " implements org.apache.thrift.TEnum ";
578 scope_up(f_enum);
579
580 vector<t_enum_value*> constants = tenum->get_constants();
581 vector<t_enum_value*>::iterator c_iter;
582 bool first = true;
583 for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
584 int value = (*c_iter)->get_value();
585
586 if (first) {
587 first = false;
588 } else {
589 f_enum << "," << endl;
590 }
591
592 generate_java_doc(f_enum, *c_iter);
593 if (this->is_deprecated((*c_iter)->annotations_)) {
594 indent(f_enum) << "@Deprecated" << endl;
595 }
596 indent(f_enum) << (*c_iter)->get_name() << "(" << value << ")";
597 }
598 f_enum << ";" << endl << endl;
599
600 // Field for thriftCode
601 indent(f_enum) << "private final int value;" << endl << endl;
602
603 indent(f_enum) << "private " << tenum->get_name() << "(int value) {" << endl;
604 indent(f_enum) << " this.value = value;" << endl;
605 indent(f_enum) << "}" << endl << endl;
606
607 indent(f_enum) << "/**" << endl;
608 indent(f_enum) << " * Get the integer value of this enum value, as defined in the Thrift IDL."
609 << endl;
610 indent(f_enum) << " */" << endl;
611 indent(f_enum) << java_override_annotation() << endl;
612 indent(f_enum) << "public int getValue() {" << endl;
613 indent(f_enum) << " return value;" << endl;
614 indent(f_enum) << "}" << endl << endl;
615
616 indent(f_enum) << "/**" << endl;
617 indent(f_enum) << " * Find a the enum type by its integer value, as defined in the Thrift IDL."
618 << endl;
619 indent(f_enum) << " * @return null if the value is not found." << endl;
620 indent(f_enum) << " */" << endl;
621 indent(f_enum) << java_nullable_annotation() << endl;
622 indent(f_enum) << "public static " + tenum->get_name() + " findByValue(int value) { " << endl;
623
624 indent_up();
625
626 indent(f_enum) << "switch (value) {" << endl;
627 indent_up();
628
629 for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
630 int value = (*c_iter)->get_value();
631 indent(f_enum) << "case " << value << ":" << endl;
632 indent(f_enum) << " return " << (*c_iter)->get_name() << ";" << endl;
633 }
634
635 indent(f_enum) << "default:" << endl;
636 indent(f_enum) << " return null;" << endl;
637
638 indent_down();
639
640 indent(f_enum) << "}" << endl;
641
642 indent_down();
643
644 indent(f_enum) << "}" << endl;
645
646 scope_down(f_enum);
647
648 f_enum.close();
649 }
650
651 /**
652 * Generates a class that holds all the constants.
653 */
generate_consts(std::vector<t_const * > consts)654 void t_java_generator::generate_consts(std::vector<t_const*> consts) {
655 if (consts.empty()) {
656 return;
657 }
658
659 string f_consts_name
660 = package_dir_ + '/' + make_valid_java_filename(program_name_) + "Constants.java";
661 ofstream_with_content_based_conditional_update f_consts;
662 f_consts.open(f_consts_name.c_str());
663
664 // Print header
665 f_consts << autogen_comment() << java_package() << java_suppressions();
666 f_consts << "public class " << make_valid_java_identifier(program_name_) << "Constants {" << endl
667 << endl;
668 indent_up();
669 vector<t_const*>::iterator c_iter;
670 for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
671 generate_java_doc(f_consts, (*c_iter));
672 print_const_value(f_consts, (*c_iter)->get_name(), (*c_iter)->get_type(),
673 (*c_iter)->get_value(), false);
674 }
675 indent_down();
676 indent(f_consts) << "}" << endl;
677 f_consts.close();
678 }
679
680 /**
681 * Prints the value of a constant with the given type. Note that type checking
682 * is NOT performed in this function as it is always run beforehand using the
683 * validate_types method in main.cc
684 */
print_const_value(std::ostream & out,string name,t_type * type,t_const_value * value,bool in_static,bool defval)685 void t_java_generator::print_const_value(std::ostream& out,
686 string name,
687 t_type* type,
688 t_const_value* value,
689 bool in_static,
690 bool defval) {
691 type = get_true_type(type);
692
693 indent(out);
694 if (!defval) {
695 out << (in_static ? "" : "public static final ") << type_name(type) << " ";
696 }
697 if (type->is_base_type()) {
698 string v2 = render_const_value(out, type, value);
699 out << name << " = " << v2 << ";" << endl << endl;
700 } else if (type->is_enum()) {
701 out << name << " = " << render_const_value(out, type, value) << ";" << endl << endl;
702 } else if (type->is_struct() || type->is_xception()) {
703 const vector<t_field*>& unsorted_fields = ((t_struct*)type)->get_members();
704 vector<t_field*> fields = unsorted_fields;
705 std::sort(fields.begin(), fields.end(), t_field::key_compare());
706 vector<t_field*>::const_iterator f_iter;
707 const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
708 map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
709 out << name << " = new " << type_name(type, false, true) << "();" << endl;
710 if (!in_static) {
711 indent(out) << "static {" << endl;
712 indent_up();
713 }
714 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
715 t_type* field_type = nullptr;
716 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
717 if ((*f_iter)->get_name() == v_iter->first->get_string()) {
718 field_type = (*f_iter)->get_type();
719 }
720 }
721 if (field_type == nullptr) {
722 throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
723 }
724 string val = render_const_value(out, field_type, v_iter->second);
725 indent(out) << name << ".";
726 std::string cap_name = get_cap_name(v_iter->first->get_string());
727 out << "set" << cap_name << "(" << val << ");" << endl;
728 }
729 if (!in_static) {
730 indent_down();
731 indent(out) << "}" << endl;
732 }
733 out << endl;
734 } else if (type->is_map()) {
735 std::string constructor_args;
736 if (is_enum_map(type)) {
737 constructor_args = inner_enum_type_name(type);
738 }
739 out << name << " = new " << type_name(type, false, true) << "(" << constructor_args << ");"
740 << endl;
741 if (!in_static) {
742 indent(out) << "static {" << endl;
743 indent_up();
744 }
745 t_type* ktype = ((t_map*)type)->get_key_type();
746 t_type* vtype = ((t_map*)type)->get_val_type();
747 const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
748 map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
749 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
750 string key = render_const_value(out, ktype, v_iter->first);
751 string val = render_const_value(out, vtype, v_iter->second);
752 indent(out) << name << ".put(" << key << ", " << val << ");" << endl;
753 }
754 if (!in_static) {
755 indent_down();
756 indent(out) << "}" << endl;
757 }
758 out << endl;
759 } else if (type->is_list() || type->is_set()) {
760 if (is_enum_set(type)) {
761 out << name << " = " << type_name(type, false, true, true) << ".noneOf("
762 << inner_enum_type_name(type) << ");" << endl;
763 } else {
764 out << name << " = new " << type_name(type, false, true) << "();" << endl;
765 }
766 if (!in_static) {
767 indent(out) << "static {" << endl;
768 indent_up();
769 }
770 t_type* etype;
771 if (type->is_list()) {
772 etype = ((t_list*)type)->get_elem_type();
773 } else {
774 etype = ((t_set*)type)->get_elem_type();
775 }
776 const vector<t_const_value*>& val = value->get_list();
777 vector<t_const_value*>::const_iterator v_iter;
778 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
779 string val = render_const_value(out, etype, *v_iter);
780 indent(out) << name << ".add(" << val << ");" << endl;
781 }
782 if (!in_static) {
783 indent_down();
784 indent(out) << "}" << endl;
785 }
786 out << endl;
787 } else {
788 throw "compiler error: no const of type " + type->get_name();
789 }
790 }
791
render_const_value(ostream & out,t_type * type,t_const_value * value)792 string t_java_generator::render_const_value(ostream& out, t_type* type, t_const_value* value) {
793 type = get_true_type(type);
794 std::ostringstream render;
795
796 if (type->is_base_type()) {
797 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
798 switch (tbase) {
799 case t_base_type::TYPE_STRING:
800 if (((t_base_type*)type)->is_binary()) {
801 render << "java.nio.ByteBuffer.wrap(\"" << get_escaped_string(value) << "\".getBytes())";
802 } else {
803 render << '"' << get_escaped_string(value) << '"';
804 }
805 break;
806 case t_base_type::TYPE_UUID:
807 render << "java.util.UUID.fromString(\"" << get_escaped_string(value) << "\")";
808 break;
809 case t_base_type::TYPE_BOOL:
810 render << ((value->get_integer() > 0) ? "true" : "false");
811 break;
812 case t_base_type::TYPE_I8:
813 render << "(byte)" << value->get_integer();
814 break;
815 case t_base_type::TYPE_I16:
816 render << "(short)" << value->get_integer();
817 break;
818 case t_base_type::TYPE_I32:
819 render << value->get_integer();
820 break;
821 case t_base_type::TYPE_I64:
822 render << value->get_integer() << "L";
823 break;
824 case t_base_type::TYPE_DOUBLE:
825 if (value->get_type() == t_const_value::CV_INTEGER) {
826 render << value->get_integer() << "d";
827 } else {
828 render << emit_double_as_string(value->get_double());
829 }
830 break;
831 default:
832 throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
833 }
834 } else if (type->is_enum()) {
835 std::string namespace_prefix = type->get_program()->get_namespace("java");
836 if (namespace_prefix.length() > 0) {
837 namespace_prefix += ".";
838 }
839 render << namespace_prefix << value->get_identifier_with_parent();
840 } else {
841 string t = tmp("tmp");
842 print_const_value(out, t, type, value, true);
843 render << t;
844 }
845
846 return render.str();
847 }
848
849 /**
850 * Generates a struct definition for a thrift data type. This will be a org.apache.thrift.TBase
851 * implementor.
852 *
853 * @param tstruct The struct definition
854 */
generate_struct(t_struct * tstruct)855 void t_java_generator::generate_struct(t_struct* tstruct) {
856 if (tstruct->is_union()) {
857 generate_java_union(tstruct);
858 } else {
859 generate_java_struct(tstruct, false);
860 }
861 }
862
863 /**
864 * Exceptions are structs, but they inherit from Exception
865 *
866 * @param tstruct The struct definition
867 */
generate_xception(t_struct * txception)868 void t_java_generator::generate_xception(t_struct* txception) {
869 generate_java_struct(txception, true);
870 }
871
872 /**
873 * Java struct definition.
874 *
875 * @param tstruct The struct definition
876 */
generate_java_struct(t_struct * tstruct,bool is_exception)877 void t_java_generator::generate_java_struct(t_struct* tstruct, bool is_exception) {
878 // Make output file
879 string f_struct_name
880 = package_dir_ + "/" + make_valid_java_filename(tstruct->get_name()) + ".java";
881 ofstream_with_content_based_conditional_update f_struct;
882 f_struct.open(f_struct_name.c_str());
883
884 f_struct << autogen_comment() << java_package();
885
886 generate_java_struct_definition(f_struct, tstruct, is_exception);
887 f_struct.close();
888 }
889
890 /**
891 * Java union definition.
892 *
893 * @param tstruct The struct definition
894 */
generate_java_union(t_struct * tstruct)895 void t_java_generator::generate_java_union(t_struct* tstruct) {
896 // Make output file
897 string f_struct_name
898 = package_dir_ + "/" + make_valid_java_filename(tstruct->get_name()) + ".java";
899 ofstream_with_content_based_conditional_update f_struct;
900 f_struct.open(f_struct_name.c_str());
901
902 f_struct << autogen_comment() << java_package();
903
904 generate_java_doc(f_struct, tstruct);
905 f_struct << java_suppressions();
906
907 bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end());
908 bool is_deprecated = this->is_deprecated(tstruct->annotations_);
909
910 if (!suppress_generated_annotations_) {
911 generate_javax_generated_annotation(f_struct);
912 }
913
914 if (is_deprecated) {
915 indent(f_struct) << "@Deprecated" << endl;
916 }
917 indent(f_struct) << "public " << (is_final ? "final " : "") << "class " << make_valid_java_identifier(tstruct->get_name())
918 << " extends org.apache.thrift.TUnion<" << make_valid_java_identifier(tstruct->get_name()) << ", "
919 << make_valid_java_identifier(tstruct->get_name()) << "._Fields> ";
920
921 scope_up(f_struct);
922
923 generate_struct_desc(f_struct, tstruct);
924 generate_field_descs(f_struct, tstruct);
925
926 f_struct << endl;
927
928 generate_field_name_constants(f_struct, tstruct);
929
930 f_struct << endl;
931
932 generate_java_meta_data_map(f_struct, tstruct);
933
934 generate_union_constructor(f_struct, tstruct);
935
936 f_struct << endl;
937
938 generate_union_abstract_methods(f_struct, tstruct);
939
940 f_struct << endl;
941
942 generate_java_struct_field_by_id(f_struct, tstruct);
943
944 f_struct << endl;
945
946 generate_union_getters_and_setters(f_struct, tstruct);
947
948 f_struct << endl;
949
950 generate_union_is_set_methods(f_struct, tstruct);
951
952 f_struct << endl;
953
954 generate_union_comparisons(f_struct, tstruct);
955
956 f_struct << endl;
957
958 generate_union_hashcode(f_struct, tstruct);
959
960 f_struct << endl;
961
962 generate_java_struct_write_object(f_struct, tstruct);
963
964 f_struct << endl;
965
966 generate_java_struct_read_object(f_struct, tstruct);
967
968 f_struct << endl;
969
970 scope_down(f_struct);
971
972 f_struct.close();
973 }
974
generate_union_constructor(ostream & out,t_struct * tstruct)975 void t_java_generator::generate_union_constructor(ostream& out, t_struct* tstruct) {
976 const vector<t_field*>& members = tstruct->get_members();
977 vector<t_field*>::const_iterator m_iter;
978
979 indent(out) << "public " << type_name(tstruct) << "() {" << endl;
980 indent_up();
981 bool default_value = false;
982 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
983 t_type* type = get_true_type((*m_iter)->get_type());
984 if ((*m_iter)->get_value() != nullptr) {
985 indent(out) << "super(_Fields." << constant_name((*m_iter)->get_name()) << ", "
986 << render_const_value(out, type, (*m_iter)->get_value()) << ");" << endl;
987 default_value = true;
988 break;
989 }
990 }
991 if (default_value == false) {
992 indent(out) << "super();" << endl;
993 }
994 indent_down();
995 indent(out) << "}" << endl << endl;
996
997 indent(out) << "public " << type_name(tstruct) << "(_Fields setField, java.lang.Object value) {"
998 << endl;
999 indent(out) << " super(setField, value);" << endl;
1000 indent(out) << "}" << endl << endl;
1001
1002 indent(out) << "public " << type_name(tstruct)
1003 << "(" << type_name(tstruct) << " other) {"
1004 << endl;
1005 indent(out) << " super(other);" << endl;
1006 indent(out) << "}" << endl;
1007
1008 indent(out) << java_override_annotation() << endl;
1009 indent(out) << "public " << make_valid_java_identifier(tstruct->get_name()) << " deepCopy() {" << endl;
1010 indent(out) << " return new " << tstruct->get_name() << "(this);" << endl;
1011 indent(out) << "}" << endl << endl;
1012
1013 // generate "constructors" for each field
1014 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1015 t_type* type = (*m_iter)->get_type();
1016 indent(out) << "public static " << type_name(tstruct) << " " << (*m_iter)->get_name() << "("
1017 << type_name(type) << " value) {" << endl;
1018 indent(out) << " " << type_name(tstruct) << " x = new " << type_name(tstruct) << "();" << endl;
1019 indent(out) << " x.set" << get_cap_name((*m_iter)->get_name()) << "(value);" << endl;
1020 indent(out) << " return x;" << endl;
1021 indent(out) << "}" << endl << endl;
1022
1023 if (type->is_binary()) {
1024 indent(out) << "public static " << type_name(tstruct) << " " << (*m_iter)->get_name()
1025 << "(byte[] value) {" << endl;
1026 indent(out) << " " << type_name(tstruct) << " x = new " << type_name(tstruct) << "();"
1027 << endl;
1028 indent(out) << " x.set" << get_cap_name((*m_iter)->get_name());
1029 if (unsafe_binaries_) {
1030 indent(out) << "(java.nio.ByteBuffer.wrap(value));" << endl;
1031 } else {
1032 indent(out) << "(java.nio.ByteBuffer.wrap(value.clone()));" << endl;
1033 }
1034 indent(out) << " return x;" << endl;
1035 indent(out) << "}" << endl << endl;
1036 }
1037 }
1038 }
1039
generate_union_getters_and_setters(ostream & out,t_struct * tstruct)1040 void t_java_generator::generate_union_getters_and_setters(ostream& out, t_struct* tstruct) {
1041 const vector<t_field*>& members = tstruct->get_members();
1042 vector<t_field*>::const_iterator m_iter;
1043
1044 bool first = true;
1045 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1046 if (first) {
1047 first = false;
1048 } else {
1049 out << endl;
1050 }
1051
1052 t_field* field = (*m_iter);
1053 t_type* type = field->get_type();
1054 std::string cap_name = get_cap_name(field->get_name());
1055 bool is_deprecated = this->is_deprecated(field->annotations_);
1056
1057 generate_java_doc(out, field);
1058 if (type->is_binary()) {
1059 if (is_deprecated) {
1060 indent(out) << "@Deprecated" << endl;
1061 }
1062 indent(out) << "public byte[] get" << cap_name << "() {" << endl;
1063 indent(out) << " set" << cap_name << "(org.apache.thrift.TBaseHelper.rightSize(buffer"
1064 << get_cap_name("for") << cap_name << "()));" << endl;
1065 indent(out) << " java.nio.ByteBuffer b = buffer" << get_cap_name("for") << cap_name << "();"
1066 << endl;
1067 indent(out) << " return b == null ? null : b.array();" << endl;
1068 indent(out) << "}" << endl;
1069
1070 out << endl;
1071
1072 indent(out) << "public java.nio.ByteBuffer buffer" << get_cap_name("for")
1073 << get_cap_name(field->get_name()) << "() {" << endl;
1074 indent(out) << " if (getSetField() == _Fields." << constant_name(field->get_name()) << ") {"
1075 << endl;
1076
1077 if (unsafe_binaries_) {
1078 indent(out) << " return (java.nio.ByteBuffer)getFieldValue();" << endl;
1079 } else {
1080 indent(out)
1081 << " return "
1082 "org.apache.thrift.TBaseHelper.copyBinary((java.nio.ByteBuffer)getFieldValue());"
1083 << endl;
1084 }
1085
1086 indent(out) << " } else {" << endl;
1087 indent(out) << " throw new java.lang.RuntimeException(\"Cannot get field '"
1088 << field->get_name()
1089 << "' because union is currently set to \" + getFieldDesc(getSetField()).name);"
1090 << endl;
1091 indent(out) << " }" << endl;
1092 indent(out) << "}" << endl;
1093 } else {
1094 if (is_deprecated) {
1095 indent(out) << "@Deprecated" << endl;
1096 }
1097 indent(out) << "public " << type_name(field->get_type()) << " get"
1098 << get_cap_name(field->get_name()) << "() {" << endl;
1099 indent(out) << " if (getSetField() == _Fields." << constant_name(field->get_name()) << ") {"
1100 << endl;
1101 indent(out) << " return (" << type_name(field->get_type(), true) << ")getFieldValue();"
1102 << endl;
1103 indent(out) << " } else {" << endl;
1104 indent(out) << " throw new java.lang.RuntimeException(\"Cannot get field '"
1105 << field->get_name()
1106 << "' because union is currently set to \" + getFieldDesc(getSetField()).name);"
1107 << endl;
1108 indent(out) << " }" << endl;
1109 indent(out) << "}" << endl;
1110 }
1111
1112 out << endl;
1113
1114 generate_java_doc(out, field);
1115 if (type->is_binary()) {
1116 if (is_deprecated) {
1117 indent(out) << "@Deprecated" << endl;
1118 }
1119 indent(out) << "public void set" << get_cap_name(field->get_name()) << "(byte[] value) {"
1120 << endl;
1121 indent(out) << " set" << get_cap_name(field->get_name());
1122
1123 if (unsafe_binaries_) {
1124 indent(out) << "(java.nio.ByteBuffer.wrap(value));" << endl;
1125 } else {
1126 indent(out) << "(java.nio.ByteBuffer.wrap(value.clone()));" << endl;
1127 }
1128
1129 indent(out) << "}" << endl;
1130
1131 out << endl;
1132 }
1133 if (is_deprecated) {
1134 indent(out) << "@Deprecated" << endl;
1135 }
1136 indent(out) << "public void set" << get_cap_name(field->get_name()) << "("
1137 << type_name(field->get_type()) << " value) {" << endl;
1138
1139 indent(out) << " setField_ = _Fields." << constant_name(field->get_name()) << ";" << endl;
1140
1141 if (type_can_be_null(field->get_type())) {
1142 indent(out) << " value_ = java.util.Objects.requireNonNull(value,\""
1143 << "_Fields." << constant_name(field->get_name()) << "\");" << endl;
1144 } else {
1145 indent(out) << " value_ = value;" << endl;
1146 }
1147
1148 indent(out) << "}" << endl;
1149 }
1150 }
1151
generate_union_is_set_methods(ostream & out,t_struct * tstruct)1152 void t_java_generator::generate_union_is_set_methods(ostream& out, t_struct* tstruct) {
1153 const vector<t_field*>& members = tstruct->get_members();
1154 vector<t_field*>::const_iterator m_iter;
1155
1156 bool first = true;
1157 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1158 if (first) {
1159 first = false;
1160 } else {
1161 out << endl;
1162 }
1163
1164 std::string field_name = (*m_iter)->get_name();
1165
1166 indent(out) << "public boolean is" << get_cap_name("set") << get_cap_name(field_name) << "() {"
1167 << endl;
1168 indent_up();
1169 indent(out) << "return setField_ == _Fields." << constant_name(field_name) << ";" << endl;
1170 indent_down();
1171 indent(out) << "}" << endl << endl;
1172 }
1173 }
1174
generate_union_abstract_methods(ostream & out,t_struct * tstruct)1175 void t_java_generator::generate_union_abstract_methods(ostream& out, t_struct* tstruct) {
1176 generate_check_type(out, tstruct);
1177 out << endl;
1178 generate_standard_scheme_read_value(out, tstruct);
1179 out << endl;
1180 generate_standard_scheme_write_value(out, tstruct);
1181 out << endl;
1182 generate_tuple_scheme_read_value(out, tstruct);
1183 out << endl;
1184 generate_tuple_scheme_write_value(out, tstruct);
1185 out << endl;
1186 generate_get_field_desc(out, tstruct);
1187 out << endl;
1188 generate_get_struct_desc(out, tstruct);
1189 out << endl;
1190 indent(out) << java_override_annotation() << endl;
1191 indent(out) << "protected _Fields enumForId(short id) {" << endl;
1192 indent(out) << " return _Fields.findByThriftIdOrThrow(id);" << endl;
1193 indent(out) << "}" << endl;
1194 }
1195
generate_check_type(ostream & out,t_struct * tstruct)1196 void t_java_generator::generate_check_type(ostream& out, t_struct* tstruct) {
1197 indent(out) << java_override_annotation() << endl;
1198 indent(out) << "protected void checkType(_Fields setField, java.lang.Object value) throws "
1199 "java.lang.ClassCastException {"
1200 << endl;
1201 indent_up();
1202
1203 indent(out) << "switch (setField) {" << endl;
1204 indent_up();
1205
1206 const vector<t_field*>& members = tstruct->get_members();
1207 vector<t_field*>::const_iterator m_iter;
1208
1209 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1210 t_field* field = (*m_iter);
1211
1212 indent(out) << "case " << constant_name(field->get_name()) << ":" << endl;
1213 indent(out) << " if (value instanceof " << type_name(field->get_type(), true, false, true)
1214 << ") {" << endl;
1215 indent(out) << " break;" << endl;
1216 indent(out) << " }" << endl;
1217 indent(out) << " throw new java.lang.ClassCastException(\"Was expecting value of type "
1218 << type_name(field->get_type(), true, false) << " for field '" << field->get_name()
1219 << "', but got \" + value.getClass().getSimpleName());" << endl;
1220 // do the real check here
1221 }
1222
1223 indent(out) << "default:" << endl;
1224 indent(out) << " throw new java.lang.IllegalArgumentException(\"Unknown field id \" + setField);"
1225 << endl;
1226
1227 indent_down();
1228 indent(out) << "}" << endl;
1229
1230 indent_down();
1231 indent(out) << "}" << endl;
1232 }
1233
generate_standard_scheme_read_value(ostream & out,t_struct * tstruct)1234 void t_java_generator::generate_standard_scheme_read_value(ostream& out, t_struct* tstruct) {
1235 indent(out) << java_override_annotation() << endl;
1236 indent(out)
1237 << "protected java.lang.Object standardSchemeReadValue(org.apache.thrift.protocol.TProtocol "
1238 "iprot, org.apache.thrift.protocol.TField field) throws "
1239 "org.apache.thrift.TException {"
1240 << endl;
1241
1242 indent_up();
1243
1244 indent(out) << "_Fields setField = _Fields.findByThriftId(field.id);" << endl;
1245 indent(out) << "if (setField != null) {" << endl;
1246 indent_up();
1247 indent(out) << "switch (setField) {" << endl;
1248 indent_up();
1249
1250 const vector<t_field*>& members = tstruct->get_members();
1251 vector<t_field*>::const_iterator m_iter;
1252
1253 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1254 t_field* field = (*m_iter);
1255
1256 indent(out) << "case " << constant_name(field->get_name()) << ":" << endl;
1257 indent_up();
1258 indent(out) << "if (field.type == " << constant_name(field->get_name()) << "_FIELD_DESC.type) {"
1259 << endl;
1260 indent_up();
1261 indent(out) << type_name(field->get_type(), true, false) << " " << field->get_name() << ";"
1262 << endl;
1263 generate_deserialize_field(out, field, "");
1264 indent(out) << "return " << field->get_name() << ";" << endl;
1265 indent_down();
1266 indent(out) << "} else {" << endl;
1267 indent(out) << " org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type);" << endl;
1268 indent(out) << " return null;" << endl;
1269 indent(out) << "}" << endl;
1270 indent_down();
1271 }
1272
1273 indent(out) << "default:" << endl;
1274 indent(out)
1275 << " throw new java.lang.IllegalStateException(\"setField wasn't null, but didn't match any "
1276 "of the case statements!\");"
1277 << endl;
1278
1279 indent_down();
1280 indent(out) << "}" << endl;
1281
1282 indent_down();
1283 indent(out) << "} else {" << endl;
1284 indent_up();
1285 indent(out) << "org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type);" << endl;
1286 indent(out) << "return null;" << endl;
1287 indent_down();
1288 indent(out) << "}" << endl;
1289
1290 indent_down();
1291 indent(out) << "}" << endl;
1292 }
1293
generate_standard_scheme_write_value(ostream & out,t_struct * tstruct)1294 void t_java_generator::generate_standard_scheme_write_value(ostream& out, t_struct* tstruct) {
1295 indent(out) << java_override_annotation() << endl;
1296 indent(out) << "protected void standardSchemeWriteValue(org.apache.thrift.protocol.TProtocol "
1297 "oprot) throws org.apache.thrift.TException {"
1298 << endl;
1299
1300 indent_up();
1301
1302 indent(out) << "switch (setField_) {" << endl;
1303 indent_up();
1304
1305 const vector<t_field*>& members = tstruct->get_members();
1306 vector<t_field*>::const_iterator m_iter;
1307
1308 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1309 t_field* field = (*m_iter);
1310
1311 indent(out) << "case " << constant_name(field->get_name()) << ":" << endl;
1312 indent_up();
1313 indent(out) << type_name(field->get_type(), true, false) << " " << field->get_name() << " = ("
1314 << type_name(field->get_type(), true, false) << ")value_;" << endl;
1315 generate_serialize_field(out, field);
1316 indent(out) << "return;" << endl;
1317 indent_down();
1318 }
1319
1320 indent(out) << "default:" << endl;
1321 indent(out)
1322 << " throw new java.lang.IllegalStateException(\"Cannot write union with unknown field \" + "
1323 "setField_);"
1324 << endl;
1325
1326 indent_down();
1327 indent(out) << "}" << endl;
1328
1329 indent_down();
1330
1331 indent(out) << "}" << endl;
1332 }
1333
generate_tuple_scheme_read_value(ostream & out,t_struct * tstruct)1334 void t_java_generator::generate_tuple_scheme_read_value(ostream& out, t_struct* tstruct) {
1335 indent(out) << java_override_annotation() << endl;
1336 indent(out)
1337 << "protected java.lang.Object tupleSchemeReadValue(org.apache.thrift.protocol.TProtocol "
1338 "iprot, short fieldID) throws org.apache.thrift.TException {"
1339 << endl;
1340
1341 indent_up();
1342
1343 indent(out) << "_Fields setField = _Fields.findByThriftId(fieldID);" << endl;
1344 indent(out) << "if (setField != null) {" << endl;
1345 indent_up();
1346 indent(out) << "switch (setField) {" << endl;
1347 indent_up();
1348
1349 const vector<t_field*>& members = tstruct->get_members();
1350 vector<t_field*>::const_iterator m_iter;
1351
1352 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1353 t_field* field = (*m_iter);
1354
1355 indent(out) << "case " << constant_name(field->get_name()) << ":" << endl;
1356 indent_up();
1357 indent(out) << type_name(field->get_type(), true, false) << " " << field->get_name() << ";"
1358 << endl;
1359 generate_deserialize_field(out, field, "");
1360 indent(out) << "return " << field->get_name() << ";" << endl;
1361 indent_down();
1362 }
1363
1364 indent(out) << "default:" << endl;
1365 indent(out)
1366 << " throw new java.lang.IllegalStateException(\"setField wasn't null, but didn't match any "
1367 "of the case statements!\");"
1368 << endl;
1369
1370 indent_down();
1371 indent(out) << "}" << endl;
1372
1373 indent_down();
1374 indent(out) << "} else {" << endl;
1375 indent_up();
1376 indent(out) << "throw new org.apache.thrift.protocol.TProtocolException(\"Couldn't find a field "
1377 "with field id \" + fieldID);"
1378 << endl;
1379 indent_down();
1380 indent(out) << "}" << endl;
1381 indent_down();
1382 indent(out) << "}" << endl;
1383 }
1384
generate_tuple_scheme_write_value(ostream & out,t_struct * tstruct)1385 void t_java_generator::generate_tuple_scheme_write_value(ostream& out, t_struct* tstruct) {
1386 indent(out) << java_override_annotation() << endl;
1387 indent(out) << "protected void tupleSchemeWriteValue(org.apache.thrift.protocol.TProtocol oprot) "
1388 "throws org.apache.thrift.TException {"
1389 << endl;
1390
1391 indent_up();
1392
1393 indent(out) << "switch (setField_) {" << endl;
1394 indent_up();
1395
1396 const vector<t_field*>& members = tstruct->get_members();
1397 vector<t_field*>::const_iterator m_iter;
1398
1399 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1400 t_field* field = (*m_iter);
1401
1402 indent(out) << "case " << constant_name(field->get_name()) << ":" << endl;
1403 indent_up();
1404 indent(out) << type_name(field->get_type(), true, false) << " " << field->get_name() << " = ("
1405 << type_name(field->get_type(), true, false) << ")value_;" << endl;
1406 generate_serialize_field(out, field);
1407 indent(out) << "return;" << endl;
1408 indent_down();
1409 }
1410
1411 indent(out) << "default:" << endl;
1412 indent(out)
1413 << " throw new java.lang.IllegalStateException(\"Cannot write union with unknown field \" + "
1414 "setField_);"
1415 << endl;
1416
1417 indent_down();
1418 indent(out) << "}" << endl;
1419
1420 indent_down();
1421
1422 indent(out) << "}" << endl;
1423 }
1424
generate_get_field_desc(ostream & out,t_struct * tstruct)1425 void t_java_generator::generate_get_field_desc(ostream& out, t_struct* tstruct) {
1426 indent(out) << java_override_annotation() << endl;
1427 indent(out) << "protected org.apache.thrift.protocol.TField getFieldDesc(_Fields setField) {"
1428 << endl;
1429 indent_up();
1430
1431 const vector<t_field*>& members = tstruct->get_members();
1432 vector<t_field*>::const_iterator m_iter;
1433
1434 indent(out) << "switch (setField) {" << endl;
1435 indent_up();
1436
1437 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1438 t_field* field = (*m_iter);
1439 indent(out) << "case " << constant_name(field->get_name()) << ":" << endl;
1440 indent(out) << " return " << constant_name(field->get_name()) << "_FIELD_DESC;" << endl;
1441 }
1442
1443 indent(out) << "default:" << endl;
1444 indent(out) << " throw new java.lang.IllegalArgumentException(\"Unknown field id \" + setField);"
1445 << endl;
1446
1447 indent_down();
1448 indent(out) << "}" << endl;
1449
1450 indent_down();
1451 indent(out) << "}" << endl;
1452 }
1453
generate_get_struct_desc(ostream & out,t_struct * tstruct)1454 void t_java_generator::generate_get_struct_desc(ostream& out, t_struct* tstruct) {
1455 (void)tstruct;
1456 indent(out) << java_override_annotation() << endl;
1457 indent(out) << "protected org.apache.thrift.protocol.TStruct getStructDesc() {" << endl;
1458 indent(out) << " return STRUCT_DESC;" << endl;
1459 indent(out) << "}" << endl;
1460 }
1461
generate_union_comparisons(ostream & out,t_struct * tstruct)1462 void t_java_generator::generate_union_comparisons(ostream& out, t_struct* tstruct) {
1463 // equality
1464 indent(out) << "public boolean equals(java.lang.Object other) {" << endl;
1465 indent(out) << " if (other instanceof " << make_valid_java_identifier(tstruct->get_name()) << ") {" << endl;
1466 indent(out) << " return equals((" << make_valid_java_identifier(tstruct->get_name()) << ")other);" << endl;
1467 indent(out) << " } else {" << endl;
1468 indent(out) << " return false;" << endl;
1469 indent(out) << " }" << endl;
1470 indent(out) << "}" << endl;
1471
1472 out << endl;
1473
1474 indent(out) << "public boolean equals(" << make_valid_java_identifier(tstruct->get_name()) << " other) {" << endl;
1475 indent(out) << " return other != null && getSetField() == other.getSetField() && "
1476 "getFieldValue().equals(other.getFieldValue());"
1477 << endl;
1478 indent(out) << "}" << endl;
1479 out << endl;
1480
1481 indent(out) << java_override_annotation() << endl;
1482 indent(out) << "public int compareTo(" << type_name(tstruct) << " other) {" << endl;
1483 indent(out) << " int lastComparison = org.apache.thrift.TBaseHelper.compareTo(getSetField(), "
1484 "other.getSetField());"
1485 << endl;
1486 indent(out) << " if (lastComparison == 0) {" << endl;
1487 indent(out) << " return org.apache.thrift.TBaseHelper.compareTo(getFieldValue(), "
1488 "other.getFieldValue());"
1489 << endl;
1490 indent(out) << " }" << endl;
1491 indent(out) << " return lastComparison;" << endl;
1492 indent(out) << "}" << endl;
1493 out << endl;
1494 }
1495
generate_union_hashcode(ostream & out,t_struct * tstruct)1496 void t_java_generator::generate_union_hashcode(ostream& out, t_struct* tstruct) {
1497 (void)tstruct;
1498 indent(out) << java_override_annotation() << endl;
1499 indent(out) << "public int hashCode() {" << endl;
1500 indent(out)
1501 << " java.util.List<java.lang.Object> list = new java.util.ArrayList<java.lang.Object>();"
1502 << endl;
1503 indent(out) << " list.add(this.getClass().getName());" << endl;
1504 indent(out) << " org.apache.thrift.TFieldIdEnum setField = getSetField();" << endl;
1505 indent(out) << " if (setField != null) {" << endl;
1506 indent(out) << " list.add(setField.getThriftFieldId());" << endl;
1507 indent(out) << " java.lang.Object value = getFieldValue();" << endl;
1508 indent(out) << " if (value instanceof org.apache.thrift.TEnum) {" << endl;
1509 indent(out) << " list.add(((org.apache.thrift.TEnum)getFieldValue()).getValue());" << endl;
1510 indent(out) << " } else {" << endl;
1511 indent(out) << " list.add(value);" << endl;
1512 indent(out) << " }" << endl;
1513 indent(out) << " }" << endl;
1514 indent(out) << " return list.hashCode();" << endl;
1515 indent(out) << "}";
1516 }
1517
1518 /**
1519 * Java struct definition. This has various parameters, as it could be
1520 * generated standalone or inside another class as a helper. If it
1521 * is a helper than it is a static class.
1522 *
1523 * @param tstruct The struct definition
1524 * @param is_exception Is this an exception?
1525 * @param in_class If inside a class, needs to be static class
1526 * @param is_result If this is a result it needs a different writer
1527 */
generate_java_struct_definition(ostream & out,t_struct * tstruct,bool is_exception,bool in_class,bool is_result)1528 void t_java_generator::generate_java_struct_definition(ostream& out,
1529 t_struct* tstruct,
1530 bool is_exception,
1531 bool in_class,
1532 bool is_result) {
1533 generate_java_doc(out, tstruct);
1534 indent(out) << java_suppressions();
1535
1536 bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end());
1537 bool is_deprecated = this->is_deprecated(tstruct->annotations_);
1538
1539 if (!in_class && !suppress_generated_annotations_) {
1540 generate_javax_generated_annotation(out);
1541 }
1542
1543 if (is_deprecated) {
1544 indent(out) << "@Deprecated" << endl;
1545 }
1546 indent(out) << "public " << (is_final ? "final " : "") << (in_class ? "static " : "") << "class "
1547 << make_valid_java_identifier(tstruct->get_name()) << " ";
1548
1549 if (is_exception) {
1550 out << "extends org.apache.thrift.TException ";
1551 }
1552 out << "implements org.apache.thrift.TBase<" << make_valid_java_identifier(tstruct->get_name())
1553 << ", " << make_valid_java_identifier(tstruct->get_name())
1554 << "._Fields>, java.io.Serializable, Cloneable, Comparable<" << make_valid_java_identifier(tstruct->get_name()) << ">";
1555
1556 if (android_style_) {
1557 out << ", android.os.Parcelable";
1558 }
1559
1560 out << " ";
1561
1562 scope_up(out);
1563
1564 generate_struct_desc(out, tstruct);
1565
1566 // Members are public for -java, private for -javabean
1567 const vector<t_field*>& members = tstruct->get_members();
1568 vector<t_field*>::const_iterator m_iter;
1569
1570 out << endl;
1571
1572 generate_field_descs(out, tstruct);
1573
1574 out << endl;
1575
1576 generate_scheme_map(out, tstruct);
1577
1578 out << endl;
1579
1580 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1581 if (bean_style_ || private_members_) {
1582 indent(out) << "private ";
1583 } else {
1584 generate_java_doc(out, *m_iter);
1585 indent(out) << "public ";
1586 }
1587 out << declare_field(*m_iter, false, true) << endl;
1588 }
1589
1590 out << endl;
1591
1592 if (android_style_) {
1593 generate_java_struct_parcelable(out, tstruct);
1594 }
1595
1596 generate_field_name_constants(out, tstruct);
1597
1598 // isset data
1599 if (members.size() > 0) {
1600 out << endl;
1601
1602 indent(out) << "// isset id assignments" << endl;
1603
1604 int i = 0;
1605 int optionals = 0;
1606 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1607 if ((*m_iter)->get_req() == t_field::T_OPTIONAL) {
1608 optionals++;
1609 }
1610 if (!type_can_be_null((*m_iter)->get_type())) {
1611 indent(out) << "private static final int " << isset_field_id(*m_iter) << " = " << i << ";"
1612 << endl;
1613 i++;
1614 }
1615 }
1616
1617 std::string primitiveType;
1618 switch (needs_isset(tstruct, &primitiveType)) {
1619 case ISSET_NONE:
1620 break;
1621 case ISSET_PRIMITIVE:
1622 indent(out) << "private " << primitiveType << " __isset_bitfield = 0;" << endl;
1623 break;
1624 case ISSET_BITSET:
1625 indent(out) << "private java.util.BitSet __isset_bit_vector = new java.util.BitSet(" << i
1626 << ");" << endl;
1627 break;
1628 }
1629
1630 if (optionals > 0) {
1631 std::string output_string = "private static final _Fields optionals[] = {";
1632 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1633 if ((*m_iter)->get_req() == t_field::T_OPTIONAL) {
1634 output_string = output_string + "_Fields." + constant_name((*m_iter)->get_name()) + ",";
1635 }
1636 }
1637 indent(out) << output_string.substr(0, output_string.length() - 1) << "};" << endl;
1638 }
1639 }
1640
1641 generate_java_meta_data_map(out, tstruct);
1642
1643 bool all_optional_members = true;
1644
1645 // Default constructor
1646 indent(out) << "public " << make_valid_java_identifier(tstruct->get_name()) << "() {" << endl;
1647 indent_up();
1648 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1649 t_type* t = get_true_type((*m_iter)->get_type());
1650 if ((*m_iter)->get_value() != nullptr) {
1651 print_const_value(out, "this." + (*m_iter)->get_name(), t, (*m_iter)->get_value(), true,
1652 true);
1653 }
1654 if ((*m_iter)->get_req() != t_field::T_OPTIONAL) {
1655 all_optional_members = false;
1656 }
1657 }
1658 indent_down();
1659 indent(out) << "}" << endl << endl;
1660
1661 if (!members.empty() && !all_optional_members) {
1662 // Full constructor for all fields
1663 indent(out) << "public " << make_valid_java_identifier(tstruct->get_name()) << "(" << endl;
1664 indent_up();
1665 bool first = true;
1666 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1667 if ((*m_iter)->get_req() != t_field::T_OPTIONAL) {
1668 if (!first) {
1669 out << "," << endl;
1670 }
1671 first = false;
1672 indent(out) << type_name((*m_iter)->get_type()) << " " << make_valid_java_identifier((*m_iter)->get_name());
1673 }
1674 }
1675 out << ")" << endl;
1676 indent_down();
1677 indent(out) << "{" << endl;
1678 indent_up();
1679 indent(out) << "this();" << endl;
1680 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1681 if ((*m_iter)->get_req() != t_field::T_OPTIONAL) {
1682 t_type* type = get_true_type((*m_iter)->get_type());
1683 if (type->is_binary()) {
1684 if (unsafe_binaries_) {
1685 indent(out) << "this." << make_valid_java_identifier((*m_iter)->get_name())
1686 << " = " << make_valid_java_identifier((*m_iter)->get_name()) << ";"
1687 << endl;
1688 } else {
1689 indent(out) << "this." << make_valid_java_identifier((*m_iter)->get_name())
1690 << " = org.apache.thrift.TBaseHelper.copyBinary("
1691 << make_valid_java_identifier((*m_iter)->get_name())
1692 << ");" << endl;
1693 }
1694 } else {
1695 indent(out) << "this." << make_valid_java_identifier((*m_iter)->get_name()) << " = "
1696 << make_valid_java_identifier((*m_iter)->get_name()) << ";"
1697 << endl;
1698 }
1699 generate_isset_set(out, (*m_iter), "");
1700 }
1701 }
1702
1703 indent_down();
1704 indent(out) << "}" << endl << endl;
1705 }
1706
1707 // copy constructor
1708 indent(out) << "/**" << endl;
1709 indent(out) << " * Performs a deep copy on <i>other</i>." << endl;
1710 indent(out) << " */" << endl;
1711 indent(out) << "public " << make_valid_java_identifier(tstruct->get_name())
1712 << "(" << make_valid_java_identifier(tstruct->get_name()) << " other) {"
1713 << endl;
1714 indent_up();
1715
1716 switch (needs_isset(tstruct)) {
1717 case ISSET_NONE:
1718 break;
1719 case ISSET_PRIMITIVE:
1720 indent(out) << "__isset_bitfield = other.__isset_bitfield;" << endl;
1721 break;
1722 case ISSET_BITSET:
1723 indent(out) << "__isset_bit_vector.clear();" << endl;
1724 indent(out) << "__isset_bit_vector.or(other.__isset_bit_vector);" << endl;
1725 break;
1726 }
1727
1728 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1729 t_field* field = (*m_iter);
1730 std::string field_name = field->get_name();
1731 t_type* type = field->get_type()->get_true_type();
1732 bool can_be_null = type_can_be_null(type);
1733
1734 if (can_be_null) {
1735 indent(out) << "if (other." << generate_isset_check(field) << ") {" << endl;
1736 indent_up();
1737 }
1738
1739 if (type->is_container()) {
1740 generate_deep_copy_container(out, "other", field_name, "__this__" + field_name, type);
1741 indent(out) << "this." << make_valid_java_identifier(field_name) << " = __this__" << field_name << ";" << endl;
1742 } else {
1743 indent(out) << "this." << make_valid_java_identifier(field_name) << " = ";
1744 generate_deep_copy_non_container(out, "other." + make_valid_java_identifier(field_name), field_name, type);
1745 out << ";" << endl;
1746 }
1747
1748 if (can_be_null) {
1749 indent_down();
1750 indent(out) << "}" << endl;
1751 }
1752 }
1753
1754 indent_down();
1755 indent(out) << "}" << endl << endl;
1756
1757 // clone method, so that you can deep copy an object when you don't know its class.
1758 indent(out) << java_override_annotation() << endl;
1759 indent(out) << "public " << make_valid_java_identifier(tstruct->get_name()) << " deepCopy() {" << endl;
1760 indent(out) << " return new " << make_valid_java_identifier(tstruct->get_name()) << "(this);" << endl;
1761 indent(out) << "}" << endl << endl;
1762
1763 generate_java_struct_clear(out, tstruct);
1764
1765 generate_java_bean_boilerplate(out, tstruct);
1766 generate_generic_field_getters_setters(out, tstruct);
1767 generate_generic_isset_method(out, tstruct);
1768
1769 generate_java_struct_equality(out, tstruct);
1770 generate_java_struct_compare_to(out, tstruct);
1771 generate_java_struct_field_by_id(out, tstruct);
1772
1773 generate_java_struct_reader(out, tstruct);
1774 if (is_result) {
1775 generate_java_struct_result_writer(out, tstruct);
1776 } else {
1777 generate_java_struct_writer(out, tstruct);
1778 }
1779 generate_java_struct_tostring(out, tstruct);
1780 generate_java_validator(out, tstruct);
1781
1782 generate_java_struct_write_object(out, tstruct);
1783 generate_java_struct_read_object(out, tstruct);
1784
1785 generate_java_struct_standard_scheme(out, tstruct, is_result);
1786 generate_java_struct_tuple_scheme(out, tstruct);
1787 generate_java_scheme_lookup(out);
1788
1789 scope_down(out);
1790 out << endl;
1791 }
1792
1793 /**
1794 * generates parcelable interface implementation
1795 */
generate_java_struct_parcelable(ostream & out,t_struct * tstruct)1796 void t_java_generator::generate_java_struct_parcelable(ostream& out, t_struct* tstruct) {
1797 string tname = tstruct->get_name();
1798
1799 const vector<t_field*>& members = tstruct->get_members();
1800 vector<t_field*>::const_iterator m_iter;
1801
1802 out << indent() << java_override_annotation() << endl
1803 << indent() << "public void writeToParcel(android.os.Parcel out, int flags) {" << endl;
1804 indent_up();
1805 string bitsetPrimitiveType = "";
1806 switch (needs_isset(tstruct, &bitsetPrimitiveType)) {
1807 case ISSET_NONE:
1808 break;
1809 case ISSET_PRIMITIVE:
1810 indent(out) << "//primitive bitfield of type: " << bitsetPrimitiveType << endl;
1811 if (bitsetPrimitiveType == "byte") {
1812 indent(out) << "out.writeByte(__isset_bitfield);" << endl;
1813 } else if (bitsetPrimitiveType == "short") {
1814 indent(out) << "out.writeInt(new Short(__isset_bitfield).intValue());" << endl;
1815 } else if (bitsetPrimitiveType == "int") {
1816 indent(out) << "out.writeInt(__isset_bitfield);" << endl;
1817 } else if (bitsetPrimitiveType == "long") {
1818 indent(out) << "out.writeLong(__isset_bitfield);" << endl;
1819 }
1820 out << endl;
1821 break;
1822 case ISSET_BITSET:
1823 indent(out) << "//BitSet" << endl;
1824 indent(out) << "out.writeSerializable(__isset_bit_vector);" << endl;
1825 out << endl;
1826 break;
1827 }
1828 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1829 t_type* t = get_true_type((*m_iter)->get_type());
1830 string name = (*m_iter)->get_name();
1831
1832 if (t->is_struct()) {
1833 indent(out) << "out.writeParcelable(" << name << ", flags);" << endl;
1834 } else if (type_name(t) == "float") {
1835 indent(out) << "out.writeFloat(" << name << ");" << endl;
1836 } else if (t->is_enum()) {
1837 indent(out) << "out.writeInt(" << name << " != null ? " << name << ".getValue() : -1);"
1838 << endl;
1839 } else if (t->is_list()) {
1840 if (((t_list*)t)->get_elem_type()->get_true_type()->is_struct()) {
1841 indent(out) << "out.writeTypedList(" << name << ");" << endl;
1842 } else {
1843 indent(out) << "out.writeList(" << name << ");" << endl;
1844 }
1845 } else if (t->is_map()) {
1846 indent(out) << "out.writeMap(" << name << ");" << endl;
1847 } else if (t->is_base_type()) {
1848 if (t->is_binary()) {
1849 indent(out) << "out.writeInt(" << name << "!=null ? 1 : 0);" << endl;
1850 indent(out) << "if(" << name << " != null) { " << endl;
1851 indent_up();
1852 indent(out) << "out.writeByteArray(" << name << ".array(), " << name << ".position() + "
1853 << name << ".arrayOffset(), " << name << ".limit() - " << name
1854 << ".position() );" << endl;
1855 scope_down(out);
1856 } else {
1857 switch (((t_base_type*)t)->get_base()) {
1858 case t_base_type::TYPE_I16:
1859 indent(out) << "out.writeInt(new Short(" << name << ").intValue());" << endl;
1860 break;
1861 case t_base_type::TYPE_UUID:
1862 indent(out) << "out.writeUuid(" << name << ");" << endl;
1863 break;
1864 case t_base_type::TYPE_I32:
1865 indent(out) << "out.writeInt(" << name << ");" << endl;
1866 break;
1867 case t_base_type::TYPE_I64:
1868 indent(out) << "out.writeLong(" << name << ");" << endl;
1869 break;
1870 case t_base_type::TYPE_BOOL:
1871 indent(out) << "out.writeInt(" << name << " ? 1 : 0);" << endl;
1872 break;
1873 case t_base_type::TYPE_I8:
1874 indent(out) << "out.writeByte(" << name << ");" << endl;
1875 break;
1876 case t_base_type::TYPE_DOUBLE:
1877 indent(out) << "out.writeDouble(" << name << ");" << endl;
1878 break;
1879 case t_base_type::TYPE_STRING:
1880 indent(out) << "out.writeString(" << name << ");" << endl;
1881 break;
1882 case t_base_type::TYPE_VOID:
1883 break;
1884 default:
1885 throw "compiler error: unhandled type";
1886 }
1887 }
1888 }
1889 }
1890 scope_down(out);
1891 out << endl;
1892
1893 out << indent() << java_override_annotation() << endl
1894 << indent() << "public int describeContents() {" << endl;
1895 indent_up();
1896 out << indent() << "return 0;" << endl;
1897 scope_down(out);
1898 out << endl;
1899
1900 indent(out) << "public " << tname << "(android.os.Parcel in) {" << endl;
1901 indent_up();
1902 // read in the required bitfield
1903 switch (needs_isset(tstruct, &bitsetPrimitiveType)) {
1904 case ISSET_NONE:
1905 break;
1906 case ISSET_PRIMITIVE:
1907 indent(out) << "//primitive bitfield of type: " << bitsetPrimitiveType << endl;
1908 if (bitsetPrimitiveType == "byte") {
1909 indent(out) << "__isset_bitfield = in.readByte();" << endl;
1910 } else if (bitsetPrimitiveType == "short") {
1911 indent(out) << "__isset_bitfield = (short) in.readInt();" << endl;
1912 } else if (bitsetPrimitiveType == "int") {
1913 indent(out) << "__isset_bitfield = in.readInt();" << endl;
1914 } else if (bitsetPrimitiveType == "long") {
1915 indent(out) << "__isset_bitfield = in.readLong();" << endl;
1916 }
1917 out << endl;
1918 break;
1919 case ISSET_BITSET:
1920 indent(out) << "//BitSet" << endl;
1921 indent(out) << "__isset_bit_vector = (java.util.BitSet) in.readSerializable();" << endl;
1922 out << endl;
1923 break;
1924 }
1925 // read all the fields
1926 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1927 t_type* t = get_true_type((*m_iter)->get_type());
1928 string name = (*m_iter)->get_name();
1929 string prefix = "this." + name;
1930
1931 if (t->is_struct()) {
1932 indent(out) << prefix << "= in.readParcelable(" << tname << ".class.getClassLoader());"
1933 << endl;
1934 } else if (t->is_enum()) {
1935 indent(out) << prefix << " = " << type_name(t) << ".findByValue(in.readInt());" << endl;
1936 } else if (t->is_list()) {
1937 t_list* list = (t_list*)t;
1938 indent(out) << prefix << " = new " << type_name(t, false, true) << "();" << endl;
1939 if (list->get_elem_type()->get_true_type()->is_struct()) {
1940 indent(out) << "in.readTypedList(" << prefix << ", " << type_name(list->get_elem_type())
1941 << ".CREATOR);" << endl;
1942 } else {
1943 indent(out) << "in.readList(" << prefix << ", " << tname << ".class.getClassLoader());"
1944 << endl;
1945 }
1946 } else if (t->is_map()) {
1947 indent(out) << prefix << " = new " << type_name(t, false, true) << "();" << endl;
1948 indent(out) << " in.readMap(" << prefix << ", " << tname << ".class.getClassLoader());"
1949 << endl;
1950 } else if (type_name(t) == "float") {
1951 indent(out) << prefix << " = in.readFloat();" << endl;
1952 } else if (t->is_base_type()) {
1953 t_base_type* bt = (t_base_type*)t;
1954 if (bt->is_binary()) {
1955 indent(out) << "if(in.readInt()==1) {" << endl;
1956 indent_up();
1957 indent(out) << prefix << " = java.nio.ByteBuffer.wrap(in.createByteArray());" << endl;
1958 scope_down(out);
1959 } else {
1960 switch (bt->get_base()) {
1961 case t_base_type::TYPE_I8:
1962 indent(out) << prefix << " = in.readByte();" << endl;
1963 break;
1964 case t_base_type::TYPE_I16:
1965 indent(out) << prefix << " = (short) in.readInt();" << endl;
1966 break;
1967 case t_base_type::TYPE_I32:
1968 indent(out) << prefix << " = in.readInt();" << endl;
1969 break;
1970 case t_base_type::TYPE_I64:
1971 indent(out) << prefix << " = in.readLong();" << endl;
1972 break;
1973 case t_base_type::TYPE_UUID:
1974 indent(out) << prefix << " = in.readUuid();" << endl;
1975 break;
1976 case t_base_type::TYPE_BOOL:
1977 indent(out) << prefix << " = (in.readInt()==1);" << endl;
1978 break;
1979 case t_base_type::TYPE_DOUBLE:
1980 indent(out) << prefix << " = in.readDouble();" << endl;
1981 break;
1982 case t_base_type::TYPE_STRING:
1983 indent(out) << prefix << "= in.readString();" << endl;
1984 break;
1985 case t_base_type::TYPE_VOID:
1986 break;
1987 default:
1988 throw "compiler error: unhandled type";
1989 }
1990 }
1991 }
1992 }
1993
1994 scope_down(out);
1995 out << endl;
1996
1997 indent(out) << "public static final android.os.Parcelable.Creator<" << tname
1998 << "> CREATOR = new android.os.Parcelable.Creator<" << tname << ">() {" << endl;
1999 indent_up();
2000
2001 indent(out) << java_override_annotation() << endl
2002 << indent() << "public " << tname << "[] newArray(int size) {" << endl;
2003 indent_up();
2004 indent(out) << "return new " << tname << "[size];" << endl;
2005 scope_down(out);
2006 out << endl;
2007
2008 indent(out) << java_override_annotation() << endl
2009 << indent() << "public " << tname << " createFromParcel(android.os.Parcel in) {"
2010 << endl;
2011 indent_up();
2012 indent(out) << "return new " << tname << "(in);" << endl;
2013 scope_down(out);
2014
2015 indent_down();
2016 indent(out) << "};" << endl;
2017 out << endl;
2018 }
2019
2020 /**
2021 * Generates equals methods and a hashCode method for a structure.
2022 *
2023 * @param tstruct The struct definition
2024 */
generate_java_struct_equality(ostream & out,t_struct * tstruct)2025 void t_java_generator::generate_java_struct_equality(ostream& out, t_struct* tstruct) {
2026 out << indent() << java_override_annotation() << endl
2027 << indent() << "public boolean equals(java.lang.Object that) {" << endl;
2028 indent_up();
2029 out << indent() << "if (that instanceof " << make_valid_java_identifier(tstruct->get_name()) << ")" << endl
2030 << indent() << " return this.equals((" << make_valid_java_identifier(tstruct->get_name()) << ")that);" << endl
2031 << indent() << "return false;" << endl;
2032 scope_down(out);
2033 out << endl;
2034
2035 out << indent() << "public boolean equals(" << make_valid_java_identifier(tstruct->get_name()) << " that) {" << endl;
2036 indent_up();
2037 out << indent() << "if (that == null)" << endl
2038 << indent() << " return false;" << endl
2039 << indent() << "if (this == that)" << endl
2040 << indent() << " return true;" << endl;
2041
2042 const vector<t_field*>& members = tstruct->get_members();
2043 vector<t_field*>::const_iterator m_iter;
2044 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
2045 out << endl;
2046
2047 t_type* t = get_true_type((*m_iter)->get_type());
2048 // Most existing Thrift code does not use isset or optional/required,
2049 // so we treat "default" fields as required.
2050 bool is_optional = (*m_iter)->get_req() == t_field::T_OPTIONAL;
2051 bool can_be_null = type_can_be_null(t);
2052 string name = (*m_iter)->get_name();
2053
2054 string this_present = "true";
2055 string that_present = "true";
2056 string unequal;
2057
2058 if (is_optional || can_be_null) {
2059 this_present += " && this." + generate_isset_check(*m_iter);
2060 that_present += " && that." + generate_isset_check(*m_iter);
2061 }
2062
2063 out << indent() << "boolean this_present_" << name << " = " << this_present << ";" << endl
2064 << indent() << "boolean that_present_" << name << " = " << that_present << ";" << endl
2065 << indent() << "if ("
2066 << "this_present_" << name << " || that_present_" << name << ") {" << endl;
2067 indent_up();
2068 out << indent() << "if (!("
2069 << "this_present_" << name << " && that_present_" << name << "))" << endl
2070 << indent() << " return false;" << endl;
2071
2072 if (t->is_binary()) {
2073 unequal = "!this." + make_valid_java_identifier(name) + ".equals(that." + make_valid_java_identifier(name) + ")";
2074 } else if (can_be_null) {
2075 unequal = "!this." + make_valid_java_identifier(name) + ".equals(that." + make_valid_java_identifier(name) + ")";
2076 } else {
2077 unequal = "this." + make_valid_java_identifier(name) + " != that." + make_valid_java_identifier(name);
2078 }
2079
2080 out << indent() << "if (" << unequal << ")" << endl << indent() << " return false;" << endl;
2081
2082 scope_down(out);
2083 }
2084 out << endl;
2085 indent(out) << "return true;" << endl;
2086 scope_down(out);
2087 out << endl;
2088
2089 const int MUL = 8191; // HashCode multiplier
2090 const int B_YES = 131071;
2091 const int B_NO = 524287;
2092 out << indent() << java_override_annotation() << endl
2093 << indent() << "public int hashCode() {" << endl;
2094 indent_up();
2095 indent(out) << "int hashCode = 1;" << endl;
2096
2097 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
2098 out << endl;
2099
2100 t_type* t = get_true_type((*m_iter)->get_type());
2101 bool is_optional = (*m_iter)->get_req() == t_field::T_OPTIONAL;
2102 bool can_be_null = type_can_be_null(t);
2103 string name = make_valid_java_identifier((*m_iter)->get_name());
2104
2105 if (is_optional || can_be_null) {
2106 indent(out) << "hashCode = hashCode * " << MUL << " + ((" << generate_isset_check(*m_iter)
2107 << ") ? " << B_YES << " : " << B_NO << ");" << endl;
2108 }
2109
2110 if (is_optional || can_be_null) {
2111 indent(out) << "if (" + generate_isset_check(*m_iter) + ")" << endl;
2112 indent_up();
2113 }
2114
2115 if (t->is_enum()) {
2116 indent(out) << "hashCode = hashCode * " << MUL << " + " << name << ".getValue();" << endl;
2117 } else if (t->is_base_type()) {
2118 switch (((t_base_type*)t)->get_base()) {
2119 case t_base_type::TYPE_STRING:
2120 case t_base_type::TYPE_UUID:
2121 indent(out) << "hashCode = hashCode * " << MUL << " + " << name << ".hashCode();" << endl;
2122 break;
2123 case t_base_type::TYPE_BOOL:
2124 indent(out) << "hashCode = hashCode * " << MUL << " + ((" << name << ") ? " << B_YES
2125 << " : " << B_NO << ");" << endl;
2126 break;
2127 case t_base_type::TYPE_I8:
2128 indent(out) << "hashCode = hashCode * " << MUL << " + (int) (" << name << ");" << endl;
2129 break;
2130 case t_base_type::TYPE_I16:
2131 case t_base_type::TYPE_I32:
2132 indent(out) << "hashCode = hashCode * " << MUL << " + " << name << ";" << endl;
2133 break;
2134 case t_base_type::TYPE_I64:
2135 case t_base_type::TYPE_DOUBLE:
2136 indent(out) << "hashCode = hashCode * " << MUL
2137 << " + org.apache.thrift.TBaseHelper.hashCode(" << name << ");" << endl;
2138 break;
2139 case t_base_type::TYPE_VOID:
2140 throw std::logic_error("compiler error: a struct field cannot be void");
2141 default:
2142 throw std::logic_error("compiler error: the following base type has no hashcode generator: "
2143 + t_base_type::t_base_name(((t_base_type*)t)->get_base()));
2144 }
2145 } else {
2146 indent(out) << "hashCode = hashCode * " << MUL << " + " << name << ".hashCode();" << endl;
2147 }
2148
2149 if (is_optional || can_be_null) {
2150 indent_down();
2151 }
2152 }
2153
2154 out << endl;
2155 indent(out) << "return hashCode;" << endl;
2156 indent_down();
2157 indent(out) << "}" << endl << endl;
2158 }
2159
generate_java_struct_compare_to(ostream & out,t_struct * tstruct)2160 void t_java_generator::generate_java_struct_compare_to(ostream& out, t_struct* tstruct) {
2161 indent(out) << java_override_annotation() << endl;
2162 indent(out) << "public int compareTo(" << type_name(tstruct) << " other) {" << endl;
2163 indent_up();
2164
2165 indent(out) << "if (!getClass().equals(other.getClass())) {" << endl;
2166 indent(out) << " return getClass().getName().compareTo(other.getClass().getName());" << endl;
2167 indent(out) << "}" << endl;
2168 out << endl;
2169
2170 indent(out) << "int lastComparison = 0;" << endl;
2171 out << endl;
2172
2173 const vector<t_field*>& members = tstruct->get_members();
2174 vector<t_field*>::const_iterator m_iter;
2175 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
2176 t_field* field = *m_iter;
2177 indent(out) << "lastComparison = java.lang.Boolean.compare(" << generate_isset_check(field)
2178 << ", other." << generate_isset_check(field) << ");" << endl;
2179 indent(out) << "if (lastComparison != 0) {" << endl;
2180 indent(out) << " return lastComparison;" << endl;
2181 indent(out) << "}" << endl;
2182
2183 indent(out) << "if (" << generate_isset_check(field) << ") {" << endl;
2184 indent(out) << " lastComparison = org.apache.thrift.TBaseHelper.compareTo(this."
2185 << make_valid_java_identifier(field->get_name())
2186 << ", other." << make_valid_java_identifier(field->get_name()) << ");" << endl;
2187 indent(out) << " if (lastComparison != 0) {" << endl;
2188 indent(out) << " return lastComparison;" << endl;
2189 indent(out) << " }" << endl;
2190 indent(out) << "}" << endl;
2191 }
2192
2193 indent(out) << "return 0;" << endl;
2194
2195 indent_down();
2196 indent(out) << "}" << endl << endl;
2197 }
2198
2199 /**
2200 * Generates a function to read all the fields of the struct.
2201 *
2202 * @param tstruct The struct definition
2203 */
generate_java_struct_reader(ostream & out,t_struct *)2204 void t_java_generator::generate_java_struct_reader(ostream& out, t_struct* /*tstruct*/) {
2205 indent(out) << java_override_annotation() << endl;
2206 indent(out) << "public void read(org.apache.thrift.protocol.TProtocol iprot) throws "
2207 "org.apache.thrift.TException {"
2208 << endl;
2209 indent_up();
2210 indent(out) << "scheme(iprot).read(iprot, this);" << endl;
2211 indent_down();
2212 indent(out) << "}" << endl << endl;
2213 }
2214
2215 // generates java method to perform various checks
2216 // (e.g. check that all required fields are set)
generate_java_validator(ostream & out,t_struct * tstruct)2217 void t_java_generator::generate_java_validator(ostream& out, t_struct* tstruct) {
2218 indent(out) << "public void validate() throws org.apache.thrift.TException {" << endl;
2219 indent_up();
2220
2221 const vector<t_field*>& fields = tstruct->get_members();
2222 vector<t_field*>::const_iterator f_iter;
2223
2224 out << indent() << "// check for required fields" << endl;
2225 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
2226 if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
2227 if (bean_style_) {
2228 out << indent() << "if (!" << generate_isset_check(*f_iter) << ") {" << endl
2229 << indent()
2230 << " throw new org.apache.thrift.protocol.TProtocolException(\"Required field '"
2231 << (*f_iter)->get_name() << "' is unset! Struct:\" + toString());" << endl
2232 << indent() << "}" << endl
2233 << endl;
2234 } else {
2235 if (type_can_be_null((*f_iter)->get_type())) {
2236 indent(out) << "if (" << (*f_iter)->get_name() << " == null) {" << endl;
2237 indent(out)
2238 << " throw new org.apache.thrift.protocol.TProtocolException(\"Required field '"
2239 << (*f_iter)->get_name() << "' was not present! Struct: \" + toString());" << endl;
2240 indent(out) << "}" << endl;
2241 } else {
2242 indent(out) << "// alas, we cannot check '" << (*f_iter)->get_name()
2243 << "' because it's a primitive and you chose the non-beans generator."
2244 << endl;
2245 }
2246 }
2247 }
2248 }
2249
2250 out << indent() << "// check for sub-struct validity" << endl;
2251 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
2252 t_type* type = get_true_type((*f_iter)->get_type());
2253 if (type->is_struct() && !((t_struct*)type)->is_union()) {
2254 out << indent() << "if (" << make_valid_java_identifier((*f_iter)->get_name()) << " != null) {" << endl;
2255 out << indent() << " " << make_valid_java_identifier((*f_iter)->get_name()) << ".validate();" << endl;
2256 out << indent() << "}" << endl;
2257 }
2258 }
2259
2260 indent_down();
2261 indent(out) << "}" << endl << endl;
2262 }
2263
2264 /**
2265 * Generates a function to write all the fields of the struct
2266 *
2267 * @param tstruct The struct definition
2268 */
generate_java_struct_writer(ostream & out,t_struct *)2269 void t_java_generator::generate_java_struct_writer(ostream& out, t_struct* /*tstruct*/) {
2270 indent(out) << java_override_annotation() << endl;
2271 indent(out) << "public void write(org.apache.thrift.protocol.TProtocol oprot) throws "
2272 "org.apache.thrift.TException {"
2273 << endl;
2274 indent_up();
2275 indent(out) << "scheme(oprot).write(oprot, this);" << endl;
2276
2277 indent_down();
2278 indent(out) << "}" << endl << endl;
2279 }
2280
2281 /**
2282 * Generates a function to write all the fields of the struct,
2283 * which is a function result. These fields are only written
2284 * if they are set in the Isset array, and only one of them
2285 * can be set at a time.
2286 *
2287 * @param tstruct The struct definition
2288 */
generate_java_struct_result_writer(ostream & out,t_struct * tstruct)2289 void t_java_generator::generate_java_struct_result_writer(ostream& out, t_struct* tstruct) {
2290 (void)tstruct;
2291 indent(out) << "public void write(org.apache.thrift.protocol.TProtocol oprot) throws "
2292 "org.apache.thrift.TException {"
2293 << endl;
2294 indent_up();
2295 indent(out) << "scheme(oprot).write(oprot, this);" << endl;
2296
2297 indent_down();
2298 indent(out) << " }" << endl << endl;
2299 }
2300
generate_java_struct_field_by_id(ostream & out,t_struct * tstruct)2301 void t_java_generator::generate_java_struct_field_by_id(ostream& out, t_struct* tstruct) {
2302 (void)tstruct;
2303 indent(out) << java_nullable_annotation() << endl;
2304 indent(out) << java_override_annotation() << endl;
2305 indent(out) << "public _Fields fieldForId(int fieldId) {" << endl;
2306 indent(out) << " return _Fields.findByThriftId(fieldId);" << endl;
2307 indent(out) << "}" << endl << endl;
2308 }
2309
generate_reflection_getters(ostringstream & out,t_type * type,string field_name,string cap_name)2310 void t_java_generator::generate_reflection_getters(ostringstream& out,
2311 t_type* type,
2312 string field_name,
2313 string cap_name) {
2314 indent(out) << "case " << constant_name(field_name) << ":" << endl;
2315 indent_up();
2316 indent(out) << "return " << (type->is_bool() ? "is" : "get") << cap_name << "();" << endl << endl;
2317 indent_down();
2318 }
2319
generate_reflection_setters(ostringstream & out,t_type * type,string field_name,string cap_name)2320 void t_java_generator::generate_reflection_setters(ostringstream& out,
2321 t_type* type,
2322 string field_name,
2323 string cap_name) {
2324 const bool is_binary = type->is_binary();
2325 indent(out) << "case " << constant_name(field_name) << ":" << endl;
2326 indent_up();
2327 indent(out) << "if (value == null) {" << endl;
2328 indent(out) << " unset" << get_cap_name(field_name) << "();" << endl;
2329 indent(out) << "} else {" << endl;
2330 if (is_binary) {
2331 indent_up();
2332 indent(out) << "if (value instanceof byte[]) {" << endl;
2333 indent(out) << " set" << cap_name << "((byte[])value);" << endl;
2334 indent(out) << "} else {" << endl;
2335 }
2336 indent(out) << " set" << cap_name << "((" << type_name(type, true, false) << ")value);" << endl;
2337 if (is_binary) {
2338 indent(out) << "}" << endl;
2339 indent_down();
2340 }
2341 indent(out) << "}" << endl;
2342 indent(out) << "break;" << endl << endl;
2343
2344 indent_down();
2345 }
2346
generate_generic_field_getters_setters(std::ostream & out,t_struct * tstruct)2347 void t_java_generator::generate_generic_field_getters_setters(std::ostream& out,
2348 t_struct* tstruct) {
2349 std::ostringstream getter_stream;
2350 std::ostringstream setter_stream;
2351
2352 // build up the bodies of both the getter and setter at once
2353 const vector<t_field*>& fields = tstruct->get_members();
2354 vector<t_field*>::const_iterator f_iter;
2355 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
2356 t_field* field = *f_iter;
2357 t_type* type = get_true_type(field->get_type());
2358 std::string field_name = field->get_name();
2359 std::string cap_name = get_cap_name(field_name);
2360
2361 indent_up();
2362 generate_reflection_setters(setter_stream, type, field_name, cap_name);
2363 generate_reflection_getters(getter_stream, type, field_name, cap_name);
2364 indent_down();
2365 }
2366
2367 // create the setter
2368
2369 indent(out) << java_override_annotation() << endl;
2370 indent(out) << "public void setFieldValue(_Fields field, " << java_nullable_annotation()
2371 << " java.lang.Object value) {" << endl;
2372 indent(out) << " switch (field) {" << endl;
2373 out << setter_stream.str();
2374 indent(out) << " }" << endl;
2375 indent(out) << "}" << endl << endl;
2376
2377 // create the getter
2378 indent(out) << java_nullable_annotation() << endl;
2379 indent(out) << java_override_annotation() << endl;
2380 indent(out) << "public java.lang.Object getFieldValue(_Fields field) {" << endl;
2381 indent_up();
2382 indent(out) << "switch (field) {" << endl;
2383 out << getter_stream.str();
2384 indent(out) << "}" << endl;
2385 indent(out) << "throw new java.lang.IllegalStateException();" << endl;
2386 indent_down();
2387 indent(out) << "}" << endl << endl;
2388 }
2389
2390 // Creates a generic isSet method that takes the field number as argument
generate_generic_isset_method(std::ostream & out,t_struct * tstruct)2391 void t_java_generator::generate_generic_isset_method(std::ostream& out, t_struct* tstruct) {
2392 const vector<t_field*>& fields = tstruct->get_members();
2393 vector<t_field*>::const_iterator f_iter;
2394
2395 // create the isSet method
2396 indent(out) << "/** Returns true if field corresponding to fieldID is set (has been assigned a "
2397 "value) and false otherwise */"
2398 << endl;
2399 indent(out) << java_override_annotation() << endl;
2400 indent(out) << "public boolean isSet(_Fields field) {" << endl;
2401 indent_up();
2402 indent(out) << "if (field == null) {" << endl;
2403 indent(out) << " throw new java.lang.IllegalArgumentException();" << endl;
2404 indent(out) << "}" << endl << endl;
2405
2406 indent(out) << "switch (field) {" << endl;
2407
2408 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
2409 t_field* field = *f_iter;
2410 indent(out) << "case " << constant_name(field->get_name()) << ":" << endl;
2411 indent_up();
2412 indent(out) << "return " << generate_isset_check(field) << ";" << endl;
2413 indent_down();
2414 }
2415
2416 indent(out) << "}" << endl;
2417 indent(out) << "throw new java.lang.IllegalStateException();" << endl;
2418 indent_down();
2419 indent(out) << "}" << endl << endl;
2420 }
2421
2422 /**
2423 * Generates a set of Java Bean boilerplate functions (setters, getters, etc.)
2424 * for the given struct.
2425 *
2426 * @param tstruct The struct definition
2427 */
generate_java_bean_boilerplate(ostream & out,t_struct * tstruct)2428 void t_java_generator::generate_java_bean_boilerplate(ostream& out, t_struct* tstruct) {
2429 isset_type issetType = needs_isset(tstruct);
2430 const vector<t_field*>& fields = tstruct->get_members();
2431 vector<t_field*>::const_iterator f_iter;
2432 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
2433 t_field* field = *f_iter;
2434 t_type* type = get_true_type(field->get_type());
2435 std::string field_name = field->get_name();
2436 std::string cap_name = get_cap_name(field_name);
2437 bool optional = use_option_type_ && field->get_req() == t_field::T_OPTIONAL;
2438 bool is_deprecated = this->is_deprecated(field->annotations_);
2439
2440 if (type->is_container()) {
2441 // Method to return the size of the collection
2442 if (optional) {
2443 if (is_deprecated) {
2444 indent(out) << "@Deprecated" << endl;
2445 }
2446
2447 if (use_jdk8_option_type_) {
2448 indent(out) << "public " << jdk_option_class << "<Integer> get" << cap_name;
2449 } else {
2450 indent(out) << "public " << thrift_option_class << "<Integer> get" << cap_name;
2451 }
2452
2453 out << get_cap_name("size() {") << endl;
2454
2455 indent_up();
2456 indent(out) << "if (this." << field_name << " == null) {" << endl;
2457 indent_up();
2458
2459 if (use_jdk8_option_type_) {
2460 indent(out) << "return " << jdk_option_class << ".empty();" << endl;
2461 } else {
2462 indent(out) << "return " << thrift_option_class << ".none();" << endl;
2463 }
2464
2465 indent_down();
2466 indent(out) << "} else {" << endl;
2467 indent_up();
2468
2469 if (use_jdk8_option_type_) {
2470 indent(out) << "return " << jdk_option_class << ".of(this.";
2471 } else {
2472 indent(out) << "return " << thrift_option_class << ".some(this.";
2473 }
2474 out << field_name << ".size());" << endl;
2475
2476 indent_down();
2477 indent(out) << "}" << endl;
2478 indent_down();
2479 indent(out) << "}" << endl << endl;
2480 } else {
2481 if (is_deprecated) {
2482 indent(out) << "@Deprecated" << endl;
2483 }
2484 indent(out) << "public int get" << cap_name;
2485 out << get_cap_name("size() {") << endl;
2486
2487 indent_up();
2488 indent(out) << "return (this." << field_name << " == null) ? 0 : "
2489 << "this." << field_name << ".size();" << endl;
2490 indent_down();
2491 indent(out) << "}" << endl << endl;
2492 }
2493 }
2494
2495 if (type->is_set() || type->is_list()) {
2496 t_type* element_type;
2497 if (type->is_set()) {
2498 element_type = ((t_set*)type)->get_elem_type();
2499 } else {
2500 element_type = ((t_list*)type)->get_elem_type();
2501 }
2502
2503 // Iterator getter for sets and lists
2504 if (optional) {
2505 if (is_deprecated) {
2506 indent(out) << "@Deprecated" << endl;
2507 }
2508
2509 if (use_jdk8_option_type_) {
2510 indent(out) << "public " << jdk_option_class << "<";
2511 } else {
2512 indent(out) << "public " << thrift_option_class << "<";
2513 }
2514 out << "java.util.Iterator<" << type_name(element_type, true, false) << ">> get"
2515 << cap_name;
2516
2517 out << get_cap_name("iterator() {") << endl;
2518
2519 indent_up();
2520 indent(out) << "if (this." << field_name << " == null) {" << endl;
2521 indent_up();
2522
2523 if (use_jdk8_option_type_) {
2524 indent(out) << "return " << jdk_option_class << ".empty();" << endl;
2525 } else {
2526 indent(out) << "return " << thrift_option_class << ".none();" << endl;
2527 }
2528
2529 indent_down();
2530 indent(out) << "} else {" << endl;
2531 indent_up();
2532
2533 if (use_jdk8_option_type_) {
2534 indent(out) << "return " << jdk_option_class << ".of(this.";
2535 } else {
2536 indent(out) << "return " << thrift_option_class << ".some(this.";
2537 }
2538 out << field_name << ".iterator());" << endl;
2539
2540 indent_down();
2541 indent(out) << "}" << endl;
2542 indent_down();
2543 indent(out) << "}" << endl << endl;
2544 } else {
2545 if (is_deprecated) {
2546 indent(out) << "@Deprecated" << endl;
2547 }
2548 indent(out) << java_nullable_annotation() << endl;
2549 indent(out) << "public java.util.Iterator<" << type_name(element_type, true, false)
2550 << "> get" << cap_name;
2551 out << get_cap_name("iterator() {") << endl;
2552
2553 indent_up();
2554 indent(out) << "return (this." << field_name << " == null) ? null : "
2555 << "this." << field_name << ".iterator();" << endl;
2556 indent_down();
2557 indent(out) << "}" << endl << endl;
2558 }
2559
2560 // Add to set or list, create if the set/list is null
2561 if (is_deprecated) {
2562 indent(out) << "@Deprecated" << endl;
2563 }
2564 indent(out) << "public void add" << get_cap_name("to");
2565 out << cap_name << "(" << type_name(element_type) << " elem) {" << endl;
2566
2567 indent_up();
2568 indent(out) << "if (this." << field_name << " == null) {" << endl;
2569 indent_up();
2570 indent(out) << "this." << field_name;
2571 if (is_enum_set(type)) {
2572 out << " = " << type_name(type, false, true, true) << ".noneOf("
2573 << inner_enum_type_name(type) << ");" << endl;
2574 } else {
2575 out << " = new " << type_name(type, false, true) << "();" << endl;
2576 }
2577 indent_down();
2578 indent(out) << "}" << endl;
2579 indent(out) << "this." << field_name << ".add(elem);" << endl;
2580 indent_down();
2581 indent(out) << "}" << endl << endl;
2582 } else if (type->is_map()) {
2583 // Put to map
2584 t_type* key_type = ((t_map*)type)->get_key_type();
2585 t_type* val_type = ((t_map*)type)->get_val_type();
2586
2587 if (is_deprecated) {
2588 indent(out) << "@Deprecated" << endl;
2589 }
2590 indent(out) << "public void put" << get_cap_name("to");
2591 out << cap_name << "(" << type_name(key_type) << " key, " << type_name(val_type) << " val) {"
2592 << endl;
2593
2594 indent_up();
2595 indent(out) << "if (this." << field_name << " == null) {" << endl;
2596 indent_up();
2597 std::string constructor_args;
2598 if (is_enum_map(type)) {
2599 constructor_args = inner_enum_type_name(type);
2600 }
2601 indent(out) << "this." << field_name << " = new " << type_name(type, false, true) << "("
2602 << constructor_args << ");" << endl;
2603 indent_down();
2604 indent(out) << "}" << endl;
2605 indent(out) << "this." << field_name << ".put(key, val);" << endl;
2606 indent_down();
2607 indent(out) << "}" << endl << endl;
2608 }
2609
2610 // Simple getter
2611 generate_java_doc(out, field);
2612 if (type->is_binary()) {
2613 if (is_deprecated) {
2614 indent(out) << "@Deprecated" << endl;
2615 }
2616 indent(out) << "public byte[] get" << cap_name << "() {" << endl;
2617 indent(out) << " set" << cap_name << "(org.apache.thrift.TBaseHelper.rightSize("
2618 << field_name << "));" << endl;
2619 indent(out) << " return " << field_name << " == null ? null : " << field_name << ".array();"
2620 << endl;
2621 indent(out) << "}" << endl << endl;
2622
2623 indent(out) << "public java.nio.ByteBuffer buffer" << get_cap_name("for") << cap_name
2624 << "() {" << endl;
2625 if (unsafe_binaries_) {
2626 indent(out) << " return " << field_name << ";" << endl;
2627 } else {
2628 indent(out) << " return org.apache.thrift.TBaseHelper.copyBinary(" << field_name << ");"
2629 << endl;
2630 }
2631 indent(out) << "}" << endl << endl;
2632 } else {
2633 if (optional) {
2634 if (is_deprecated) {
2635 indent(out) << "@Deprecated" << endl;
2636 }
2637
2638 if (use_jdk8_option_type_) {
2639 indent(out) << "public " << jdk_option_class << "<" << type_name(type, true) << ">";
2640 } else {
2641 indent(out) << "public " << thrift_option_class << "<" << type_name(type, true) << ">";
2642 }
2643
2644 if (type->is_base_type() && ((t_base_type*)type)->get_base() == t_base_type::TYPE_BOOL) {
2645 out << " is";
2646 } else {
2647 out << " get";
2648 }
2649 out << cap_name << "() {" << endl;
2650 indent_up();
2651
2652 indent(out) << "if (this.isSet" << cap_name << "()) {" << endl;
2653 indent_up();
2654
2655 if (use_jdk8_option_type_) {
2656 indent(out) << "return " << jdk_option_class << ".of(this.";
2657 } else {
2658 indent(out) << "return " << thrift_option_class << ".some(this.";
2659 }
2660 out << field_name << ");" << endl;
2661
2662 indent_down();
2663 indent(out) << "} else {" << endl;
2664 indent_up();
2665
2666 if (use_jdk8_option_type_) {
2667 indent(out) << "return " << jdk_option_class << ".empty();" << endl;
2668 } else {
2669 indent(out) << "return " << thrift_option_class << ".none();" << endl;
2670 }
2671
2672 indent_down();
2673 indent(out) << "}" << endl;
2674 indent_down();
2675 indent(out) << "}" << endl << endl;
2676 } else {
2677 if (is_deprecated) {
2678 indent(out) << "@Deprecated" << endl;
2679 }
2680 if (type_can_be_null(type)) {
2681 indent(out) << java_nullable_annotation() << endl;
2682 }
2683 indent(out) << "public " << type_name(type);
2684 if (type->is_base_type() && ((t_base_type*)type)->get_base() == t_base_type::TYPE_BOOL) {
2685 out << " is";
2686 } else {
2687 out << " get";
2688 }
2689 out << cap_name << "() {" << endl;
2690 indent_up();
2691 indent(out) << "return this." << make_valid_java_identifier(field_name) << ";" << endl;
2692 indent_down();
2693 indent(out) << "}" << endl << endl;
2694 }
2695 }
2696
2697 // Simple setter
2698 generate_java_doc(out, field);
2699 if (type->is_binary()) {
2700 if (is_deprecated) {
2701 indent(out) << "@Deprecated" << endl;
2702 }
2703 indent(out) << "public ";
2704 if (bean_style_) {
2705 out << "void";
2706 } else {
2707 out << type_name(tstruct);
2708 }
2709 out << " set" << cap_name << "(byte[] " << make_valid_java_identifier(field_name) << ") {" << endl;
2710 indent(out) << " this." << make_valid_java_identifier(field_name) << " = " << make_valid_java_identifier(field_name)
2711 << " == null ? (java.nio.ByteBuffer)null";
2712
2713 if (unsafe_binaries_) {
2714 indent(out) << " : java.nio.ByteBuffer.wrap(" << make_valid_java_identifier(field_name) << ");" << endl;
2715 } else {
2716 indent(out) << " : java.nio.ByteBuffer.wrap(" << make_valid_java_identifier(field_name) << ".clone());" << endl;
2717 }
2718
2719 if (!bean_style_) {
2720 indent(out) << " return this;" << endl;
2721 }
2722 indent(out) << "}" << endl << endl;
2723 }
2724 if (is_deprecated) {
2725 indent(out) << "@Deprecated" << endl;
2726 }
2727 indent(out) << "public ";
2728 if (bean_style_) {
2729 out << "void";
2730 } else {
2731 out << type_name(tstruct);
2732 }
2733 out << " set" << cap_name << "("
2734 << (type_can_be_null(type) ? (java_nullable_annotation() + " ") : "")
2735 << type_name(type)
2736 << " " << make_valid_java_identifier(field_name) << ") {" << endl;
2737 indent_up();
2738 indent(out) << "this." << make_valid_java_identifier(field_name) << " = ";
2739 if (type->is_binary() && !unsafe_binaries_) {
2740 out << "org.apache.thrift.TBaseHelper.copyBinary(" << make_valid_java_identifier(field_name) << ")";
2741 } else {
2742 out << make_valid_java_identifier(field_name);
2743 }
2744 out << ";" << endl;
2745 generate_isset_set(out, field, "");
2746 if (!bean_style_) {
2747 indent(out) << "return this;" << endl;
2748 }
2749
2750 indent_down();
2751 indent(out) << "}" << endl << endl;
2752
2753 // Unsetter
2754 if (is_deprecated) {
2755 indent(out) << "@Deprecated" << endl;
2756 }
2757 indent(out) << "public void unset" << cap_name << "() {" << endl;
2758 indent_up();
2759 if (type_can_be_null(type)) {
2760 indent(out) << "this." << make_valid_java_identifier(field_name) << " = null;" << endl;
2761 } else if (issetType == ISSET_PRIMITIVE) {
2762 indent(out)
2763 << "__isset_bitfield = org.apache.thrift.EncodingUtils.clearBit(__isset_bitfield, "
2764 << isset_field_id(field) << ");" << endl;
2765 } else {
2766 indent(out) << "__isset_bit_vector.clear(" << isset_field_id(field) << ");" << endl;
2767 }
2768 indent_down();
2769 indent(out) << "}" << endl << endl;
2770
2771 // isSet method
2772 indent(out) << "/** Returns true if field " << field_name
2773 << " is set (has been assigned a value) and false otherwise */" << endl;
2774 if (is_deprecated) {
2775 indent(out) << "@Deprecated" << endl;
2776 }
2777 indent(out) << "public boolean is" << get_cap_name("set") << cap_name << "() {" << endl;
2778 indent_up();
2779 if (type_can_be_null(type)) {
2780 indent(out) << "return this." << make_valid_java_identifier(field_name) << " != null;" << endl;
2781 } else if (issetType == ISSET_PRIMITIVE) {
2782 indent(out) << "return org.apache.thrift.EncodingUtils.testBit(__isset_bitfield, "
2783 << isset_field_id(field) << ");" << endl;
2784 } else {
2785 indent(out) << "return __isset_bit_vector.get(" << isset_field_id(field) << ");" << endl;
2786 }
2787 indent_down();
2788 indent(out) << "}" << endl << endl;
2789
2790 if (is_deprecated) {
2791 indent(out) << "@Deprecated" << endl;
2792 }
2793 indent(out) << "public void set" << cap_name << get_cap_name("isSet") << "(boolean value) {"
2794 << endl;
2795 indent_up();
2796 if (type_can_be_null(type)) {
2797 indent(out) << "if (!value) {" << endl;
2798 indent(out) << " this." << make_valid_java_identifier(field_name) << " = null;" << endl;
2799 indent(out) << "}" << endl;
2800 } else if (issetType == ISSET_PRIMITIVE) {
2801 indent(out) << "__isset_bitfield = org.apache.thrift.EncodingUtils.setBit(__isset_bitfield, "
2802 << isset_field_id(field) << ", value);" << endl;
2803 } else {
2804 indent(out) << "__isset_bit_vector.set(" << isset_field_id(field) << ", value);" << endl;
2805 }
2806 indent_down();
2807 indent(out) << "}" << endl << endl;
2808 }
2809 }
2810
2811 /**
2812 * Generates a toString() method for the given struct
2813 *
2814 * @param tstruct The struct definition
2815 */
generate_java_struct_tostring(ostream & out,t_struct * tstruct)2816 void t_java_generator::generate_java_struct_tostring(ostream& out, t_struct* tstruct) {
2817 out << indent() << java_override_annotation() << endl
2818 << indent() << "public java.lang.String toString() {" << endl;
2819 indent_up();
2820
2821 out << indent() << "java.lang.StringBuilder sb = new java.lang.StringBuilder(\""
2822 << tstruct->get_name() << "(\");" << endl;
2823 out << indent() << "boolean first = true;" << endl << endl;
2824
2825 const vector<t_field*>& fields = tstruct->get_members();
2826 vector<t_field*>::const_iterator f_iter;
2827 bool first = true;
2828 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
2829 bool could_be_unset = (*f_iter)->get_req() == t_field::T_OPTIONAL;
2830 if (could_be_unset) {
2831 indent(out) << "if (" << generate_isset_check(*f_iter) << ") {" << endl;
2832 indent_up();
2833 }
2834
2835 t_field* field = (*f_iter);
2836
2837 if (!first) {
2838 indent(out) << "if (!first) sb.append(\", \");" << endl;
2839 }
2840 indent(out) << "sb.append(\"" << (*f_iter)->get_name() << ":\");" << endl;
2841 bool can_be_null = type_can_be_null(field->get_type());
2842 if (can_be_null) {
2843 indent(out) << "if (this." << make_valid_java_identifier((*f_iter)->get_name()) << " == null) {" << endl;
2844 indent(out) << " sb.append(\"null\");" << endl;
2845 indent(out) << "} else {" << endl;
2846 indent_up();
2847 }
2848
2849 if (get_true_type(field->get_type())->is_binary()) {
2850 indent(out) << "org.apache.thrift.TBaseHelper.toString(this." << make_valid_java_identifier(field->get_name()) << ", sb);"
2851 << endl;
2852 } else if ((field->get_type()->is_set())
2853 && (get_true_type(((t_set*)field->get_type())->get_elem_type())->is_binary())) {
2854 indent(out) << "org.apache.thrift.TBaseHelper.toString(this." << make_valid_java_identifier(field->get_name()) << ", sb);"
2855 << endl;
2856 } else if ((field->get_type()->is_list())
2857 && (get_true_type(((t_list*)field->get_type())->get_elem_type())->is_binary())) {
2858 indent(out) << "org.apache.thrift.TBaseHelper.toString(this." << make_valid_java_identifier(field->get_name()) << ", sb);"
2859 << endl;
2860 } else {
2861 indent(out) << "sb.append(this." << make_valid_java_identifier((*f_iter)->get_name()) << ");" << endl;
2862 }
2863
2864 if (can_be_null) {
2865 indent_down();
2866 indent(out) << "}" << endl;
2867 }
2868 indent(out) << "first = false;" << endl;
2869
2870 if (could_be_unset) {
2871 indent_down();
2872 indent(out) << "}" << endl;
2873 }
2874 first = false;
2875 }
2876 out << indent() << "sb.append(\")\");" << endl << indent() << "return sb.toString();" << endl;
2877
2878 indent_down();
2879 indent(out) << "}" << endl << endl;
2880 }
2881
2882 /**
2883 * Generates a static map with meta data to store information such as fieldID to
2884 * fieldName mapping
2885 *
2886 * @param tstruct The struct definition
2887 */
generate_java_meta_data_map(ostream & out,t_struct * tstruct)2888 void t_java_generator::generate_java_meta_data_map(ostream& out, t_struct* tstruct) {
2889 const vector<t_field*>& fields = tstruct->get_members();
2890 vector<t_field*>::const_iterator f_iter;
2891
2892 // Static Map with fieldID -> org.apache.thrift.meta_data.FieldMetaData mappings
2893 indent(out) << "public static final java.util.Map<_Fields, "
2894 "org.apache.thrift.meta_data.FieldMetaData> metaDataMap;"
2895 << endl;
2896 indent(out) << "static {" << endl;
2897 indent_up();
2898
2899 indent(out)
2900 << "java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new "
2901 "java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class);"
2902 << endl;
2903
2904 // Populate map
2905 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
2906 t_field* field = *f_iter;
2907 std::string field_name = field->get_name();
2908 indent(out) << "tmpMap.put(_Fields." << constant_name(field_name)
2909 << ", new org.apache.thrift.meta_data.FieldMetaData(\"" << field_name << "\", ";
2910
2911 // Set field requirement type (required, optional, etc.)
2912 if (field->get_req() == t_field::T_REQUIRED) {
2913 out << "org.apache.thrift.TFieldRequirementType.REQUIRED, ";
2914 } else if (field->get_req() == t_field::T_OPTIONAL) {
2915 out << "org.apache.thrift.TFieldRequirementType.OPTIONAL, ";
2916 } else {
2917 out << "org.apache.thrift.TFieldRequirementType.DEFAULT, ";
2918 }
2919
2920 // Create value meta data
2921 generate_field_value_meta_data(out, field->get_type());
2922
2923 // Include the annotation into metadata when asked
2924 if (annotations_as_metadata_) {
2925 generate_metadata_for_field_annotations(out, field);
2926 }
2927 out << "));" << endl;
2928 }
2929
2930 indent(out) << "metaDataMap = java.util.Collections.unmodifiableMap(tmpMap);" << endl;
2931
2932 indent(out) << "org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap("
2933 << type_name(tstruct) << ".class, metaDataMap);" << endl;
2934 indent_down();
2935 indent(out) << "}" << endl << endl;
2936 }
2937
2938 /**
2939 * Returns a string with the java representation of the given thrift type
2940 * (e.g. for the type struct it returns "org.apache.thrift.protocol.TType.STRUCT")
2941 */
get_java_type_string(t_type * type)2942 std::string t_java_generator::get_java_type_string(t_type* type) {
2943 if (type->is_list()) {
2944 return "org.apache.thrift.protocol.TType.LIST";
2945 } else if (type->is_map()) {
2946 return "org.apache.thrift.protocol.TType.MAP";
2947 } else if (type->is_set()) {
2948 return "org.apache.thrift.protocol.TType.SET";
2949 } else if (type->is_struct() || type->is_xception()) {
2950 return "org.apache.thrift.protocol.TType.STRUCT";
2951 } else if (type->is_enum()) {
2952 return "org.apache.thrift.protocol.TType.ENUM";
2953 } else if (type->is_typedef()) {
2954 return get_java_type_string(((t_typedef*)type)->get_type());
2955 } else if (type->is_base_type()) {
2956 switch (((t_base_type*)type)->get_base()) {
2957 case t_base_type::TYPE_VOID:
2958 return "org.apache.thrift.protocol.TType.VOID";
2959 break;
2960 case t_base_type::TYPE_STRING:
2961 return "org.apache.thrift.protocol.TType.STRING";
2962 break;
2963 case t_base_type::TYPE_UUID:
2964 return "org.apache.thrift.protocol.TType.UUID";
2965 break;
2966 case t_base_type::TYPE_BOOL:
2967 return "org.apache.thrift.protocol.TType.BOOL";
2968 break;
2969 case t_base_type::TYPE_I8:
2970 return "org.apache.thrift.protocol.TType.BYTE";
2971 break;
2972 case t_base_type::TYPE_I16:
2973 return "org.apache.thrift.protocol.TType.I16";
2974 break;
2975 case t_base_type::TYPE_I32:
2976 return "org.apache.thrift.protocol.TType.I32";
2977 break;
2978 case t_base_type::TYPE_I64:
2979 return "org.apache.thrift.protocol.TType.I64";
2980 break;
2981 case t_base_type::TYPE_DOUBLE:
2982 return "org.apache.thrift.protocol.TType.DOUBLE";
2983 break;
2984 default:
2985 throw std::runtime_error("Unknown thrift type \"" + type->get_name()
2986 + "\" passed to t_java_generator::get_java_type_string!");
2987 return "Unknown thrift type \"" + type->get_name()
2988 + "\" passed to t_java_generator::get_java_type_string!";
2989 break; // This should never happen!
2990 }
2991 } else {
2992 throw std::runtime_error("Unknown thrift type \"" + type->get_name()
2993 + "\" passed to t_java_generator::get_java_type_string!");
2994 // This should never happen!
2995 }
2996 }
2997
generate_metadata_for_field_annotations(std::ostream & out,t_field * field)2998 void t_java_generator::generate_metadata_for_field_annotations(std::ostream& out, t_field* field) {
2999 if (field->annotations_.size() == 0) {
3000 return;
3001 }
3002 out << ", " << endl;
3003 indent_up();
3004 indent_up();
3005 indent(out) << "java.util.stream.Stream.<java.util.Map.Entry<java.lang.String, "
3006 "java.lang.String>>builder()"
3007 << endl;
3008
3009 indent_up();
3010 indent_up();
3011 for (auto& annotation : field->annotations_) {
3012 indent(out) << ".add(new java.util.AbstractMap.SimpleImmutableEntry<>(\"" + annotation.first
3013 + "\", \"" + annotation.second.back() + "\"))"
3014 << endl;
3015 }
3016 indent(out) << ".build().collect(java.util.stream.Collectors.toMap(java.util.Map.Entry::getKey, "
3017 "java.util.Map.Entry::getValue))";
3018 indent_down();
3019 indent_down();
3020
3021 indent_down();
3022 indent_down();
3023 }
3024
generate_field_value_meta_data(std::ostream & out,t_type * type)3025 void t_java_generator::generate_field_value_meta_data(std::ostream& out, t_type* type) {
3026 out << endl;
3027 indent_up();
3028 indent_up();
3029 t_type* ttype = get_true_type(type);
3030 if (ttype->is_struct() || ttype->is_xception()) {
3031 indent(out) << "new "
3032 "org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType."
3033 "STRUCT, "
3034 << type_name(type) << ".class";
3035 } else if (type->is_container()) {
3036 if (type->is_list()) {
3037 indent(out)
3038 << "new org.apache.thrift.meta_data.ListMetaData(org.apache.thrift.protocol.TType.LIST, ";
3039 t_type* elem_type = ((t_list*)type)->get_elem_type();
3040 generate_field_value_meta_data(out, elem_type);
3041 } else if (type->is_set()) {
3042 indent(out)
3043 << "new org.apache.thrift.meta_data.SetMetaData(org.apache.thrift.protocol.TType.SET, ";
3044 t_type* elem_type = ((t_set*)type)->get_elem_type();
3045 generate_field_value_meta_data(out, elem_type);
3046 } else { // map
3047 indent(out)
3048 << "new org.apache.thrift.meta_data.MapMetaData(org.apache.thrift.protocol.TType.MAP, ";
3049 t_type* key_type = ((t_map*)type)->get_key_type();
3050 t_type* val_type = ((t_map*)type)->get_val_type();
3051 generate_field_value_meta_data(out, key_type);
3052 out << ", ";
3053 generate_field_value_meta_data(out, val_type);
3054 }
3055 } else if (type->is_enum()) {
3056 indent(out)
3057 << "new org.apache.thrift.meta_data.EnumMetaData(org.apache.thrift.protocol.TType.ENUM, "
3058 << type_name(type) << ".class";
3059 } else {
3060 indent(out) << "new org.apache.thrift.meta_data.FieldValueMetaData("
3061 << get_java_type_string(type);
3062 if (type->is_typedef()) {
3063 indent(out) << ", \"" << ((t_typedef*)type)->get_symbolic() << "\"";
3064 } else if (type->is_binary()) {
3065 indent(out) << ", true";
3066 }
3067 }
3068 out << ")";
3069 indent_down();
3070 indent_down();
3071 }
3072
3073 /**
3074 * Generates a thrift service. In C++, this comprises an entirely separate
3075 * header and source file. The header file defines the methods and includes
3076 * the data types defined in the main header file, and the implementation
3077 * file contains implementations of the basic printer and default interfaces.
3078 *
3079 * @param tservice The service definition
3080 */
generate_service(t_service * tservice)3081 void t_java_generator::generate_service(t_service* tservice) {
3082 // Make output file
3083 string f_service_name = package_dir_ + "/" + make_valid_java_filename(service_name_) + ".java";
3084 f_service_.open(f_service_name.c_str());
3085
3086 f_service_ << autogen_comment() << java_package();
3087
3088 if (!suppress_generated_annotations_) {
3089 generate_javax_generated_annotation(f_service_);
3090 }
3091 f_service_ << java_suppressions();
3092 f_service_ << "public class " << make_valid_java_identifier(service_name_) << " {" << endl << endl;
3093 indent_up();
3094
3095 // Generate the three main parts of the service
3096 generate_service_interface(tservice);
3097 generate_service_async_interface(tservice);
3098 if (generate_future_iface_) {
3099 generate_service_future_interface(tservice);
3100 }
3101 generate_service_client(tservice);
3102 generate_service_async_client(tservice);
3103 if (generate_future_iface_) {
3104 generate_service_future_client(tservice);
3105 }
3106 generate_service_server(tservice);
3107 generate_service_async_server(tservice);
3108 generate_service_helpers(tservice);
3109
3110 indent_down();
3111 f_service_ << "}" << endl;
3112 f_service_.close();
3113 }
3114
3115 /**
3116 * Generates a service interface definition.
3117 *
3118 * @param tservice The service to generate a header definition for
3119 */
generate_service_interface(t_service * tservice)3120 void t_java_generator::generate_service_interface(t_service* tservice) {
3121 string extends = "";
3122 string extends_iface = "";
3123 if (tservice->get_extends() != nullptr) {
3124 extends = type_name(tservice->get_extends());
3125 extends_iface = " extends " + extends + ".Iface";
3126 }
3127
3128 generate_java_doc(f_service_, tservice);
3129 f_service_ << indent() << "public interface Iface" << extends_iface << " {" << endl << endl;
3130 indent_up();
3131 vector<t_function*> functions = tservice->get_functions();
3132 vector<t_function*>::iterator f_iter;
3133 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
3134 generate_java_doc(f_service_, *f_iter);
3135 indent(f_service_) << "public " << function_signature(*f_iter) << ";" << endl << endl;
3136 }
3137 indent_down();
3138 f_service_ << indent() << "}" << endl << endl;
3139 }
3140
generate_service_async_interface(t_service * tservice)3141 void t_java_generator::generate_service_async_interface(t_service* tservice) {
3142 string extends = "";
3143 string extends_iface = "";
3144 if (tservice->get_extends() != nullptr) {
3145 extends = type_name(tservice->get_extends());
3146 extends_iface = " extends " + extends + ".AsyncIface";
3147 }
3148
3149 f_service_ << indent() << "public interface AsyncIface" << extends_iface << " {" << endl << endl;
3150 indent_up();
3151 vector<t_function*> functions = tservice->get_functions();
3152 vector<t_function*>::iterator f_iter;
3153 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
3154 indent(f_service_) << "public " << function_signature_async(*f_iter, true)
3155 << " throws org.apache.thrift.TException;" << endl
3156 << endl;
3157 }
3158 indent_down();
3159 f_service_ << indent() << "}" << endl << endl;
3160 }
3161
generate_service_future_interface(t_service * tservice)3162 void t_java_generator::generate_service_future_interface(t_service* tservice) {
3163 string extends = "";
3164 string extends_iface = "";
3165 if (tservice->get_extends() != nullptr) {
3166 extends = type_name(tservice->get_extends());
3167 extends_iface = " extends " + extends + " .FutureIface";
3168 }
3169
3170 f_service_ << indent() << "public interface FutureIface" << extends_iface << " {" << endl << endl;
3171 indent_up();
3172 for (auto tfunc : tservice->get_functions()) {
3173 indent(f_service_) << "public " << function_signature_future(tfunc)
3174 << " throws org.apache.thrift.TException;" << endl
3175 << endl;
3176 }
3177 scope_down(f_service_);
3178 f_service_ << endl << endl;
3179 }
3180
3181 /**
3182 * Generates structs for all the service args and return types
3183 *
3184 * @param tservice The service
3185 */
generate_service_helpers(t_service * tservice)3186 void t_java_generator::generate_service_helpers(t_service* tservice) {
3187 vector<t_function*> functions = tservice->get_functions();
3188 vector<t_function*>::iterator f_iter;
3189 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
3190 t_struct* ts = (*f_iter)->get_arglist();
3191 generate_java_struct_definition(f_service_, ts, false, true);
3192 generate_function_helpers(*f_iter);
3193 }
3194 }
3195
3196 /**
3197 * Generates a service client definition.
3198 *
3199 * @param tservice The service to generate a server for.
3200 */
generate_service_client(t_service * tservice)3201 void t_java_generator::generate_service_client(t_service* tservice) {
3202 string extends = "";
3203 string extends_client = "";
3204 if (tservice->get_extends() == nullptr) {
3205 extends_client = "org.apache.thrift.TServiceClient";
3206 } else {
3207 extends = type_name(tservice->get_extends());
3208 extends_client = extends + ".Client";
3209 }
3210
3211 indent(f_service_) << "public static class Client extends " << extends_client
3212 << " implements Iface {" << endl;
3213 indent_up();
3214
3215 indent(f_service_)
3216 << "public static class Factory implements org.apache.thrift.TServiceClientFactory<Client> {"
3217 << endl;
3218 indent_up();
3219 indent(f_service_) << "public Factory() {}" << endl;
3220 indent(f_service_) << java_override_annotation() << endl;
3221 indent(f_service_) << "public Client getClient(org.apache.thrift.protocol.TProtocol prot) {"
3222 << endl;
3223 indent_up();
3224 indent(f_service_) << "return new Client(prot);" << endl;
3225 indent_down();
3226 indent(f_service_) << "}" << endl;
3227 indent(f_service_) << java_override_annotation() << endl;
3228 indent(f_service_) << "public Client getClient(org.apache.thrift.protocol.TProtocol iprot, "
3229 "org.apache.thrift.protocol.TProtocol oprot) {"
3230 << endl;
3231 indent_up();
3232 indent(f_service_) << "return new Client(iprot, oprot);" << endl;
3233 indent_down();
3234 indent(f_service_) << "}" << endl;
3235 indent_down();
3236 indent(f_service_) << "}" << endl << endl;
3237
3238 indent(f_service_) << "public Client(org.apache.thrift.protocol.TProtocol prot)" << endl;
3239 scope_up(f_service_);
3240 indent(f_service_) << "super(prot, prot);" << endl;
3241 scope_down(f_service_);
3242 f_service_ << endl;
3243
3244 indent(f_service_) << "public Client(org.apache.thrift.protocol.TProtocol iprot, "
3245 "org.apache.thrift.protocol.TProtocol oprot) {"
3246 << endl;
3247 indent(f_service_) << " super(iprot, oprot);" << endl;
3248 indent(f_service_) << "}" << endl << endl;
3249
3250 // Generate client method implementations
3251 vector<t_function*> functions = tservice->get_functions();
3252 vector<t_function*>::const_iterator f_iter;
3253 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
3254 string funname = (*f_iter)->get_name();
3255 string sep = "_";
3256 string javaname = funname;
3257 if (fullcamel_style_) {
3258 sep = "";
3259 javaname = as_camel_case(funname);
3260 }
3261
3262 // Open function
3263 indent(f_service_) << java_override_annotation() << endl;
3264 indent(f_service_) << "public " << function_signature(*f_iter) << endl;
3265 scope_up(f_service_);
3266 indent(f_service_) << "send" << sep << javaname << "(";
3267
3268 // Get the struct of function call params
3269 t_struct* arg_struct = (*f_iter)->get_arglist();
3270
3271 // Declare the function arguments
3272 const vector<t_field*>& fields = arg_struct->get_members();
3273 vector<t_field*>::const_iterator fld_iter;
3274 bool first = true;
3275 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
3276 if (first) {
3277 first = false;
3278 } else {
3279 f_service_ << ", ";
3280 }
3281 f_service_ << make_valid_java_identifier((*fld_iter)->get_name());
3282 }
3283 f_service_ << ");" << endl;
3284
3285 if (!(*f_iter)->is_oneway()) {
3286 f_service_ << indent();
3287 if (!(*f_iter)->get_returntype()->is_void()) {
3288 f_service_ << "return ";
3289 }
3290 f_service_ << "recv" << sep << javaname << "();" << endl;
3291 }
3292 scope_down(f_service_);
3293 f_service_ << endl;
3294
3295 t_function send_function(g_type_void, string("send") + sep + javaname,
3296 (*f_iter)->get_arglist());
3297
3298 string argsname = (*f_iter)->get_name() + "_args";
3299
3300 // Open function
3301 indent(f_service_) << "public " << function_signature(&send_function) << endl;
3302 scope_up(f_service_);
3303
3304 // Serialize the request
3305 indent(f_service_) << argsname << " args = new " << argsname << "();" << endl;
3306
3307 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
3308 indent(f_service_) << "args.set" << get_cap_name((*fld_iter)->get_name()) << "("
3309 << make_valid_java_identifier((*fld_iter)->get_name()) << ");" << endl;
3310 }
3311
3312 const string sendBaseName = (*f_iter)->is_oneway() ? "sendBaseOneway" : "sendBase";
3313 indent(f_service_) << sendBaseName << "(\"" << funname << "\", args);" << endl;
3314
3315 scope_down(f_service_);
3316 f_service_ << endl;
3317
3318 if (!(*f_iter)->is_oneway()) {
3319 string resultname = (*f_iter)->get_name() + "_result";
3320
3321 t_struct noargs(program_);
3322 t_function recv_function((*f_iter)->get_returntype(), string("recv") + sep + javaname,
3323 &noargs, (*f_iter)->get_xceptions());
3324 // Open function
3325 indent(f_service_) << "public " << function_signature(&recv_function) << endl;
3326 scope_up(f_service_);
3327
3328 f_service_ << indent() << resultname << " result = new " << resultname << "();" << endl
3329 << indent() << "receiveBase(result, \"" << funname << "\");" << endl;
3330
3331 // Careful, only return _result if not a void function
3332 if (!(*f_iter)->get_returntype()->is_void()) {
3333 f_service_ << indent() << "if (result." << generate_isset_check("success") << ") {" << endl
3334 << indent() << " return result.success;" << endl
3335 << indent() << "}" << endl;
3336 }
3337
3338 t_struct* xs = (*f_iter)->get_xceptions();
3339 const std::vector<t_field*>& xceptions = xs->get_members();
3340 vector<t_field*>::const_iterator x_iter;
3341 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
3342 f_service_ << indent() << "if (result." << make_valid_java_identifier((*x_iter)->get_name()) << " != null) {" << endl
3343 << indent() << " throw result." << make_valid_java_identifier((*x_iter)->get_name()) << ";" << endl
3344 << indent() << "}" << endl;
3345 }
3346
3347 // If you get here it's an exception, unless a void function
3348 if ((*f_iter)->get_returntype()->is_void()) {
3349 indent(f_service_) << "return;" << endl;
3350 } else {
3351 f_service_ << indent()
3352 << "throw new "
3353 "org.apache.thrift.TApplicationException(org.apache.thrift."
3354 "TApplicationException.MISSING_RESULT, \""
3355 << (*f_iter)->get_name() << " failed: unknown result\");" << endl;
3356 }
3357
3358 // Close function
3359 scope_down(f_service_);
3360 f_service_ << endl;
3361 }
3362 }
3363
3364 indent_down();
3365 indent(f_service_) << "}" << endl;
3366 }
3367
generate_service_future_client(t_service * tservice)3368 void t_java_generator::generate_service_future_client(t_service* tservice) {
3369 static string adapter_class = "org.apache.thrift.async.AsyncMethodFutureAdapter";
3370 indent(f_service_) << "public static class FutureClient implements FutureIface {" << endl;
3371 indent_up();
3372 indent(f_service_) << "public FutureClient(AsyncIface delegate) {" << endl;
3373 indent_up();
3374 indent(f_service_) << "this.delegate = delegate;" << endl;
3375 scope_down(f_service_);
3376 indent(f_service_) << "private final AsyncIface delegate;" << endl;
3377 for (auto tfunc : tservice->get_functions()) {
3378 string funname = tfunc->get_name();
3379 string sep = "_";
3380 string javaname = funname;
3381 if (fullcamel_style_) {
3382 sep = "";
3383 javaname = as_camel_case(javaname);
3384 }
3385 auto ret_type_name = type_name(tfunc->get_returntype(), /*in_container=*/true);
3386 t_struct* arg_struct = tfunc->get_arglist();
3387 string funclassname = funname + "_call";
3388 auto fields = arg_struct->get_members();
3389
3390 string args_name = funname + "_args";
3391 string result_name = funname + "_result";
3392
3393 indent(f_service_) << "@Override" << endl;
3394 indent(f_service_) << "public " << function_signature_future(tfunc)
3395 << " throws org.apache.thrift.TException {" << endl;
3396 indent_up();
3397 auto adapter = tmp("asyncMethodFutureAdapter");
3398 indent(f_service_) << adapter_class << "<" << ret_type_name << "> " << adapter << " = "
3399 << adapter_class << ".<" << ret_type_name << ">create();" << endl;
3400 bool empty_args = tfunc->get_arglist()->get_members().empty();
3401 indent(f_service_) << "delegate." << get_rpc_method_name(funname) << "("
3402 << argument_list(tfunc->get_arglist(), false) << (empty_args ? "" : ", ")
3403 << adapter << ");" << endl;
3404 indent(f_service_) << "return " << adapter << ".getFuture();" << endl;
3405 scope_down(f_service_);
3406 f_service_ << endl;
3407 }
3408 scope_down(f_service_);
3409 f_service_ << endl;
3410 }
3411
generate_service_async_client(t_service * tservice)3412 void t_java_generator::generate_service_async_client(t_service* tservice) {
3413 string extends = "org.apache.thrift.async.TAsyncClient";
3414 string extends_client = "";
3415 if (tservice->get_extends() != nullptr) {
3416 extends = type_name(tservice->get_extends()) + ".AsyncClient";
3417 }
3418
3419 indent(f_service_) << "public static class AsyncClient extends " << extends
3420 << " implements AsyncIface {" << endl;
3421 indent_up();
3422
3423 // Factory method
3424 indent(f_service_) << "public static class Factory implements "
3425 "org.apache.thrift.async.TAsyncClientFactory<AsyncClient> {"
3426 << endl;
3427 indent(f_service_) << " private org.apache.thrift.async.TAsyncClientManager clientManager;"
3428 << endl;
3429 indent(f_service_) << " private org.apache.thrift.protocol.TProtocolFactory protocolFactory;"
3430 << endl;
3431 indent(f_service_) << " public Factory(org.apache.thrift.async.TAsyncClientManager "
3432 "clientManager, org.apache.thrift.protocol.TProtocolFactory "
3433 "protocolFactory) {"
3434 << endl;
3435 indent(f_service_) << " this.clientManager = clientManager;" << endl;
3436 indent(f_service_) << " this.protocolFactory = protocolFactory;" << endl;
3437 indent(f_service_) << " }" << endl;
3438 indent(f_service_) << java_override_annotation() << endl;
3439 indent(f_service_) << " public AsyncClient "
3440 "getAsyncClient(org.apache.thrift.transport.TNonblockingTransport "
3441 "transport) {"
3442 << endl;
3443 indent(f_service_) << " return new AsyncClient(protocolFactory, clientManager, transport);"
3444 << endl;
3445 indent(f_service_) << " }" << endl;
3446 indent(f_service_) << "}" << endl << endl;
3447
3448 indent(f_service_) << "public AsyncClient(org.apache.thrift.protocol.TProtocolFactory "
3449 "protocolFactory, org.apache.thrift.async.TAsyncClientManager "
3450 "clientManager, org.apache.thrift.transport.TNonblockingTransport "
3451 "transport) {"
3452 << endl;
3453 indent(f_service_) << " super(protocolFactory, clientManager, transport);" << endl;
3454 indent(f_service_) << "}" << endl << endl;
3455
3456 // Generate client method implementations
3457 vector<t_function*> functions = tservice->get_functions();
3458 vector<t_function*>::const_iterator f_iter;
3459 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
3460 string funname = (*f_iter)->get_name();
3461 string sep = "_";
3462 string javaname = funname;
3463 if (fullcamel_style_) {
3464 sep = "";
3465 javaname = as_camel_case(javaname);
3466 }
3467 t_type* ret_type = (*f_iter)->get_returntype();
3468 t_struct* arg_struct = (*f_iter)->get_arglist();
3469 string funclassname = funname + "_call";
3470 const vector<t_field*>& fields = arg_struct->get_members();
3471 const std::vector<t_field*>& xceptions = (*f_iter)->get_xceptions()->get_members();
3472 vector<t_field*>::const_iterator fld_iter;
3473 string args_name = (*f_iter)->get_name() + "_args";
3474 string result_name = (*f_iter)->get_name() + "_result";
3475
3476 // Main method body
3477 indent(f_service_) << java_override_annotation() << endl;
3478 indent(f_service_) << "public " << function_signature_async(*f_iter, false)
3479 << " throws org.apache.thrift.TException {" << endl;
3480 indent(f_service_) << " checkReady();" << endl;
3481 indent(f_service_) << " " << funclassname << " method_call = new " + funclassname + "("
3482 << async_argument_list(*f_iter, arg_struct, ret_type)
3483 << ", this, ___protocolFactory, ___transport);" << endl;
3484 indent(f_service_) << " this.___currentMethod = method_call;" << endl;
3485 indent(f_service_) << " ___manager.call(method_call);" << endl;
3486 indent(f_service_) << "}" << endl;
3487
3488 f_service_ << endl;
3489
3490 // TAsyncMethod object for this function call
3491 indent(f_service_) << "public static class " + funclassname
3492 + " extends org.apache.thrift.async.TAsyncMethodCall<"
3493 + type_name((*f_iter)->get_returntype(), true) + "> {"
3494 << endl;
3495 indent_up();
3496
3497 // Member variables
3498 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
3499 indent(f_service_) << "private " + type_name((*fld_iter)->get_type()) + " "
3500 + make_valid_java_identifier((*fld_iter)->get_name()) + ";"
3501 << endl;
3502 }
3503
3504 // NOTE since we use a new Client instance to deserialize, let's keep seqid to 0 for now
3505 // indent(f_service_) << "private int seqid;" << endl << endl;
3506
3507 // Constructor
3508 indent(f_service_) << "public " + funclassname + "("
3509 + async_argument_list(*f_iter, arg_struct, ret_type, true)
3510 << ", org.apache.thrift.async.TAsyncClient client, "
3511 "org.apache.thrift.protocol.TProtocolFactory protocolFactory, "
3512 "org.apache.thrift.transport.TNonblockingTransport transport) throws "
3513 "org.apache.thrift.TException {"
3514 << endl;
3515 indent(f_service_) << " super(client, protocolFactory, transport, resultHandler, "
3516 << ((*f_iter)->is_oneway() ? "true" : "false") << ");" << endl;
3517
3518 // Assign member variables
3519 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
3520 indent(f_service_) << " this." + make_valid_java_identifier((*fld_iter)->get_name()) + " = " + make_valid_java_identifier((*fld_iter)->get_name())
3521 + ";"
3522 << endl;
3523 }
3524
3525 indent(f_service_) << "}" << endl << endl;
3526 indent(f_service_) << java_override_annotation() << endl;
3527 indent(f_service_) << "public void write_args(org.apache.thrift.protocol.TProtocol prot) "
3528 "throws org.apache.thrift.TException {"
3529 << endl;
3530 indent_up();
3531
3532 // Serialize request
3533 // NOTE we are leaving seqid as 0, for now (see above)
3534 f_service_ << indent() << "prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage(\""
3535 << funname << "\", org.apache.thrift.protocol."
3536 << ((*f_iter)->is_oneway() ? "TMessageType.ONEWAY" : "TMessageType.CALL") << ", 0));"
3537 << endl
3538 << indent() << args_name << " args = new " << args_name << "();" << endl;
3539
3540 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
3541 f_service_ << indent() << "args.set" << get_cap_name((*fld_iter)->get_name()) << "("
3542 << make_valid_java_identifier((*fld_iter)->get_name()) << ");" << endl;
3543 }
3544
3545 f_service_ << indent() << "args.write(prot);" << endl
3546 << indent() << "prot.writeMessageEnd();" << endl;
3547
3548 indent_down();
3549 indent(f_service_) << "}" << endl << endl;
3550
3551 // Return method
3552 indent(f_service_) << java_override_annotation() << endl;
3553 indent(f_service_) << "public " + type_name(ret_type, true) + " getResult() throws ";
3554 vector<t_field*>::const_iterator x_iter;
3555 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
3556 f_service_ << type_name((*x_iter)->get_type(), false, false) + ", ";
3557 }
3558 f_service_ << "org.apache.thrift.TException {" << endl;
3559
3560 indent_up();
3561 f_service_
3562 << indent()
3563 << "if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) {"
3564 << endl
3565 << indent() << " throw new java.lang.IllegalStateException(\"Method call not finished!\");"
3566 << endl
3567 << indent() << "}" << endl
3568 << indent()
3569 << "org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new "
3570 "org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array());"
3571 << endl
3572 << indent()
3573 << "org.apache.thrift.protocol.TProtocol prot = "
3574 "client.getProtocolFactory().getProtocol(memoryTransport);"
3575 << endl;
3576 indent(f_service_);
3577 if (ret_type->is_void()) { // NB: Includes oneways which always return void.
3578 if (!(*f_iter)->is_oneway()) {
3579 f_service_ << "(new Client(prot)).recv" + sep + javaname + "();" << endl;
3580 indent(f_service_);
3581 }
3582 f_service_ << "return null;" << endl;
3583 } else {
3584 f_service_ << "return (new Client(prot)).recv" + sep + javaname + "();" << endl;
3585 }
3586
3587 // Close function
3588 indent_down();
3589 indent(f_service_) << "}" << endl;
3590
3591 // Close class
3592 indent_down();
3593 indent(f_service_) << "}" << endl << endl;
3594 }
3595
3596 // Close AsyncClient
3597 scope_down(f_service_);
3598 f_service_ << endl;
3599 }
3600
3601 /**
3602 * Generates a service server definition.
3603 *
3604 * @param tservice The service to generate a server for.
3605 */
generate_service_server(t_service * tservice)3606 void t_java_generator::generate_service_server(t_service* tservice) {
3607 // Generate the dispatch methods
3608 vector<t_function*> functions = tservice->get_functions();
3609 vector<t_function*>::iterator f_iter;
3610
3611 // Extends stuff
3612 string extends = "";
3613 string extends_processor = "";
3614 if (tservice->get_extends() == nullptr) {
3615 extends_processor = "org.apache.thrift.TBaseProcessor<I>";
3616 } else {
3617 extends = type_name(tservice->get_extends());
3618 extends_processor = extends + ".Processor<I>";
3619 }
3620
3621 // Generate the header portion
3622 indent(f_service_) << "public static class Processor<I extends Iface> extends "
3623 << extends_processor << " implements org.apache.thrift.TProcessor {" << endl;
3624 indent_up();
3625
3626 indent(f_service_) << "private static final org.slf4j.Logger _LOGGER = "
3627 "org.slf4j.LoggerFactory.getLogger(Processor.class.getName());"
3628 << endl;
3629
3630 indent(f_service_) << "public Processor(I iface) {" << endl;
3631 indent(f_service_) << " super(iface, getProcessMap(new java.util.HashMap<java.lang.String, "
3632 "org.apache.thrift.ProcessFunction<I, ? extends "
3633 "org.apache.thrift.TBase>>()));"
3634 << endl;
3635 indent(f_service_) << "}" << endl << endl;
3636
3637 indent(f_service_) << "protected Processor(I iface, java.util.Map<java.lang.String, "
3638 "org.apache.thrift.ProcessFunction<I, ? extends org.apache.thrift.TBase>> "
3639 "processMap) {"
3640 << endl;
3641 indent(f_service_) << " super(iface, getProcessMap(processMap));" << endl;
3642 indent(f_service_) << "}" << endl << endl;
3643
3644 indent(f_service_) << "private static <I extends Iface> java.util.Map<java.lang.String, "
3645 "org.apache.thrift.ProcessFunction<I, ? extends org.apache.thrift.TBase>> "
3646 "getProcessMap(java.util.Map<java.lang.String, "
3647 "org.apache.thrift.ProcessFunction<I, ? extends "
3648 " org.apache.thrift.TBase>> processMap) {"
3649 << endl;
3650 indent_up();
3651 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
3652 indent(f_service_) << "processMap.put(\"" << (*f_iter)->get_name() << "\", new "
3653 << make_valid_java_identifier((*f_iter)->get_name()) << "());" << endl;
3654 }
3655 indent(f_service_) << "return processMap;" << endl;
3656 indent_down();
3657 indent(f_service_) << "}" << endl << endl;
3658
3659 // Generate the process subfunctions
3660 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
3661 generate_process_function(tservice, *f_iter);
3662 }
3663
3664 indent_down();
3665 indent(f_service_) << "}" << endl << endl;
3666 }
3667
3668 /**
3669 * Generates a service server definition.
3670 *
3671 * @param tservice The service to generate a server for.
3672 */
generate_service_async_server(t_service * tservice)3673 void t_java_generator::generate_service_async_server(t_service* tservice) {
3674 // Generate the dispatch methods
3675 vector<t_function*> functions = tservice->get_functions();
3676 vector<t_function*>::iterator f_iter;
3677
3678 // Extends stuff
3679 string extends = "";
3680 string extends_processor = "";
3681 if (tservice->get_extends() == nullptr) {
3682 extends_processor = "org.apache.thrift.TBaseAsyncProcessor<I>";
3683 } else {
3684 extends = type_name(tservice->get_extends());
3685 extends_processor = extends + ".AsyncProcessor<I>";
3686 }
3687
3688 // Generate the header portion
3689 indent(f_service_) << "public static class AsyncProcessor<I extends AsyncIface> extends "
3690 << extends_processor << " {" << endl;
3691 indent_up();
3692
3693 indent(f_service_) << "private static final org.slf4j.Logger _LOGGER = "
3694 "org.slf4j.LoggerFactory.getLogger(AsyncProcessor.class.getName());"
3695 << endl;
3696
3697 indent(f_service_) << "public AsyncProcessor(I iface) {" << endl;
3698 indent(f_service_) << " super(iface, getProcessMap(new java.util.HashMap<java.lang.String, "
3699 "org.apache.thrift.AsyncProcessFunction<I, ? extends "
3700 "org.apache.thrift.TBase, ?>>()));"
3701 << endl;
3702 indent(f_service_) << "}" << endl << endl;
3703
3704 indent(f_service_) << "protected AsyncProcessor(I iface, java.util.Map<java.lang.String, "
3705 "org.apache.thrift.AsyncProcessFunction<I, ? extends "
3706 "org.apache.thrift.TBase, ?>> processMap) {"
3707 << endl;
3708 indent(f_service_) << " super(iface, getProcessMap(processMap));" << endl;
3709 indent(f_service_) << "}" << endl << endl;
3710
3711 indent(f_service_)
3712 << "private static <I extends AsyncIface> java.util.Map<java.lang.String, "
3713 "org.apache.thrift.AsyncProcessFunction<I, ? extends "
3714 "org.apache.thrift.TBase,?>> getProcessMap(java.util.Map<java.lang.String, "
3715 "org.apache.thrift.AsyncProcessFunction<I, ? extends "
3716 "org.apache.thrift.TBase, ?>> processMap) {"
3717 << endl;
3718 indent_up();
3719 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
3720 indent(f_service_) << "processMap.put(\"" << (*f_iter)->get_name() << "\", new "
3721 << make_valid_java_identifier((*f_iter)->get_name()) << "());" << endl;
3722 }
3723 indent(f_service_) << "return processMap;" << endl;
3724 indent_down();
3725 indent(f_service_) << "}" << endl << endl;
3726
3727 // Generate the process subfunctions
3728 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
3729 generate_process_async_function(tservice, *f_iter);
3730 }
3731
3732 indent_down();
3733 indent(f_service_) << "}" << endl << endl;
3734 }
3735
3736 /**
3737 * Generates a struct and helpers for a function.
3738 *
3739 * @param tfunction The function
3740 */
generate_function_helpers(t_function * tfunction)3741 void t_java_generator::generate_function_helpers(t_function* tfunction) {
3742 if (tfunction->is_oneway()) {
3743 return;
3744 }
3745
3746 t_struct result(program_, tfunction->get_name() + "_result");
3747 t_field success(tfunction->get_returntype(), "success", 0);
3748 if (!tfunction->get_returntype()->is_void()) {
3749 result.append(&success);
3750 }
3751
3752 t_struct* xs = tfunction->get_xceptions();
3753 const vector<t_field*>& fields = xs->get_members();
3754 vector<t_field*>::const_iterator f_iter;
3755 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
3756 result.append(*f_iter);
3757 }
3758
3759 generate_java_struct_definition(f_service_, &result, false, true, true);
3760 }
3761
3762 /**
3763 * Generates a process function definition.
3764 *
3765 * @param tfunction The function to write a dispatcher for
3766 */
generate_process_async_function(t_service * tservice,t_function * tfunction)3767 void t_java_generator::generate_process_async_function(t_service* tservice, t_function* tfunction) {
3768 string argsname = tfunction->get_name() + "_args";
3769
3770 string resultname = tfunction->get_name() + "_result";
3771 if (tfunction->is_oneway()) {
3772 resultname = "org.apache.thrift.TBase";
3773 }
3774
3775 string resulttype = type_name(tfunction->get_returntype(), true);
3776
3777 (void)tservice;
3778 // Open class
3779 indent(f_service_) << "public static class " << make_valid_java_identifier(tfunction->get_name())
3780 << "<I extends AsyncIface> extends org.apache.thrift.AsyncProcessFunction<I, "
3781 << argsname << ", " << resulttype << "> {" << endl;
3782 indent_up();
3783
3784 indent(f_service_) << "public " << make_valid_java_identifier(tfunction->get_name()) << "() {" << endl;
3785 indent(f_service_) << " super(\"" << tfunction->get_name() << "\");" << endl;
3786 indent(f_service_) << "}" << endl << endl;
3787
3788 indent(f_service_) << java_override_annotation() << endl;
3789 indent(f_service_) << "public " << argsname << " getEmptyArgsInstance() {" << endl;
3790 indent(f_service_) << " return new " << argsname << "();" << endl;
3791 indent(f_service_) << "}" << endl << endl;
3792
3793 indent(f_service_) << java_override_annotation() << endl;
3794 indent(f_service_) << "public org.apache.thrift.async.AsyncMethodCallback<" << resulttype
3795 << "> getResultHandler(final "
3796 "org.apache.thrift.server.AbstractNonblockingServer.AsyncFrameBuffer fb, "
3797 "final int seqid) {"
3798 << endl;
3799 indent_up();
3800 indent(f_service_) << "final org.apache.thrift.AsyncProcessFunction fcall = this;" << endl;
3801 indent(f_service_) << "return new org.apache.thrift.async.AsyncMethodCallback<" << resulttype
3802 << ">() { " << endl;
3803 indent_up();
3804 indent(f_service_) << java_override_annotation() << endl;
3805 indent(f_service_) << "public void onComplete(" << resulttype << " o) {" << endl;
3806
3807 indent_up();
3808 if (!tfunction->is_oneway()) {
3809 indent(f_service_) << resultname << " result = new " << resultname << "();" << endl;
3810
3811 if (!tfunction->get_returntype()->is_void()) {
3812 indent(f_service_) << "result.success = o;" << endl;
3813 // Set isset on success field
3814 if (!type_can_be_null(tfunction->get_returntype())) {
3815 indent(f_service_) << "result.set" << get_cap_name("success") << get_cap_name("isSet")
3816 << "(true);" << endl;
3817 }
3818 }
3819
3820 indent(f_service_) << "try {" << endl;
3821 indent(f_service_)
3822 << " fcall.sendResponse(fb, result, org.apache.thrift.protocol.TMessageType.REPLY,seqid);"
3823 << endl;
3824 indent(f_service_) << "} catch (org.apache.thrift.transport.TTransportException e) {" << endl;
3825 indent_up();
3826 f_service_ << indent()
3827 << "_LOGGER.error(\"TTransportException writing to internal frame buffer\", e);"
3828 << endl
3829 << indent() << "fb.close();" << endl;
3830 indent_down();
3831 indent(f_service_) << "} catch (java.lang.Exception e) {" << endl;
3832 indent_up();
3833 f_service_ << indent() << "_LOGGER.error(\"Exception writing to internal frame buffer\", e);"
3834 << endl
3835 << indent() << "onError(e);" << endl;
3836 indent_down();
3837 indent(f_service_) << "}" << endl;
3838 }
3839 indent_down();
3840 indent(f_service_) << "}" << endl;
3841
3842 indent(f_service_) << java_override_annotation() << endl;
3843 indent(f_service_) << "public void onError(java.lang.Exception e) {" << endl;
3844 indent_up();
3845
3846 if (tfunction->is_oneway()) {
3847 indent(f_service_) << "if (e instanceof org.apache.thrift.transport.TTransportException) {"
3848 << endl;
3849 indent_up();
3850
3851 f_service_ << indent() << "_LOGGER.error(\"TTransportException inside handler\", e);" << endl
3852 << indent() << "fb.close();" << endl;
3853
3854 indent_down();
3855 indent(f_service_) << "} else {" << endl;
3856 indent_up();
3857
3858 f_service_ << indent() << "_LOGGER.error(\"Exception inside oneway handler\", e);" << endl;
3859
3860 indent_down();
3861 indent(f_service_) << "}" << endl;
3862 } else {
3863 indent(f_service_) << "byte msgType = org.apache.thrift.protocol.TMessageType.REPLY;" << endl;
3864 indent(f_service_) << "org.apache.thrift.TSerializable msg;" << endl;
3865 indent(f_service_) << resultname << " result = new " << resultname << "();" << endl;
3866
3867 t_struct* xs = tfunction->get_xceptions();
3868 const std::vector<t_field*>& xceptions = xs->get_members();
3869
3870 vector<t_field*>::const_iterator x_iter;
3871 if (xceptions.size() > 0) {
3872 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
3873 if (x_iter == xceptions.begin())
3874 f_service_ << indent();
3875 string type = type_name((*x_iter)->get_type(), false, false);
3876 string name = (*x_iter)->get_name();
3877 f_service_ << "if (e instanceof " << type << ") {" << endl;
3878 indent_up();
3879 f_service_ << indent() << "result." << make_valid_java_identifier(name) << " = (" << type << ") e;" << endl
3880 << indent() << "result.set" << get_cap_name(name) << get_cap_name("isSet")
3881 << "(true);" << endl
3882 << indent() << "msg = result;" << endl;
3883 indent_down();
3884 indent(f_service_) << "} else ";
3885 }
3886 } else {
3887 indent(f_service_);
3888 }
3889 f_service_ << "if (e instanceof org.apache.thrift.transport.TTransportException) {" << endl;
3890 indent_up();
3891 f_service_ << indent() << "_LOGGER.error(\"TTransportException inside handler\", e);" << endl
3892 << indent() << "fb.close();" << endl
3893 << indent() << "return;" << endl;
3894 indent_down();
3895 indent(f_service_) << "} else if (e instanceof org.apache.thrift.TApplicationException) {"
3896 << endl;
3897 indent_up();
3898 f_service_ << indent() << "_LOGGER.error(\"TApplicationException inside handler\", e);" << endl
3899 << indent() << "msgType = org.apache.thrift.protocol.TMessageType.EXCEPTION;" << endl
3900 << indent() << "msg = (org.apache.thrift.TApplicationException)e;" << endl;
3901 indent_down();
3902 indent(f_service_) << "} else {" << endl;
3903 indent_up();
3904 f_service_ << indent() << "_LOGGER.error(\"Exception inside handler\", e);" << endl
3905 << indent() << "msgType = org.apache.thrift.protocol.TMessageType.EXCEPTION;" << endl
3906 << indent()
3907 << "msg = new "
3908 "org.apache.thrift.TApplicationException(org.apache.thrift."
3909 "TApplicationException.INTERNAL_ERROR, e.getMessage());"
3910 << endl;
3911 indent_down();
3912 f_service_ << indent() << "}" << endl
3913 << indent() << "try {" << endl
3914 << indent() << " fcall.sendResponse(fb,msg,msgType,seqid);" << endl
3915 << indent() << "} catch (java.lang.Exception ex) {" << endl
3916 << indent() << " _LOGGER.error(\"Exception writing to internal frame buffer\", ex);"
3917 << endl
3918 << indent() << " fb.close();" << endl
3919 << indent() << "}" << endl;
3920 }
3921 indent_down();
3922 indent(f_service_) << "}" << endl;
3923 indent_down();
3924 indent(f_service_) << "};" << endl;
3925 indent_down();
3926 indent(f_service_) << "}" << endl << endl;
3927
3928 indent(f_service_) << java_override_annotation() << endl;
3929 indent(f_service_) << "protected boolean isOneway() {" << endl;
3930 indent(f_service_) << " return " << ((tfunction->is_oneway()) ? "true" : "false") << ";" << endl;
3931 indent(f_service_) << "}" << endl << endl;
3932
3933 indent(f_service_) << java_override_annotation() << endl;
3934 indent(f_service_) << "public void start(I iface, " << argsname
3935 << " args, org.apache.thrift.async.AsyncMethodCallback<" << resulttype
3936 << "> resultHandler) throws org.apache.thrift.TException {" << endl;
3937 indent_up();
3938
3939 // Generate the function call
3940 t_struct* arg_struct = tfunction->get_arglist();
3941 const std::vector<t_field*>& fields = arg_struct->get_members();
3942 vector<t_field*>::const_iterator f_iter;
3943 f_service_ << indent();
3944
3945 f_service_ << "iface." << get_rpc_method_name(tfunction->get_name()) << "(";
3946 bool first = true;
3947 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
3948 if (first) {
3949 first = false;
3950 } else {
3951 f_service_ << ", ";
3952 }
3953 f_service_ << "args." << make_valid_java_identifier((*f_iter)->get_name());
3954 }
3955 if (!first)
3956 f_service_ << ",";
3957 f_service_ << "resultHandler";
3958 f_service_ << ");" << endl;
3959
3960 indent_down();
3961 indent(f_service_) << "}";
3962
3963 // Close function
3964 f_service_ << endl;
3965
3966 // Close class
3967 indent_down();
3968 f_service_ << indent() << "}" << endl << endl;
3969 }
3970
3971 /**
3972 * Generates a process function definition.
3973 *
3974 * @param tfunction The function to write a dispatcher for
3975 */
generate_process_function(t_service * tservice,t_function * tfunction)3976 void t_java_generator::generate_process_function(t_service* tservice, t_function* tfunction) {
3977 string argsname = tfunction->get_name() + "_args";
3978 string resultname = tfunction->get_name() + "_result";
3979 if (tfunction->is_oneway()) {
3980 resultname = "org.apache.thrift.TBase";
3981 }
3982
3983 (void)tservice;
3984 // Open class
3985 indent(f_service_) << "public static class " << make_valid_java_identifier(tfunction->get_name())
3986 << "<I extends Iface> extends org.apache.thrift.ProcessFunction<I, "
3987 << argsname << "> {" << endl;
3988 indent_up();
3989
3990 indent(f_service_) << "public " << make_valid_java_identifier(tfunction->get_name()) << "() {" << endl;
3991 indent(f_service_) << " super(\"" << tfunction->get_name() << "\");" << endl;
3992 indent(f_service_) << "}" << endl << endl;
3993
3994 indent(f_service_) << java_override_annotation() << endl;
3995 indent(f_service_) << "public " << argsname << " getEmptyArgsInstance() {" << endl;
3996 indent(f_service_) << " return new " << argsname << "();" << endl;
3997 indent(f_service_) << "}" << endl << endl;
3998
3999 indent(f_service_) << java_override_annotation() << endl;
4000 indent(f_service_) << "protected boolean isOneway() {" << endl;
4001 indent(f_service_) << " return " << ((tfunction->is_oneway()) ? "true" : "false") << ";" << endl;
4002 indent(f_service_) << "}" << endl << endl;
4003
4004 indent(f_service_) << java_override_annotation() << endl;
4005 indent(f_service_) << "protected boolean rethrowUnhandledExceptions() {" << endl;
4006 indent(f_service_) << " return " << ((rethrow_unhandled_exceptions_) ? "true" : "false") << ";"
4007 << endl;
4008 indent(f_service_) << "}" << endl << endl;
4009
4010 indent(f_service_) << java_override_annotation() << endl;
4011 indent(f_service_) << "public " << resultname << " getResult(I iface, " << argsname
4012 << " args) throws org.apache.thrift.TException {" << endl;
4013 indent_up();
4014 if (!tfunction->is_oneway()) {
4015 indent(f_service_) << resultname << " result = new " << resultname << "();" << endl;
4016 }
4017
4018 t_struct* xs = tfunction->get_xceptions();
4019 const std::vector<t_field*>& xceptions = xs->get_members();
4020 vector<t_field*>::const_iterator x_iter;
4021
4022 // Try block for a function with exceptions
4023 if (xceptions.size() > 0) {
4024 f_service_ << indent() << "try {" << endl;
4025 indent_up();
4026 }
4027
4028 // Generate the function call
4029 t_struct* arg_struct = tfunction->get_arglist();
4030 const std::vector<t_field*>& fields = arg_struct->get_members();
4031 vector<t_field*>::const_iterator f_iter;
4032 f_service_ << indent();
4033
4034 if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
4035 f_service_ << "result.success = ";
4036 }
4037 f_service_ << "iface." << get_rpc_method_name(tfunction->get_name()) << "(";
4038 bool first = true;
4039 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
4040 if (first) {
4041 first = false;
4042 } else {
4043 f_service_ << ", ";
4044 }
4045 f_service_ << "args." << make_valid_java_identifier((*f_iter)->get_name());
4046 }
4047 f_service_ << ");" << endl;
4048
4049 // Set isset on success field
4050 if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()
4051 && !type_can_be_null(tfunction->get_returntype())) {
4052 indent(f_service_) << "result.set" << get_cap_name("success") << get_cap_name("isSet")
4053 << "(true);" << endl;
4054 }
4055
4056 if (!tfunction->is_oneway() && xceptions.size() > 0) {
4057 indent_down();
4058 f_service_ << indent() << "}";
4059 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
4060 f_service_ << " catch (" << type_name((*x_iter)->get_type(), false, false) << " "
4061 << make_valid_java_identifier((*x_iter)->get_name()) << ") {" << endl;
4062 if (!tfunction->is_oneway()) {
4063 indent_up();
4064 f_service_ << indent() << "result." << make_valid_java_identifier((*x_iter)->get_name()) << " = "
4065 << make_valid_java_identifier((*x_iter)->get_name()) << ";" << endl;
4066 indent_down();
4067 f_service_ << indent() << "}";
4068 } else {
4069 f_service_ << "}";
4070 }
4071 }
4072 f_service_ << endl;
4073 }
4074
4075 if (tfunction->is_oneway()) {
4076 indent(f_service_) << "return null;" << endl;
4077 } else {
4078 indent(f_service_) << "return result;" << endl;
4079 }
4080 indent_down();
4081 indent(f_service_) << "}";
4082
4083 // Close function
4084 f_service_ << endl;
4085
4086 // Close class
4087 indent_down();
4088 f_service_ << indent() << "}" << endl << endl;
4089 }
4090
4091 /**
4092 * Deserializes a field of any type.
4093 *
4094 * @param tfield The field
4095 * @param prefix The variable name or container for this field
4096 */
generate_deserialize_field(ostream & out,t_field * tfield,string prefix,bool has_metadata)4097 void t_java_generator::generate_deserialize_field(ostream& out,
4098 t_field* tfield,
4099 string prefix,
4100 bool has_metadata) {
4101 t_type* type = get_true_type(tfield->get_type());
4102
4103 if (type->is_void()) {
4104 throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name();
4105 }
4106
4107 string name = prefix + make_valid_java_identifier(tfield->get_name());
4108
4109 if (type->is_struct() || type->is_xception()) {
4110 generate_deserialize_struct(out, (t_struct*)type, name);
4111 } else if (type->is_container()) {
4112 generate_deserialize_container(out, type, name, has_metadata);
4113 } else if (type->is_base_type()) {
4114 indent(out) << name << " = iprot.";
4115
4116 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
4117 switch (tbase) {
4118 case t_base_type::TYPE_VOID:
4119 throw "compiler error: cannot serialize void field in a struct: " + name;
4120 break;
4121 case t_base_type::TYPE_STRING:
4122 if (type->is_binary()) {
4123 out << "readBinary();";
4124 } else {
4125 out << "readString();";
4126 }
4127 break;
4128 case t_base_type::TYPE_BOOL:
4129 out << "readBool();";
4130 break;
4131 case t_base_type::TYPE_I8:
4132 out << "readByte();";
4133 break;
4134 case t_base_type::TYPE_I16:
4135 out << "readI16();";
4136 break;
4137 case t_base_type::TYPE_I32:
4138 out << "readI32();";
4139 break;
4140 case t_base_type::TYPE_I64:
4141 out << "readI64();";
4142 break;
4143 case t_base_type::TYPE_UUID:
4144 out << "readUuid();";
4145 break;
4146 case t_base_type::TYPE_DOUBLE:
4147 out << "readDouble();";
4148 break;
4149 default:
4150 throw "compiler error: no Java name for base type " + t_base_type::t_base_name(tbase);
4151 }
4152 out << endl;
4153 } else if (type->is_enum()) {
4154 indent(out) << name << " = "
4155 << type_name(tfield->get_type(), true, false, false, true)
4156 + ".findByValue(iprot.readI32());"
4157 << endl;
4158 } else {
4159 printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", tfield->get_name().c_str(),
4160 type_name(type).c_str());
4161 }
4162 }
4163
4164 /**
4165 * Generates an unserializer for a struct, invokes read()
4166 */
generate_deserialize_struct(ostream & out,t_struct * tstruct,string prefix)4167 void t_java_generator::generate_deserialize_struct(ostream& out, t_struct* tstruct, string prefix) {
4168
4169 if (reuse_objects_) {
4170 indent(out) << "if (" << prefix << " == null) {" << endl;
4171 indent_up();
4172 }
4173 indent(out) << prefix << " = new " << type_name(tstruct) << "();" << endl;
4174 if (reuse_objects_) {
4175 indent_down();
4176 indent(out) << "}" << endl;
4177 }
4178 indent(out) << prefix << ".read(iprot);" << endl;
4179 }
4180
4181 /**
4182 * Deserializes a container by reading its size and then iterating
4183 */
generate_deserialize_container(ostream & out,t_type * ttype,string prefix,bool has_metadata)4184 void t_java_generator::generate_deserialize_container(ostream& out,
4185 t_type* ttype,
4186 string prefix,
4187 bool has_metadata) {
4188
4189 scope_up(out);
4190
4191 string obj;
4192
4193 if (ttype->is_map()) {
4194 obj = tmp("_map");
4195 } else if (ttype->is_set()) {
4196 obj = tmp("_set");
4197 } else if (ttype->is_list()) {
4198 obj = tmp("_list");
4199 }
4200
4201 if (has_metadata) {
4202 // Declare variables, read header
4203 if (ttype->is_map()) {
4204 indent(out) << "org.apache.thrift.protocol.TMap " << obj << " = iprot.readMapBegin();"
4205 << endl;
4206 } else if (ttype->is_set()) {
4207 indent(out) << "org.apache.thrift.protocol.TSet " << obj << " = iprot.readSetBegin();"
4208 << endl;
4209 } else if (ttype->is_list()) {
4210 indent(out) << "org.apache.thrift.protocol.TList " << obj << " = iprot.readListBegin();"
4211 << endl;
4212 }
4213 } else {
4214 // Declare variables, read header
4215 if (ttype->is_map()) {
4216 indent(out) << "org.apache.thrift.protocol.TMap " << obj << " = iprot.readMapBegin("
4217 << type_to_enum(((t_map*)ttype)->get_key_type()) << ", "
4218 << type_to_enum(((t_map*)ttype)->get_val_type()) << "); " << endl;
4219 } else if (ttype->is_set()) {
4220 indent(out) << "org.apache.thrift.protocol.TSet " << obj << " = iprot.readSetBegin("
4221 << type_to_enum(((t_set*)ttype)->get_elem_type()) << ");" << endl;
4222 } else if (ttype->is_list()) {
4223 indent(out) << "org.apache.thrift.protocol.TList " << obj << " = iprot.readListBegin("
4224 << type_to_enum(((t_list*)ttype)->get_elem_type()) << ");" << endl;
4225 }
4226 }
4227
4228 if (reuse_objects_) {
4229 indent(out) << "if (" << prefix << " == null) {" << endl;
4230 indent_up();
4231 }
4232
4233 if (is_enum_set(ttype)) {
4234 out << indent() << prefix << " = " << type_name(ttype, false, true, true) << ".noneOf";
4235 } else {
4236 out << indent() << prefix << " = new " << type_name(ttype, false, true);
4237 }
4238
4239 // construct the collection correctly i.e. with appropriate size/type
4240 if (is_enum_set(ttype) || is_enum_map(ttype)) {
4241 out << "(" << inner_enum_type_name(ttype) << ");" << endl;
4242 } else if (sorted_containers_ && (ttype->is_map() || ttype->is_set())) {
4243 // TreeSet and TreeMap don't have any constructor which takes a capacity as an argument
4244 out << "();" << endl;
4245 } else {
4246 out << "(" << (ttype->is_list() ? "" : "2*") << obj << ".size"
4247 << ");" << endl;
4248 }
4249
4250 if (reuse_objects_) {
4251 indent_down();
4252 indent(out) << "}" << endl;
4253 }
4254
4255 if (ttype->is_map()) {
4256 generate_deserialize_map_element(out, (t_map*)ttype, prefix, obj, has_metadata);
4257 } else if (ttype->is_set()) {
4258 generate_deserialize_set_element(out, (t_set*)ttype, prefix, obj, has_metadata);
4259 } else if (ttype->is_list()) {
4260 generate_deserialize_list_element(out, (t_list*)ttype, prefix, obj, has_metadata);
4261 }
4262
4263 scope_down(out);
4264
4265 if (has_metadata) {
4266 // Read container end
4267 if (ttype->is_map()) {
4268 indent(out) << "iprot.readMapEnd();" << endl;
4269 } else if (ttype->is_set()) {
4270 indent(out) << "iprot.readSetEnd();" << endl;
4271 } else if (ttype->is_list()) {
4272 indent(out) << "iprot.readListEnd();" << endl;
4273 }
4274 }
4275 scope_down(out);
4276 }
4277
4278 /**
4279 * Generates code to deserialize a map
4280 */
generate_deserialize_map_element(ostream & out,t_map * tmap,string prefix,string obj,bool has_metadata)4281 void t_java_generator::generate_deserialize_map_element(ostream& out,
4282 t_map* tmap,
4283 string prefix,
4284 string obj,
4285 bool has_metadata) {
4286 string key = tmp("_key");
4287 string val = tmp("_val");
4288 t_field fkey(tmap->get_key_type(), key);
4289 t_field fval(tmap->get_val_type(), val);
4290
4291 indent(out) << declare_field(&fkey, reuse_objects_, false) << endl;
4292 indent(out) << declare_field(&fval, reuse_objects_, false) << endl;
4293
4294 // For loop iterates over elements
4295 string i = tmp("_i");
4296 indent(out) << "for (int " << i << " = 0; " << i << " < " << obj << ".size"
4297 << "; "
4298 << "++" << i << ")" << endl;
4299
4300 scope_up(out);
4301
4302 generate_deserialize_field(out, &fkey, "", has_metadata);
4303 generate_deserialize_field(out, &fval, "", has_metadata);
4304
4305 if (get_true_type(fkey.get_type())->is_enum()) {
4306 indent(out) << "if (" << key << " != null)" << endl;
4307 scope_up(out);
4308 }
4309
4310 indent(out) << prefix << ".put(" << key << ", " << val << ");" << endl;
4311
4312 if (get_true_type(fkey.get_type())->is_enum()) {
4313 scope_down(out);
4314 }
4315
4316 if (reuse_objects_ && !get_true_type(fkey.get_type())->is_base_type()) {
4317 indent(out) << key << " = null;" << endl;
4318 }
4319
4320 if (reuse_objects_ && !get_true_type(fval.get_type())->is_base_type()) {
4321 indent(out) << val << " = null;" << endl;
4322 }
4323 }
4324
4325 /**
4326 * Deserializes a set element
4327 */
generate_deserialize_set_element(ostream & out,t_set * tset,string prefix,string obj,bool has_metadata)4328 void t_java_generator::generate_deserialize_set_element(ostream& out,
4329 t_set* tset,
4330 string prefix,
4331 string obj,
4332 bool has_metadata) {
4333 string elem = tmp("_elem");
4334 t_field felem(tset->get_elem_type(), elem);
4335
4336 indent(out) << declare_field(&felem, reuse_objects_, false) << endl;
4337
4338 // For loop iterates over elements
4339 string i = tmp("_i");
4340 indent(out) << "for (int " << i << " = 0; " << i << " < " << obj << ".size"
4341 << "; "
4342 << "++" << i << ")" << endl;
4343 scope_up(out);
4344
4345 generate_deserialize_field(out, &felem, "", has_metadata);
4346
4347 if (get_true_type(felem.get_type())->is_enum()) {
4348 indent(out) << "if (" << elem << " != null)" << endl;
4349 scope_up(out);
4350 }
4351
4352 indent(out) << prefix << ".add(" << elem << ");" << endl;
4353
4354 if (get_true_type(felem.get_type())->is_enum()) {
4355 scope_down(out);
4356 }
4357
4358 if (reuse_objects_ && !get_true_type(felem.get_type())->is_base_type()) {
4359 indent(out) << elem << " = null;" << endl;
4360 }
4361 }
4362
4363 /**
4364 * Deserializes a list element
4365 */
generate_deserialize_list_element(ostream & out,t_list * tlist,string prefix,string obj,bool has_metadata)4366 void t_java_generator::generate_deserialize_list_element(ostream& out,
4367 t_list* tlist,
4368 string prefix,
4369 string obj,
4370 bool has_metadata) {
4371 string elem = tmp("_elem");
4372 t_field felem(tlist->get_elem_type(), elem);
4373
4374 indent(out) << declare_field(&felem, reuse_objects_, false) << endl;
4375
4376 // For loop iterates over elements
4377 string i = tmp("_i");
4378 indent(out) << "for (int " << i << " = 0; " << i << " < " << obj << ".size"
4379 << "; "
4380 << "++" << i << ")" << endl;
4381 scope_up(out);
4382
4383 generate_deserialize_field(out, &felem, "", has_metadata);
4384
4385 if (get_true_type(felem.get_type())->is_enum()) {
4386 indent(out) << "if (" << elem << " != null)" << endl;
4387 scope_up(out);
4388 }
4389
4390 indent(out) << prefix << ".add(" << elem << ");" << endl;
4391
4392 if (get_true_type(felem.get_type())->is_enum()) {
4393 scope_down(out);
4394 }
4395
4396 if (reuse_objects_ && !get_true_type(felem.get_type())->is_base_type()) {
4397 indent(out) << elem << " = null;" << endl;
4398 }
4399 }
4400
4401 /**
4402 * Serializes a field of any type.
4403 *
4404 * @param tfield The field to serialize
4405 * @param prefix Name to prepend to field name
4406 */
generate_serialize_field(ostream & out,t_field * tfield,string prefix,string postfix,bool has_metadata)4407 void t_java_generator::generate_serialize_field(ostream& out,
4408 t_field* tfield,
4409 string prefix, string postfix,
4410 bool has_metadata) {
4411 t_type* type = get_true_type(tfield->get_type());
4412
4413 // Do nothing for void types
4414 if (type->is_void()) {
4415 throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name() + postfix;
4416 }
4417
4418 if (type->is_struct() || type->is_xception()) {
4419 generate_serialize_struct(out, (t_struct*)type, prefix + make_valid_java_identifier(tfield->get_name()) + postfix);
4420 } else if (type->is_container()) {
4421 generate_serialize_container(out, type, prefix + make_valid_java_identifier(tfield->get_name()) + postfix, has_metadata);
4422 } else if (type->is_enum()) {
4423 indent(out) << "oprot.writeI32(" << prefix + make_valid_java_identifier(tfield->get_name()) + postfix << ".getValue());" << endl;
4424 } else if (type->is_base_type()) {
4425 string name = prefix + make_valid_java_identifier(tfield->get_name()) + postfix;
4426 indent(out) << "oprot.";
4427
4428 if (type->is_base_type()) {
4429 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
4430 switch (tbase) {
4431 case t_base_type::TYPE_VOID:
4432 throw "compiler error: cannot serialize void field in a struct: " + name;
4433 break;
4434 case t_base_type::TYPE_STRING:
4435 if (type->is_binary()) {
4436 out << "writeBinary(" << name << ");";
4437 } else {
4438 out << "writeString(" << name << ");";
4439 }
4440 break;
4441 case t_base_type::TYPE_BOOL:
4442 out << "writeBool(" << name << ");";
4443 break;
4444 case t_base_type::TYPE_I8:
4445 out << "writeByte(" << name << ");";
4446 break;
4447 case t_base_type::TYPE_I16:
4448 out << "writeI16(" << name << ");";
4449 break;
4450 case t_base_type::TYPE_I32:
4451 out << "writeI32(" << name << ");";
4452 break;
4453 case t_base_type::TYPE_I64:
4454 out << "writeI64(" << name << ");";
4455 break;
4456 case t_base_type::TYPE_UUID:
4457 out << "writeUuid(" << name << ");";
4458 break;
4459 case t_base_type::TYPE_DOUBLE:
4460 out << "writeDouble(" << name << ");";
4461 break;
4462 default:
4463 throw "compiler error: no Java name for base type " + t_base_type::t_base_name(tbase);
4464 }
4465 } else if (type->is_enum()) {
4466 out << "writeI32(struct." << name << ");";
4467 }
4468 out << endl;
4469 } else {
4470 printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s%s' TYPE '%s'\n", prefix.c_str(),
4471 tfield->get_name().c_str(), postfix.c_str(), type_name(type).c_str());
4472 }
4473 }
4474
4475 /**
4476 * Serializes all the members of a struct.
4477 *
4478 * @param tstruct The struct to serialize
4479 * @param prefix String prefix to attach to all fields
4480 */
generate_serialize_struct(ostream & out,t_struct * tstruct,string prefix)4481 void t_java_generator::generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix) {
4482 (void)tstruct;
4483 out << indent() << prefix << ".write(oprot);" << endl;
4484 }
4485
4486 /**
4487 * Serializes a container by writing its size then the elements.
4488 *
4489 * @param ttype The type of container
4490 * @param prefix String prefix for fields
4491 */
generate_serialize_container(ostream & out,t_type * ttype,string prefix,bool has_metadata)4492 void t_java_generator::generate_serialize_container(ostream& out,
4493 t_type* ttype,
4494 string prefix,
4495 bool has_metadata) {
4496 scope_up(out);
4497
4498 if (has_metadata) {
4499 if (ttype->is_map()) {
4500 indent(out) << "oprot.writeMapBegin(new org.apache.thrift.protocol.TMap("
4501 << type_to_enum(((t_map*)ttype)->get_key_type()) << ", "
4502 << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " << prefix << ".size()));"
4503 << endl;
4504 } else if (ttype->is_set()) {
4505 indent(out) << "oprot.writeSetBegin(new org.apache.thrift.protocol.TSet("
4506 << type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " << prefix
4507 << ".size()));" << endl;
4508 } else if (ttype->is_list()) {
4509 indent(out) << "oprot.writeListBegin(new org.apache.thrift.protocol.TList("
4510 << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " << prefix
4511 << ".size()));" << endl;
4512 }
4513 } else {
4514 indent(out) << "oprot.writeI32(" << prefix << ".size());" << endl;
4515 }
4516
4517 string iter = tmp("_iter");
4518 if (ttype->is_map()) {
4519 indent(out) << "for (java.util.Map.Entry<"
4520 << type_name(((t_map*)ttype)->get_key_type(), true, false) << ", "
4521 << type_name(((t_map*)ttype)->get_val_type(), true, false) << "> " << iter << " : "
4522 << prefix << ".entrySet())";
4523 } else if (ttype->is_set()) {
4524 indent(out) << "for (" << type_name(((t_set*)ttype)->get_elem_type()) << " " << iter << " : "
4525 << prefix << ")";
4526 } else if (ttype->is_list()) {
4527 indent(out) << "for (" << type_name(((t_list*)ttype)->get_elem_type()) << " " << iter << " : "
4528 << prefix << ")";
4529 }
4530
4531 out << endl;
4532 scope_up(out);
4533 if (ttype->is_map()) {
4534 generate_serialize_map_element(out, (t_map*)ttype, iter, prefix, has_metadata);
4535 } else if (ttype->is_set()) {
4536 generate_serialize_set_element(out, (t_set*)ttype, iter, has_metadata);
4537 } else if (ttype->is_list()) {
4538 generate_serialize_list_element(out, (t_list*)ttype, iter, has_metadata);
4539 }
4540 scope_down(out);
4541
4542 if (has_metadata) {
4543 if (ttype->is_map()) {
4544 indent(out) << "oprot.writeMapEnd();" << endl;
4545 } else if (ttype->is_set()) {
4546 indent(out) << "oprot.writeSetEnd();" << endl;
4547 } else if (ttype->is_list()) {
4548 indent(out) << "oprot.writeListEnd();" << endl;
4549 }
4550 }
4551
4552 scope_down(out);
4553 }
4554
4555 /**
4556 * Serializes the members of a map.
4557 */
generate_serialize_map_element(ostream & out,t_map * tmap,string iter,string map,bool has_metadata)4558 void t_java_generator::generate_serialize_map_element(ostream& out,
4559 t_map* tmap,
4560 string iter,
4561 string map,
4562 bool has_metadata) {
4563 (void)map;
4564 t_field kfield(tmap->get_key_type(), iter);
4565 generate_serialize_field(out, &kfield, "", ".getKey()", has_metadata);
4566 t_field vfield(tmap->get_val_type(), iter);
4567 generate_serialize_field(out, &vfield, "", ".getValue()", has_metadata);
4568 }
4569
4570 /**
4571 * Serializes the members of a set.
4572 */
generate_serialize_set_element(ostream & out,t_set * tset,string iter,bool has_metadata)4573 void t_java_generator::generate_serialize_set_element(ostream& out,
4574 t_set* tset,
4575 string iter,
4576 bool has_metadata) {
4577 t_field efield(tset->get_elem_type(), iter);
4578 generate_serialize_field(out, &efield, "", "", has_metadata);
4579 }
4580
4581 /**
4582 * Serializes the members of a list.
4583 */
generate_serialize_list_element(ostream & out,t_list * tlist,string iter,bool has_metadata)4584 void t_java_generator::generate_serialize_list_element(ostream& out,
4585 t_list* tlist,
4586 string iter,
4587 bool has_metadata) {
4588 t_field efield(tlist->get_elem_type(), iter);
4589 generate_serialize_field(out, &efield, "", "", has_metadata);
4590 }
4591
4592 /**
4593 * Returns a Java type name
4594 *
4595 * @param ttype The type
4596 * @param container Is the type going inside a container?
4597 * @return Java type name, i.e. java.util.HashMap<Key,Value>
4598 */
type_name(t_type * ttype,bool in_container,bool in_init,bool skip_generic,bool force_namespace)4599 string t_java_generator::type_name(t_type* ttype,
4600 bool in_container,
4601 bool in_init,
4602 bool skip_generic,
4603 bool force_namespace) {
4604 // In Java typedefs are just resolved to their real type
4605 ttype = get_true_type(ttype);
4606 string prefix;
4607
4608 if (ttype->is_base_type()) {
4609 return base_type_name((t_base_type*)ttype, in_container);
4610 } else if (ttype->is_map()) {
4611 t_map* tmap = (t_map*)ttype;
4612 if (in_init) {
4613 if (is_enum_map(tmap)) {
4614 prefix = "java.util.EnumMap";
4615 } else if (sorted_containers_) {
4616 prefix = "java.util.TreeMap";
4617 } else {
4618 prefix = "java.util.HashMap";
4619 }
4620 } else {
4621 prefix = "java.util.Map";
4622 }
4623 return prefix
4624 + (skip_generic ? ""
4625 : "<" + type_name(tmap->get_key_type(), true) + ","
4626 + type_name(tmap->get_val_type(), true) + ">");
4627 } else if (ttype->is_set()) {
4628 t_set* tset = (t_set*)ttype;
4629 if (in_init) {
4630 if (is_enum_set(tset)) {
4631 prefix = "java.util.EnumSet";
4632 } else if (sorted_containers_) {
4633 prefix = "java.util.TreeSet";
4634 } else {
4635 prefix = "java.util.HashSet";
4636 }
4637 } else {
4638 prefix = "java.util.Set";
4639 }
4640 return prefix + (skip_generic ? "" : "<" + type_name(tset->get_elem_type(), true) + ">");
4641 } else if (ttype->is_list()) {
4642 t_list* tlist = (t_list*)ttype;
4643 if (in_init) {
4644 prefix = "java.util.ArrayList";
4645 } else {
4646 prefix = "java.util.List";
4647 }
4648 return prefix + (skip_generic ? "" : "<" + type_name(tlist->get_elem_type(), true) + ">");
4649 }
4650
4651 // Check for namespacing
4652 t_program* program = ttype->get_program();
4653 if ((program != nullptr) && ((program != program_) || force_namespace)) {
4654 string package = program->get_namespace("java");
4655 if (!package.empty()) {
4656 return package + "." + make_valid_java_identifier(ttype->get_name());
4657 }
4658 }
4659
4660 return make_valid_java_identifier(ttype->get_name());
4661 }
4662
4663 /**
4664 * Returns the Java type that corresponds to the thrift type.
4665 *
4666 * @param tbase The base type
4667 * @param container Is it going in a Java container?
4668 */
base_type_name(t_base_type * type,bool in_container)4669 string t_java_generator::base_type_name(t_base_type* type, bool in_container) {
4670 t_base_type::t_base tbase = type->get_base();
4671
4672 switch (tbase) {
4673 case t_base_type::TYPE_VOID:
4674 return (in_container ? "Void" : "void");
4675 case t_base_type::TYPE_STRING:
4676 if (type->is_binary()) {
4677 return "java.nio.ByteBuffer";
4678 } else {
4679 return "java.lang.String";
4680 }
4681 case t_base_type::TYPE_UUID:
4682 return "java.util.UUID";
4683 case t_base_type::TYPE_BOOL:
4684 return (in_container ? "java.lang.Boolean" : "boolean");
4685 case t_base_type::TYPE_I8:
4686 return (in_container ? "java.lang.Byte" : "byte");
4687 case t_base_type::TYPE_I16:
4688 return (in_container ? "java.lang.Short" : "short");
4689 case t_base_type::TYPE_I32:
4690 return (in_container ? "java.lang.Integer" : "int");
4691 case t_base_type::TYPE_I64:
4692 return (in_container ? "java.lang.Long" : "long");
4693 case t_base_type::TYPE_DOUBLE:
4694 return (in_container ? "java.lang.Double" : "double");
4695 default:
4696 throw "compiler error: no Java name for base type " + t_base_type::t_base_name(tbase);
4697 }
4698 }
4699
4700 /**
4701 * Declares a field, which may include initialization as necessary.
4702 *
4703 * @param tfield The field
4704 * @param init Whether to initialize the field
4705 */
declare_field(t_field * tfield,bool init,bool comment)4706 string t_java_generator::declare_field(t_field* tfield, bool init, bool comment) {
4707 // TODO(mcslee): do we ever need to initialize the field?
4708 string result = "";
4709 t_type* ttype = get_true_type(tfield->get_type());
4710 if (type_can_be_null(ttype)) {
4711 result += java_nullable_annotation() + " ";
4712 }
4713 result += type_name(tfield->get_type()) + " " + make_valid_java_identifier(tfield->get_name());
4714 if (init) {
4715 if (ttype->is_base_type() && tfield->get_value() != nullptr) {
4716 std::ofstream dummy;
4717 result += " = " + render_const_value(dummy, ttype, tfield->get_value());
4718 } else if (ttype->is_base_type()) {
4719 t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
4720 switch (tbase) {
4721 case t_base_type::TYPE_VOID:
4722 throw "NO T_VOID CONSTRUCT";
4723 case t_base_type::TYPE_STRING:
4724 case t_base_type::TYPE_UUID:
4725 result += " = null";
4726 break;
4727 case t_base_type::TYPE_BOOL:
4728 result += " = false";
4729 break;
4730 case t_base_type::TYPE_I8:
4731 case t_base_type::TYPE_I16:
4732 case t_base_type::TYPE_I32:
4733 case t_base_type::TYPE_I64:
4734 result += " = 0";
4735 break;
4736 case t_base_type::TYPE_DOUBLE:
4737 result += " = (double)0";
4738 break;
4739 default:
4740 throw "compiler error: unhandled type";
4741 }
4742 } else if (ttype->is_enum()) {
4743 result += " = null";
4744 } else if (ttype->is_container()) {
4745 result += " = new " + type_name(ttype, false, true) + "()";
4746 } else {
4747 result += " = new " + type_name(ttype, false, true) + "()";
4748 ;
4749 }
4750 }
4751 result += ";";
4752 if (comment) {
4753 result += " // ";
4754 if (tfield->get_req() == t_field::T_OPTIONAL) {
4755 result += "optional";
4756 } else {
4757 result += "required";
4758 }
4759 }
4760 return result;
4761 }
4762
4763 /**
4764 * Renders a function signature of the form 'type name(args)'
4765 *
4766 * @param tfunction Function definition
4767 * @return String of rendered function definition
4768 */
function_signature(t_function * tfunction,string prefix)4769 string t_java_generator::function_signature(t_function* tfunction, string prefix) {
4770 t_type* ttype = tfunction->get_returntype();
4771 std::string fn_name = get_rpc_method_name(tfunction->get_name());
4772 std::string result = type_name(ttype) + " " + prefix + fn_name + "("
4773 + argument_list(tfunction->get_arglist()) + ") throws ";
4774 t_struct* xs = tfunction->get_xceptions();
4775 const std::vector<t_field*>& xceptions = xs->get_members();
4776 vector<t_field*>::const_iterator x_iter;
4777 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
4778 result += type_name((*x_iter)->get_type(), false, false) + ", ";
4779 }
4780 result += "org.apache.thrift.TException";
4781 return result;
4782 }
4783
4784 /**
4785 * Renders a function signature of the form 'void name(args, resultHandler)'
4786 *
4787 * @params tfunction Function definition
4788 * @return String of rendered function definition
4789 */
function_signature_async(t_function * tfunction,bool use_base_method,string prefix)4790 string t_java_generator::function_signature_async(t_function* tfunction,
4791 bool use_base_method,
4792 string prefix) {
4793 std::string arglist = async_function_call_arglist(tfunction, use_base_method, true);
4794
4795 std::string ret_type = "";
4796 if (use_base_method) {
4797 ret_type += "AsyncClient.";
4798 }
4799 ret_type += tfunction->get_name() + "_call";
4800
4801 std::string fn_name = get_rpc_method_name(tfunction->get_name());
4802
4803 std::string result = prefix + "void " + fn_name + "(" + arglist + ")";
4804 return result;
4805 }
4806
4807 /**
4808 * Renders a function signature of the form 'CompletableFuture<R> name(args)'
4809 *
4810 * @params tfunction Function definition
4811 * @return String of rendered function definition
4812 */
function_signature_future(t_function * tfunction,string prefix)4813 string t_java_generator::function_signature_future(t_function* tfunction, string prefix) {
4814 t_type* ttype = tfunction->get_returntype();
4815 std::string fn_name = get_rpc_method_name(tfunction->get_name());
4816 return "java.util.concurrent.CompletableFuture<" + type_name(ttype, /*in_container=*/true) + "> "
4817 + prefix + fn_name + "(" + argument_list(tfunction->get_arglist()) + ")";
4818 }
4819
async_function_call_arglist(t_function * tfunc,bool use_base_method,bool include_types)4820 string t_java_generator::async_function_call_arglist(t_function* tfunc,
4821 bool use_base_method,
4822 bool include_types) {
4823 (void)use_base_method;
4824 std::string arglist = "";
4825 if (tfunc->get_arglist()->get_members().size() > 0) {
4826 arglist = argument_list(tfunc->get_arglist(), include_types) + ", ";
4827 }
4828
4829 if (include_types) {
4830 arglist += "org.apache.thrift.async.AsyncMethodCallback<";
4831 arglist += type_name(tfunc->get_returntype(), true) + "> ";
4832 }
4833 arglist += "resultHandler";
4834
4835 return arglist;
4836 }
4837
4838 /**
4839 * Renders a comma separated field list, with type names
4840 */
argument_list(t_struct * tstruct,bool include_types)4841 string t_java_generator::argument_list(t_struct* tstruct, bool include_types) {
4842 string result = "";
4843
4844 const vector<t_field*>& fields = tstruct->get_members();
4845 vector<t_field*>::const_iterator f_iter;
4846 bool first = true;
4847 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
4848 if (first) {
4849 first = false;
4850 } else {
4851 result += ", ";
4852 }
4853 if (include_types) {
4854 result += type_name((*f_iter)->get_type()) + " ";
4855 }
4856 result += make_valid_java_identifier((*f_iter)->get_name());
4857 }
4858 return result;
4859 }
4860
async_argument_list(t_function * tfunct,t_struct * tstruct,t_type * ttype,bool include_types)4861 string t_java_generator::async_argument_list(t_function* tfunct,
4862 t_struct* tstruct,
4863 t_type* ttype,
4864 bool include_types) {
4865 (void)tfunct;
4866 (void)ttype;
4867 string result = "";
4868 const vector<t_field*>& fields = tstruct->get_members();
4869 vector<t_field*>::const_iterator f_iter;
4870 bool first = true;
4871 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
4872 if (first) {
4873 first = false;
4874 } else {
4875 result += ", ";
4876 }
4877 if (include_types) {
4878 result += type_name((*f_iter)->get_type()) + " ";
4879 }
4880 result += make_valid_java_identifier((*f_iter)->get_name());
4881 }
4882 if (!first) {
4883 result += ", ";
4884 }
4885 if (include_types) {
4886 result += "org.apache.thrift.async.AsyncMethodCallback<";
4887 result += type_name(tfunct->get_returntype(), true) + "> ";
4888 }
4889 result += "resultHandler";
4890 return result;
4891 }
4892
4893 /**
4894 * Converts the parse type to a Java enum string for the given type.
4895 */
type_to_enum(t_type * type)4896 string t_java_generator::type_to_enum(t_type* type) {
4897 type = get_true_type(type);
4898
4899 if (type->is_base_type()) {
4900 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
4901 switch (tbase) {
4902 case t_base_type::TYPE_VOID:
4903 throw "NO T_VOID CONSTRUCT";
4904 case t_base_type::TYPE_STRING:
4905 return "org.apache.thrift.protocol.TType.STRING";
4906 case t_base_type::TYPE_BOOL:
4907 return "org.apache.thrift.protocol.TType.BOOL";
4908 case t_base_type::TYPE_I8:
4909 return "org.apache.thrift.protocol.TType.BYTE";
4910 case t_base_type::TYPE_I16:
4911 return "org.apache.thrift.protocol.TType.I16";
4912 case t_base_type::TYPE_I32:
4913 return "org.apache.thrift.protocol.TType.I32";
4914 case t_base_type::TYPE_I64:
4915 return "org.apache.thrift.protocol.TType.I64";
4916 case t_base_type::TYPE_UUID:
4917 return "org.apache.thrift.protocol.TType.UUID";
4918 case t_base_type::TYPE_DOUBLE:
4919 return "org.apache.thrift.protocol.TType.DOUBLE";
4920 default:
4921 throw "compiler error: unhandled type";
4922 }
4923 } else if (type->is_enum()) {
4924 return "org.apache.thrift.protocol.TType.I32";
4925 } else if (type->is_struct() || type->is_xception()) {
4926 return "org.apache.thrift.protocol.TType.STRUCT";
4927 } else if (type->is_map()) {
4928 return "org.apache.thrift.protocol.TType.MAP";
4929 } else if (type->is_set()) {
4930 return "org.apache.thrift.protocol.TType.SET";
4931 } else if (type->is_list()) {
4932 return "org.apache.thrift.protocol.TType.LIST";
4933 }
4934
4935 throw "INVALID TYPE IN type_to_enum: " + type->get_name();
4936 }
4937
4938 /**
4939 * Takes a name and produes a valid Java source file name from it
4940 *
4941 * @param fromName The name which shall become a valid Java source file name
4942 * @return The produced identifier
4943 */
make_valid_java_filename(std::string const & fromName)4944 std::string t_java_generator::make_valid_java_filename(std::string const& fromName) {
4945 // if any further rules apply to source file names in Java, modify as necessary
4946 return make_valid_java_identifier(fromName);
4947 }
4948
4949 /**
4950 * Takes a name and produes a valid Java identifier from it
4951 *
4952 * @param fromName The name which shall become a valid Java identifier
4953 * @return The produced identifier
4954 */
make_valid_java_identifier(std::string const & fromName)4955 std::string t_java_generator::make_valid_java_identifier(std::string const& fromName) {
4956 std::string str = fromName;
4957 if (str.empty()) {
4958 return str;
4959 }
4960
4961 // tests rely on this
4962 assert(('A' < 'Z') && ('a' < 'z') && ('0' < '9'));
4963
4964 // if the first letter is a number, we add an additional underscore in front of it
4965 char c = str.at(0);
4966 if (('0' <= c) && (c <= '9')) {
4967 str = "_" + str;
4968 }
4969
4970 // following chars: letter, number or underscore
4971 for (size_t i = 0; i < str.size(); ++i) {
4972 c = str.at(i);
4973 if ((('A' > c) || (c > 'Z')) && (('a' > c) || (c > 'z')) && (('0' > c) || (c > '9'))
4974 && ('_' != c)) {
4975 str.replace(i, 1, "_");
4976 }
4977 }
4978
4979 return normalize_name(str);
4980 }
4981
as_camel_case(std::string name,bool ucfirst)4982 std::string t_java_generator::as_camel_case(std::string name, bool ucfirst) {
4983 std::string new_name;
4984 size_t i = 0;
4985 for (i = 0; i < name.size(); i++) {
4986 if (name[i] != '_')
4987 break;
4988 }
4989 if (ucfirst) {
4990 new_name += toupper(name[i++]);
4991 } else {
4992 new_name += tolower(name[i++]);
4993 }
4994 for (; i < name.size(); i++) {
4995 if (name[i] == '_') {
4996 if (i < name.size() - 1) {
4997 i++;
4998 new_name += toupper(name[i]);
4999 }
5000 } else {
5001 new_name += name[i];
5002 }
5003 }
5004 return new_name;
5005 }
5006
get_rpc_method_name(std::string name)5007 std::string t_java_generator::get_rpc_method_name(std::string name) {
5008 if (fullcamel_style_) {
5009 return make_valid_java_identifier(as_camel_case(name, false));
5010 } else {
5011 return make_valid_java_identifier(name);
5012 }
5013 }
5014
5015 /**
5016 * Applies the correct style to a string based on the value of nocamel_style_
5017 * and/or fullcamel_style_
5018 */
get_cap_name(std::string name)5019 std::string t_java_generator::get_cap_name(std::string name) {
5020 if (nocamel_style_) {
5021 return "_" + name;
5022 } else if (fullcamel_style_) {
5023 return as_camel_case(name);
5024 } else {
5025 name[0] = toupper(name[0]);
5026 return name;
5027 }
5028 }
5029
constant_name(string name)5030 string t_java_generator::constant_name(string name) {
5031 string constant_name;
5032
5033 bool is_first = true;
5034 bool was_previous_char_upper = false;
5035 for (char character : name) {
5036 bool is_upper = isupper(character);
5037
5038 if (is_upper && !is_first && !was_previous_char_upper) {
5039 constant_name += '_';
5040 }
5041 constant_name += toupper(character);
5042
5043 is_first = false;
5044 was_previous_char_upper = is_upper;
5045 }
5046
5047 return constant_name;
5048 }
5049
generate_deep_copy_container(ostream & out,std::string source_name_p1,std::string source_name_p2,std::string result_name,t_type * type)5050 void t_java_generator::generate_deep_copy_container(ostream& out,
5051 std::string source_name_p1,
5052 std::string source_name_p2,
5053 std::string result_name,
5054 t_type* type) {
5055
5056 t_container* container = (t_container*)type;
5057 std::string source_name;
5058 if (source_name_p2 == "")
5059 source_name = source_name_p1;
5060 else
5061 source_name = source_name_p1 + "." + source_name_p2;
5062
5063 bool copy_construct_container;
5064 if (container->is_map()) {
5065 t_map* tmap = (t_map*)container;
5066 copy_construct_container
5067 = tmap->get_key_type()->is_base_type() && tmap->get_val_type()->is_base_type();
5068 } else {
5069 t_type* elem_type = container->is_list() ? ((t_list*)container)->get_elem_type()
5070 : ((t_set*)container)->get_elem_type();
5071 copy_construct_container = elem_type->is_base_type();
5072 }
5073
5074 if (copy_construct_container) {
5075 // deep copy of base types can be done much more efficiently than iterating over all the
5076 // elements manually
5077 indent(out) << type_name(type, true, false) << " " << result_name << " = new "
5078 << type_name(container, false, true) << "(" << source_name << ");" << endl;
5079 return;
5080 }
5081
5082 std::string constructor_args;
5083 if (is_enum_set(container) || is_enum_map(container)) {
5084 constructor_args = inner_enum_type_name(container);
5085 } else if (!(sorted_containers_ && (container->is_map() || container->is_set()))) {
5086 // unsorted containers accept a capacity value
5087 constructor_args = source_name + ".size()";
5088 }
5089
5090 if (is_enum_set(container)) {
5091 indent(out) << type_name(type, true, false) << " " << result_name << " = "
5092 << type_name(container, false, true, true) << ".noneOf(" << constructor_args << ");"
5093 << endl;
5094 } else {
5095 indent(out) << type_name(type, true, false) << " " << result_name << " = new "
5096 << type_name(container, false, true) << "(" << constructor_args << ");" << endl;
5097 }
5098
5099 std::string iterator_element_name = source_name_p1 + "_element";
5100 std::string result_element_name = result_name + "_copy";
5101
5102 if (container->is_map()) {
5103 t_type* key_type = ((t_map*)container)->get_key_type();
5104 t_type* val_type = ((t_map*)container)->get_val_type();
5105
5106 indent(out) << "for (java.util.Map.Entry<" << type_name(key_type, true, false) << ", "
5107 << type_name(val_type, true, false) << "> " << iterator_element_name << " : "
5108 << source_name << ".entrySet()) {" << endl;
5109 indent_up();
5110
5111 out << endl;
5112
5113 indent(out) << type_name(key_type, true, false) << " " << iterator_element_name
5114 << "_key = " << iterator_element_name << ".getKey();" << endl;
5115 indent(out) << type_name(val_type, true, false) << " " << iterator_element_name
5116 << "_value = " << iterator_element_name << ".getValue();" << endl;
5117
5118 out << endl;
5119
5120 if (key_type->is_container()) {
5121 generate_deep_copy_container(out, iterator_element_name + "_key", "",
5122 result_element_name + "_key", key_type);
5123 } else {
5124 indent(out) << type_name(key_type, true, false) << " " << result_element_name << "_key = ";
5125 generate_deep_copy_non_container(out, iterator_element_name + "_key",
5126 result_element_name + "_key", key_type);
5127 out << ";" << endl;
5128 }
5129
5130 out << endl;
5131
5132 if (val_type->is_container()) {
5133 generate_deep_copy_container(out, iterator_element_name + "_value", "",
5134 result_element_name + "_value", val_type);
5135 } else {
5136 indent(out) << type_name(val_type, true, false) << " " << result_element_name << "_value = ";
5137 generate_deep_copy_non_container(out, iterator_element_name + "_value",
5138 result_element_name + "_value", val_type);
5139 out << ";" << endl;
5140 }
5141
5142 out << endl;
5143
5144 indent(out) << result_name << ".put(" << result_element_name << "_key, " << result_element_name
5145 << "_value);" << endl;
5146
5147 indent_down();
5148 indent(out) << "}" << endl;
5149
5150 } else {
5151 t_type* elem_type;
5152
5153 if (container->is_set()) {
5154 elem_type = ((t_set*)container)->get_elem_type();
5155 } else {
5156 elem_type = ((t_list*)container)->get_elem_type();
5157 }
5158
5159 indent(out) << "for (" << type_name(elem_type, true, false) << " " << iterator_element_name
5160 << " : " << source_name << ") {" << endl;
5161
5162 indent_up();
5163
5164 if (elem_type->is_container()) {
5165 // recursive deep copy
5166 generate_deep_copy_container(out, iterator_element_name, "", result_element_name, elem_type);
5167 indent(out) << result_name << ".add(" << result_element_name << ");" << endl;
5168 } else {
5169 // iterative copy
5170 if (elem_type->is_binary()) {
5171 indent(out) << "java.nio.ByteBuffer temp_binary_element = ";
5172 generate_deep_copy_non_container(out, iterator_element_name, "temp_binary_element",
5173 elem_type);
5174 out << ";" << endl;
5175 indent(out) << result_name << ".add(temp_binary_element);" << endl;
5176 } else {
5177 indent(out) << result_name << ".add(";
5178 generate_deep_copy_non_container(out, iterator_element_name, result_name, elem_type);
5179 out << ");" << endl;
5180 }
5181 }
5182
5183 indent_down();
5184
5185 indent(out) << "}" << endl;
5186 }
5187 }
5188
generate_deep_copy_non_container(ostream & out,std::string source_name,std::string dest_name,t_type * type)5189 void t_java_generator::generate_deep_copy_non_container(ostream& out,
5190 std::string source_name,
5191 std::string dest_name,
5192 t_type* type) {
5193 (void)dest_name;
5194 type = get_true_type(type);
5195 if (type->is_base_type() || type->is_enum() || type->is_typedef()) {
5196 if (type->is_binary()) {
5197 out << "org.apache.thrift.TBaseHelper.copyBinary(" << source_name << ")";
5198 } else {
5199 // everything else can be copied directly
5200 out << source_name;
5201 }
5202 } else {
5203 out << "new " << type_name(type, true, true) << "(" << source_name << ")";
5204 }
5205 }
5206
generate_isset_check(t_field * field)5207 std::string t_java_generator::generate_isset_check(t_field* field) {
5208 return generate_isset_check(field->get_name());
5209 }
5210
isset_field_id(t_field * field)5211 std::string t_java_generator::isset_field_id(t_field* field) {
5212 return "__" + upcase_string(field->get_name() + "_isset_id");
5213 }
5214
generate_isset_check(std::string field_name)5215 std::string t_java_generator::generate_isset_check(std::string field_name) {
5216 return "is" + get_cap_name("set") + get_cap_name(field_name) + "()";
5217 }
5218
generate_isset_set(ostream & out,t_field * field,string prefix)5219 void t_java_generator::generate_isset_set(ostream& out, t_field* field, string prefix) {
5220 if (!type_can_be_null(field->get_type())) {
5221 indent(out) << prefix << "set" << get_cap_name(field->get_name()) << get_cap_name("isSet")
5222 << "(true);" << endl;
5223 }
5224 }
5225
generate_struct_desc(ostream & out,t_struct * tstruct)5226 void t_java_generator::generate_struct_desc(ostream& out, t_struct* tstruct) {
5227 indent(out) << "private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new "
5228 "org.apache.thrift.protocol.TStruct(\""
5229 << tstruct->get_name() << "\");" << endl;
5230 }
5231
generate_field_descs(ostream & out,t_struct * tstruct)5232 void t_java_generator::generate_field_descs(ostream& out, t_struct* tstruct) {
5233 const vector<t_field*>& members = tstruct->get_members();
5234 vector<t_field*>::const_iterator m_iter;
5235
5236 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
5237 indent(out) << "private static final org.apache.thrift.protocol.TField "
5238 << constant_name((*m_iter)->get_name())
5239 << "_FIELD_DESC = new org.apache.thrift.protocol.TField(\"" << (*m_iter)->get_name()
5240 << "\", " << type_to_enum((*m_iter)->get_type()) << ", "
5241 << "(short)" << (*m_iter)->get_key() << ");" << endl;
5242 }
5243 }
5244
generate_scheme_map(ostream & out,t_struct * tstruct)5245 void t_java_generator::generate_scheme_map(ostream& out, t_struct* tstruct) {
5246 indent(out) << "private static final org.apache.thrift.scheme.SchemeFactory "
5247 "STANDARD_SCHEME_FACTORY = new "
5248 << tstruct->get_name() << "StandardSchemeFactory();" << endl;
5249 indent(out)
5250 << "private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new "
5251 << tstruct->get_name() << "TupleSchemeFactory();" << endl;
5252 }
5253
generate_field_name_constants(ostream & out,t_struct * tstruct)5254 void t_java_generator::generate_field_name_constants(ostream& out, t_struct* tstruct) {
5255 indent(out) << "/** The set of fields this struct contains, along with convenience methods for "
5256 "finding and manipulating them. */"
5257 << endl;
5258 indent(out) << "public enum _Fields implements org.apache.thrift.TFieldIdEnum {" << endl;
5259
5260 indent_up();
5261 bool first = true;
5262 const vector<t_field*>& members = tstruct->get_members();
5263 vector<t_field*>::const_iterator m_iter;
5264 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
5265 if (!first) {
5266 out << "," << endl;
5267 }
5268 first = false;
5269 generate_java_doc(out, *m_iter);
5270 indent(out) << constant_name((*m_iter)->get_name()) << "((short)" << (*m_iter)->get_key()
5271 << ", \"" << (*m_iter)->get_name() << "\")";
5272 }
5273
5274 out << ";" << endl << endl;
5275
5276 indent(out) << "private static final java.util.Map<java.lang.String, _Fields> byName = new "
5277 "java.util.HashMap<java.lang.String, _Fields>();"
5278 << endl;
5279 out << endl;
5280
5281 indent(out) << "static {" << endl;
5282 indent(out) << " for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) {" << endl;
5283 indent(out) << " byName.put(field.getFieldName(), field);" << endl;
5284 indent(out) << " }" << endl;
5285 indent(out) << "}" << endl << endl;
5286
5287 indent(out) << "/**" << endl;
5288 indent(out) << " * Find the _Fields constant that matches fieldId, or null if its not found."
5289 << endl;
5290 indent(out) << " */" << endl;
5291 indent(out) << java_nullable_annotation() << endl;
5292 indent(out) << "public static _Fields findByThriftId(int fieldId) {" << endl;
5293 indent_up();
5294 indent(out) << "switch(fieldId) {" << endl;
5295 indent_up();
5296
5297 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
5298 indent(out) << "case " << (*m_iter)->get_key() << ": // "
5299 << constant_name((*m_iter)->get_name()) << endl;
5300 indent(out) << " return " << constant_name((*m_iter)->get_name()) << ";" << endl;
5301 }
5302
5303 indent(out) << "default:" << endl;
5304 indent(out) << " return null;" << endl;
5305
5306 indent_down();
5307 indent(out) << "}" << endl;
5308
5309 indent_down();
5310 indent(out) << "}" << endl << endl;
5311
5312 indent(out) << "/**" << endl;
5313 indent(out) << " * Find the _Fields constant that matches fieldId, throwing an exception" << endl;
5314 indent(out) << " * if it is not found." << endl;
5315 indent(out) << " */" << endl;
5316 indent(out) << "public static _Fields findByThriftIdOrThrow(int fieldId) {" << endl;
5317 indent(out) << " _Fields fields = findByThriftId(fieldId);" << endl;
5318 indent(out) << " if (fields == null) throw new java.lang.IllegalArgumentException(\"Field \" + "
5319 "fieldId + "
5320 "\" doesn't exist!\");"
5321 << endl;
5322 indent(out) << " return fields;" << endl;
5323 indent(out) << "}" << endl << endl;
5324
5325 indent(out) << "/**" << endl;
5326 indent(out) << " * Find the _Fields constant that matches name, or null if its not found."
5327 << endl;
5328 indent(out) << " */" << endl;
5329 indent(out) << java_nullable_annotation() << endl;
5330 indent(out) << "public static _Fields findByName(java.lang.String name) {" << endl;
5331 indent(out) << " return byName.get(name);" << endl;
5332 indent(out) << "}" << endl << endl;
5333
5334 indent(out) << "private final short _thriftId;" << endl;
5335 indent(out) << "private final java.lang.String _fieldName;" << endl << endl;
5336
5337 indent(out) << "_Fields(short thriftId, java.lang.String fieldName) {" << endl;
5338 indent(out) << " _thriftId = thriftId;" << endl;
5339 indent(out) << " _fieldName = fieldName;" << endl;
5340 indent(out) << "}" << endl << endl;
5341
5342 indent(out) << java_override_annotation() << endl;
5343 indent(out) << "public short getThriftFieldId() {" << endl;
5344 indent(out) << " return _thriftId;" << endl;
5345 indent(out) << "}" << endl << endl;
5346
5347 indent(out) << java_override_annotation() << endl;
5348 indent(out) << "public java.lang.String getFieldName() {" << endl;
5349 indent(out) << " return _fieldName;" << endl;
5350 indent(out) << "}" << endl;
5351
5352 indent_down();
5353
5354 indent(out) << "}" << endl;
5355 }
5356
needs_isset(t_struct * tstruct,std::string * outPrimitiveType)5357 t_java_generator::isset_type t_java_generator::needs_isset(t_struct* tstruct,
5358 std::string* outPrimitiveType) {
5359 const vector<t_field*>& members = tstruct->get_members();
5360 vector<t_field*>::const_iterator m_iter;
5361
5362 int count = 0;
5363 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
5364 if (!type_can_be_null(get_true_type((*m_iter)->get_type()))) {
5365 count++;
5366 }
5367 }
5368 if (count == 0) {
5369 return ISSET_NONE;
5370 } else if (count <= 64) {
5371 if (outPrimitiveType != nullptr) {
5372 if (count <= 8)
5373 *outPrimitiveType = "byte";
5374 else if (count <= 16)
5375 *outPrimitiveType = "short";
5376 else if (count <= 32)
5377 *outPrimitiveType = "int";
5378 else if (count <= 64)
5379 *outPrimitiveType = "long";
5380 }
5381 return ISSET_PRIMITIVE;
5382 } else {
5383 return ISSET_BITSET;
5384 }
5385 }
5386
generate_java_struct_clear(std::ostream & out,t_struct * tstruct)5387 void t_java_generator::generate_java_struct_clear(std::ostream& out, t_struct* tstruct) {
5388 indent(out) << java_override_annotation() << endl;
5389 indent(out) << "public void clear() {" << endl;
5390
5391 indent_up();
5392 for (auto field : tstruct->get_members()) {
5393 t_type* t = get_true_type(field->get_type());
5394
5395 if (field->get_value() != nullptr) {
5396 print_const_value(out, "this." + make_valid_java_identifier(field->get_name()), t, field->get_value(), true, true);
5397 continue;
5398 }
5399
5400 if (type_can_be_null(t)) {
5401 if (reuse_objects_ && (t->is_container() || t->is_struct())) {
5402 indent(out) << "if (this." << make_valid_java_identifier(field->get_name()) << " != null) {" << endl;
5403 indent_up();
5404 indent(out) << "this." << make_valid_java_identifier(field->get_name()) << ".clear();" << endl;
5405 indent_down();
5406 indent(out) << "}" << endl;
5407 } else {
5408 indent(out) << "this." << make_valid_java_identifier(field->get_name()) << " = null;" << endl;
5409 }
5410 continue;
5411 }
5412
5413 // must be a base type
5414 // means it also needs to be explicitly unset
5415 indent(out) << "set" << get_cap_name(field->get_name()) << get_cap_name("isSet") << "(false);"
5416 << endl;
5417 t_base_type* base_type = (t_base_type*)t;
5418
5419 switch (base_type->get_base()) {
5420 case t_base_type::TYPE_I8:
5421 case t_base_type::TYPE_I16:
5422 case t_base_type::TYPE_I32:
5423 case t_base_type::TYPE_I64:
5424 indent(out) << "this." << make_valid_java_identifier(field->get_name()) << " = 0;" << endl;
5425 break;
5426 case t_base_type::TYPE_DOUBLE:
5427 indent(out) << "this." << make_valid_java_identifier(field->get_name()) << " = 0.0;" << endl;
5428 break;
5429 case t_base_type::TYPE_BOOL:
5430 indent(out) << "this." << make_valid_java_identifier(field->get_name()) << " = false;" << endl;
5431 break;
5432 default:
5433 throw "unsupported type: " + base_type->get_name() + " for field " + field->get_name();
5434 }
5435 }
5436 indent_down();
5437
5438 indent(out) << "}" << endl << endl;
5439 }
5440
5441 // generates java method to serialize (in the Java sense) the object
generate_java_struct_write_object(ostream & out,t_struct * tstruct)5442 void t_java_generator::generate_java_struct_write_object(ostream& out, t_struct* tstruct) {
5443 (void)tstruct;
5444 indent(out)
5445 << "private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {"
5446 << endl;
5447 indent(out) << " try {" << endl;
5448 indent(out) << " write(new org.apache.thrift.protocol.TCompactProtocol(new "
5449 "org.apache.thrift.transport.TIOStreamTransport(out)));"
5450 << endl;
5451 indent(out) << " } catch (org.apache.thrift.TException te) {" << endl;
5452 indent(out) << " throw new java.io.IOException(te" << (android_legacy_ ? ".getMessage()" : "")
5453 << ");" << endl;
5454 indent(out) << " }" << endl;
5455 indent(out) << "}" << endl << endl;
5456 }
5457
5458 // generates java method to serialize (in the Java sense) the object
generate_java_struct_read_object(ostream & out,t_struct * tstruct)5459 void t_java_generator::generate_java_struct_read_object(ostream& out, t_struct* tstruct) {
5460 indent(out) << "private void readObject(java.io.ObjectInputStream in) throws "
5461 "java.io.IOException, java.lang.ClassNotFoundException {"
5462 << endl;
5463 indent(out) << " try {" << endl;
5464 if (!tstruct->is_union()) {
5465 switch (needs_isset(tstruct)) {
5466 case ISSET_NONE:
5467 break;
5468 case ISSET_PRIMITIVE:
5469 indent(out) << " // it doesn't seem like you should have to do this, but java "
5470 "serialization is wacky, and doesn't call the default constructor."
5471 << endl;
5472 indent(out) << " __isset_bitfield = 0;" << endl;
5473 break;
5474 case ISSET_BITSET:
5475 indent(out) << " // it doesn't seem like you should have to do this, but java "
5476 "serialization is wacky, and doesn't call the default constructor."
5477 << endl;
5478 indent(out) << " __isset_bit_vector = new java.util.BitSet(1);" << endl;
5479 break;
5480 }
5481 }
5482 indent(out) << " read(new org.apache.thrift.protocol.TCompactProtocol(new "
5483 "org.apache.thrift.transport.TIOStreamTransport(in)));"
5484 << endl;
5485 indent(out) << " } catch (org.apache.thrift.TException te) {" << endl;
5486 indent(out) << " throw new java.io.IOException(te" << (android_legacy_ ? ".getMessage()" : "")
5487 << ");" << endl;
5488 indent(out) << " }" << endl;
5489 indent(out) << "}" << endl << endl;
5490 }
5491
generate_standard_reader(ostream & out,t_struct * tstruct)5492 void t_java_generator::generate_standard_reader(ostream& out, t_struct* tstruct) {
5493 indent(out) << java_override_annotation() << endl;
5494 indent(out) << "public void read(org.apache.thrift.protocol.TProtocol iprot, "
5495 << make_valid_java_identifier(tstruct->get_name()) << " struct) throws org.apache.thrift.TException {" << endl;
5496 indent_up();
5497
5498 const vector<t_field*>& fields = tstruct->get_members();
5499 vector<t_field*>::const_iterator f_iter;
5500
5501 // Declare stack tmp variables and read struct header
5502 out << indent() << "org.apache.thrift.protocol.TField schemeField;" << endl
5503 << indent() << "iprot.readStructBegin();" << endl;
5504
5505 // Loop over reading in fields
5506 indent(out) << "while (true)" << endl;
5507 scope_up(out);
5508
5509 // Read beginning field marker
5510 indent(out) << "schemeField = iprot.readFieldBegin();" << endl;
5511
5512 // Check for field STOP marker and break
5513 indent(out) << "if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { " << endl;
5514 indent_up();
5515 indent(out) << "break;" << endl;
5516 indent_down();
5517 indent(out) << "}" << endl;
5518
5519 // Switch statement on the field we are reading
5520 indent(out) << "switch (schemeField.id) {" << endl;
5521
5522 indent_up();
5523
5524 // Generate deserialization code for known cases
5525 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
5526 indent(out) << "case " << (*f_iter)->get_key() << ": // "
5527 << constant_name((*f_iter)->get_name()) << endl;
5528 indent_up();
5529 indent(out) << "if (schemeField.type == " << type_to_enum((*f_iter)->get_type()) << ") {"
5530 << endl;
5531 indent_up();
5532
5533 generate_deserialize_field(out, *f_iter, "struct.", true);
5534 indent(out) << "struct."
5535 << "set" << get_cap_name((*f_iter)->get_name()) << get_cap_name("isSet")
5536 << "(true);" << endl;
5537 indent_down();
5538 out << indent() << "} else { " << endl
5539 << indent() << " org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);"
5540 << endl
5541 << indent() << "}" << endl
5542 << indent() << "break;" << endl;
5543 indent_down();
5544 }
5545
5546 indent(out) << "default:" << endl;
5547 indent(out) << " org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);"
5548 << endl;
5549
5550 indent_down();
5551 indent(out) << "}" << endl;
5552
5553 // Read field end marker
5554 indent(out) << "iprot.readFieldEnd();" << endl;
5555
5556 indent_down();
5557 indent(out) << "}" << endl;
5558
5559 out << indent() << "iprot.readStructEnd();" << endl;
5560
5561 // in non-beans style, check for required fields of primitive type
5562 // (which can be checked here but not in the general validate method)
5563 if (!bean_style_) {
5564 out << endl
5565 << indent()
5566 << "// check for required fields of primitive type, which can't be "
5567 "checked in the validate method"
5568 << endl;
5569 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
5570 if ((*f_iter)->get_req() == t_field::T_REQUIRED && !type_can_be_null((*f_iter)->get_type())) {
5571 out << indent() << "if (!struct." << generate_isset_check(*f_iter) << ") {" << endl
5572 << indent()
5573 << " throw new org.apache.thrift.protocol.TProtocolException(\"Required field '"
5574 << (*f_iter)->get_name()
5575 << "' was not found in serialized data! Struct: \" + toString());" << endl
5576 << indent() << "}" << endl;
5577 }
5578 }
5579 }
5580
5581 // performs various checks (e.g. check that all required fields are set)
5582 indent(out) << "struct.validate();" << endl;
5583
5584 indent_down();
5585 out << indent() << "}" << endl;
5586 }
5587
generate_standard_writer(ostream & out,t_struct * tstruct,bool is_result)5588 void t_java_generator::generate_standard_writer(ostream& out, t_struct* tstruct, bool is_result) {
5589 indent_up();
5590 indent(out) << java_override_annotation() << endl;
5591 indent(out) << "public void write(org.apache.thrift.protocol.TProtocol oprot, "
5592 << make_valid_java_identifier(tstruct->get_name()) << " struct) throws org.apache.thrift.TException {" << endl;
5593 indent_up();
5594 const vector<t_field*>& fields = tstruct->get_sorted_members();
5595 vector<t_field*>::const_iterator f_iter;
5596
5597 // performs various checks (e.g. check that all required fields are set)
5598 indent(out) << "struct.validate();" << endl << endl;
5599
5600 indent(out) << "oprot.writeStructBegin(STRUCT_DESC);" << endl;
5601
5602 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
5603 bool null_allowed = type_can_be_null((*f_iter)->get_type());
5604 if (null_allowed) {
5605 out << indent() << "if (struct." << make_valid_java_identifier((*f_iter)->get_name()) << " != null) {" << endl;
5606 indent_up();
5607 }
5608 bool optional = ((*f_iter)->get_req() == t_field::T_OPTIONAL) || (is_result && !null_allowed);
5609 if (optional) {
5610 indent(out) << "if ("
5611 << "struct." << generate_isset_check((*f_iter)) << ") {" << endl;
5612 indent_up();
5613 }
5614
5615 indent(out) << "oprot.writeFieldBegin(" << constant_name((*f_iter)->get_name())
5616 << "_FIELD_DESC);" << endl;
5617
5618 // Write field contents
5619 generate_serialize_field(out, *f_iter, "struct.", "", true);
5620
5621 // Write field closer
5622 indent(out) << "oprot.writeFieldEnd();" << endl;
5623
5624 if (optional) {
5625 indent_down();
5626 indent(out) << "}" << endl;
5627 }
5628 if (null_allowed) {
5629 indent_down();
5630 indent(out) << "}" << endl;
5631 }
5632 }
5633 // Write the struct map
5634 out << indent() << "oprot.writeFieldStop();" << endl
5635 << indent() << "oprot.writeStructEnd();" << endl;
5636
5637 indent_down();
5638 out << indent() << "}" << endl << endl;
5639 indent_down();
5640 }
5641
generate_java_struct_standard_scheme(ostream & out,t_struct * tstruct,bool is_result)5642 void t_java_generator::generate_java_struct_standard_scheme(ostream& out,
5643 t_struct* tstruct,
5644 bool is_result) {
5645 indent(out) << "private static class " << tstruct->get_name()
5646 << "StandardSchemeFactory implements org.apache.thrift.scheme.SchemeFactory {"
5647 << endl;
5648 indent_up();
5649 indent(out) << java_override_annotation() << endl;
5650 indent(out) << "public " << tstruct->get_name() << "StandardScheme getScheme() {" << endl;
5651 indent_up();
5652 indent(out) << "return new " << tstruct->get_name() << "StandardScheme();" << endl;
5653 indent_down();
5654 indent(out) << "}" << endl;
5655 indent_down();
5656 indent(out) << "}" << endl << endl;
5657
5658 out << indent() << "private static class " << tstruct->get_name()
5659 << "StandardScheme extends org.apache.thrift.scheme.StandardScheme<" << make_valid_java_identifier(tstruct->get_name())
5660 << "> {" << endl
5661 << endl;
5662 indent_up();
5663 generate_standard_reader(out, tstruct);
5664 indent_down();
5665 out << endl;
5666 generate_standard_writer(out, tstruct, is_result);
5667
5668 out << indent() << "}" << endl << endl;
5669 }
5670
generate_java_struct_tuple_reader(ostream & out,t_struct * tstruct)5671 void t_java_generator::generate_java_struct_tuple_reader(ostream& out, t_struct* tstruct) {
5672 indent(out) << java_override_annotation() << endl;
5673 indent(out) << "public void read(org.apache.thrift.protocol.TProtocol prot, "
5674 << make_valid_java_identifier(tstruct->get_name()) << " struct) throws org.apache.thrift.TException {" << endl;
5675 indent_up();
5676 indent(out) << "org.apache.thrift.protocol.TTupleProtocol iprot = "
5677 "(org.apache.thrift.protocol.TTupleProtocol) prot;"
5678 << endl;
5679 int optional_count = 0;
5680 const vector<t_field*>& fields = tstruct->get_members();
5681 vector<t_field*>::const_iterator f_iter;
5682 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
5683 if ((*f_iter)->get_req() == t_field::T_OPTIONAL
5684 || (*f_iter)->get_req() == t_field::T_OPT_IN_REQ_OUT) {
5685 optional_count++;
5686 }
5687 if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
5688 generate_deserialize_field(out, (*f_iter), "struct.", false);
5689 indent(out) << "struct.set" << get_cap_name((*f_iter)->get_name()) << get_cap_name("isSet")
5690 << "(true);" << endl;
5691 }
5692 }
5693 if (optional_count > 0) {
5694 indent(out) << "java.util.BitSet incoming = iprot.readBitSet(" << optional_count << ");"
5695 << endl;
5696 int i = 0;
5697 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
5698 if ((*f_iter)->get_req() == t_field::T_OPTIONAL
5699 || (*f_iter)->get_req() == t_field::T_OPT_IN_REQ_OUT) {
5700 indent(out) << "if (incoming.get(" << i << ")) {" << endl;
5701 indent_up();
5702 generate_deserialize_field(out, (*f_iter), "struct.", false);
5703 indent(out) << "struct.set" << get_cap_name((*f_iter)->get_name()) << get_cap_name("isSet")
5704 << "(true);" << endl;
5705 indent_down();
5706 indent(out) << "}" << endl;
5707 i++;
5708 }
5709 }
5710 }
5711 indent_down();
5712 indent(out) << "}" << endl;
5713 }
5714
generate_java_struct_tuple_writer(ostream & out,t_struct * tstruct)5715 void t_java_generator::generate_java_struct_tuple_writer(ostream& out, t_struct* tstruct) {
5716 indent(out) << java_override_annotation() << endl;
5717 indent(out) << "public void write(org.apache.thrift.protocol.TProtocol prot, "
5718 << make_valid_java_identifier(tstruct->get_name()) << " struct) throws org.apache.thrift.TException {" << endl;
5719 indent_up();
5720 indent(out) << "org.apache.thrift.protocol.TTupleProtocol oprot = "
5721 "(org.apache.thrift.protocol.TTupleProtocol) prot;"
5722 << endl;
5723
5724 const vector<t_field*>& fields = tstruct->get_members();
5725 vector<t_field*>::const_iterator f_iter;
5726 bool has_optional = false;
5727 int optional_count = 0;
5728 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
5729 if ((*f_iter)->get_req() == t_field::T_OPTIONAL
5730 || (*f_iter)->get_req() == t_field::T_OPT_IN_REQ_OUT) {
5731 optional_count++;
5732 has_optional = true;
5733 }
5734 if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
5735 generate_serialize_field(out, (*f_iter), "struct.", "", false);
5736 }
5737 }
5738 if (has_optional) {
5739 indent(out) << "java.util.BitSet optionals = new java.util.BitSet();" << endl;
5740 int i = 0;
5741 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
5742 if ((*f_iter)->get_req() == t_field::T_OPTIONAL
5743 || (*f_iter)->get_req() == t_field::T_OPT_IN_REQ_OUT) {
5744 indent(out) << "if (struct." << generate_isset_check((*f_iter)) << ") {" << endl;
5745 indent_up();
5746 indent(out) << "optionals.set(" << i << ");" << endl;
5747 indent_down();
5748 indent(out) << "}" << endl;
5749 i++;
5750 }
5751 }
5752
5753 indent(out) << "oprot.writeBitSet(optionals, " << optional_count << ");" << endl;
5754 int j = 0;
5755 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
5756 if ((*f_iter)->get_req() == t_field::T_OPTIONAL
5757 || (*f_iter)->get_req() == t_field::T_OPT_IN_REQ_OUT) {
5758 indent(out) << "if (struct." << generate_isset_check(*f_iter) << ") {" << endl;
5759 indent_up();
5760 generate_serialize_field(out, (*f_iter), "struct.", "", false);
5761 indent_down();
5762 indent(out) << "}" << endl;
5763 j++;
5764 }
5765 }
5766 }
5767 indent_down();
5768 indent(out) << "}" << endl;
5769 }
5770
generate_java_struct_tuple_scheme(ostream & out,t_struct * tstruct)5771 void t_java_generator::generate_java_struct_tuple_scheme(ostream& out, t_struct* tstruct) {
5772 indent(out) << "private static class " << tstruct->get_name()
5773 << "TupleSchemeFactory implements org.apache.thrift.scheme.SchemeFactory {" << endl;
5774 indent_up();
5775 indent(out) << java_override_annotation() << endl;
5776 indent(out) << "public " << tstruct->get_name() << "TupleScheme getScheme() {" << endl;
5777 indent_up();
5778 indent(out) << "return new " << tstruct->get_name() << "TupleScheme();" << endl;
5779 indent_down();
5780 indent(out) << "}" << endl;
5781 indent_down();
5782 indent(out) << "}" << endl << endl;
5783 out << indent() << "private static class " << tstruct->get_name()
5784 << "TupleScheme extends org.apache.thrift.scheme.TupleScheme<" << make_valid_java_identifier(tstruct->get_name()) << "> {"
5785 << endl
5786 << endl;
5787 indent_up();
5788 generate_java_struct_tuple_writer(out, tstruct);
5789 out << endl;
5790 generate_java_struct_tuple_reader(out, tstruct);
5791 indent_down();
5792 out << indent() << "}" << endl << endl;
5793 }
5794
generate_java_scheme_lookup(ostream & out)5795 void t_java_generator::generate_java_scheme_lookup(ostream& out) {
5796 indent(out) << "private static <S extends org.apache.thrift.scheme.IScheme> S scheme("
5797 << "org.apache.thrift.protocol.TProtocol proto) {" << endl;
5798 indent_up();
5799 indent(out) << "return (org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) "
5800 << "? STANDARD_SCHEME_FACTORY "
5801 << ": TUPLE_SCHEME_FACTORY"
5802 << ").getScheme();" << endl;
5803 indent_down();
5804 indent(out) << "}" << endl;
5805 }
5806
generate_javax_generated_annotation(ostream & out)5807 void t_java_generator::generate_javax_generated_annotation(ostream& out) {
5808 time_t seconds = time(nullptr);
5809 struct tm* now = localtime(&seconds);
5810 indent(out) << "@javax.annotation.Generated(value = \"" << autogen_summary() << "\"";
5811 if (undated_generated_annotations_) {
5812 out << ")" << endl;
5813 } else {
5814 indent(out) << ", date = \"" << (now->tm_year + 1900) << "-" << setfill('0') << setw(2)
5815 << (now->tm_mon + 1) << "-" << setfill('0') << setw(2) << now->tm_mday << "\")"
5816 << endl;
5817 }
5818 }
5819
display_name() const5820 std::string t_java_generator::display_name() const {
5821 return "Java";
5822 }
5823
5824
5825 THRIFT_REGISTER_GENERATOR(
5826 java,
5827 "Java",
5828 " beans: Members will be private, and setter methods will return void.\n"
5829 " private_members: Members will be private, but setter methods will return 'this' like usual.\n"
5830 " private-members: Same as 'private_members' (deprecated).\n"
5831 " nocamel: Do not use CamelCase field accessors with beans.\n"
5832 " fullcamel: Convert underscored_accessor_or_service_names to camelCase.\n"
5833 " android: Generated structures are Parcelable.\n"
5834 " android_legacy: Do not use java.io.IOException(throwable) (available for Android 2.3 and above).\n"
5835 " option_type=[thrift|jdk8]:\n"
5836 " thrift: wrap optional fields in thrift Option type.\n"
5837 " jdk8: Wrap optional fields in JDK8+ Option type.\n"
5838 " If the Option type is not specified, 'thrift' is used.\n"
5839 " rethrow_unhandled_exceptions:\n"
5840 " Enable rethrow of unhandled exceptions and let them propagate further. (Default behavior is to catch and log it.)\n"
5841 " java5: Generate Java 1.5 compliant code (includes android_legacy flag).\n"
5842 " future_iface: Generate CompletableFuture based iface based on async client.\n"
5843 " reuse_objects: Data objects will not be allocated, but existing instances will be used (read and write).\n"
5844 " reuse-objects: Same as 'reuse_objects' (deprecated).\n"
5845 " sorted_containers:\n"
5846 " Use TreeSet/TreeMap instead of HashSet/HashMap as a implementation of set/map.\n"
5847 " generated_annotations=[undated|suppress]:\n"
5848 " undated: suppress the date at @Generated annotations\n"
5849 " suppress: suppress @Generated annotations entirely\n"
5850 " unsafe_binaries: Do not copy ByteBuffers in constructors, getters, and setters.\n"
5851 " annotations_as_metadata:\n"
5852 " Include Thrift field annotations as metadata in the generated code.\n")
5853