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 <sstream>
21 #include <string>
22 #include <fstream>
23 #include <iostream>
24 #include <vector>
25 #include <cctype>
26 
27 #include <sys/stat.h>
28 #include <stdexcept>
29 
30 #include "thrift/platform.h"
31 #include "thrift/generate/t_oop_generator.h"
32 
33 using std::map;
34 using std::ostream;
35 using std::ostringstream;
36 using std::string;
37 using std::stringstream;
38 using std::vector;
39 
40 static const string endl = "\n"; // avoid ostream << std::endl flushes
41 
42 /**
43  * Java code generator.
44  *
45  */
46 class t_javame_generator : public t_oop_generator {
47 public:
t_javame_generator(t_program * program,const std::map<std::string,std::string> & parsed_options,const std::string & option_string)48   t_javame_generator(t_program* program,
49                      const std::map<std::string, std::string>& parsed_options,
50                      const std::string& option_string)
51     : t_oop_generator(program) {
52     (void)parsed_options;
53     (void)option_string;
54     std::map<std::string, std::string>::const_iterator iter;
55 
56     /* no options yet */
57     for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
58       throw "unknown option javame:" + iter->first;
59     }
60 
61     out_dir_base_ = "gen-javame";
62   }
63 
64   /**
65    * Init and close methods
66    */
67 
68   void init_generator() override;
69   void close_generator() override;
70   std::string display_name() const override;
71 
72   void generate_consts(std::vector<t_const*> consts) override;
73 
74   /**
75    * Program-level generation functions
76    */
77 
78   void generate_typedef(t_typedef* ttypedef) override;
79   void generate_enum(t_enum* tenum) override;
80   void generate_struct(t_struct* tstruct) override;
81   void generate_union(t_struct* tunion);
82   void generate_xception(t_struct* txception) override;
83   void generate_service(t_service* tservice) override;
84 
85   void print_const_value(std::ostream& out,
86                          std::string name,
87                          t_type* type,
88                          t_const_value* value,
89                          bool in_static,
90                          bool defval = false);
91   std::string render_const_value(std::ostream& out,
92                                  std::string name,
93                                  t_type* type,
94                                  t_const_value* value);
95 
96   /**
97    * Service-level generation functions
98    */
99 
100   void generate_java_struct(t_struct* tstruct, bool is_exception);
101 
102   void generate_java_struct_definition(std::ostream& out,
103                                        t_struct* tstruct,
104                                        bool is_xception = false,
105                                        bool in_class = false,
106                                        bool is_result = false);
107   void generate_java_struct_equality(std::ostream& out, t_struct* tstruct);
108   void generate_java_struct_compare_to(std::ostream& out, t_struct* tstruct);
109   void generate_java_struct_reader(std::ostream& out, t_struct* tstruct);
110   void generate_java_validator(std::ostream& out, t_struct* tstruct);
111   void generate_java_struct_result_writer(std::ostream& out, t_struct* tstruct);
112   void generate_java_struct_writer(std::ostream& out, t_struct* tstruct);
113   void generate_java_struct_tostring(std::ostream& out, t_struct* tstruct);
114   void generate_java_struct_clear(std::ostream& out, t_struct* tstruct);
115   void generate_field_value_meta_data(std::ostream& out, t_type* type);
116   std::string get_java_type_string(t_type* type);
117   void generate_reflection_setters(std::ostringstream& out,
118                                    t_type* type,
119                                    std::string field_name,
120                                    std::string cap_name);
121   void generate_reflection_getters(std::ostringstream& out,
122                                    t_type* type,
123                                    std::string field_name,
124                                    std::string cap_name);
125   void generate_generic_field_getters_setters(std::ostream& out, t_struct* tstruct);
126   void generate_java_bean_boilerplate(std::ostream& out, t_struct* tstruct);
127 
128   void generate_function_helpers(t_function* tfunction);
129   std::string get_cap_name(std::string name);
130   std::string generate_isset_check(t_field* field);
131   std::string generate_isset_check(std::string field);
132   void generate_isset_set(ostream& out, t_field* field);
133   std::string isset_field_id(t_field* field);
134 
135   void generate_primitive_service_interface(t_service* tservice);
136   void generate_service_interface(t_service* tservice);
137   void generate_service_helpers(t_service* tservice);
138   void generate_service_client(t_service* tservice);
139   void generate_service_server(t_service* tservice);
140   void generate_process_function(t_service* tservice, t_function* tfunction);
141 
142   void generate_java_union(t_struct* tstruct);
143   void generate_union_constructor(ostream& out, t_struct* tstruct);
144   void generate_union_getters_and_setters(ostream& out, t_struct* tstruct);
145   void generate_union_abstract_methods(ostream& out, t_struct* tstruct);
146   void generate_check_type(ostream& out, t_struct* tstruct);
147   void generate_read_value(ostream& out, t_struct* tstruct);
148   void generate_write_value(ostream& out, t_struct* tstruct);
149   void generate_get_field_desc(ostream& out, t_struct* tstruct);
150   void generate_get_struct_desc(ostream& out, t_struct* tstruct);
151   void generate_get_field_name(ostream& out, t_struct* tstruct);
152 
153   void generate_union_comparisons(ostream& out, t_struct* tstruct);
154   void generate_union_hashcode(ostream& out, t_struct* tstruct);
155 
156   /**
157    * Serialization constructs
158    */
159 
160   void generate_deserialize_field(std::ostream& out, t_field* tfield, std::string prefix = "");
161 
162   void generate_deserialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
163 
164   void generate_deserialize_container(std::ostream& out, t_type* ttype, std::string prefix = "");
165 
166   void generate_deserialize_set_element(std::ostream& out, t_set* tset, std::string prefix = "");
167 
168   void generate_deserialize_map_element(std::ostream& out, t_map* tmap, std::string prefix = "");
169 
170   void generate_deserialize_list_element(std::ostream& out,
171                                          t_list* tlist,
172                                          std::string prefix = "");
173 
174   void generate_serialize_field(std::ostream& out, t_field* tfield, std::string prefix = "");
175 
176   void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
177 
178   void generate_serialize_container(std::ostream& out, t_type* ttype, std::string prefix = "");
179 
180   void generate_serialize_map_element(std::ostream& out,
181                                       t_map* tmap,
182                                       std::string iter,
183                                       std::string map);
184 
185   void generate_serialize_set_element(std::ostream& out, t_set* tmap, std::string iter);
186 
187   void generate_serialize_list_element(std::ostream& out, t_list* tlist, std::string iter);
188 
189   void generate_java_doc(std::ostream& out, t_field* field) override;
190 
191   void generate_java_doc(std::ostream& out, t_doc* tdoc) override;
192 
193   void generate_java_doc(std::ostream& out, t_function* tdoc) override;
194 
195   void generate_java_docstring_comment(std::ostream& out, string contents) override;
196 
197   void generate_deep_copy_container(std::ostream& out,
198                                     std::string source_name_p1,
199                                     std::string source_name_p2,
200                                     std::string result_name,
201                                     t_type* type);
202   void generate_deep_copy_non_container(std::ostream& out,
203                                         std::string source_name,
204                                         std::string dest_name,
205                                         t_type* type);
206 
207   bool has_bit_vector(t_struct* tstruct);
208 
209   /**
210    * Helper rendering functions
211    */
212 
213   std::string java_package();
214   std::string java_type_imports();
215   std::string java_thrift_imports();
216   std::string type_name(t_type* ttype,
217                         bool in_container = false,
218                         bool in_init = false,
219                         bool skip_generic = false);
220   std::string base_type_name(t_base_type* tbase, bool in_container = false);
221   std::string declare_field(t_field* tfield, bool init = false);
222   std::string function_signature(t_function* tfunction, std::string prefix = "");
223   std::string argument_list(t_struct* tstruct, bool include_types = true);
224   std::string type_to_enum(t_type* ttype);
225   std::string get_enum_class_name(t_type* type) override;
226   void generate_struct_desc(ostream& out, t_struct* tstruct);
227   void generate_field_descs(ostream& out, t_struct* tstruct);
228   std::string box_type(t_type* type, string value);
229 
type_can_be_null(t_type * ttype)230   bool type_can_be_null(t_type* ttype) {
231     ttype = get_true_type(ttype);
232 
233     return ttype->is_container() || ttype->is_struct() || ttype->is_xception() || ttype->is_string()
234            || ttype->is_enum();
235   }
236 
237   std::string constant_name(std::string name);
238 
239 private:
240   /**
241    * File streams
242    */
243 
244   std::string package_name_;
245   ofstream_with_content_based_conditional_update f_service_;
246   std::string package_dir_;
247 };
248 
249 /**
250  * Prepares for file generation by opening up the necessary file output
251  * streams.
252  *
253  * @param tprogram The program to generate
254  */
init_generator()255 void t_javame_generator::init_generator() {
256   // Make output directory
257   MKDIR(get_out_dir().c_str());
258   package_name_ = program_->get_namespace("java");
259 
260   string dir = package_name_;
261   string subdir = get_out_dir();
262   string::size_type loc;
263   while ((loc = dir.find(".")) != string::npos) {
264     subdir = subdir + "/" + dir.substr(0, loc);
265     MKDIR(subdir.c_str());
266     dir = dir.substr(loc + 1);
267   }
268   if (dir.size() > 0) {
269     subdir = subdir + "/" + dir;
270     MKDIR(subdir.c_str());
271   }
272 
273   package_dir_ = subdir;
274 }
275 
276 /**
277  * Packages the generated file
278  *
279  * @return String of the package, i.e. "package org.apache.thriftdemo;"
280  */
java_package()281 string t_javame_generator::java_package() {
282   if (!package_name_.empty()) {
283     return string("package ") + package_name_ + ";\n\n";
284   }
285   return "";
286 }
287 
288 /**
289  * Prints standard java imports
290  *
291  * @return List of imports for Java types that are used in here
292  */
java_type_imports()293 string t_javame_generator::java_type_imports() {
294   return string() + "import java.util.Hashtable;\n" + "import java.util.Vector;\n"
295          + "import java.util.Enumeration;\n\n";
296 }
297 
298 /**
299  * Prints standard java imports
300  *
301  * @return List of imports necessary for thrift
302  */
java_thrift_imports()303 string t_javame_generator::java_thrift_imports() {
304   return string() + "import org.apache.thrift.*;\n" + "import org.apache.thrift.meta_data.*;\n"
305          + "import org.apache.thrift.transport.*;\n" + "import org.apache.thrift.protocol.*;\n\n";
306 }
307 
308 /**
309  * Nothing in Java
310  */
close_generator()311 void t_javame_generator::close_generator() {
312 }
313 
314 /**
315  * Generates a typedef. This is not done in Java, since it does
316  * not support arbitrary name replacements, and it'd be a wacky waste
317  * of overhead to make wrapper classes.
318  *
319  * @param ttypedef The type definition
320  */
generate_typedef(t_typedef * ttypedef)321 void t_javame_generator::generate_typedef(t_typedef* ttypedef) {
322   (void)ttypedef;
323 }
324 
325 /**
326  * Enums are a class with a set of static constants.
327  *
328  * @param tenum The enumeration
329  */
generate_enum(t_enum * tenum)330 void t_javame_generator::generate_enum(t_enum* tenum) {
331   // Make output file
332   string f_enum_name = package_dir_ + "/" + (tenum->get_name()) + ".java";
333   ofstream_with_content_based_conditional_update f_enum;
334   f_enum.open(f_enum_name.c_str());
335 
336   // Comment and package it
337   f_enum << autogen_comment() << java_package();
338 
339   generate_java_doc(f_enum, tenum);
340   indent(f_enum) << "public class " << tenum->get_name() << " implements org.apache.thrift.TEnum ";
341   scope_up(f_enum);
342   f_enum << endl;
343 
344   vector<t_enum_value*> constants = tenum->get_constants();
345   vector<t_enum_value*>::iterator c_iter;
346   for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
347     int value = (*c_iter)->get_value();
348     generate_java_doc(f_enum, *c_iter);
349     indent(f_enum) << "public static final " << tenum->get_name() << " " << (*c_iter)->get_name()
350                    << " = new " << tenum->get_name() << "(" << value << ");" << endl;
351   }
352   f_enum << endl;
353 
354   // Field for thriftCode
355   indent(f_enum) << "private final int value;" << endl << endl;
356 
357   indent(f_enum) << "private " << tenum->get_name() << "(int value) {" << endl;
358   indent(f_enum) << "  this.value = value;" << endl;
359   indent(f_enum) << "}" << endl << endl;
360 
361   indent(f_enum) << "/**" << endl;
362   indent(f_enum) << " * Get the integer value of this enum value, as defined in the Thrift IDL."
363                  << endl;
364   indent(f_enum) << " */" << endl;
365   indent(f_enum) << "public int getValue() {" << endl;
366   indent(f_enum) << "  return value;" << endl;
367   indent(f_enum) << "}" << endl << endl;
368 
369   indent(f_enum) << "/**" << endl;
370   indent(f_enum) << " * Find a the enum type by its integer value, as defined in the Thrift IDL."
371                  << endl;
372   indent(f_enum) << " * @return null if the value is not found." << endl;
373   indent(f_enum) << " */" << endl;
374   indent(f_enum) << "public static " + tenum->get_name() + " findByValue(int value) { " << endl;
375 
376   indent_up();
377 
378   indent(f_enum) << "switch (value) {" << endl;
379   indent_up();
380 
381   for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
382     int value = (*c_iter)->get_value();
383     indent(f_enum) << "case " << value << ":" << endl;
384     indent(f_enum) << "  return " << (*c_iter)->get_name() << ";" << endl;
385   }
386 
387   indent(f_enum) << "default:" << endl;
388   indent(f_enum) << "  return null;" << endl;
389 
390   indent_down();
391 
392   indent(f_enum) << "}" << endl;
393 
394   indent_down();
395 
396   indent(f_enum) << "}" << endl;
397 
398   scope_down(f_enum);
399 
400   f_enum.close();
401 }
402 
403 /**
404  * Generates a class that holds all the constants.
405  */
generate_consts(std::vector<t_const * > consts)406 void t_javame_generator::generate_consts(std::vector<t_const*> consts) {
407   if (consts.empty()) {
408     return;
409   }
410 
411   string f_consts_name = package_dir_ + "/" + program_name_ + "Constants.java";
412   ofstream_with_content_based_conditional_update f_consts;
413   f_consts.open(f_consts_name.c_str());
414 
415   // Print header
416   f_consts << autogen_comment() << java_package() << java_type_imports();
417 
418   f_consts << "public class " << program_name_ << "Constants {" << endl << endl;
419   indent_up();
420   vector<t_const*>::iterator c_iter;
421   for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
422     print_const_value(f_consts,
423                       (*c_iter)->get_name(),
424                       (*c_iter)->get_type(),
425                       (*c_iter)->get_value(),
426                       false);
427   }
428   indent_down();
429   indent(f_consts) << "}" << endl;
430   f_consts.close();
431 }
432 
433 /**
434  * Prints the value of a constant with the given type. Note that type checking
435  * is NOT performed in this function as it is always run beforehand using the
436  * validate_types method in main.cc
437  */
print_const_value(std::ostream & out,string name,t_type * type,t_const_value * value,bool in_static,bool defval)438 void t_javame_generator::print_const_value(std::ostream& out,
439                                            string name,
440                                            t_type* type,
441                                            t_const_value* value,
442                                            bool in_static,
443                                            bool defval) {
444   type = get_true_type(type);
445 
446   indent(out);
447   if (!defval) {
448     out << (in_static ? "" : "public static final ") << type_name(type) << " ";
449   }
450   if (type->is_base_type()) {
451     string v2 = render_const_value(out, name, type, value);
452     out << name << " = " << v2 << ";" << endl << endl;
453   } else if (type->is_enum()) {
454     out << name << " = " << render_const_value(out, name, type, value) << ";" << endl << endl;
455   } else if (type->is_struct() || type->is_xception()) {
456     const vector<t_field*>& fields = ((t_struct*)type)->get_members();
457     vector<t_field*>::const_iterator f_iter;
458     const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
459     map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
460     out << name << " = new " << type_name(type, false, true) << "();" << endl;
461     if (!in_static) {
462       indent(out) << "static {" << endl;
463       indent_up();
464     }
465     for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
466       t_type* field_type = nullptr;
467       for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
468         if ((*f_iter)->get_name() == v_iter->first->get_string()) {
469           field_type = (*f_iter)->get_type();
470         }
471       }
472       if (field_type == nullptr) {
473         throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
474       }
475       string val = render_const_value(out, name, field_type, v_iter->second);
476       indent(out) << name << ".";
477       std::string cap_name = get_cap_name(v_iter->first->get_string());
478       out << "set" << cap_name << "(" << val << ");" << endl;
479     }
480     if (!in_static) {
481       indent_down();
482       indent(out) << "}" << endl;
483     }
484     out << endl;
485   } else if (type->is_map()) {
486     out << name << " = new " << type_name(type, false, true) << "();" << endl;
487     if (!in_static) {
488       indent(out) << "static {" << endl;
489       indent_up();
490     }
491     t_type* ktype = ((t_map*)type)->get_key_type();
492     t_type* vtype = ((t_map*)type)->get_val_type();
493     const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
494     map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
495     for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
496       string key = render_const_value(out, name, ktype, v_iter->first);
497       string val = render_const_value(out, name, vtype, v_iter->second);
498       indent(out) << name << ".put(" << box_type(ktype, key) << ", " << box_type(vtype, val) << ");"
499                   << endl;
500     }
501     if (!in_static) {
502       indent_down();
503       indent(out) << "}" << endl;
504     }
505     out << endl;
506   } else if (type->is_list() || type->is_set()) {
507     out << name << " = new " << type_name(type, false, true) << "();" << endl;
508     if (!in_static) {
509       indent(out) << "static {" << endl;
510       indent_up();
511     }
512     t_type* etype;
513     if (type->is_list()) {
514       etype = ((t_list*)type)->get_elem_type();
515     } else {
516       etype = ((t_set*)type)->get_elem_type();
517     }
518     const vector<t_const_value*>& val = value->get_list();
519     vector<t_const_value*>::const_iterator v_iter;
520     for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
521       string val = render_const_value(out, name, etype, *v_iter);
522       if (type->is_list()) {
523         indent(out) << name << ".addElement(" << box_type(etype, val) << ");" << endl;
524       } else {
525         indent(out) << name << ".put(" << box_type(etype, val) << ", " << box_type(etype, val)
526                     << ");" << endl;
527       }
528     }
529     if (!in_static) {
530       indent_down();
531       indent(out) << "}" << endl;
532     }
533     out << endl;
534   } else {
535     throw "compiler error: no const of type " + type->get_name();
536   }
537 }
538 
render_const_value(ostream & out,string name,t_type * type,t_const_value * value)539 string t_javame_generator::render_const_value(ostream& out,
540                                               string name,
541                                               t_type* type,
542                                               t_const_value* value) {
543   (void)name;
544   type = get_true_type(type);
545   std::ostringstream render;
546 
547   if (type->is_base_type()) {
548     t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
549     switch (tbase) {
550     case t_base_type::TYPE_STRING:
551       render << '"' << get_escaped_string(value) << '"';
552       break;
553     case t_base_type::TYPE_BOOL:
554       render << ((value->get_integer() > 0) ? "true" : "false");
555       break;
556     case t_base_type::TYPE_I8:
557       render << "(byte)" << value->get_integer();
558       break;
559     case t_base_type::TYPE_I16:
560       render << "(short)" << value->get_integer();
561       break;
562     case t_base_type::TYPE_I32:
563       render << value->get_integer();
564       break;
565     case t_base_type::TYPE_I64:
566       render << value->get_integer() << "L";
567       break;
568     case t_base_type::TYPE_DOUBLE:
569       if (value->get_type() == t_const_value::CV_INTEGER) {
570         render << "(double)" << value->get_integer();
571       } else {
572         render << value->get_double();
573       }
574       break;
575     default:
576       throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
577     }
578   } else if (type->is_enum()) {
579     render << type_name(type, false, false) << "." << value->get_identifier();
580   } else {
581     string t = tmp("tmp");
582     print_const_value(out, t, type, value, true);
583     render << t;
584   }
585 
586   return render.str();
587 }
588 
box_type(t_type * type,string value)589 string t_javame_generator::box_type(t_type* type, string value) {
590   if (type->is_base_type()) {
591     switch (((t_base_type*)type)->get_base()) {
592     case t_base_type::TYPE_BOOL:
593       return "new Boolean(" + value + ")";
594     case t_base_type::TYPE_I8:
595       return "new Byte(" + value + ")";
596     case t_base_type::TYPE_I16:
597       return "new Short(" + value + ")";
598     case t_base_type::TYPE_I32:
599       return "new Integer(" + value + ")";
600     case t_base_type::TYPE_I64:
601       return "new Long(" + value + ")";
602     case t_base_type::TYPE_DOUBLE:
603       return "new Double(" + value + ")";
604     default:
605       break;
606     }
607   }
608   return value;
609 }
610 
611 /**
612  * Generates a struct definition for a thrift data type. This will be a TBase
613  * implementor.
614  *
615  * @param tstruct The struct definition
616  */
generate_struct(t_struct * tstruct)617 void t_javame_generator::generate_struct(t_struct* tstruct) {
618   if (tstruct->is_union()) {
619     generate_java_union(tstruct);
620   } else {
621     generate_java_struct(tstruct, false);
622   }
623 }
624 
625 /**
626  * Exceptions are structs, but they inherit from Exception
627  *
628  * @param tstruct The struct definition
629  */
generate_xception(t_struct * txception)630 void t_javame_generator::generate_xception(t_struct* txception) {
631   generate_java_struct(txception, true);
632 }
633 
634 /**
635  * Java struct definition.
636  *
637  * @param tstruct The struct definition
638  */
generate_java_struct(t_struct * tstruct,bool is_exception)639 void t_javame_generator::generate_java_struct(t_struct* tstruct, bool is_exception) {
640   // Make output file
641   string f_struct_name = package_dir_ + "/" + (tstruct->get_name()) + ".java";
642   ofstream_with_content_based_conditional_update f_struct;
643   f_struct.open(f_struct_name.c_str());
644 
645   f_struct << autogen_comment() << java_package() << java_type_imports() << java_thrift_imports();
646 
647   generate_java_struct_definition(f_struct, tstruct, is_exception);
648   f_struct.close();
649 }
650 
651 /**
652  * Java union definition.
653  *
654  * @param tstruct The struct definition
655  */
generate_java_union(t_struct * tstruct)656 void t_javame_generator::generate_java_union(t_struct* tstruct) {
657   // Make output file
658   string f_struct_name = package_dir_ + "/" + (tstruct->get_name()) + ".java";
659   ofstream_with_content_based_conditional_update f_struct;
660   f_struct.open(f_struct_name.c_str());
661 
662   f_struct << autogen_comment() << java_package() << java_type_imports() << java_thrift_imports();
663 
664   generate_java_doc(f_struct, tstruct);
665 
666   bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end());
667 
668   indent(f_struct) << "public " << (is_final ? "final " : "") << "class " << tstruct->get_name()
669                    << " extends TUnion ";
670 
671   scope_up(f_struct);
672 
673   generate_struct_desc(f_struct, tstruct);
674   generate_field_descs(f_struct, tstruct);
675 
676   f_struct << endl;
677 
678   generate_union_constructor(f_struct, tstruct);
679 
680   f_struct << endl;
681 
682   generate_union_abstract_methods(f_struct, tstruct);
683 
684   f_struct << endl;
685 
686   generate_union_getters_and_setters(f_struct, tstruct);
687 
688   f_struct << endl;
689 
690   generate_union_comparisons(f_struct, tstruct);
691 
692   f_struct << endl;
693 
694   generate_union_hashcode(f_struct, tstruct);
695 
696   f_struct << endl;
697 
698   scope_down(f_struct);
699 
700   f_struct.close();
701 }
702 
generate_union_constructor(ostream & out,t_struct * tstruct)703 void t_javame_generator::generate_union_constructor(ostream& out, t_struct* tstruct) {
704   indent(out) << "public " << type_name(tstruct) << "() {" << endl;
705   indent(out) << "  super();" << endl;
706   indent(out) << "}" << endl << endl;
707 
708   indent(out) << "public " << type_name(tstruct) << "(_Fields setField, Object value) {" << endl;
709   indent(out) << "  super(setField, value);" << endl;
710   indent(out) << "}" << endl << endl;
711 
712   indent(out) << "public " << type_name(tstruct) << "(" << type_name(tstruct) << " other) {"
713               << endl;
714   indent(out) << "  super(other);" << endl;
715   indent(out) << "}" << endl;
716 
717   indent(out) << "public " << tstruct->get_name() << " deepCopy() {" << endl;
718   indent(out) << "  return new " << tstruct->get_name() << "(this);" << endl;
719   indent(out) << "}" << endl << endl;
720 
721   // generate "constructors" for each field
722   const vector<t_field*>& members = tstruct->get_members();
723   vector<t_field*>::const_iterator m_iter;
724   for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
725     indent(out) << "public static " << type_name(tstruct) << " " << (*m_iter)->get_name() << "("
726                 << type_name((*m_iter)->get_type()) << " value) {" << endl;
727     indent(out) << "  " << type_name(tstruct) << " x = new " << type_name(tstruct) << "();" << endl;
728     indent(out) << "  x.set" << get_cap_name((*m_iter)->get_name()) << "(value);" << endl;
729     indent(out) << "  return x;" << endl;
730     indent(out) << "}" << endl << endl;
731   }
732 }
733 
generate_union_getters_and_setters(ostream & out,t_struct * tstruct)734 void t_javame_generator::generate_union_getters_and_setters(ostream& out, t_struct* tstruct) {
735   const vector<t_field*>& members = tstruct->get_members();
736   vector<t_field*>::const_iterator m_iter;
737 
738   bool first = true;
739   for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
740     if (first) {
741       first = false;
742     } else {
743       out << endl;
744     }
745 
746     t_field* field = (*m_iter);
747 
748     generate_java_doc(out, field);
749     indent(out) << "public " << type_name(field->get_type()) << " get"
750                 << get_cap_name(field->get_name()) << "() {" << endl;
751     indent(out) << "  if (getSetField() == _Fields." << constant_name(field->get_name()) << ") {"
752                 << endl;
753     indent(out) << "    return (" << type_name(field->get_type(), true) << ")getFieldValue();"
754                 << endl;
755     indent(out) << "  } else {" << endl;
756     indent(out) << "    throw new RuntimeException(\"Cannot get field '" << field->get_name()
757                 << "' because union is currently set to \" + getFieldDesc(getSetField()).name);"
758                 << endl;
759     indent(out) << "  }" << endl;
760     indent(out) << "}" << endl;
761 
762     out << endl;
763 
764     generate_java_doc(out, field);
765     indent(out) << "public void set" << get_cap_name(field->get_name()) << "("
766                 << type_name(field->get_type()) << " value) {" << endl;
767     if (type_can_be_null(field->get_type())) {
768       indent(out) << "  if (value == null) throw new NullPointerException();" << endl;
769     }
770     indent(out) << "  setField_ = _Fields." << constant_name(field->get_name()) << ";" << endl;
771     indent(out) << "  value_ = value;" << endl;
772     indent(out) << "}" << endl;
773   }
774 }
775 
generate_union_abstract_methods(ostream & out,t_struct * tstruct)776 void t_javame_generator::generate_union_abstract_methods(ostream& out, t_struct* tstruct) {
777   generate_check_type(out, tstruct);
778   out << endl;
779   generate_read_value(out, tstruct);
780   out << endl;
781   generate_write_value(out, tstruct);
782   out << endl;
783   generate_get_field_desc(out, tstruct);
784   out << endl;
785   generate_get_struct_desc(out, tstruct);
786   out << endl;
787 }
788 
generate_check_type(ostream & out,t_struct * tstruct)789 void t_javame_generator::generate_check_type(ostream& out, t_struct* tstruct) {
790   indent(out)
791       << "protected void checkType(_Fields setField, Object value) throws ClassCastException {"
792       << endl;
793   indent_up();
794 
795   indent(out) << "switch (setField) {" << endl;
796   indent_up();
797 
798   const vector<t_field*>& members = tstruct->get_members();
799   vector<t_field*>::const_iterator m_iter;
800 
801   for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
802     t_field* field = (*m_iter);
803 
804     indent(out) << "case " << constant_name(field->get_name()) << ":" << endl;
805     indent(out) << "  if (value instanceof " << type_name(field->get_type(), true, false, true)
806                 << ") {" << endl;
807     indent(out) << "    break;" << endl;
808     indent(out) << "  }" << endl;
809     indent(out) << "  throw new ClassCastException(\"Was expecting value of type "
810                 << type_name(field->get_type(), true, false) << " for field '" << field->get_name()
811                 << "', but got \" + value.getClass().getSimpleName());" << endl;
812     // do the real check here
813   }
814 
815   indent(out) << "default:" << endl;
816   indent(out) << "  throw new IllegalArgumentException(\"Unknown field id \" + setField);" << endl;
817 
818   indent_down();
819   indent(out) << "}" << endl;
820 
821   indent_down();
822   indent(out) << "}" << endl;
823 }
824 
generate_read_value(ostream & out,t_struct * tstruct)825 void t_javame_generator::generate_read_value(ostream& out, t_struct* tstruct) {
826   indent(out) << "protected Object readValue(TProtocol iprot, TField field) throws TException {"
827               << endl;
828 
829   indent_up();
830 
831   indent(out) << "_Fields setField = _Fields.findByThriftId(field.id);" << endl;
832   indent(out) << "if (setField != null) {" << endl;
833   indent_up();
834   indent(out) << "switch (setField) {" << endl;
835   indent_up();
836 
837   const vector<t_field*>& members = tstruct->get_members();
838   vector<t_field*>::const_iterator m_iter;
839 
840   for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
841     t_field* field = (*m_iter);
842 
843     indent(out) << "case " << constant_name(field->get_name()) << ":" << endl;
844     indent_up();
845     indent(out) << "if (field.type == " << constant_name(field->get_name()) << "_FIELD_DESC.type) {"
846                 << endl;
847     indent_up();
848     indent(out) << type_name(field->get_type(), true, false) << " " << field->get_name() << ";"
849                 << endl;
850     generate_deserialize_field(out, field, "");
851     indent(out) << "return " << field->get_name() << ";" << endl;
852     indent_down();
853     indent(out) << "} else {" << endl;
854     indent(out) << "  TProtocolUtil.skip(iprot, field.type);" << endl;
855     indent(out) << "  return null;" << endl;
856     indent(out) << "}" << endl;
857     indent_down();
858   }
859 
860   indent(out) << "default:" << endl;
861   indent(out) << "  throw new IllegalStateException(\"setField wasn't null, but didn't match any "
862                  "of the case statements!\");" << endl;
863 
864   indent_down();
865   indent(out) << "}" << endl;
866 
867   indent_down();
868   indent(out) << "} else {" << endl;
869   indent_up();
870   indent(out) << "TProtocolUtil.skip(iprot, field.type);" << endl;
871   indent(out) << "return null;" << endl;
872   indent_down();
873   indent(out) << "}" << endl;
874 
875   indent_down();
876   indent(out) << "}" << endl;
877 }
878 
generate_write_value(ostream & out,t_struct * tstruct)879 void t_javame_generator::generate_write_value(ostream& out, t_struct* tstruct) {
880   indent(out) << "protected void writeValue(TProtocol oprot) throws TException {" << endl;
881 
882   indent_up();
883 
884   indent(out) << "switch (setField_) {" << endl;
885   indent_up();
886 
887   const vector<t_field*>& members = tstruct->get_members();
888   vector<t_field*>::const_iterator m_iter;
889 
890   for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
891     t_field* field = (*m_iter);
892 
893     indent(out) << "case " << constant_name(field->get_name()) << ":" << endl;
894     indent_up();
895     indent(out) << type_name(field->get_type(), true, false) << " " << field->get_name() << " = ("
896                 << type_name(field->get_type(), true, false) << ")value_;" << endl;
897     generate_serialize_field(out, field, "");
898     indent(out) << "return;" << endl;
899     indent_down();
900   }
901 
902   indent(out) << "default:" << endl;
903   indent(out) << "  throw new IllegalStateException(\"Cannot write union with unknown field \" + "
904                  "setField_);" << endl;
905 
906   indent_down();
907   indent(out) << "}" << endl;
908 
909   indent_down();
910 
911   indent(out) << "}" << endl;
912 }
913 
generate_get_field_desc(ostream & out,t_struct * tstruct)914 void t_javame_generator::generate_get_field_desc(ostream& out, t_struct* tstruct) {
915   indent(out) << "protected TField getFieldDesc(_Fields setField) {" << endl;
916   indent_up();
917 
918   const vector<t_field*>& members = tstruct->get_members();
919   vector<t_field*>::const_iterator m_iter;
920 
921   indent(out) << "switch (setField) {" << endl;
922   indent_up();
923 
924   for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
925     t_field* field = (*m_iter);
926     indent(out) << "case " << constant_name(field->get_name()) << ":" << endl;
927     indent(out) << "  return " << constant_name(field->get_name()) << "_FIELD_DESC;" << endl;
928   }
929 
930   indent(out) << "default:" << endl;
931   indent(out) << "  throw new IllegalArgumentException(\"Unknown field id \" + setField);" << endl;
932 
933   indent_down();
934   indent(out) << "}" << endl;
935 
936   indent_down();
937   indent(out) << "}" << endl;
938 }
939 
generate_get_struct_desc(ostream & out,t_struct * tstruct)940 void t_javame_generator::generate_get_struct_desc(ostream& out, t_struct* tstruct) {
941   (void)tstruct;
942   indent(out) << "protected TStruct getStructDesc() {" << endl;
943   indent(out) << "  return STRUCT_DESC;" << endl;
944   indent(out) << "}" << endl;
945 }
946 
generate_union_comparisons(ostream & out,t_struct * tstruct)947 void t_javame_generator::generate_union_comparisons(ostream& out, t_struct* tstruct) {
948   // equality
949   indent(out) << "public boolean equals(Object other) {" << endl;
950   indent(out) << "  if (other instanceof " << tstruct->get_name() << ") {" << endl;
951   indent(out) << "    return equals((" << tstruct->get_name() << ")other);" << endl;
952   indent(out) << "  } else {" << endl;
953   indent(out) << "    return false;" << endl;
954   indent(out) << "  }" << endl;
955   indent(out) << "}" << endl;
956 
957   out << endl;
958 
959   indent(out) << "public boolean equals(" << tstruct->get_name() << " other) {" << endl;
960   indent(out) << "  return other != null && getSetField() == other.getSetField() && "
961                  "getFieldValue().equals(other.getFieldValue());" << endl;
962   indent(out) << "}" << endl;
963   out << endl;
964 
965   indent(out) << "public int compareTo(" << type_name(tstruct) << " other) {" << endl;
966   indent(out) << "  int lastComparison = TBaseHelper.compareTo(getSetField(), other.getSetField());"
967               << endl;
968   indent(out) << "  if (lastComparison == 0) {" << endl;
969   indent(out) << "    return TBaseHelper.compareTo(getFieldValue(), other.getFieldValue());"
970               << endl;
971   indent(out) << "  }" << endl;
972   indent(out) << "  return lastComparison;" << endl;
973   indent(out) << "}" << endl;
974   out << endl;
975 }
976 
generate_union_hashcode(ostream & out,t_struct * tstruct)977 void t_javame_generator::generate_union_hashcode(ostream& out, t_struct* tstruct) {
978   (void)tstruct;
979   indent(out) << "/**" << endl;
980   indent(out)
981       << " * If you'd like this to perform more respectably, use the hashcode generator option."
982       << endl;
983   indent(out) << " */" << endl;
984   indent(out) << "public int hashCode() {" << endl;
985   indent(out) << "  return 0;" << endl;
986   indent(out) << "}" << endl;
987 }
988 
989 /**
990  * Java struct definition. This has various parameters, as it could be
991  * generated standalone or inside another class as a helper. If it
992  * is a helper than it is a static class.
993  *
994  * @param tstruct      The struct definition
995  * @param is_exception Is this an exception?
996  * @param in_class     If inside a class, needs to be static class
997  * @param is_result    If this is a result it needs a different writer
998  */
generate_java_struct_definition(ostream & out,t_struct * tstruct,bool is_exception,bool in_class,bool is_result)999 void t_javame_generator::generate_java_struct_definition(ostream& out,
1000                                                          t_struct* tstruct,
1001                                                          bool is_exception,
1002                                                          bool in_class,
1003                                                          bool is_result) {
1004   generate_java_doc(out, tstruct);
1005 
1006   bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end());
1007 
1008   indent(out) << "public " << (is_final ? "final " : "") << (in_class ? "static " : "") << "class "
1009               << tstruct->get_name() << " ";
1010 
1011   if (is_exception) {
1012     out << "extends Exception ";
1013   }
1014   out << "implements TBase ";
1015 
1016   scope_up(out);
1017 
1018   generate_struct_desc(out, tstruct);
1019 
1020   // Members are public for -java, private for -javabean
1021   const vector<t_field*>& members = tstruct->get_members();
1022   vector<t_field*>::const_iterator m_iter;
1023 
1024   out << endl;
1025 
1026   generate_field_descs(out, tstruct);
1027 
1028   out << endl;
1029 
1030   for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1031     indent(out) << "private ";
1032     out << declare_field(*m_iter, false) << endl;
1033   }
1034 
1035   // isset data
1036   if (members.size() > 0) {
1037     out << endl;
1038 
1039     indent(out) << "// isset id assignments" << endl;
1040 
1041     int i = 0;
1042     for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1043       if (!type_can_be_null((*m_iter)->get_type())) {
1044         indent(out) << "private static final int " << isset_field_id(*m_iter) << " = " << i << ";"
1045                     << endl;
1046         i++;
1047       }
1048     }
1049 
1050     if (i > 0) {
1051       indent(out) << "private boolean[] __isset_vector = new boolean[" << i << "];" << endl;
1052     }
1053 
1054     out << endl;
1055   }
1056 
1057   bool all_optional_members = true;
1058 
1059   // Default constructor
1060   indent(out) << "public " << tstruct->get_name() << "() {" << endl;
1061   indent_up();
1062   for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1063     t_type* t = get_true_type((*m_iter)->get_type());
1064     if ((*m_iter)->get_value() != nullptr) {
1065       print_const_value(out,
1066                         "this." + (*m_iter)->get_name(),
1067                         t,
1068                         (*m_iter)->get_value(),
1069                         true,
1070                         true);
1071     }
1072     if ((*m_iter)->get_req() != t_field::T_OPTIONAL) {
1073       all_optional_members = false;
1074     }
1075   }
1076   indent_down();
1077   indent(out) << "}" << endl << endl;
1078 
1079   if (!members.empty() && !all_optional_members) {
1080     // Full constructor for all fields
1081     indent(out) << "public " << tstruct->get_name() << "(" << endl;
1082     indent_up();
1083     bool first = true;
1084     for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1085       if ((*m_iter)->get_req() != t_field::T_OPTIONAL) {
1086         if (!first) {
1087           out << "," << endl;
1088         }
1089         first = false;
1090         indent(out) << type_name((*m_iter)->get_type()) << " " << (*m_iter)->get_name();
1091       }
1092     }
1093     out << ")" << endl;
1094     indent_down();
1095     indent(out) << "{" << endl;
1096     indent_up();
1097     indent(out) << "this();" << endl;
1098     for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1099       if ((*m_iter)->get_req() != t_field::T_OPTIONAL) {
1100         indent(out) << "this." << (*m_iter)->get_name() << " = " << (*m_iter)->get_name() << ";"
1101                     << endl;
1102         generate_isset_set(out, (*m_iter));
1103       }
1104     }
1105     indent_down();
1106     indent(out) << "}" << endl << endl;
1107   }
1108 
1109   // copy constructor
1110   indent(out) << "/**" << endl;
1111   indent(out) << " * Performs a deep copy on <i>other</i>." << endl;
1112   indent(out) << " */" << endl;
1113   indent(out) << "public " << tstruct->get_name() << "(" << tstruct->get_name() << " other) {"
1114               << endl;
1115   indent_up();
1116 
1117   if (has_bit_vector(tstruct)) {
1118     indent(out) << "System.arraycopy(other.__isset_vector, 0, __isset_vector, 0, "
1119                    "other.__isset_vector.length);" << endl;
1120   }
1121 
1122   for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1123     t_field* field = (*m_iter);
1124     std::string field_name = field->get_name();
1125     t_type* type = field->get_type();
1126     bool can_be_null = type_can_be_null(type);
1127 
1128     if (can_be_null) {
1129       indent(out) << "if (other." << generate_isset_check(field) << ") {" << endl;
1130       indent_up();
1131     }
1132 
1133     if (type->is_container()) {
1134       generate_deep_copy_container(out, "other", field_name, "__this__" + field_name, type);
1135       indent(out) << "this." << field_name << " = __this__" << field_name << ";" << endl;
1136     } else {
1137       indent(out) << "this." << field_name << " = ";
1138       generate_deep_copy_non_container(out, "other." + field_name, field_name, type);
1139       out << ";" << endl;
1140     }
1141 
1142     if (can_be_null) {
1143       indent_down();
1144       indent(out) << "}" << endl;
1145     }
1146   }
1147 
1148   indent_down();
1149   indent(out) << "}" << endl << endl;
1150 
1151   // clone method, so that you can deep copy an object when you don't know its class.
1152   indent(out) << "public " << tstruct->get_name() << " deepCopy() {" << endl;
1153   indent(out) << "  return new " << tstruct->get_name() << "(this);" << endl;
1154   indent(out) << "}" << endl << endl;
1155 
1156   generate_java_struct_clear(out, tstruct);
1157 
1158   generate_java_bean_boilerplate(out, tstruct);
1159   generate_generic_field_getters_setters(out, tstruct);
1160 
1161   generate_java_struct_equality(out, tstruct);
1162   generate_java_struct_compare_to(out, tstruct);
1163 
1164   generate_java_struct_reader(out, tstruct);
1165   if (is_result) {
1166     generate_java_struct_result_writer(out, tstruct);
1167   } else {
1168     generate_java_struct_writer(out, tstruct);
1169   }
1170   generate_java_struct_tostring(out, tstruct);
1171   generate_java_validator(out, tstruct);
1172   scope_down(out);
1173   out << endl;
1174 }
1175 
1176 /**
1177  * Generates equals methods and a hashCode method for a structure.
1178  *
1179  * @param tstruct The struct definition
1180  */
generate_java_struct_equality(ostream & out,t_struct * tstruct)1181 void t_javame_generator::generate_java_struct_equality(ostream& out, t_struct* tstruct) {
1182   out << indent() << "public boolean equals(Object that) {" << endl;
1183   indent_up();
1184   out << indent() << "if (that == null)" << endl << indent() << "  return false;" << endl
1185       << indent() << "if (that instanceof " << tstruct->get_name() << ")" << endl << indent()
1186       << "  return this.equals((" << tstruct->get_name() << ")that);" << endl << indent()
1187       << "return false;" << endl;
1188   scope_down(out);
1189   out << endl;
1190 
1191   out << indent() << "public boolean equals(" << tstruct->get_name() << " that) {" << endl;
1192   indent_up();
1193   out << indent() << "if (that == null)" << endl << indent() << "  return false;" << endl
1194       << indent() << "if (this == that)" << endl << indent() << "  return true;"  << endl;
1195 
1196   const vector<t_field*>& members = tstruct->get_members();
1197   vector<t_field*>::const_iterator m_iter;
1198   for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1199     out << endl;
1200 
1201     t_type* t = get_true_type((*m_iter)->get_type());
1202     // Most existing Thrift code does not use isset or optional/required,
1203     // so we treat "default" fields as required.
1204     bool is_optional = (*m_iter)->get_req() == t_field::T_OPTIONAL;
1205     bool can_be_null = type_can_be_null(t);
1206     string name = (*m_iter)->get_name();
1207 
1208     string this_present = "true";
1209     string that_present = "true";
1210     string unequal;
1211 
1212     if (is_optional || can_be_null) {
1213       this_present += " && this." + generate_isset_check(*m_iter);
1214       that_present += " && that." + generate_isset_check(*m_iter);
1215     }
1216 
1217     out << indent() << "boolean this_present_" << name << " = " << this_present << ";" << endl
1218         << indent() << "boolean that_present_" << name << " = " << that_present << ";" << endl
1219         << indent() << "if ("
1220         << "this_present_" << name << " || that_present_" << name << ") {" << endl;
1221     indent_up();
1222     out << indent() << "if (!("
1223         << "this_present_" << name << " && that_present_" << name << "))" << endl << indent()
1224         << "  return false;" << endl;
1225 
1226     if (t->is_binary()) {
1227       unequal = "TBaseHelper.compareTo(this." + name + ", that." + name + ") != 0";
1228     } else if (can_be_null) {
1229       unequal = "!this." + name + ".equals(that." + name + ")";
1230     } else {
1231       unequal = "this." + name + " != that." + name;
1232     }
1233 
1234     out << indent() << "if (" << unequal << ")" << endl << indent() << "  return false;" << endl;
1235 
1236     scope_down(out);
1237   }
1238   out << endl;
1239   indent(out) << "return true;" << endl;
1240   scope_down(out);
1241   out << endl;
1242 
1243   out << indent() << "public int hashCode() {" << endl;
1244   indent_up();
1245   indent(out) << "return 0;" << endl;
1246   indent_down();
1247   indent(out) << "}" << endl << endl;
1248 }
1249 
generate_java_struct_compare_to(ostream & out,t_struct * tstruct)1250 void t_javame_generator::generate_java_struct_compare_to(ostream& out, t_struct* tstruct) {
1251   indent(out) << "public int compareTo(Object otherObject) {" << endl;
1252   //  indent(out) << "public int compareTo(" << type_name(tstruct) << " other) {" << endl;
1253   indent_up();
1254 
1255   indent(out) << "if (!getClass().equals(otherObject.getClass())) {" << endl;
1256   indent(out) << "  return getClass().getName().compareTo(otherObject.getClass().getName());"
1257               << endl;
1258   indent(out) << "}" << endl;
1259   out << endl;
1260   indent(out) << type_name(tstruct) << " other = (" << type_name(tstruct) << ")otherObject;";
1261 
1262   indent(out) << "int lastComparison = 0;" << endl;
1263   out << endl;
1264 
1265   const vector<t_field*>& members = tstruct->get_members();
1266   vector<t_field*>::const_iterator m_iter;
1267   for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1268     t_field* field = *m_iter;
1269     indent(out) << "lastComparison = TBaseHelper.compareTo(" << generate_isset_check(field)
1270                 << ", other." << generate_isset_check(field) << ");" << endl;
1271     indent(out) << "if (lastComparison != 0) {" << endl;
1272     indent(out) << "  return lastComparison;" << endl;
1273     indent(out) << "}" << endl;
1274 
1275     indent(out) << "if (" << generate_isset_check(field) << ") {" << endl;
1276     if (field->get_type()->is_struct() || field->get_type()->is_xception()) {
1277       indent(out) << "  lastComparison = this." << field->get_name() << ".compareTo(other."
1278                   << field->get_name() << ");" << endl;
1279     } else {
1280       indent(out) << "  lastComparison = TBaseHelper.compareTo(this." << field->get_name()
1281                   << ", other." << field->get_name() << ");" << endl;
1282     }
1283 
1284     indent(out) << "  if (lastComparison != 0) {" << endl;
1285     indent(out) << "    return lastComparison;" << endl;
1286     indent(out) << "  }" << endl;
1287     indent(out) << "}" << endl;
1288   }
1289 
1290   indent(out) << "return 0;" << endl;
1291 
1292   indent_down();
1293   indent(out) << "}" << endl << endl;
1294 }
1295 
1296 /**
1297  * Generates a function to read all the fields of the struct.
1298  *
1299  * @param tstruct The struct definition
1300  */
generate_java_struct_reader(ostream & out,t_struct * tstruct)1301 void t_javame_generator::generate_java_struct_reader(ostream& out, t_struct* tstruct) {
1302   out << indent() << "public void read(TProtocol iprot) throws TException {" << endl;
1303   indent_up();
1304 
1305   const vector<t_field*>& fields = tstruct->get_members();
1306   vector<t_field*>::const_iterator f_iter;
1307 
1308   // Declare stack tmp variables and read struct header
1309   out << indent() << "TField field;" << endl << indent() << "iprot.readStructBegin();" << endl;
1310 
1311   // Loop over reading in fields
1312   indent(out) << "while (true)" << endl;
1313   scope_up(out);
1314 
1315   // Read beginning field marker
1316   indent(out) << "field = iprot.readFieldBegin();" << endl;
1317 
1318   // Check for field STOP marker and break
1319   indent(out) << "if (field.type == TType.STOP) { " << endl;
1320   indent_up();
1321   indent(out) << "break;" << endl;
1322   indent_down();
1323   indent(out) << "}" << endl;
1324 
1325   // Switch statement on the field we are reading
1326   indent(out) << "switch (field.id) {" << endl;
1327 
1328   indent_up();
1329 
1330   // Generate deserialization code for known cases
1331   for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1332     indent(out) << "case " << (*f_iter)->get_key() << ": // "
1333                 << constant_name((*f_iter)->get_name()) << endl;
1334     indent_up();
1335     indent(out) << "if (field.type == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
1336     indent_up();
1337 
1338     generate_deserialize_field(out, *f_iter, "this.");
1339     generate_isset_set(out, *f_iter);
1340     indent_down();
1341     out << indent() << "} else { " << endl << indent() << "  TProtocolUtil.skip(iprot, field.type);"
1342         << endl << indent() << "}" << endl << indent() << "break;" << endl;
1343     indent_down();
1344   }
1345 
1346   indent(out) << "default:" << endl;
1347   indent(out) << "  TProtocolUtil.skip(iprot, field.type);" << endl;
1348 
1349   indent_down();
1350   indent(out) << "}" << endl;
1351 
1352   // Read field end marker
1353   indent(out) << "iprot.readFieldEnd();" << endl;
1354 
1355   indent_down();
1356   indent(out) << "}" << endl;
1357 
1358   out << indent() << "iprot.readStructEnd();" << endl;
1359 
1360   // performs various checks (e.g. check that all required fields are set)
1361   indent(out) << "validate();" << endl;
1362 
1363   indent_down();
1364   out << indent() << "}" << endl << endl;
1365 }
1366 
1367 // generates java method to perform various checks
1368 // (e.g. check that all required fields are set)
generate_java_validator(ostream & out,t_struct * tstruct)1369 void t_javame_generator::generate_java_validator(ostream& out, t_struct* tstruct) {
1370   indent(out) << "public void validate() throws TException {" << endl;
1371   indent_up();
1372 
1373   const vector<t_field*>& fields = tstruct->get_members();
1374   vector<t_field*>::const_iterator f_iter;
1375 
1376   out << indent() << "// check for required fields" << endl;
1377   for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1378     if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
1379       out << indent() << "if (!" << generate_isset_check(*f_iter) << ") {" << endl << indent()
1380           << "  throw new TProtocolException(\"Required field '" << (*f_iter)->get_name()
1381           << "' is unset! Struct:\" + toString());" << endl << indent() << "}" << endl << endl;
1382     }
1383   }
1384 
1385   indent_down();
1386   indent(out) << "}" << endl << endl;
1387 }
1388 
1389 /**
1390  * Generates a function to write all the fields of the struct
1391  *
1392  * @param tstruct The struct definition
1393  */
generate_java_struct_writer(ostream & out,t_struct * tstruct)1394 void t_javame_generator::generate_java_struct_writer(ostream& out, t_struct* tstruct) {
1395   out << indent() << "public void write(TProtocol oprot) throws TException {" << endl;
1396   indent_up();
1397 
1398   string name = tstruct->get_name();
1399   const vector<t_field*>& fields = tstruct->get_sorted_members();
1400   vector<t_field*>::const_iterator f_iter;
1401 
1402   // performs various checks (e.g. check that all required fields are set)
1403   indent(out) << "validate();" << endl << endl;
1404 
1405   indent(out) << "oprot.writeStructBegin(STRUCT_DESC);" << endl;
1406 
1407   for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1408     bool null_allowed = type_can_be_null((*f_iter)->get_type());
1409     if (null_allowed) {
1410       out << indent() << "if (this." << (*f_iter)->get_name() << " != null) {" << endl;
1411       indent_up();
1412     }
1413     bool optional = (*f_iter)->get_req() == t_field::T_OPTIONAL;
1414     if (optional) {
1415       indent(out) << "if (" << generate_isset_check((*f_iter)) << ") {" << endl;
1416       indent_up();
1417     }
1418 
1419     indent(out) << "oprot.writeFieldBegin(" << constant_name((*f_iter)->get_name())
1420                 << "_FIELD_DESC);" << endl;
1421 
1422     // Write field contents
1423     generate_serialize_field(out, *f_iter, "this.");
1424 
1425     // Write field closer
1426     indent(out) << "oprot.writeFieldEnd();" << endl;
1427 
1428     if (optional) {
1429       indent_down();
1430       indent(out) << "}" << endl;
1431     }
1432     if (null_allowed) {
1433       indent_down();
1434       indent(out) << "}" << endl;
1435     }
1436   }
1437   // Write the struct map
1438   out << indent() << "oprot.writeFieldStop();" << endl << indent() << "oprot.writeStructEnd();"
1439       << endl;
1440 
1441   indent_down();
1442   out << indent() << "}" << endl << endl;
1443 }
1444 
1445 /**
1446  * Generates a function to write all the fields of the struct,
1447  * which is a function result. These fields are only written
1448  * if they are set in the Isset array, and only one of them
1449  * can be set at a time.
1450  *
1451  * @param tstruct The struct definition
1452  */
generate_java_struct_result_writer(ostream & out,t_struct * tstruct)1453 void t_javame_generator::generate_java_struct_result_writer(ostream& out, t_struct* tstruct) {
1454   out << indent() << "public void write(TProtocol oprot) throws TException {" << endl;
1455   indent_up();
1456 
1457   string name = tstruct->get_name();
1458   const vector<t_field*>& fields = tstruct->get_sorted_members();
1459   vector<t_field*>::const_iterator f_iter;
1460 
1461   indent(out) << "oprot.writeStructBegin(STRUCT_DESC);" << endl;
1462 
1463   bool first = true;
1464   for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1465     if (first) {
1466       first = false;
1467       out << endl << indent() << "if ";
1468     } else {
1469       out << " else if ";
1470     }
1471 
1472     out << "(this." << generate_isset_check(*f_iter) << ") {" << endl;
1473 
1474     indent_up();
1475 
1476     indent(out) << "oprot.writeFieldBegin(" << constant_name((*f_iter)->get_name())
1477                 << "_FIELD_DESC);" << endl;
1478 
1479     // Write field contents
1480     generate_serialize_field(out, *f_iter, "this.");
1481 
1482     // Write field closer
1483     indent(out) << "oprot.writeFieldEnd();" << endl;
1484 
1485     indent_down();
1486     indent(out) << "}";
1487   }
1488   // Write the struct map
1489   out << endl << indent() << "oprot.writeFieldStop();" << endl << indent()
1490       << "oprot.writeStructEnd();" << endl;
1491 
1492   indent_down();
1493   out << indent() << "}" << endl << endl;
1494 }
1495 
generate_reflection_getters(ostringstream & out,t_type * type,string field_name,string cap_name)1496 void t_javame_generator::generate_reflection_getters(ostringstream& out,
1497                                                      t_type* type,
1498                                                      string field_name,
1499                                                      string cap_name) {
1500   indent(out) << "case " << constant_name(field_name) << ":" << endl;
1501   indent_up();
1502 
1503   if (type->is_base_type() && !type->is_string()) {
1504     t_base_type* base_type = (t_base_type*)type;
1505 
1506     indent(out) << "return new " << type_name(type, true, false) << "("
1507                 << (base_type->is_bool() ? "is" : "get") << cap_name << "());" << endl << endl;
1508   } else {
1509     indent(out) << "return get" << cap_name << "();" << endl << endl;
1510   }
1511 
1512   indent_down();
1513 }
1514 
generate_reflection_setters(ostringstream & out,t_type * type,string field_name,string cap_name)1515 void t_javame_generator::generate_reflection_setters(ostringstream& out,
1516                                                      t_type* type,
1517                                                      string field_name,
1518                                                      string cap_name) {
1519   indent(out) << "case " << constant_name(field_name) << ":" << endl;
1520   indent_up();
1521   indent(out) << "if (value == null) {" << endl;
1522   indent(out) << "  unset" << get_cap_name(field_name) << "();" << endl;
1523   indent(out) << "} else {" << endl;
1524   indent(out) << "  set" << cap_name << "((" << type_name(type, true, false) << ")value);" << endl;
1525   indent(out) << "}" << endl;
1526   indent(out) << "break;" << endl << endl;
1527 
1528   indent_down();
1529 }
1530 
generate_generic_field_getters_setters(std::ostream & out,t_struct * tstruct)1531 void t_javame_generator::generate_generic_field_getters_setters(std::ostream& out,
1532                                                                 t_struct* tstruct) {
1533   (void)out;
1534   std::ostringstream getter_stream;
1535   std::ostringstream setter_stream;
1536 
1537   // build up the bodies of both the getter and setter at once
1538   const vector<t_field*>& fields = tstruct->get_members();
1539   vector<t_field*>::const_iterator f_iter;
1540   for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1541     t_field* field = *f_iter;
1542     t_type* type = get_true_type(field->get_type());
1543     std::string field_name = field->get_name();
1544     std::string cap_name = get_cap_name(field_name);
1545 
1546     indent_up();
1547     generate_reflection_setters(setter_stream, type, field_name, cap_name);
1548     generate_reflection_getters(getter_stream, type, field_name, cap_name);
1549     indent_down();
1550   }
1551 }
1552 
1553 /**
1554  * Generates a set of Java Bean boilerplate functions (setters, getters, etc.)
1555  * for the given struct.
1556  *
1557  * @param tstruct The struct definition
1558  */
generate_java_bean_boilerplate(ostream & out,t_struct * tstruct)1559 void t_javame_generator::generate_java_bean_boilerplate(ostream& out, t_struct* tstruct) {
1560   const vector<t_field*>& fields = tstruct->get_members();
1561   vector<t_field*>::const_iterator f_iter;
1562   for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1563     t_field* field = *f_iter;
1564     t_type* type = get_true_type(field->get_type());
1565     std::string field_name = field->get_name();
1566     std::string cap_name = get_cap_name(field_name);
1567 
1568     if (type->is_container()) {
1569       // Method to return the size of the collection
1570       indent(out) << "public int get" << cap_name;
1571       out << get_cap_name("size() {") << endl;
1572 
1573       indent_up();
1574       indent(out) << "return (this." << field_name << " == null) ? 0 : "
1575                   << "this." << field_name << ".size();" << endl;
1576       indent_down();
1577       indent(out) << "}" << endl << endl;
1578     }
1579 
1580     if (type->is_set() || type->is_list()) {
1581 
1582       t_type* element_type;
1583       if (type->is_set()) {
1584         element_type = ((t_set*)type)->get_elem_type();
1585       } else {
1586         element_type = ((t_list*)type)->get_elem_type();
1587       }
1588 
1589       // Iterator getter for sets and lists
1590       indent(out) << "public Enumeration get" << cap_name;
1591       out << get_cap_name("Enumeration() {") << endl;
1592 
1593       indent_up();
1594       indent(out) << "return (this." << field_name << " == null) ? null : "
1595                   << "this." << field_name << ".elements();" << endl;
1596       indent_down();
1597       indent(out) << "}" << endl << endl;
1598 
1599       // Add to set or list, create if the set/list is null
1600       indent(out);
1601       out << "public void add" << get_cap_name("to");
1602       out << cap_name << "(" << type_name(element_type) << " elem) {" << endl;
1603 
1604       indent_up();
1605       indent(out) << "if (this." << field_name << " == null) {" << endl;
1606       indent_up();
1607       indent(out) << "this." << field_name << " = new " << type_name(type, false, true) << "();"
1608                   << endl;
1609       indent_down();
1610       indent(out) << "}" << endl;
1611       if (type->is_set()) {
1612         indent(out) << "this." << field_name << ".put(" << box_type(element_type, "elem") << ", "
1613                     << box_type(element_type, "elem") << ");" << endl;
1614       } else {
1615         indent(out) << "this." << field_name << ".addElement(" << box_type(element_type, "elem")
1616                     << ");" << endl;
1617       }
1618       indent_down();
1619       indent(out) << "}" << endl << endl;
1620 
1621     } else if (type->is_map()) {
1622       // Put to map
1623       t_type* key_type = ((t_map*)type)->get_key_type();
1624       t_type* val_type = ((t_map*)type)->get_val_type();
1625 
1626       indent(out);
1627       out << "public void putTo" << cap_name << "(" << type_name(key_type, true) << " key, "
1628           << type_name(val_type, true) << " val) {" << endl;
1629 
1630       indent_up();
1631       indent(out) << "if (this." << field_name << " == null) {" << endl;
1632       indent_up();
1633       indent(out) << "this." << field_name << " = new " << type_name(type, false, true) << "();"
1634                   << endl;
1635       indent_down();
1636       indent(out) << "}" << endl;
1637       indent(out) << "this." << field_name << ".put(key, val);" << endl;
1638       indent_down();
1639       indent(out) << "}" << endl << endl;
1640     }
1641 
1642     // Simple getter
1643     generate_java_doc(out, field);
1644     indent(out) << "public " << type_name(type);
1645     if (type->is_base_type() && ((t_base_type*)type)->get_base() == t_base_type::TYPE_BOOL) {
1646       out << " is";
1647     } else {
1648       out << " get";
1649     }
1650     out << cap_name << "() {" << endl;
1651     indent_up();
1652     indent(out) << "return this." << field_name << ";" << endl;
1653     indent_down();
1654     indent(out) << "}" << endl << endl;
1655 
1656     // Simple setter
1657     generate_java_doc(out, field);
1658     indent(out) << "public ";
1659     out << "void";
1660     out << " set" << cap_name << "(" << type_name(type) << " " << field_name << ") {" << endl;
1661     indent_up();
1662     indent(out) << "this." << field_name << " = " << field_name << ";" << endl;
1663     generate_isset_set(out, field);
1664 
1665     indent_down();
1666     indent(out) << "}" << endl << endl;
1667 
1668     // Unsetter
1669     indent(out) << "public void unset" << cap_name << "() {" << endl;
1670     indent_up();
1671     if (type_can_be_null(type)) {
1672       indent(out) << "this." << field_name << " = null;" << endl;
1673     } else {
1674       indent(out) << "__isset_vector[" << isset_field_id(field) << "] = false;" << endl;
1675     }
1676     indent_down();
1677     indent(out) << "}" << endl << endl;
1678 
1679     // isSet method
1680     indent(out) << "/** Returns true if field " << field_name
1681                 << " is set (has been assigned a value) and false otherwise */" << endl;
1682     indent(out) << "public boolean is" << get_cap_name("set") << cap_name << "() {" << endl;
1683     indent_up();
1684     if (type_can_be_null(type)) {
1685       indent(out) << "return this." << field_name << " != null;" << endl;
1686     } else {
1687       indent(out) << "return __isset_vector[" << isset_field_id(field) << "];" << endl;
1688     }
1689     indent_down();
1690     indent(out) << "}" << endl << endl;
1691 
1692     indent(out) << "public void set" << cap_name << get_cap_name("isSet") << "(boolean value) {"
1693                 << endl;
1694     indent_up();
1695     if (type_can_be_null(type)) {
1696       indent(out) << "if (!value) {" << endl;
1697       indent(out) << "  this." << field_name << " = null;" << endl;
1698       indent(out) << "}" << endl;
1699     } else {
1700       indent(out) << "__isset_vector[" << isset_field_id(field) << "] = value;" << endl;
1701     }
1702     indent_down();
1703     indent(out) << "}" << endl << endl;
1704   }
1705 }
1706 
1707 /**
1708  * Generates a toString() method for the given struct
1709  *
1710  * @param tstruct The struct definition
1711  */
generate_java_struct_tostring(ostream & out,t_struct * tstruct)1712 void t_javame_generator::generate_java_struct_tostring(ostream& out, t_struct* tstruct) {
1713   out << indent() << "public String toString() {" << endl;
1714   indent_up();
1715 
1716   out << indent() << "StringBuffer sb = new StringBuffer(\"" << tstruct->get_name() << "(\");"
1717       << endl;
1718   out << indent() << "boolean first = true;" << endl << endl;
1719 
1720   const vector<t_field*>& fields = tstruct->get_members();
1721   vector<t_field*>::const_iterator f_iter;
1722   bool first = true;
1723   for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1724     bool could_be_unset = (*f_iter)->get_req() == t_field::T_OPTIONAL;
1725     if (could_be_unset) {
1726       indent(out) << "if (" << generate_isset_check(*f_iter) << ") {" << endl;
1727       indent_up();
1728     }
1729 
1730     t_field* field = (*f_iter);
1731 
1732     if (!first) {
1733       indent(out) << "if (!first) sb.append(\", \");" << endl;
1734     }
1735     indent(out) << "sb.append(\"" << (*f_iter)->get_name() << ":\");" << endl;
1736     bool can_be_null = type_can_be_null(field->get_type());
1737     if (can_be_null) {
1738       indent(out) << "if (this." << (*f_iter)->get_name() << " == null) {" << endl;
1739       indent(out) << "  sb.append(\"null\");" << endl;
1740       indent(out) << "} else {" << endl;
1741       indent_up();
1742     }
1743 
1744     if (field->get_type()->is_binary()) {
1745       indent(out) << "TBaseHelper.toString(this." << field->get_name() << ", sb);" << endl;
1746     } else {
1747       indent(out) << "sb.append(this." << (*f_iter)->get_name() << ");" << endl;
1748     }
1749 
1750     if (can_be_null) {
1751       indent_down();
1752       indent(out) << "}" << endl;
1753     }
1754     indent(out) << "first = false;" << endl;
1755 
1756     if (could_be_unset) {
1757       indent_down();
1758       indent(out) << "}" << endl;
1759     }
1760     first = false;
1761   }
1762   out << indent() << "sb.append(\")\");" << endl << indent() << "return sb.toString();" << endl;
1763 
1764   indent_down();
1765   indent(out) << "}" << endl << endl;
1766 }
1767 
1768 /**
1769  * Returns a string with the java representation of the given thrift type
1770  * (e.g. for the type struct it returns "TType.STRUCT")
1771  */
get_java_type_string(t_type * type)1772 std::string t_javame_generator::get_java_type_string(t_type* type) {
1773   if (type->is_list()) {
1774     return "TType.LIST";
1775   } else if (type->is_map()) {
1776     return "TType.MAP";
1777   } else if (type->is_set()) {
1778     return "TType.SET";
1779   } else if (type->is_struct() || type->is_xception()) {
1780     return "TType.STRUCT";
1781   } else if (type->is_enum()) {
1782     return "TType.ENUM";
1783   } else if (type->is_typedef()) {
1784     return get_java_type_string(((t_typedef*)type)->get_type());
1785   } else if (type->is_base_type()) {
1786     switch (((t_base_type*)type)->get_base()) {
1787     case t_base_type::TYPE_VOID:
1788       return "TType.VOID";
1789       break;
1790     case t_base_type::TYPE_STRING:
1791       return "TType.STRING";
1792       break;
1793     case t_base_type::TYPE_BOOL:
1794       return "TType.BOOL";
1795       break;
1796     case t_base_type::TYPE_I8:
1797       return "TType.BYTE";
1798       break;
1799     case t_base_type::TYPE_I16:
1800       return "TType.I16";
1801       break;
1802     case t_base_type::TYPE_I32:
1803       return "TType.I32";
1804       break;
1805     case t_base_type::TYPE_I64:
1806       return "TType.I64";
1807       break;
1808     case t_base_type::TYPE_DOUBLE:
1809       return "TType.DOUBLE";
1810       break;
1811     default:
1812       throw std::runtime_error("Unknown thrift type \"" + type->get_name()
1813                                + "\" passed to t_javame_generator::get_java_type_string!");
1814       break; // This should never happen!
1815     }
1816   } else {
1817     throw std::runtime_error(
1818         "Unknown thrift type \"" + type->get_name()
1819         + "\" passed to t_javame_generator::get_java_type_string!"); // This should never happen!
1820   }
1821 }
1822 
generate_field_value_meta_data(std::ostream & out,t_type * type)1823 void t_javame_generator::generate_field_value_meta_data(std::ostream& out, t_type* type) {
1824   out << endl;
1825   indent_up();
1826   indent_up();
1827   if (type->is_struct() || type->is_xception()) {
1828     indent(out) << "new StructMetaData(TType.STRUCT, " << type_name(type) << ".class";
1829   } else if (type->is_container()) {
1830     if (type->is_list()) {
1831       indent(out) << "new ListMetaData(TType.LIST, ";
1832       t_type* elem_type = ((t_list*)type)->get_elem_type();
1833       generate_field_value_meta_data(out, elem_type);
1834     } else if (type->is_set()) {
1835       indent(out) << "new SetMetaData(TType.SET, ";
1836       t_type* elem_type = ((t_list*)type)->get_elem_type();
1837       generate_field_value_meta_data(out, elem_type);
1838     } else { // map
1839       indent(out) << "new MapMetaData(TType.MAP, ";
1840       t_type* key_type = ((t_map*)type)->get_key_type();
1841       t_type* val_type = ((t_map*)type)->get_val_type();
1842       generate_field_value_meta_data(out, key_type);
1843       out << ", ";
1844       generate_field_value_meta_data(out, val_type);
1845     }
1846   } else if (type->is_enum()) {
1847     indent(out) << "new EnumMetaData(TType.ENUM, " << type_name(type) << ".class";
1848   } else {
1849     indent(out) << "new FieldValueMetaData(" << get_java_type_string(type);
1850     if (type->is_typedef()) {
1851       indent(out) << ", \"" << ((t_typedef*)type)->get_symbolic() << "\"";
1852     }
1853   }
1854   out << ")";
1855   indent_down();
1856   indent_down();
1857 }
1858 
1859 /**
1860  * Generates a thrift service. In C++, this comprises an entirely separate
1861  * header and source file. The header file defines the methods and includes
1862  * the data types defined in the main header file, and the implementation
1863  * file contains implementations of the basic printer and default interfaces.
1864  *
1865  * @param tservice The service definition
1866  */
generate_service(t_service * tservice)1867 void t_javame_generator::generate_service(t_service* tservice) {
1868   // Make output file
1869   string f_service_name = package_dir_ + "/" + service_name_ + ".java";
1870   f_service_.open(f_service_name.c_str());
1871 
1872   f_service_ << autogen_comment() << java_package() << java_type_imports() << java_thrift_imports();
1873 
1874   f_service_ << "public class " << service_name_ << " {" << endl << endl;
1875   indent_up();
1876 
1877   // Generate the three main parts of the service
1878   generate_service_interface(tservice);
1879   generate_service_client(tservice);
1880   generate_service_server(tservice);
1881   generate_service_helpers(tservice);
1882 
1883   indent_down();
1884   f_service_ << "}" << endl;
1885   f_service_.close();
1886 }
1887 
1888 /**
1889  * Generates a service interface definition.
1890  *
1891  * @param tservice The service to generate a header definition for
1892  */
generate_primitive_service_interface(t_service * tservice)1893 void t_javame_generator::generate_primitive_service_interface(t_service* tservice) {
1894   f_service_ << indent() << "public interface Iface extends " << service_name_ << "Iface { }"
1895              << endl << endl;
1896 
1897   string f_interface_name = package_dir_ + "/" + service_name_ + "Iface.java";
1898   ofstream_with_content_based_conditional_update f_iface;
1899   f_iface.open(f_interface_name.c_str());
1900 
1901   string extends_iface = "";
1902   if (tservice->get_extends() != nullptr) {
1903     extends_iface = " extends " + type_name(tservice->get_extends()) + "Iface";
1904   }
1905 
1906   f_iface << autogen_comment() << java_package() << java_type_imports() << java_thrift_imports();
1907   generate_java_doc(f_iface, tservice);
1908   f_iface << "public interface " << service_name_ << "Iface" << extends_iface << " {" << endl
1909           << endl;
1910   vector<t_function*> functions = tservice->get_functions();
1911   vector<t_function*>::iterator f_iter;
1912   for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1913     generate_java_doc(f_iface, *f_iter);
1914     f_iface << "  public " << function_signature(*f_iter) << ";" << endl << endl;
1915   }
1916   f_iface << "}" << endl << endl;
1917 }
1918 
1919 /**
1920  * Generates a service interface definition.
1921  *
1922  * @param tservice The service to generate a header definition for
1923  */
generate_service_interface(t_service * tservice)1924 void t_javame_generator::generate_service_interface(t_service* tservice) {
1925   string extends = "";
1926   string extends_iface = "";
1927   if (tservice->get_extends() != nullptr) {
1928     extends = type_name(tservice->get_extends());
1929     extends_iface = " extends " + extends + ".Iface";
1930   }
1931 
1932   generate_java_doc(f_service_, tservice);
1933   f_service_ << indent() << "public interface Iface" << extends_iface << " {" << endl << endl;
1934   indent_up();
1935   vector<t_function*> functions = tservice->get_functions();
1936   vector<t_function*>::iterator f_iter;
1937   for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1938     generate_java_doc(f_service_, *f_iter);
1939     indent(f_service_) << "public " << function_signature(*f_iter) << ";" << endl << endl;
1940   }
1941   indent_down();
1942   f_service_ << indent() << "}" << endl << endl;
1943 }
1944 
1945 /**
1946  * Generates structs for all the service args and return types
1947  *
1948  * @param tservice The service
1949  */
generate_service_helpers(t_service * tservice)1950 void t_javame_generator::generate_service_helpers(t_service* tservice) {
1951   vector<t_function*> functions = tservice->get_functions();
1952   vector<t_function*>::iterator f_iter;
1953   for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1954     t_struct* ts = (*f_iter)->get_arglist();
1955     generate_java_struct_definition(f_service_, ts, false, true);
1956     generate_function_helpers(*f_iter);
1957   }
1958 }
1959 
1960 /**
1961  * Generates a service client definition.
1962  *
1963  * @param tservice The service to generate a server for.
1964  */
generate_service_client(t_service * tservice)1965 void t_javame_generator::generate_service_client(t_service* tservice) {
1966   string extends = "";
1967   string extends_client = "";
1968   if (tservice->get_extends() != nullptr) {
1969     extends = type_name(tservice->get_extends());
1970     extends_client = " extends " + extends + ".Client";
1971   }
1972 
1973   indent(f_service_) << "public static class Client" << extends_client
1974                      << " implements TServiceClient, Iface {" << endl;
1975   indent_up();
1976 
1977   indent(f_service_) << "public Client(TProtocol prot)" << endl;
1978   scope_up(f_service_);
1979   indent(f_service_) << "this(prot, prot);" << endl;
1980   scope_down(f_service_);
1981   f_service_ << endl;
1982 
1983   indent(f_service_) << "public Client(TProtocol iprot, TProtocol oprot)" << endl;
1984   scope_up(f_service_);
1985   if (extends.empty()) {
1986     f_service_ << indent() << "iprot_ = iprot;" << endl << indent() << "oprot_ = oprot;" << endl;
1987   } else {
1988     f_service_ << indent() << "super(iprot, oprot);" << endl;
1989   }
1990   scope_down(f_service_);
1991   f_service_ << endl;
1992 
1993   if (extends.empty()) {
1994     f_service_ << indent() << "protected TProtocol iprot_;" << endl << indent()
1995                << "protected TProtocol oprot_;" << endl << endl << indent()
1996                << "protected int seqid_;" << endl << endl;
1997 
1998     indent(f_service_) << "public TProtocol getInputProtocol()" << endl;
1999     scope_up(f_service_);
2000     indent(f_service_) << "return this.iprot_;" << endl;
2001     scope_down(f_service_);
2002     f_service_ << endl;
2003 
2004     indent(f_service_) << "public TProtocol getOutputProtocol()" << endl;
2005     scope_up(f_service_);
2006     indent(f_service_) << "return this.oprot_;" << endl;
2007     scope_down(f_service_);
2008     f_service_ << endl;
2009   }
2010 
2011   // Generate client method implementations
2012   vector<t_function*> functions = tservice->get_functions();
2013   vector<t_function*>::const_iterator f_iter;
2014   for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
2015     string funname = (*f_iter)->get_name();
2016 
2017     // Open function
2018     indent(f_service_) << "public " << function_signature(*f_iter) << endl;
2019     scope_up(f_service_);
2020     indent(f_service_) << "send_" << funname << "(";
2021 
2022     // Get the struct of function call params
2023     t_struct* arg_struct = (*f_iter)->get_arglist();
2024 
2025     // Declare the function arguments
2026     const vector<t_field*>& fields = arg_struct->get_members();
2027     vector<t_field*>::const_iterator fld_iter;
2028     bool first = true;
2029     for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
2030       if (first) {
2031         first = false;
2032       } else {
2033         f_service_ << ", ";
2034       }
2035       f_service_ << (*fld_iter)->get_name();
2036     }
2037     f_service_ << ");" << endl;
2038 
2039     if (!(*f_iter)->is_oneway()) {
2040       f_service_ << indent();
2041       if (!(*f_iter)->get_returntype()->is_void()) {
2042         f_service_ << "return ";
2043       }
2044       f_service_ << "recv_" << funname << "();" << endl;
2045     }
2046     scope_down(f_service_);
2047     f_service_ << endl;
2048 
2049     t_function send_function(g_type_void,
2050                              string("send_") + (*f_iter)->get_name(),
2051                              (*f_iter)->get_arglist());
2052 
2053     string argsname = (*f_iter)->get_name() + "_args";
2054 
2055     // Open function
2056     indent(f_service_) << "public " << function_signature(&send_function) << endl;
2057     scope_up(f_service_);
2058 
2059     // Serialize the request
2060     f_service_ << indent() << "oprot_.writeMessageBegin(new TMessage(\"" << funname << "\", "
2061                << ((*f_iter)->is_oneway() ? "TMessageType.ONEWAY" : "TMessageType.CALL")
2062                << ", ++seqid_));" << endl << indent() << argsname << " args = new " << argsname
2063                << "();" << endl;
2064 
2065     for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
2066       f_service_ << indent() << "args.set" << get_cap_name((*fld_iter)->get_name()) << "("
2067                  << (*fld_iter)->get_name() << ");" << endl;
2068     }
2069 
2070     f_service_ << indent() << "args.write(oprot_);" << endl << indent()
2071                << "oprot_.writeMessageEnd();" << endl << indent()
2072                << "oprot_.getTransport().flush();" << endl;
2073 
2074     scope_down(f_service_);
2075     f_service_ << endl;
2076 
2077     if (!(*f_iter)->is_oneway()) {
2078       string resultname = (*f_iter)->get_name() + "_result";
2079 
2080       t_struct noargs(program_);
2081       t_function recv_function((*f_iter)->get_returntype(),
2082                                string("recv_") + (*f_iter)->get_name(),
2083                                &noargs,
2084                                (*f_iter)->get_xceptions());
2085       // Open function
2086       indent(f_service_) << "public " << function_signature(&recv_function) << endl;
2087       scope_up(f_service_);
2088 
2089       f_service_ << indent() << "TMessage msg = iprot_.readMessageBegin();" << endl << indent()
2090                  << "if (msg.type == TMessageType.EXCEPTION) {" << endl << indent()
2091                  << "  TApplicationException x = TApplicationException.read(iprot_);" << endl
2092                  << indent() << "  iprot_.readMessageEnd();" << endl << indent() << "  throw x;"
2093                  << endl << indent() << "}" << endl << indent() << "if (msg.seqid != seqid_) {"
2094                  << endl << indent()
2095                  << "  throw new TApplicationException(TApplicationException.BAD_SEQUENCE_ID, \""
2096                  << (*f_iter)->get_name() << " failed: out of sequence response\");" << endl
2097                  << indent() << "}" << endl << indent() << resultname << " result = new "
2098                  << resultname << "();" << endl << indent() << "result.read(iprot_);" << endl
2099                  << indent() << "iprot_.readMessageEnd();" << endl;
2100 
2101       // Careful, only return _result if not a void function
2102       if (!(*f_iter)->get_returntype()->is_void()) {
2103         f_service_ << indent() << "if (result." << generate_isset_check("success") << ") {" << endl
2104                    << indent() << "  return result.success;" << endl << indent() << "}" << endl;
2105       }
2106 
2107       t_struct* xs = (*f_iter)->get_xceptions();
2108       const std::vector<t_field*>& xceptions = xs->get_members();
2109       vector<t_field*>::const_iterator x_iter;
2110       for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
2111         f_service_ << indent() << "if (result." << (*x_iter)->get_name() << " != null) {" << endl
2112                    << indent() << "  throw result." << (*x_iter)->get_name() << ";" << endl
2113                    << indent() << "}" << endl;
2114       }
2115 
2116       // If you get here it's an exception, unless a void function
2117       if ((*f_iter)->get_returntype()->is_void()) {
2118         indent(f_service_) << "return;" << endl;
2119       } else {
2120         f_service_ << indent()
2121                    << "throw new TApplicationException(TApplicationException.MISSING_RESULT, \""
2122                    << (*f_iter)->get_name() << " failed: unknown result\");" << endl;
2123       }
2124 
2125       // Close function
2126       scope_down(f_service_);
2127       f_service_ << endl;
2128     }
2129   }
2130 
2131   indent_down();
2132   indent(f_service_) << "}" << endl;
2133 }
2134 
2135 /**
2136  * Generates a service server definition.
2137  *
2138  * @param tservice The service to generate a server for.
2139  */
generate_service_server(t_service * tservice)2140 void t_javame_generator::generate_service_server(t_service* tservice) {
2141   // Generate the dispatch methods
2142   vector<t_function*> functions = tservice->get_functions();
2143   vector<t_function*>::iterator f_iter;
2144 
2145   // Extends stuff
2146   string extends = "";
2147   string extends_processor = "";
2148   if (tservice->get_extends() != nullptr) {
2149     extends = type_name(tservice->get_extends());
2150     extends_processor = " extends " + extends + ".Processor";
2151   }
2152 
2153   // Generate the header portion
2154   indent(f_service_) << "public static class Processor" << extends_processor
2155                      << " implements TProcessor {" << endl;
2156   indent_up();
2157 
2158   indent(f_service_) << "public Processor(Iface iface)" << endl;
2159   scope_up(f_service_);
2160   if (!extends.empty()) {
2161     f_service_ << indent() << "super(iface);" << endl;
2162   }
2163   f_service_ << indent() << "iface_ = iface;" << endl;
2164 
2165   for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
2166     f_service_ << indent() << "processMap_.put(\"" << (*f_iter)->get_name() << "\", new "
2167                << (*f_iter)->get_name() << "());" << endl;
2168   }
2169 
2170   scope_down(f_service_);
2171   f_service_ << endl;
2172 
2173   if (extends.empty()) {
2174     f_service_
2175         << indent() << "protected static interface ProcessFunction {" << endl << indent()
2176         << "  public void process(int seqid, TProtocol iprot, TProtocol oprot) throws TException;"
2177         << endl << indent() << "}" << endl << endl;
2178   }
2179 
2180   f_service_ << indent() << "private Iface iface_;" << endl;
2181 
2182   if (extends.empty()) {
2183     f_service_ << indent() << "protected final Hashtable processMap_ = new Hashtable();" << endl;
2184   }
2185 
2186   f_service_ << endl;
2187 
2188   // Generate the server implementation
2189   indent(f_service_) << "public boolean process(TProtocol iprot, TProtocol oprot) throws TException"
2190                      << endl;
2191   scope_up(f_service_);
2192 
2193   f_service_ << indent() << "TMessage msg = iprot.readMessageBegin();" << endl;
2194 
2195   // TODO(mcslee): validate message, was the seqid etc. legit?
2196 
2197   f_service_
2198       << indent() << "ProcessFunction fn = (ProcessFunction)processMap_.get(msg.name);" << endl
2199       << indent() << "if (fn == null) {" << endl << indent()
2200       << "  TProtocolUtil.skip(iprot, TType.STRUCT);" << endl << indent()
2201       << "  iprot.readMessageEnd();" << endl << indent()
2202       << "  TApplicationException x = new "
2203          "TApplicationException(TApplicationException.UNKNOWN_METHOD, \"Invalid method name: "
2204          "'\"+msg.name+\"'\");" << endl << indent()
2205       << "  oprot.writeMessageBegin(new TMessage(msg.name, TMessageType.EXCEPTION, msg.seqid));"
2206       << endl << indent() << "  x.write(oprot);" << endl << indent() << "  oprot.writeMessageEnd();"
2207       << endl << indent() << "  oprot.getTransport().flush();" << endl << indent()
2208       << "  return true;" << endl << indent() << "}" << endl << indent()
2209       << "fn.process(msg.seqid, iprot, oprot);" << endl;
2210 
2211   f_service_ << indent() << "return true;" << endl;
2212 
2213   scope_down(f_service_);
2214   f_service_ << endl;
2215 
2216   // Generate the process subfunctions
2217   for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
2218     generate_process_function(tservice, *f_iter);
2219   }
2220 
2221   indent_down();
2222   indent(f_service_) << "}" << endl << endl;
2223 }
2224 
2225 /**
2226  * Generates a struct and helpers for a function.
2227  *
2228  * @param tfunction The function
2229  */
generate_function_helpers(t_function * tfunction)2230 void t_javame_generator::generate_function_helpers(t_function* tfunction) {
2231   if (tfunction->is_oneway()) {
2232     return;
2233   }
2234 
2235   t_struct result(program_, tfunction->get_name() + "_result");
2236   t_field success(tfunction->get_returntype(), "success", 0);
2237   if (!tfunction->get_returntype()->is_void()) {
2238     result.append(&success);
2239   }
2240 
2241   t_struct* xs = tfunction->get_xceptions();
2242   const vector<t_field*>& fields = xs->get_members();
2243   vector<t_field*>::const_iterator f_iter;
2244   for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
2245     result.append(*f_iter);
2246   }
2247 
2248   generate_java_struct_definition(f_service_, &result, false, true, true);
2249 }
2250 
2251 /**
2252  * Generates a process function definition.
2253  *
2254  * @param tfunction The function to write a dispatcher for
2255  */
generate_process_function(t_service * tservice,t_function * tfunction)2256 void t_javame_generator::generate_process_function(t_service* tservice, t_function* tfunction) {
2257   (void)tservice;
2258   // Open class
2259   indent(f_service_) << "private class " << tfunction->get_name() << " implements ProcessFunction {"
2260                      << endl;
2261   indent_up();
2262 
2263   // Open function
2264   indent(f_service_)
2265       << "public void process(int seqid, TProtocol iprot, TProtocol oprot) throws TException"
2266       << endl;
2267   scope_up(f_service_);
2268 
2269   string argsname = tfunction->get_name() + "_args";
2270   string resultname = tfunction->get_name() + "_result";
2271 
2272   f_service_ << indent() << argsname << " args = new " << argsname << "();" << endl << indent()
2273              << "try {" << endl;
2274   indent_up();
2275   f_service_ << indent() << "args.read(iprot);" << endl;
2276   indent_down();
2277   f_service_ << indent() << "} catch (TProtocolException e) {" << endl;
2278   indent_up();
2279   f_service_ << indent() << "iprot.readMessageEnd();" << endl << indent()
2280              << "TApplicationException x = new "
2281                 "TApplicationException(TApplicationException.PROTOCOL_ERROR, e.getMessage());"
2282              << endl << indent() << "oprot.writeMessageBegin(new TMessage(\""
2283              << tfunction->get_name() << "\", TMessageType.EXCEPTION, seqid));" << endl << indent()
2284              << "x.write(oprot);" << endl << indent() << "oprot.writeMessageEnd();" << endl
2285              << indent() << "oprot.getTransport().flush();" << endl << indent() << "return;"
2286              << endl;
2287   indent_down();
2288   f_service_ << indent() << "}" << endl;
2289   f_service_ << indent() << "iprot.readMessageEnd();" << endl;
2290 
2291   t_struct* xs = tfunction->get_xceptions();
2292   const std::vector<t_field*>& xceptions = xs->get_members();
2293   vector<t_field*>::const_iterator x_iter;
2294 
2295   // Declare result for non oneway function
2296   if (!tfunction->is_oneway()) {
2297     f_service_ << indent() << resultname << " result = new " << resultname << "();" << endl;
2298   }
2299 
2300   // Try block for a function with exceptions
2301   if (xceptions.size() > 0) {
2302     f_service_ << indent() << "try {" << endl;
2303     indent_up();
2304   }
2305 
2306   // Generate the function call
2307   t_struct* arg_struct = tfunction->get_arglist();
2308   const std::vector<t_field*>& fields = arg_struct->get_members();
2309   vector<t_field*>::const_iterator f_iter;
2310 
2311   f_service_ << indent();
2312   if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
2313     f_service_ << "result.success = ";
2314   }
2315   f_service_ << "iface_." << tfunction->get_name() << "(";
2316   bool first = true;
2317   for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
2318     if (first) {
2319       first = false;
2320     } else {
2321       f_service_ << ", ";
2322     }
2323     f_service_ << "args." << (*f_iter)->get_name();
2324   }
2325   f_service_ << ");" << endl;
2326 
2327   // Set isset on success field
2328   if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()
2329       && !type_can_be_null(tfunction->get_returntype())) {
2330     f_service_ << indent() << "result.set" << get_cap_name("success") << get_cap_name("isSet")
2331                << "(true);" << endl;
2332   }
2333 
2334   if (!tfunction->is_oneway() && xceptions.size() > 0) {
2335     indent_down();
2336     f_service_ << indent() << "}";
2337     for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
2338       f_service_ << " catch (" << type_name((*x_iter)->get_type(), false, false) << " "
2339                  << (*x_iter)->get_name() << ") {" << endl;
2340       if (!tfunction->is_oneway()) {
2341         indent_up();
2342         f_service_ << indent() << "result." << (*x_iter)->get_name() << " = "
2343                    << (*x_iter)->get_name() << ";" << endl;
2344         indent_down();
2345         f_service_ << indent() << "}";
2346       } else {
2347         f_service_ << "}";
2348       }
2349     }
2350     f_service_ << " catch (Throwable th) {" << endl;
2351     indent_up();
2352     f_service_ << indent() << "TApplicationException x = new "
2353                               "TApplicationException(TApplicationException.INTERNAL_ERROR, "
2354                               "\"Internal error processing " << tfunction->get_name() << "\");"
2355                << endl << indent() << "oprot.writeMessageBegin(new TMessage(\""
2356                << tfunction->get_name() << "\", TMessageType.EXCEPTION, seqid));" << endl
2357                << indent() << "x.write(oprot);" << endl << indent() << "oprot.writeMessageEnd();"
2358                << endl << indent() << "oprot.getTransport().flush();" << endl << indent()
2359                << "return;" << endl;
2360     indent_down();
2361     f_service_ << indent() << "}" << endl;
2362   }
2363 
2364   // Shortcut out here for oneway functions
2365   if (tfunction->is_oneway()) {
2366     f_service_ << indent() << "return;" << endl;
2367     scope_down(f_service_);
2368 
2369     // Close class
2370     indent_down();
2371     f_service_ << indent() << "}" << endl << endl;
2372     return;
2373   }
2374 
2375   f_service_ << indent() << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name()
2376              << "\", TMessageType.REPLY, seqid));" << endl << indent() << "result.write(oprot);"
2377              << endl << indent() << "oprot.writeMessageEnd();" << endl << indent()
2378              << "oprot.getTransport().flush();" << endl;
2379 
2380   // Close function
2381   scope_down(f_service_);
2382   f_service_ << endl;
2383 
2384   // Close class
2385   indent_down();
2386   f_service_ << indent() << "}" << endl << endl;
2387 }
2388 
2389 /**
2390  * Deserializes a field of any type.
2391  *
2392  * @param tfield The field
2393  * @param prefix The variable name or container for this field
2394  */
generate_deserialize_field(ostream & out,t_field * tfield,string prefix)2395 void t_javame_generator::generate_deserialize_field(ostream& out, t_field* tfield, string prefix) {
2396   t_type* type = get_true_type(tfield->get_type());
2397 
2398   if (type->is_void()) {
2399     throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name();
2400   }
2401 
2402   string name = prefix + tfield->get_name();
2403 
2404   if (type->is_struct() || type->is_xception()) {
2405     generate_deserialize_struct(out, (t_struct*)type, name);
2406   } else if (type->is_container()) {
2407     generate_deserialize_container(out, type, name);
2408   } else if (type->is_base_type()) {
2409     indent(out) << name << " = iprot.";
2410 
2411     t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2412     switch (tbase) {
2413     case t_base_type::TYPE_VOID:
2414       throw "compiler error: cannot serialize void field in a struct: " + name;
2415       break;
2416     case t_base_type::TYPE_STRING:
2417       if (!type->is_binary()) {
2418         out << "readString();";
2419       } else {
2420         out << "readBinary();";
2421       }
2422       break;
2423     case t_base_type::TYPE_BOOL:
2424       out << "readBool();";
2425       break;
2426     case t_base_type::TYPE_I8:
2427       out << "readByte();";
2428       break;
2429     case t_base_type::TYPE_I16:
2430       out << "readI16();";
2431       break;
2432     case t_base_type::TYPE_I32:
2433       out << "readI32();";
2434       break;
2435     case t_base_type::TYPE_I64:
2436       out << "readI64();";
2437       break;
2438     case t_base_type::TYPE_DOUBLE:
2439       out << "readDouble();";
2440       break;
2441     default:
2442       throw "compiler error: no Java name for base type " + t_base_type::t_base_name(tbase);
2443     }
2444     out << endl;
2445   } else if (type->is_enum()) {
2446     indent(out) << name << " = "
2447                 << type_name(tfield->get_type(), true, false) + ".findByValue(iprot.readI32());"
2448                 << endl;
2449   } else {
2450     printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
2451            tfield->get_name().c_str(),
2452            type_name(type).c_str());
2453   }
2454 }
2455 
2456 /**
2457  * Generates an unserializer for a struct, invokes read()
2458  */
generate_deserialize_struct(ostream & out,t_struct * tstruct,string prefix)2459 void t_javame_generator::generate_deserialize_struct(ostream& out,
2460                                                      t_struct* tstruct,
2461                                                      string prefix) {
2462   out << indent() << prefix << " = new " << type_name(tstruct) << "();" << endl << indent()
2463       << prefix << ".read(iprot);" << endl;
2464 }
2465 
2466 /**
2467  * Deserializes a container by reading its size and then iterating
2468  */
generate_deserialize_container(ostream & out,t_type * ttype,string prefix)2469 void t_javame_generator::generate_deserialize_container(ostream& out,
2470                                                         t_type* ttype,
2471                                                         string prefix) {
2472   scope_up(out);
2473 
2474   string obj;
2475 
2476   if (ttype->is_map()) {
2477     obj = tmp("_map");
2478   } else if (ttype->is_set()) {
2479     obj = tmp("_set");
2480   } else if (ttype->is_list()) {
2481     obj = tmp("_list");
2482   }
2483 
2484   // Declare variables, read header
2485   if (ttype->is_map()) {
2486     indent(out) << "TMap " << obj << " = iprot.readMapBegin();" << endl;
2487   } else if (ttype->is_set()) {
2488     indent(out) << "TSet " << obj << " = iprot.readSetBegin();" << endl;
2489   } else if (ttype->is_list()) {
2490     indent(out) << "TList " << obj << " = iprot.readListBegin();" << endl;
2491   }
2492 
2493   indent(out) << prefix << " = new " << type_name(ttype, false, true)
2494               // size the collection correctly
2495               << "(" << (ttype->is_list() ? "" : "2*") << obj << ".size"
2496               << ");" << endl;
2497 
2498   // For loop iterates over elements
2499   string i = tmp("_i");
2500   indent(out) << "for (int " << i << " = 0; " << i << " < " << obj << ".size"
2501               << "; "
2502               << "++" << i << ")" << endl;
2503 
2504   scope_up(out);
2505 
2506   if (ttype->is_map()) {
2507     generate_deserialize_map_element(out, (t_map*)ttype, prefix);
2508   } else if (ttype->is_set()) {
2509     generate_deserialize_set_element(out, (t_set*)ttype, prefix);
2510   } else if (ttype->is_list()) {
2511     generate_deserialize_list_element(out, (t_list*)ttype, prefix);
2512   }
2513 
2514   scope_down(out);
2515 
2516   // Read container end
2517   if (ttype->is_map()) {
2518     indent(out) << "iprot.readMapEnd();" << endl;
2519   } else if (ttype->is_set()) {
2520     indent(out) << "iprot.readSetEnd();" << endl;
2521   } else if (ttype->is_list()) {
2522     indent(out) << "iprot.readListEnd();" << endl;
2523   }
2524 
2525   scope_down(out);
2526 }
2527 
2528 /**
2529  * Generates code to deserialize a map
2530  */
generate_deserialize_map_element(ostream & out,t_map * tmap,string prefix)2531 void t_javame_generator::generate_deserialize_map_element(ostream& out,
2532                                                           t_map* tmap,
2533                                                           string prefix) {
2534   string key = tmp("_key");
2535   string val = tmp("_val");
2536   t_field fkey(tmap->get_key_type(), key);
2537   t_field fval(tmap->get_val_type(), val);
2538 
2539   indent(out) << declare_field(&fkey) << endl;
2540   indent(out) << declare_field(&fval) << endl;
2541 
2542   generate_deserialize_field(out, &fkey);
2543   generate_deserialize_field(out, &fval);
2544 
2545   indent(out) << prefix << ".put(" << box_type(tmap->get_key_type(), key) << ", "
2546               << box_type(tmap->get_val_type(), val) << ");" << endl;
2547 }
2548 
2549 /**
2550  * Deserializes a set element
2551  */
generate_deserialize_set_element(ostream & out,t_set * tset,string prefix)2552 void t_javame_generator::generate_deserialize_set_element(ostream& out,
2553                                                           t_set* tset,
2554                                                           string prefix) {
2555   string elem = tmp("_elem");
2556   t_field felem(tset->get_elem_type(), elem);
2557 
2558   indent(out) << declare_field(&felem) << endl;
2559 
2560   generate_deserialize_field(out, &felem);
2561 
2562   indent(out) << prefix << ".put(" << box_type(tset->get_elem_type(), elem) << ", "
2563               << box_type(tset->get_elem_type(), elem) << ");" << endl;
2564 }
2565 
2566 /**
2567  * Deserializes a list element
2568  */
generate_deserialize_list_element(ostream & out,t_list * tlist,string prefix)2569 void t_javame_generator::generate_deserialize_list_element(ostream& out,
2570                                                            t_list* tlist,
2571                                                            string prefix) {
2572   string elem = tmp("_elem");
2573   t_field felem(tlist->get_elem_type(), elem);
2574 
2575   indent(out) << declare_field(&felem) << endl;
2576 
2577   generate_deserialize_field(out, &felem);
2578 
2579   indent(out) << prefix << ".addElement(" << box_type(tlist->get_elem_type(), elem) << ");" << endl;
2580 }
2581 
2582 /**
2583  * Serializes a field of any type.
2584  *
2585  * @param tfield The field to serialize
2586  * @param prefix Name to prepend to field name
2587  */
generate_serialize_field(ostream & out,t_field * tfield,string prefix)2588 void t_javame_generator::generate_serialize_field(ostream& out, t_field* tfield, string prefix) {
2589   t_type* type = get_true_type(tfield->get_type());
2590 
2591   // Do nothing for void types
2592   if (type->is_void()) {
2593     throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name();
2594   }
2595 
2596   if (type->is_struct() || type->is_xception()) {
2597     generate_serialize_struct(out, (t_struct*)type, prefix + tfield->get_name());
2598   } else if (type->is_container()) {
2599     generate_serialize_container(out, type, prefix + tfield->get_name());
2600   } else if (type->is_enum()) {
2601     indent(out) << "oprot.writeI32(" << prefix + tfield->get_name() << ".getValue());" << endl;
2602   } else if (type->is_base_type()) {
2603     string name = prefix + tfield->get_name();
2604     indent(out) << "oprot.";
2605 
2606     if (type->is_base_type()) {
2607       t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2608       switch (tbase) {
2609       case t_base_type::TYPE_VOID:
2610         throw "compiler error: cannot serialize void field in a struct: " + name;
2611         break;
2612       case t_base_type::TYPE_STRING:
2613         if (type->is_binary()) {
2614           out << "writeBinary(" << name << ");";
2615         } else {
2616           out << "writeString(" << name << ");";
2617         }
2618         break;
2619       case t_base_type::TYPE_BOOL:
2620         out << "writeBool(" << name << ");";
2621         break;
2622       case t_base_type::TYPE_I8:
2623         out << "writeByte(" << name << ");";
2624         break;
2625       case t_base_type::TYPE_I16:
2626         out << "writeI16(" << name << ");";
2627         break;
2628       case t_base_type::TYPE_I32:
2629         out << "writeI32(" << name << ");";
2630         break;
2631       case t_base_type::TYPE_I64:
2632         out << "writeI64(" << name << ");";
2633         break;
2634       case t_base_type::TYPE_DOUBLE:
2635         out << "writeDouble(" << name << ");";
2636         break;
2637       default:
2638         throw "compiler error: no Java name for base type " + t_base_type::t_base_name(tbase);
2639       }
2640     } else if (type->is_enum()) {
2641       out << "writeI32(" << name << ");";
2642     }
2643     out << endl;
2644   } else {
2645     printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
2646            prefix.c_str(),
2647            tfield->get_name().c_str(),
2648            type_name(type).c_str());
2649   }
2650 }
2651 
2652 /**
2653  * Serializes all the members of a struct.
2654  *
2655  * @param tstruct The struct to serialize
2656  * @param prefix  String prefix to attach to all fields
2657  */
generate_serialize_struct(ostream & out,t_struct * tstruct,string prefix)2658 void t_javame_generator::generate_serialize_struct(ostream& out,
2659                                                    t_struct* tstruct,
2660                                                    string prefix) {
2661   (void)tstruct;
2662   out << indent() << prefix << ".write(oprot);" << endl;
2663 }
2664 
2665 /**
2666  * Serializes a container by writing its size then the elements.
2667  *
2668  * @param ttype  The type of container
2669  * @param prefix String prefix for fields
2670  */
generate_serialize_container(ostream & out,t_type * ttype,string prefix)2671 void t_javame_generator::generate_serialize_container(ostream& out, t_type* ttype, string prefix) {
2672   scope_up(out);
2673 
2674   if (ttype->is_map()) {
2675     indent(out) << "oprot.writeMapBegin(new TMap(" << type_to_enum(((t_map*)ttype)->get_key_type())
2676                 << ", " << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " << prefix
2677                 << ".size()));" << endl;
2678   } else if (ttype->is_set()) {
2679     indent(out) << "oprot.writeSetBegin(new TSet(" << type_to_enum(((t_set*)ttype)->get_elem_type())
2680                 << ", " << prefix << ".size()));" << endl;
2681   } else if (ttype->is_list()) {
2682     indent(out) << "oprot.writeListBegin(new TList("
2683                 << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " << prefix << ".size()));"
2684                 << endl;
2685   }
2686 
2687   string iter = tmp("_iter");
2688   if (ttype->is_map()) {
2689     string enumer = iter + "_enum";
2690     string key_type = type_name(((t_map*)ttype)->get_key_type(), true, false);
2691     indent(out) << "for (Enumeration " << enumer << " = " << prefix << ".keys(); " << enumer
2692                 << ".hasMoreElements(); ) ";
2693     scope_up(out);
2694     indent(out) << key_type << " " << iter << " = (" << key_type << ")" << enumer
2695                 << ".nextElement();" << endl;
2696   } else if (ttype->is_set()) {
2697     string enumer = iter + "_enum";
2698     string ele_type = type_name(((t_list*)ttype)->get_elem_type(), true);
2699     indent(out) << "for (Enumeration " << enumer << " = " << prefix << ".keys(); " << enumer
2700                 << ".hasMoreElements(); ) ";
2701     scope_up(out);
2702     indent(out) << ele_type << " " << iter << " = (" << ele_type << ")" << enumer
2703                 << ".nextElement();" << endl;
2704   } else if (ttype->is_list()) {
2705     string enumer = iter + "_enum";
2706     indent(out) << "for (Enumeration " << enumer << " = " << prefix << ".elements(); " << enumer
2707                 << ".hasMoreElements(); ) ";
2708     scope_up(out);
2709     string ele_type = type_name(((t_list*)ttype)->get_elem_type(), true);
2710     indent(out) << ele_type << " " << iter << " = (" << ele_type << ")" << enumer
2711                 << ".nextElement();" << endl;
2712   }
2713 
2714   if (ttype->is_map()) {
2715     generate_serialize_map_element(out, (t_map*)ttype, iter, prefix);
2716   } else if (ttype->is_set()) {
2717     generate_serialize_set_element(out, (t_set*)ttype, iter);
2718   } else if (ttype->is_list()) {
2719     generate_serialize_list_element(out, (t_list*)ttype, iter);
2720   }
2721   scope_down(out);
2722 
2723   if (ttype->is_map()) {
2724     indent(out) << "oprot.writeMapEnd();" << endl;
2725   } else if (ttype->is_set()) {
2726     indent(out) << "oprot.writeSetEnd();" << endl;
2727   } else if (ttype->is_list()) {
2728     indent(out) << "oprot.writeListEnd();" << endl;
2729   }
2730 
2731   scope_down(out);
2732 }
2733 
2734 /**
2735  * Serializes the members of a map.
2736  */
generate_serialize_map_element(ostream & out,t_map * tmap,string iter,string map)2737 void t_javame_generator::generate_serialize_map_element(ostream& out,
2738                                                         t_map* tmap,
2739                                                         string iter,
2740                                                         string map) {
2741   t_field kfield(tmap->get_key_type(), iter);
2742   generate_serialize_field(out, &kfield, "");
2743   string val_type = type_name(tmap->get_val_type(), true, false);
2744   t_field vfield(tmap->get_val_type(), "((" + val_type + ")" + map + ".get(" + iter + "))");
2745   generate_serialize_field(out, &vfield, "");
2746 }
2747 
2748 /**
2749  * Serializes the members of a set.
2750  */
generate_serialize_set_element(ostream & out,t_set * tset,string iter)2751 void t_javame_generator::generate_serialize_set_element(ostream& out, t_set* tset, string iter) {
2752   t_field efield(tset->get_elem_type(), iter);
2753   generate_serialize_field(out, &efield, "");
2754 }
2755 
2756 /**
2757  * Serializes the members of a list.
2758  */
generate_serialize_list_element(ostream & out,t_list * tlist,string iter)2759 void t_javame_generator::generate_serialize_list_element(ostream& out,
2760                                                          t_list* tlist,
2761                                                          string iter) {
2762   t_field efield(tlist->get_elem_type(), iter);
2763   generate_serialize_field(out, &efield, "");
2764 }
2765 
2766 /**
2767  * Returns a Java type name
2768  *
2769  * @param ttype The type
2770  * @param container Is the type going inside a container?
2771  * @return Java type name, i.e. Vector
2772  */
type_name(t_type * ttype,bool in_container,bool in_init,bool skip_generic)2773 string t_javame_generator::type_name(t_type* ttype,
2774                                      bool in_container,
2775                                      bool in_init,
2776                                      bool skip_generic) {
2777   (void)in_init;
2778   (void)skip_generic;
2779   // In Java typedefs are just resolved to their real type
2780   ttype = get_true_type(ttype);
2781   string prefix;
2782 
2783   if (ttype->is_base_type()) {
2784     return base_type_name((t_base_type*)ttype, in_container);
2785   } else if (ttype->is_map()) {
2786     return "Hashtable";
2787   } else if (ttype->is_set()) {
2788     return "Hashtable";
2789   } else if (ttype->is_list()) {
2790     return "Vector";
2791   }
2792 
2793   // Check for namespacing
2794   t_program* program = ttype->get_program();
2795   if (program != nullptr && program != program_) {
2796     string package = program->get_namespace("java");
2797     if (!package.empty()) {
2798       return package + "." + ttype->get_name();
2799     }
2800   }
2801 
2802   return ttype->get_name();
2803 }
2804 
2805 /**
2806  * Returns the C++ type that corresponds to the thrift type.
2807  *
2808  * @param tbase The base type
2809  * @param container Is it going in a Java container?
2810  */
base_type_name(t_base_type * type,bool in_container)2811 string t_javame_generator::base_type_name(t_base_type* type, bool in_container) {
2812   t_base_type::t_base tbase = type->get_base();
2813 
2814   switch (tbase) {
2815   case t_base_type::TYPE_VOID:
2816     return "void";
2817   case t_base_type::TYPE_STRING:
2818     if (!type->is_binary()) {
2819       return "String";
2820     } else {
2821       return "byte[]";
2822     }
2823   case t_base_type::TYPE_BOOL:
2824     return (in_container ? "Boolean" : "boolean");
2825   case t_base_type::TYPE_I8:
2826     return (in_container ? "Byte" : "byte");
2827   case t_base_type::TYPE_I16:
2828     return (in_container ? "Short" : "short");
2829   case t_base_type::TYPE_I32:
2830     return (in_container ? "Integer" : "int");
2831   case t_base_type::TYPE_I64:
2832     return (in_container ? "Long" : "long");
2833   case t_base_type::TYPE_DOUBLE:
2834     return (in_container ? "Double" : "double");
2835   default:
2836     throw "compiler error: no Java name for base type " + t_base_type::t_base_name(tbase);
2837   }
2838 }
2839 
2840 /**
2841  * Declares a field, which may include initialization as necessary.
2842  *
2843  * @param ttype The type
2844  */
declare_field(t_field * tfield,bool init)2845 string t_javame_generator::declare_field(t_field* tfield, bool init) {
2846   // TODO(mcslee): do we ever need to initialize the field?
2847   string result = type_name(tfield->get_type()) + " " + tfield->get_name();
2848   if (init) {
2849     t_type* ttype = get_true_type(tfield->get_type());
2850     if (ttype->is_base_type() && tfield->get_value() != nullptr) {
2851       std::ofstream dummy;
2852       result += " = " + render_const_value(dummy, tfield->get_name(), ttype, tfield->get_value());
2853     } else if (ttype->is_base_type()) {
2854       t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
2855       switch (tbase) {
2856       case t_base_type::TYPE_VOID:
2857         throw "NO T_VOID CONSTRUCT";
2858       case t_base_type::TYPE_STRING:
2859         result += " = null";
2860         break;
2861       case t_base_type::TYPE_BOOL:
2862         result += " = false";
2863         break;
2864       case t_base_type::TYPE_I8:
2865       case t_base_type::TYPE_I16:
2866       case t_base_type::TYPE_I32:
2867       case t_base_type::TYPE_I64:
2868         result += " = 0";
2869         break;
2870       case t_base_type::TYPE_DOUBLE:
2871         result += " = (double)0";
2872         break;
2873       default:
2874         throw "compiler error: unhandled type";
2875       }
2876 
2877     } else if (ttype->is_enum()) {
2878       result += " = 0";
2879     } else if (ttype->is_container()) {
2880       result += " = new " + type_name(ttype, false, true) + "()";
2881     } else {
2882       result += " = new " + type_name(ttype, false, true) + "()";
2883       ;
2884     }
2885   }
2886   return result + ";";
2887 }
2888 
2889 /**
2890  * Renders a function signature of the form 'type name(args)'
2891  *
2892  * @param tfunction Function definition
2893  * @return String of rendered function definition
2894  */
function_signature(t_function * tfunction,string prefix)2895 string t_javame_generator::function_signature(t_function* tfunction, string prefix) {
2896   t_type* ttype = tfunction->get_returntype();
2897   std::string result = type_name(ttype) + " " + prefix + tfunction->get_name() + "("
2898                        + argument_list(tfunction->get_arglist()) + ") throws ";
2899   t_struct* xs = tfunction->get_xceptions();
2900   const std::vector<t_field*>& xceptions = xs->get_members();
2901   vector<t_field*>::const_iterator x_iter;
2902   for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
2903     result += type_name((*x_iter)->get_type(), false, false) + ", ";
2904   }
2905   result += "TException";
2906   return result;
2907 }
2908 
2909 /**
2910  * Renders a comma separated field list, with type names
2911  */
argument_list(t_struct * tstruct,bool include_types)2912 string t_javame_generator::argument_list(t_struct* tstruct, bool include_types) {
2913   string result = "";
2914 
2915   const vector<t_field*>& fields = tstruct->get_members();
2916   vector<t_field*>::const_iterator f_iter;
2917   bool first = true;
2918   for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
2919     if (first) {
2920       first = false;
2921     } else {
2922       result += ", ";
2923     }
2924     if (include_types) {
2925       result += type_name((*f_iter)->get_type()) + " ";
2926     }
2927     result += (*f_iter)->get_name();
2928   }
2929   return result;
2930 }
2931 
2932 /**
2933  * Converts the parse type to a C++ enum string for the given type.
2934  */
type_to_enum(t_type * type)2935 string t_javame_generator::type_to_enum(t_type* type) {
2936   type = get_true_type(type);
2937 
2938   if (type->is_base_type()) {
2939     t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2940     switch (tbase) {
2941     case t_base_type::TYPE_VOID:
2942       throw "NO T_VOID CONSTRUCT";
2943     case t_base_type::TYPE_STRING:
2944       return "TType.STRING";
2945     case t_base_type::TYPE_BOOL:
2946       return "TType.BOOL";
2947     case t_base_type::TYPE_I8:
2948       return "TType.BYTE";
2949     case t_base_type::TYPE_I16:
2950       return "TType.I16";
2951     case t_base_type::TYPE_I32:
2952       return "TType.I32";
2953     case t_base_type::TYPE_I64:
2954       return "TType.I64";
2955     case t_base_type::TYPE_DOUBLE:
2956       return "TType.DOUBLE";
2957     default:
2958       throw "compiler error: unhandled type";
2959     }
2960   } else if (type->is_enum()) {
2961     return "TType.I32";
2962   } else if (type->is_struct() || type->is_xception()) {
2963     return "TType.STRUCT";
2964   } else if (type->is_map()) {
2965     return "TType.MAP";
2966   } else if (type->is_set()) {
2967     return "TType.SET";
2968   } else if (type->is_list()) {
2969     return "TType.LIST";
2970   }
2971 
2972   throw "INVALID TYPE IN type_to_enum: " + type->get_name();
2973 }
2974 
2975 /**
2976  * Applies the correct style to a string based on the value of nocamel_style_
2977  */
get_cap_name(std::string name)2978 std::string t_javame_generator::get_cap_name(std::string name) {
2979   name[0] = toupper(name[0]);
2980   return name;
2981 }
2982 
constant_name(string name)2983 string t_javame_generator::constant_name(string name) {
2984   string constant_name;
2985 
2986   bool is_first = true;
2987   bool was_previous_char_upper = false;
2988   for (char character : name) {
2989     bool is_upper = isupper(character);
2990 
2991     if (is_upper && !is_first && !was_previous_char_upper) {
2992       constant_name += '_';
2993     }
2994     constant_name += toupper(character);
2995 
2996     is_first = false;
2997     was_previous_char_upper = is_upper;
2998   }
2999 
3000   return constant_name;
3001 }
3002 
generate_java_docstring_comment(ostream & out,string contents)3003 void t_javame_generator::generate_java_docstring_comment(ostream& out, string contents) {
3004   generate_docstring_comment(out, "/**\n", " * ", contents, " */\n");
3005 }
3006 
generate_java_doc(ostream & out,t_field * field)3007 void t_javame_generator::generate_java_doc(ostream& out, t_field* field) {
3008   if (field->get_type()->is_enum()) {
3009     string combined_message = field->get_doc() + "\n@see " + get_enum_class_name(field->get_type());
3010     generate_java_docstring_comment(out, combined_message);
3011   } else {
3012     generate_java_doc(out, (t_doc*)field);
3013   }
3014 }
3015 
3016 /**
3017  * Emits a JavaDoc comment if the provided object has a doc in Thrift
3018  */
generate_java_doc(ostream & out,t_doc * tdoc)3019 void t_javame_generator::generate_java_doc(ostream& out, t_doc* tdoc) {
3020   if (tdoc->has_doc()) {
3021     generate_java_docstring_comment(out, tdoc->get_doc());
3022   }
3023 }
3024 
3025 /**
3026  * Emits a JavaDoc comment if the provided function object has a doc in Thrift
3027  */
generate_java_doc(ostream & out,t_function * tfunction)3028 void t_javame_generator::generate_java_doc(ostream& out, t_function* tfunction) {
3029   if (tfunction->has_doc()) {
3030     stringstream ss;
3031     ss << tfunction->get_doc();
3032     const vector<t_field*>& fields = tfunction->get_arglist()->get_members();
3033     vector<t_field*>::const_iterator p_iter;
3034     for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) {
3035       t_field* p = *p_iter;
3036       ss << "\n@param " << p->get_name();
3037       if (p->has_doc()) {
3038         ss << " " << p->get_doc();
3039       }
3040     }
3041     generate_docstring_comment(out, "/**\n", " * ", ss.str(), " */\n");
3042   }
3043 }
3044 
generate_deep_copy_container(ostream & out,std::string source_name_p1,std::string source_name_p2,std::string result_name,t_type * type)3045 void t_javame_generator::generate_deep_copy_container(ostream& out,
3046                                                       std::string source_name_p1,
3047                                                       std::string source_name_p2,
3048                                                       std::string result_name,
3049                                                       t_type* type) {
3050 
3051   t_container* container = (t_container*)type;
3052   std::string source_name;
3053   if (source_name_p2 == "")
3054     source_name = source_name_p1;
3055   else
3056     source_name = source_name_p1 + "." + source_name_p2;
3057 
3058   indent(out) << type_name(type, true, false) << " " << result_name << " = new "
3059               << type_name(container, false, true) << "();" << endl;
3060 
3061   std::string iterator_element_name = source_name_p1 + "_element";
3062   std::string enumeration_name = source_name_p1 + "_enum";
3063   std::string result_element_name = result_name + "_copy";
3064 
3065   if (container->is_map()) {
3066     t_type* key_type = ((t_map*)container)->get_key_type();
3067     t_type* val_type = ((t_map*)container)->get_val_type();
3068 
3069     indent(out) << "for (Enumeration " << enumeration_name << " = " << source_name << ".keys(); "
3070                 << enumeration_name << ".hasMoreElements(); ) {" << endl;
3071     indent_up();
3072 
3073     out << endl;
3074 
3075     indent(out) << type_name(key_type, true, false) << " " << iterator_element_name << "_key = ("
3076                 << type_name(key_type, true, false) << ")" << enumeration_name << ".nextElement();"
3077                 << endl;
3078     indent(out) << type_name(val_type, true, false) << " " << iterator_element_name << "_value = ("
3079                 << type_name(val_type, true, false) << ")" << source_name << ".get("
3080                 << iterator_element_name << "_key);" << endl;
3081 
3082     out << endl;
3083 
3084     if (key_type->is_container()) {
3085       generate_deep_copy_container(out,
3086                                    iterator_element_name + "_key",
3087                                    "",
3088                                    result_element_name + "_key",
3089                                    key_type);
3090     } else {
3091       indent(out) << type_name(key_type, true, false) << " " << result_element_name << "_key = ";
3092       generate_deep_copy_non_container(out,
3093                                        iterator_element_name + "_key",
3094                                        result_element_name + "_key",
3095                                        key_type);
3096       out << ";" << endl;
3097     }
3098 
3099     out << endl;
3100 
3101     if (val_type->is_container()) {
3102       generate_deep_copy_container(out,
3103                                    iterator_element_name + "_value",
3104                                    "",
3105                                    result_element_name + "_value",
3106                                    val_type);
3107     } else {
3108       indent(out) << type_name(val_type, true, false) << " " << result_element_name << "_value = ";
3109       generate_deep_copy_non_container(out,
3110                                        iterator_element_name + "_value",
3111                                        result_element_name + "_value",
3112                                        val_type);
3113       out << ";" << endl;
3114     }
3115 
3116     out << endl;
3117 
3118     indent(out) << result_name << ".put(" << result_element_name << "_key, " << result_element_name
3119                 << "_value);" << endl;
3120 
3121     indent_down();
3122     indent(out) << "}" << endl;
3123 
3124   } else {
3125     t_type* elem_type;
3126 
3127     if (container->is_set()) {
3128       elem_type = ((t_set*)container)->get_elem_type();
3129     } else {
3130       elem_type = ((t_list*)container)->get_elem_type();
3131     }
3132 
3133     indent(out) << "for (Enumeration " << enumeration_name << " = " << source_name
3134                 << ".elements(); " << enumeration_name << ".hasMoreElements(); ) {" << endl;
3135     indent_up();
3136     indent(out) << type_name(elem_type, true, false) << " " << iterator_element_name << " = ("
3137                 << type_name(elem_type, true, false) << ")" << enumeration_name << ".nextElement();"
3138                 << endl;
3139     if (elem_type->is_container()) {
3140       // recursive deep copy
3141       generate_deep_copy_container(out, iterator_element_name, "", result_element_name, elem_type);
3142       if (elem_type->is_list()) {
3143         indent(out) << result_name << ".addElement(" << result_element_name << ");" << endl;
3144       } else {
3145         indent(out) << result_name << ".put(" << result_element_name << ", " << result_element_name
3146                     << ");" << endl;
3147       }
3148     } else {
3149       // iterative copy
3150       if (elem_type->is_binary()) {
3151         indent(out) << type_name(elem_type, true, false) << " temp_binary_element = ";
3152         generate_deep_copy_non_container(out,
3153                                          iterator_element_name,
3154                                          "temp_binary_element",
3155                                          elem_type);
3156         out << ";" << endl;
3157         if (elem_type->is_list()) {
3158           indent(out) << result_name << ".addElement(temp_binary_element);" << endl;
3159         } else {
3160           indent(out) << result_name << ".put(temp_binary_element, temp_binary_element);" << endl;
3161         }
3162       } else {
3163         indent(out) << result_name << ".addElement(";
3164         generate_deep_copy_non_container(out, iterator_element_name, result_name, elem_type);
3165         out << ");" << endl;
3166       }
3167     }
3168 
3169     indent_down();
3170 
3171     indent(out) << "}" << endl;
3172   }
3173 }
3174 
generate_deep_copy_non_container(ostream & out,std::string source_name,std::string dest_name,t_type * type)3175 void t_javame_generator::generate_deep_copy_non_container(ostream& out,
3176                                                           std::string source_name,
3177                                                           std::string dest_name,
3178                                                           t_type* type) {
3179   if (type->is_base_type() || type->is_enum() || type->is_typedef()) {
3180     // binary fields need to be copied with System.arraycopy
3181     if (type->is_binary()) {
3182       out << "new byte[" << source_name << ".length];" << endl;
3183       indent(out) << "System.arraycopy(" << source_name << ", 0, " << dest_name << ", 0, "
3184                   << source_name << ".length)";
3185     }
3186     // everything else can be copied directly
3187     else
3188       out << source_name;
3189   } else {
3190     out << "new " << type_name(type, true, true) << "(" << source_name << ")";
3191   }
3192 }
3193 
generate_isset_check(t_field * field)3194 std::string t_javame_generator::generate_isset_check(t_field* field) {
3195   return generate_isset_check(field->get_name());
3196 }
3197 
isset_field_id(t_field * field)3198 std::string t_javame_generator::isset_field_id(t_field* field) {
3199   return "__" + upcase_string(field->get_name() + "_isset_id");
3200 }
3201 
generate_isset_check(std::string field_name)3202 std::string t_javame_generator::generate_isset_check(std::string field_name) {
3203   return "is" + get_cap_name("set") + get_cap_name(field_name) + "()";
3204 }
3205 
generate_isset_set(ostream & out,t_field * field)3206 void t_javame_generator::generate_isset_set(ostream& out, t_field* field) {
3207   if (!type_can_be_null(field->get_type())) {
3208     indent(out) << "set" << get_cap_name(field->get_name()) << get_cap_name("isSet") << "(true);"
3209                 << endl;
3210   }
3211 }
3212 
get_enum_class_name(t_type * type)3213 std::string t_javame_generator::get_enum_class_name(t_type* type) {
3214   string package = "";
3215   t_program* program = type->get_program();
3216   if (program != nullptr && program != program_) {
3217     package = program->get_namespace("java") + ".";
3218   }
3219   return package + type->get_name();
3220 }
3221 
generate_struct_desc(ostream & out,t_struct * tstruct)3222 void t_javame_generator::generate_struct_desc(ostream& out, t_struct* tstruct) {
3223   indent(out) << "private static final TStruct STRUCT_DESC = new TStruct(\"" << tstruct->get_name()
3224               << "\");" << endl;
3225 }
3226 
generate_field_descs(ostream & out,t_struct * tstruct)3227 void t_javame_generator::generate_field_descs(ostream& out, t_struct* tstruct) {
3228   const vector<t_field*>& members = tstruct->get_members();
3229   vector<t_field*>::const_iterator m_iter;
3230 
3231   for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
3232     indent(out) << "private static final TField " << constant_name((*m_iter)->get_name())
3233                 << "_FIELD_DESC = new TField(\"" << (*m_iter)->get_name() << "\", "
3234                 << type_to_enum((*m_iter)->get_type()) << ", "
3235                 << "(short)" << (*m_iter)->get_key() << ");" << endl;
3236   }
3237 }
3238 
has_bit_vector(t_struct * tstruct)3239 bool t_javame_generator::has_bit_vector(t_struct* tstruct) {
3240   const vector<t_field*>& members = tstruct->get_members();
3241   vector<t_field*>::const_iterator m_iter;
3242 
3243   for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
3244     if (!type_can_be_null(get_true_type((*m_iter)->get_type()))) {
3245       return true;
3246     }
3247   }
3248   return false;
3249 }
3250 
generate_java_struct_clear(std::ostream & out,t_struct * tstruct)3251 void t_javame_generator::generate_java_struct_clear(std::ostream& out, t_struct* tstruct) {
3252   indent(out) << "public void clear() {" << endl;
3253 
3254   const vector<t_field*>& members = tstruct->get_members();
3255   vector<t_field*>::const_iterator m_iter;
3256 
3257   indent_up();
3258   for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
3259     t_type* t = get_true_type((*m_iter)->get_type());
3260     if ((*m_iter)->get_value() != nullptr) {
3261       print_const_value(out,
3262                         "this." + (*m_iter)->get_name(),
3263                         t,
3264                         (*m_iter)->get_value(),
3265                         true,
3266                         true);
3267     } else {
3268       if (type_can_be_null(t)) {
3269         indent(out) << "this." << (*m_iter)->get_name() << " = null;" << endl;
3270       } else {
3271         // must be a base type
3272         // means it also needs to be explicitly unset
3273         indent(out) << "set" << get_cap_name((*m_iter)->get_name()) << get_cap_name("isSet")
3274                     << "(false);" << endl;
3275         switch (((t_base_type*)t)->get_base()) {
3276         case t_base_type::TYPE_I8:
3277         case t_base_type::TYPE_I16:
3278         case t_base_type::TYPE_I32:
3279         case t_base_type::TYPE_I64:
3280           indent(out) << "this." << (*m_iter)->get_name() << " = 0;" << endl;
3281           break;
3282         case t_base_type::TYPE_DOUBLE:
3283           indent(out) << "this." << (*m_iter)->get_name() << " = 0.0;" << endl;
3284           break;
3285         case t_base_type::TYPE_BOOL:
3286           indent(out) << "this." << (*m_iter)->get_name() << " = false;" << endl;
3287           break;
3288         default: // prevent gcc compiler warning
3289           break;
3290         }
3291       }
3292     }
3293   }
3294   indent_down();
3295 
3296   indent(out) << "}" << endl << endl;
3297 }
3298 
display_name() const3299 std::string t_javame_generator::display_name() const {
3300   return "Java ME";
3301 }
3302 
3303 
3304 THRIFT_REGISTER_GENERATOR(javame, "Java ME", "")
3305