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