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