r1120@dev030 (orig r57204): dreiss | 2007-08-28 14:09:06 -0700
[amiethrift.git] / compiler / cpp / src / generate / t_java_generator.cc
blob808d7ecdb081becc5f97e1a98d3a59a97a95f95d
1 // Copyright (c) 2006- Facebook
2 // Distributed under the Thrift Software License
3 //
4 // See accompanying file LICENSE or visit the Thrift site at:
5 // http://developers.facebook.com/thrift/
7 #include <stdlib.h>
8 #include <sys/stat.h>
9 #include <sstream>
10 #include "t_java_generator.h"
11 using namespace std;
13 /**
14 * Prepares for file generation by opening up the necessary file output
15 * streams.
17 * @param tprogram The program to generate
19 void t_java_generator::init_generator() {
20 // Make output directory
21 mkdir(T_JAVA_DIR, S_IREAD | S_IWRITE | S_IEXEC);
22 package_name_ = program_->get_java_package();
24 string dir = package_name_;
25 string subdir = T_JAVA_DIR;
26 string::size_type loc;
27 while ((loc = dir.find(".")) != string::npos) {
28 subdir = subdir + "/" + dir.substr(0, loc);
29 mkdir(subdir.c_str(), S_IREAD | S_IWRITE | S_IEXEC);
30 dir = dir.substr(loc+1);
32 if (dir.size() > 0) {
33 subdir = subdir + "/" + dir;
34 mkdir(subdir.c_str(), S_IREAD | S_IWRITE | S_IEXEC);
37 package_dir_ = subdir;
40 /**
41 * Packages the generated file
43 * @return String of the package, i.e. "package com.facebook.thriftdemo;"
45 string t_java_generator::java_package() {
46 if (!package_name_.empty()) {
47 return string("package ") + package_name_ + ";\n\n";
49 return "";
52 /**
53 * Prints standard java imports
55 * @return List of imports for Java types that are used in here
57 string t_java_generator::java_type_imports() {
58 return
59 string() +
60 "import java.util.ArrayList;\n" +
61 "import java.util.AbstractMap;\n" +
62 "import java.util.HashMap;\n" +
63 "import java.util.HashSet;\n" +
64 "import com.facebook.thrift.*;\n\n";
67 /**
68 * Prints standard java imports
70 * @return List of imports necessary for thrift
72 string t_java_generator::java_thrift_imports() {
73 return
74 string() +
75 "import com.facebook.thrift.protocol.*;\n" +
76 "import com.facebook.thrift.transport.*;\n\n";
79 /**
80 * Nothing in Java
82 void t_java_generator::close_generator() {}
84 /**
85 * Generates a typedef. This is not done in Java, since it does
86 * not support arbitrary name replacements, and it'd be a wacky waste
87 * of overhead to make wrapper classes.
89 * @param ttypedef The type definition
91 void t_java_generator::generate_typedef(t_typedef* ttypedef) {}
93 /**
94 * Enums are a class with a set of static constants.
96 * @param tenum The enumeration
98 void t_java_generator::generate_enum(t_enum* tenum) {
99 // Make output file
100 string f_enum_name = package_dir_+"/"+(tenum->get_name())+".java";
101 ofstream f_enum;
102 f_enum.open(f_enum_name.c_str());
104 // Comment and package it
105 f_enum <<
106 autogen_comment() <<
107 java_package() << endl;
109 f_enum <<
110 "public class " << tenum->get_name() << " ";
111 scope_up(f_enum);
113 vector<t_enum_value*> constants = tenum->get_constants();
114 vector<t_enum_value*>::iterator c_iter;
115 int value = -1;
116 for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
117 if ((*c_iter)->has_value()) {
118 value = (*c_iter)->get_value();
119 } else {
120 ++value;
123 indent(f_enum) <<
124 "public static final int " << (*c_iter)->get_name() <<
125 " = " << value << ";" << endl;
128 scope_down(f_enum);
129 f_enum.close();
133 * Generates a class that holds all the constants.
135 void t_java_generator::generate_consts(std::vector<t_const*> consts) {
136 string f_consts_name = package_dir_+"/Constants.java";
137 ofstream f_consts;
138 f_consts.open(f_consts_name.c_str());
140 // Print header
141 f_consts <<
142 autogen_comment() <<
143 java_package() <<
144 java_type_imports();
146 f_consts <<
147 "public class Constants {" << endl <<
148 endl;
149 indent_up();
150 vector<t_const*>::iterator c_iter;
151 for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
152 print_const_value(f_consts,
153 (*c_iter)->get_name(),
154 (*c_iter)->get_type(),
155 (*c_iter)->get_value(),
156 false);
158 indent_down();
159 indent(f_consts) <<
160 "}" << endl;
161 f_consts.close();
166 * Prints the value of a constant with the given type. Note that type checking
167 * is NOT performed in this function as it is always run beforehand using the
168 * validate_types method in main.cc
170 void t_java_generator::print_const_value(std::ofstream& out, string name, t_type* type, t_const_value* value, bool in_static, bool defval) {
172 indent(out);
173 if (!defval) {
174 out <<
175 (in_static ? "" : "public static final ") <<
176 type_name(type) << " ";
178 if (type->is_base_type()) {
179 string v2 = render_const_value(out, name, type, value);
180 out << name << " = " << v2 << ";" << endl << endl;
181 } else if (type->is_enum()) {
182 out << name << " = " << value->get_integer() << ";" << endl << endl;
183 } else if (type->is_struct() || type->is_xception()) {
184 const vector<t_field*>& fields = ((t_struct*)type)->get_members();
185 vector<t_field*>::const_iterator f_iter;
186 const map<t_const_value*, t_const_value*>& val = value->get_map();
187 map<t_const_value*, t_const_value*>::const_iterator v_iter;
188 out << name << " = new " << type_name(type) << "();" << endl;
189 if (!in_static) {
190 indent(out) << "static {" << endl;
191 indent_up();
193 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
194 t_type* field_type = NULL;
195 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
196 if ((*f_iter)->get_name() == v_iter->first->get_string()) {
197 field_type = (*f_iter)->get_type();
200 if (field_type == NULL) {
201 throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
203 string val = render_const_value(out, name, field_type, v_iter->second);
204 indent(out) << name << "." << v_iter->first->get_string() << " = " << val << ";" << endl;
205 indent(out) << name << ".__isset." << v_iter->first->get_string() << " = true;" << endl;
207 if (!in_static) {
208 indent_down();
209 indent(out) << "}" << endl;
211 out << endl;
212 } else if (type->is_map()) {
213 out << name << " = new " << type_name(type, true, true) << "();" << endl;
214 if (!in_static) {
215 indent(out) << "static {" << endl;
216 indent_up();
218 t_type* ktype = ((t_map*)type)->get_key_type();
219 t_type* vtype = ((t_map*)type)->get_val_type();
220 const map<t_const_value*, t_const_value*>& val = value->get_map();
221 map<t_const_value*, t_const_value*>::const_iterator v_iter;
222 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
223 string key = render_const_value(out, name, ktype, v_iter->first);
224 string val = render_const_value(out, name, vtype, v_iter->second);
225 indent(out) << name << ".put(" << key << ", " << val << ");" << endl;
227 if (!in_static) {
228 indent_down();
229 indent(out) << "}" << endl;
231 out << endl;
232 } else if (type->is_list() || type->is_set()) {
233 out << name << " = new " << type_name(type) << "();" << endl;
234 if (!in_static) {
235 indent(out) << "static {" << endl;
236 indent_up();
238 t_type* etype;
239 if (type->is_list()) {
240 etype = ((t_list*)type)->get_elem_type();
241 } else {
242 etype = ((t_set*)type)->get_elem_type();
244 const vector<t_const_value*>& val = value->get_list();
245 vector<t_const_value*>::const_iterator v_iter;
246 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
247 string val = render_const_value(out, name, etype, *v_iter);
248 indent(out) << name << ".add(" << val << ");" << endl;
250 if (!in_static) {
251 indent_down();
252 indent(out) << "}" << endl;
254 out << endl;
258 string t_java_generator::render_const_value(ofstream& out, string name, t_type* type, t_const_value* value) {
259 std::ostringstream render;
261 if (type->is_base_type()) {
262 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
263 switch (tbase) {
264 case t_base_type::TYPE_STRING:
265 render << "\"" + value->get_string() + "\"";
266 break;
267 case t_base_type::TYPE_BOOL:
268 render << ((value->get_integer() > 0) ? "true" : "false");
269 break;
270 case t_base_type::TYPE_BYTE:
271 case t_base_type::TYPE_I16:
272 case t_base_type::TYPE_I32:
273 case t_base_type::TYPE_I64:
274 render << value->get_integer();
275 break;
276 case t_base_type::TYPE_DOUBLE:
277 if (value->get_type() == t_const_value::CV_INTEGER) {
278 render << value->get_integer();
279 } else {
280 render << value->get_double();
282 break;
283 default:
284 throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
286 } else if (type->is_enum()) {
287 render << value->get_integer();
288 } else {
289 string t = tmp("tmp");
290 print_const_value(out, t, type, value, true);
291 render << t;
294 return render.str();
298 * Generates a struct definition for a thrift data type. This is a class
299 * with data members, read(), write(), and an inner Isset class.
301 * @param tstruct The struct definition
303 void t_java_generator::generate_struct(t_struct* tstruct) {
304 generate_java_struct(tstruct, false);
308 * Exceptions are structs, but they inherit from Exception
310 * @param tstruct The struct definition
312 void t_java_generator::generate_xception(t_struct* txception) {
313 generate_java_struct(txception, true);
318 * Java struct definition.
320 * @param tstruct The struct definition
322 void t_java_generator::generate_java_struct(t_struct* tstruct,
323 bool is_exception) {
324 // Make output file
325 string f_struct_name = package_dir_+"/"+(tstruct->get_name())+".java";
326 ofstream f_struct;
327 f_struct.open(f_struct_name.c_str());
329 f_struct <<
330 autogen_comment() <<
331 java_package() <<
332 java_type_imports() <<
333 java_thrift_imports();
335 generate_java_struct_definition(f_struct,
336 tstruct,
337 is_exception);
338 f_struct.close();
342 * Java struct definition. This has various parameters, as it could be
343 * generated standalone or inside another class as a helper. If it
344 * is a helper than it is a static class.
346 * @param tstruct The struct definition
347 * @param is_exception Is this an exception?
348 * @param in_class If inside a class, needs to be static class
349 * @param is_result If this is a result it needs a different writer
351 void t_java_generator::generate_java_struct_definition(ofstream &out,
352 t_struct* tstruct,
353 bool is_exception,
354 bool in_class,
355 bool is_result) {
356 indent(out) <<
357 "public " << (in_class ? "static " : "") << "class " << tstruct->get_name() << " ";
359 if (is_exception) {
360 out << "extends Exception ";
363 scope_up(out);
365 // Members are public
366 const vector<t_field*>& members = tstruct->get_members();
367 vector<t_field*>::const_iterator m_iter;
368 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
369 indent(out) <<
370 "public " << declare_field(*m_iter, false) << endl;
373 // Inner Isset class
374 if (members.size() > 0) {
375 out <<
376 endl <<
377 indent() << "public final Isset __isset = new Isset();" << endl <<
378 indent() << "public final class Isset {" << endl;
379 indent_up();
380 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
381 indent(out) <<
382 "public boolean " << (*m_iter)->get_name() << " = false;" << endl;
384 indent_down();
385 out <<
386 indent() << "}" << endl <<
387 endl;
390 // Default constructor
391 indent(out) <<
392 "public " << tstruct->get_name() << "() {" << endl;
393 indent_up();
394 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
395 t_type* t = get_true_type((*m_iter)->get_type());
396 if (!t->is_base_type() && (*m_iter)->get_value() != NULL) {
397 print_const_value(out, "this." + (*m_iter)->get_name(), t, (*m_iter)->get_value(), true, true);
400 indent_down();
401 indent(out) << "}" << endl << endl;
403 generate_java_struct_reader(out, tstruct);
404 if (is_result) {
405 generate_java_struct_result_writer(out, tstruct);
406 } else {
407 generate_java_struct_writer(out, tstruct);
409 generate_java_struct_tostring(out, tstruct);
410 scope_down(out);
411 out << endl;
415 * Generates a function to read all the fields of the struct.
417 * @param tstruct The struct definition
419 void t_java_generator::generate_java_struct_reader(ofstream& out,
420 t_struct* tstruct) {
421 out <<
422 indent() << "public void read(TProtocol iprot) throws TException {" << endl;
423 indent_up();
425 const vector<t_field*>& fields = tstruct->get_members();
426 vector<t_field*>::const_iterator f_iter;
428 // Declare stack tmp variables
429 out <<
430 indent() << "TField field;" << endl <<
431 indent() << "TStruct struct = iprot.readStructBegin();" << endl;
433 // Loop over reading in fields
434 indent(out) <<
435 "while (true)" << endl;
436 scope_up(out);
438 // Read beginning field marker
439 indent(out) <<
440 "field = iprot.readFieldBegin();" << endl;
442 // Check for field STOP marker and break
443 indent(out) <<
444 "if (field.type == TType.STOP) { " << endl;
445 indent_up();
446 indent(out) <<
447 "break;" << endl;
448 indent_down();
449 indent(out) <<
450 "}" << endl;
452 // Switch statement on the field we are reading
453 indent(out) <<
454 "switch (field.id)" << endl;
456 scope_up(out);
458 // Generate deserialization code for known cases
459 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
460 indent(out) <<
461 "case " << (*f_iter)->get_key() << ":" << endl;
462 indent_up();
463 indent(out) <<
464 "if (field.type == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
465 indent_up();
467 generate_deserialize_field(out, *f_iter, "this.");
468 out <<
469 indent() << "this.__isset." << (*f_iter)->get_name() << " = true;" << endl;
470 indent_down();
471 out <<
472 indent() << "} else { " << endl <<
473 indent() << " TProtocolUtil.skip(iprot, field.type);" << endl <<
474 indent() << "}" << endl <<
475 indent() << "break;" << endl;
476 indent_down();
479 // In the default case we skip the field
480 out <<
481 indent() << "default:" << endl <<
482 indent() << " TProtocolUtil.skip(iprot, field.type);" << endl <<
483 indent() << " break;" << endl;
485 scope_down(out);
487 // Read field end marker
488 indent(out) <<
489 "iprot.readFieldEnd();" << endl;
491 scope_down(out);
493 out <<
494 indent() << "iprot.readStructEnd();" << endl;
496 indent_down();
497 out <<
498 indent() << "}" << endl <<
499 endl;
503 * Generates a function to write all the fields of the struct
505 * @param tstruct The struct definition
507 void t_java_generator::generate_java_struct_writer(ofstream& out,
508 t_struct* tstruct) {
509 out <<
510 indent() << "public void write(TProtocol oprot) throws TException {" << endl;
511 indent_up();
513 string name = tstruct->get_name();
514 const vector<t_field*>& fields = tstruct->get_members();
515 vector<t_field*>::const_iterator f_iter;
517 out <<
518 indent() << "TStruct struct = new TStruct(\"" << name << "\");" << endl <<
519 indent() << "TField field = new TField();" << endl <<
520 indent() << "oprot.writeStructBegin(struct);" << endl;
522 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
523 bool null_allowed = type_can_be_null((*f_iter)->get_type());
524 if (null_allowed) {
525 out <<
526 indent() << "if (this." << (*f_iter)->get_name() << " != null) {" << endl;
527 indent_up();
530 out <<
531 indent() << "field.name = \"" << (*f_iter)->get_name() << "\";" << endl <<
532 indent() << "field.type = " << type_to_enum((*f_iter)->get_type()) << ";" << endl <<
533 indent() << "field.id = " << (*f_iter)->get_key() << ";" << endl <<
534 indent() << "oprot.writeFieldBegin(field);" << endl;
536 // Write field contents
537 generate_serialize_field(out, *f_iter, "this.");
539 // Write field closer
540 indent(out) <<
541 "oprot.writeFieldEnd();" << endl;
543 if (null_allowed) {
544 indent_down();
545 indent(out) << "}" << endl;
548 // Write the struct map
549 out <<
550 indent() << "oprot.writeFieldStop();" << endl <<
551 indent() << "oprot.writeStructEnd();" << endl;
553 indent_down();
554 out <<
555 indent() << "}" << endl <<
556 endl;
560 * Generates a function to write all the fields of the struct,
561 * which is a function result. These fields are only written
562 * if they are set in the Isset array, and only one of them
563 * can be set at a time.
565 * @param tstruct The struct definition
567 void t_java_generator::generate_java_struct_result_writer(ofstream& out,
568 t_struct* tstruct) {
569 out <<
570 indent() << "public void write(TProtocol oprot) throws TException {" << endl;
571 indent_up();
573 string name = tstruct->get_name();
574 const vector<t_field*>& fields = tstruct->get_members();
575 vector<t_field*>::const_iterator f_iter;
577 out <<
578 indent() << "TStruct struct = new TStruct(\"" << name << "\");" << endl <<
579 indent() << "TField field = new TField();" << endl <<
580 indent() << "oprot.writeStructBegin(struct);" << endl;
582 bool first = true;
583 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
584 if (first) {
585 first = false;
586 out <<
587 endl <<
588 indent() << "if ";
589 } else {
590 out <<
591 " else if ";
594 out <<
595 "(this.__isset." << (*f_iter)->get_name() << ") {" << endl;
596 indent_up();
598 bool null_allowed = type_can_be_null((*f_iter)->get_type());
599 if (null_allowed) {
600 out <<
601 indent() << "if (this." << (*f_iter)->get_name() << " != null) {" << endl;
602 indent_up();
605 out <<
606 indent() << "field.name = \"" << (*f_iter)->get_name() << "\";" << endl <<
607 indent() << "field.type = " << type_to_enum((*f_iter)->get_type()) << ";" << endl <<
608 indent() << "field.id = " << (*f_iter)->get_key() << ";" << endl <<
609 indent() << "oprot.writeFieldBegin(field);" << endl;
611 // Write field contents
612 generate_serialize_field(out, *f_iter, "this.");
614 // Write field closer
615 indent(out) <<
616 "oprot.writeFieldEnd();" << endl;
618 if (null_allowed) {
619 indent_down();
620 indent(out) << "}" << endl;
623 indent_down();
624 indent(out) << "}";
626 // Write the struct map
627 out <<
628 endl <<
629 indent() << "oprot.writeFieldStop();" << endl <<
630 indent() << "oprot.writeStructEnd();" << endl;
632 indent_down();
633 out <<
634 indent() << "}" << endl <<
635 endl;
639 * Generates a toString() method for the given struct
641 * @param tstruct The struct definition
643 void t_java_generator::generate_java_struct_tostring(ofstream& out,
644 t_struct* tstruct) {
645 out <<
646 indent() << "public String toString() {" << endl;
647 indent_up();
649 out <<
650 indent() << "StringBuilder sb = new StringBuilder(\"" << tstruct->get_name() << "(\");" << endl;
652 const vector<t_field*>& fields = tstruct->get_members();
653 vector<t_field*>::const_iterator f_iter;
654 bool first = true;
655 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
656 if (first) {
657 first = false;
658 indent(out) << "sb.append(\"" << (*f_iter)->get_name() << ":\");" << endl;
659 } else {
660 indent(out) << "sb.append(\"," << (*f_iter)->get_name() << ":\");" << endl;
662 t_type* ttype = (*f_iter)->get_type();
663 if (ttype->is_xception() || ttype->is_struct()) {
664 indent(out) << "sb.append(this." << (*f_iter)->get_name() << ".toString());" << endl;
665 } else {
666 indent(out) << "sb.append(this." << (*f_iter)->get_name() << ");" << endl;
669 out <<
670 indent() << "sb.append(\")\");" << endl <<
671 indent() << "return sb.toString();" << endl;
673 indent_down();
674 indent(out) << "}" << endl <<
675 endl;
680 * Generates a thrift service. In C++, this comprises an entirely separate
681 * header and source file. The header file defines the methods and includes
682 * the data types defined in the main header file, and the implementation
683 * file contains implementations of the basic printer and default interfaces.
685 * @param tservice The service definition
687 void t_java_generator::generate_service(t_service* tservice) {
688 // Make output file
689 string f_service_name = package_dir_+"/"+service_name_+".java";
690 f_service_.open(f_service_name.c_str());
692 f_service_ <<
693 autogen_comment() <<
694 java_package() <<
695 java_type_imports() <<
696 java_thrift_imports();
698 f_service_ <<
699 "public class " << service_name_ << " {" << endl <<
700 endl;
701 indent_up();
703 // Generate the three main parts of the service
704 generate_service_interface(tservice);
705 generate_service_client(tservice);
706 generate_service_server(tservice);
707 generate_service_helpers(tservice);
709 indent_down();
710 f_service_ <<
711 "}" << endl;
712 f_service_.close();
716 * Generates a service interface definition.
718 * @param tservice The service to generate a header definition for
720 void t_java_generator::generate_service_interface(t_service* tservice) {
721 string extends = "";
722 string extends_iface = "";
723 if (tservice->get_extends() != NULL) {
724 extends = type_name(tservice->get_extends());
725 extends_iface = " extends " + extends + ".Iface";
728 f_service_ <<
729 indent() << "public interface Iface" << extends_iface << " {" << endl;
730 indent_up();
731 vector<t_function*> functions = tservice->get_functions();
732 vector<t_function*>::iterator f_iter;
733 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
734 indent(f_service_) <<
735 "public " << function_signature(*f_iter) << ";" << endl;
737 indent_down();
738 f_service_ <<
739 indent() << "}" << endl <<
740 endl;
744 * Generates structs for all the service args and return types
746 * @param tservice The service
748 void t_java_generator::generate_service_helpers(t_service* tservice) {
749 vector<t_function*> functions = tservice->get_functions();
750 vector<t_function*>::iterator f_iter;
751 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
752 t_struct* ts = (*f_iter)->get_arglist();
753 generate_java_struct_definition(f_service_, ts, false, true);
754 generate_function_helpers(*f_iter);
759 * Generates a service client definition.
761 * @param tservice The service to generate a server for.
763 void t_java_generator::generate_service_client(t_service* tservice) {
764 string extends = "";
765 string extends_client = "";
766 if (tservice->get_extends() != NULL) {
767 extends = type_name(tservice->get_extends());
768 extends_client = " extends " + extends + ".Client";
771 indent(f_service_) <<
772 "public static class Client" << extends_client << " implements Iface {" << endl;
773 indent_up();
775 indent(f_service_) <<
776 "public Client(TProtocol prot)" << endl;
777 scope_up(f_service_);
778 indent(f_service_) <<
779 "this(prot, prot);" << endl;
780 scope_down(f_service_);
781 f_service_ << endl;
783 indent(f_service_) <<
784 "public Client(TProtocol iprot, TProtocol oprot)" << endl;
785 scope_up(f_service_);
786 if (extends.empty()) {
787 f_service_ <<
788 indent() << "iprot_ = iprot;" << endl <<
789 indent() << "oprot_ = oprot;" << endl;
790 } else {
791 f_service_ <<
792 indent() << "super(iprot, oprot);" << endl;
794 scope_down(f_service_);
795 f_service_ << endl;
797 if (extends.empty()) {
798 f_service_ <<
799 indent() << "protected TProtocol iprot_;" << endl <<
800 indent() << "protected TProtocol oprot_;" << endl <<
801 endl <<
802 indent() << "protected int seqid_;" << endl <<
803 endl;
806 // Generate client method implementations
807 vector<t_function*> functions = tservice->get_functions();
808 vector<t_function*>::const_iterator f_iter;
809 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
810 string funname = (*f_iter)->get_name();
812 // Open function
813 indent(f_service_) <<
814 "public " << function_signature(*f_iter) << endl;
815 scope_up(f_service_);
816 indent(f_service_) <<
817 "send_" << funname << "(";
819 // Get the struct of function call params
820 t_struct* arg_struct = (*f_iter)->get_arglist();
822 // Declare the function arguments
823 const vector<t_field*>& fields = arg_struct->get_members();
824 vector<t_field*>::const_iterator fld_iter;
825 bool first = true;
826 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
827 if (first) {
828 first = false;
829 } else {
830 f_service_ << ", ";
832 f_service_ << (*fld_iter)->get_name();
834 f_service_ << ");" << endl;
836 if (!(*f_iter)->is_async()) {
837 f_service_ << indent();
838 if (!(*f_iter)->get_returntype()->is_void()) {
839 f_service_ << "return ";
841 f_service_ <<
842 "recv_" << funname << "();" << endl;
844 scope_down(f_service_);
845 f_service_ << endl;
847 t_function send_function(g_type_void,
848 string("send_") + (*f_iter)->get_name(),
849 (*f_iter)->get_arglist());
851 string argsname = (*f_iter)->get_name() + "_args";
853 // Open function
854 indent(f_service_) <<
855 "public " << function_signature(&send_function) << endl;
856 scope_up(f_service_);
858 // Serialize the request
859 f_service_ <<
860 indent() << "oprot_.writeMessageBegin(new TMessage(\"" << funname << "\", TMessageType.CALL, seqid_));" << endl <<
861 indent() << argsname << " args = new " << argsname << "();" << endl;
863 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
864 f_service_ <<
865 indent() << "args." << (*fld_iter)->get_name() << " = " << (*fld_iter)->get_name() << ";" << endl;
868 f_service_ <<
869 indent() << "args.write(oprot_);" << endl <<
870 indent() << "oprot_.writeMessageEnd();" << endl <<
871 indent() << "oprot_.getTransport().flush();" << endl;
873 scope_down(f_service_);
874 f_service_ << endl;
876 if (!(*f_iter)->is_async()) {
877 string resultname = (*f_iter)->get_name() + "_result";
879 t_struct noargs(program_);
880 t_function recv_function((*f_iter)->get_returntype(),
881 string("recv_") + (*f_iter)->get_name(),
882 &noargs,
883 (*f_iter)->get_xceptions());
884 // Open function
885 indent(f_service_) <<
886 "public " << function_signature(&recv_function) << endl;
887 scope_up(f_service_);
889 // TODO(mcslee): Message validation here, was the seqid etc ok?
891 f_service_ <<
892 indent() << "TMessage msg = iprot_.readMessageBegin();" << endl <<
893 indent() << "if (msg.type == TMessageType.EXCEPTION) {" << endl <<
894 indent() << " TApplicationException x = TApplicationException.read(iprot_);" << endl <<
895 indent() << " iprot_.readMessageEnd();" << endl <<
896 indent() << " throw x;" << endl <<
897 indent() << "}" << endl <<
898 indent() << resultname << " result = new " << resultname << "();" << endl <<
899 indent() << "result.read(iprot_);" << endl <<
900 indent() << "iprot_.readMessageEnd();" << endl;
902 // Careful, only return _result if not a void function
903 if (!(*f_iter)->get_returntype()->is_void()) {
904 f_service_ <<
905 indent() << "if (result.__isset.success) {" << endl <<
906 indent() << " return result.success;" << endl <<
907 indent() << "}" << endl;
910 t_struct* xs = (*f_iter)->get_xceptions();
911 const std::vector<t_field*>& xceptions = xs->get_members();
912 vector<t_field*>::const_iterator x_iter;
913 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
914 f_service_ <<
915 indent() << "if (result.__isset." << (*x_iter)->get_name() << ") {" << endl <<
916 indent() << " throw result." << (*x_iter)->get_name() << ";" << endl <<
917 indent() << "}" << endl;
920 // If you get here it's an exception, unless a void function
921 if ((*f_iter)->get_returntype()->is_void()) {
922 indent(f_service_) <<
923 "return;" << endl;
924 } else {
925 f_service_ <<
926 indent() << "throw new TApplicationException(TApplicationException.MISSING_RESULT, \"" << (*f_iter)->get_name() << " failed: unknown result\");" << endl;
929 // Close function
930 scope_down(f_service_);
931 f_service_ << endl;
935 indent_down();
936 indent(f_service_) <<
937 "}" << endl;
941 * Generates a service server definition.
943 * @param tservice The service to generate a server for.
945 void t_java_generator::generate_service_server(t_service* tservice) {
946 // Generate the dispatch methods
947 vector<t_function*> functions = tservice->get_functions();
948 vector<t_function*>::iterator f_iter;
950 // Extends stuff
951 string extends = "";
952 string extends_processor = "";
953 if (tservice->get_extends() != NULL) {
954 extends = type_name(tservice->get_extends());
955 extends_processor = " extends " + extends + ".Processor";
958 // Generate the header portion
959 indent(f_service_) <<
960 "public static class Processor" << extends_processor << " implements TProcessor {" << endl;
961 indent_up();
963 indent(f_service_) <<
964 "public Processor(Iface iface)" << endl;
965 scope_up(f_service_);
966 if (!extends.empty()) {
967 f_service_ <<
968 indent() << "super(iface);" << endl;
970 f_service_ <<
971 indent() << "iface_ = iface;" << endl;
973 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
974 f_service_ <<
975 indent() << "processMap_.put(\"" << (*f_iter)->get_name() << "\", new " << (*f_iter)->get_name() << "());" << endl;
978 scope_down(f_service_);
979 f_service_ << endl;
981 if (extends.empty()) {
982 f_service_ <<
983 indent() << "protected static interface ProcessFunction {" << endl <<
984 indent() << " public void process(int seqid, TProtocol iprot, TProtocol oprot) throws TException;" << endl <<
985 indent() << "}" << endl <<
986 endl;
989 f_service_ <<
990 indent() << "private Iface iface_;" << endl;
992 if (extends.empty()) {
993 f_service_ <<
994 indent() << "protected final HashMap<String,ProcessFunction> processMap_ = new HashMap<String,ProcessFunction>();" << endl;
997 f_service_ << endl;
999 // Generate the server implementation
1000 indent(f_service_) <<
1001 "public boolean process(TProtocol iprot, TProtocol oprot) throws TException" << endl;
1002 scope_up(f_service_);
1004 f_service_ <<
1005 indent() << "TMessage msg = iprot.readMessageBegin();" << endl;
1007 // TODO(mcslee): validate message, was the seqid etc. legit?
1009 f_service_ <<
1010 indent() << "ProcessFunction fn = processMap_.get(msg.name);" << endl <<
1011 indent() << "if (fn == null) {" << endl <<
1012 indent() << " TProtocolUtil.skip(iprot, TType.STRUCT);" << endl <<
1013 indent() << " iprot.readMessageEnd();" << endl <<
1014 indent() << " TApplicationException x = new TApplicationException(TApplicationException.UNKNOWN_METHOD, \"Invalid method name: '\"+msg.name+\"'\");" << endl <<
1015 indent() << " oprot.writeMessageBegin(new TMessage(msg.name, TMessageType.EXCEPTION, msg.seqid));" << endl <<
1016 indent() << " x.write(oprot);" << endl <<
1017 indent() << " oprot.writeMessageEnd();" << endl <<
1018 indent() << " oprot.getTransport().flush();" << endl <<
1019 indent() << " return true;" << endl <<
1020 indent() << "}" << endl <<
1021 indent() << "fn.process(msg.seqid, iprot, oprot);" << endl;
1023 f_service_ <<
1024 indent() << "return true;" << endl;
1026 scope_down(f_service_);
1027 f_service_ << endl;
1029 // Generate the process subfunctions
1030 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1031 generate_process_function(tservice, *f_iter);
1034 indent_down();
1035 indent(f_service_) <<
1036 "}" << endl <<
1037 endl;
1041 * Generates a struct and helpers for a function.
1043 * @param tfunction The function
1045 void t_java_generator::generate_function_helpers(t_function* tfunction) {
1046 if (tfunction->is_async()) {
1047 return;
1050 t_struct result(program_, tfunction->get_name() + "_result");
1051 t_field success(tfunction->get_returntype(), "success", 0);
1052 if (!tfunction->get_returntype()->is_void()) {
1053 result.append(&success);
1056 t_struct* xs = tfunction->get_xceptions();
1057 const vector<t_field*>& fields = xs->get_members();
1058 vector<t_field*>::const_iterator f_iter;
1059 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1060 result.append(*f_iter);
1063 generate_java_struct_definition(f_service_, &result, false, true, true);
1067 * Generates a process function definition.
1069 * @param tfunction The function to write a dispatcher for
1071 void t_java_generator::generate_process_function(t_service* tservice,
1072 t_function* tfunction) {
1073 // Open class
1074 indent(f_service_) <<
1075 "private class " << tfunction->get_name() << " implements ProcessFunction {" << endl;
1076 indent_up();
1078 // Open function
1079 indent(f_service_) <<
1080 "public void process(int seqid, TProtocol iprot, TProtocol oprot) throws TException" << endl;
1081 scope_up(f_service_);
1083 string argsname = tfunction->get_name() + "_args";
1084 string resultname = tfunction->get_name() + "_result";
1086 f_service_ <<
1087 indent() << argsname << " args = new " << argsname << "();" << endl <<
1088 indent() << "args.read(iprot);" << endl <<
1089 indent() << "iprot.readMessageEnd();" << endl;
1091 t_struct* xs = tfunction->get_xceptions();
1092 const std::vector<t_field*>& xceptions = xs->get_members();
1093 vector<t_field*>::const_iterator x_iter;
1095 // Declare result for non async function
1096 if (!tfunction->is_async()) {
1097 f_service_ <<
1098 indent() << resultname << " result = new " << resultname << "();" << endl;
1101 // Try block for a function with exceptions
1102 if (xceptions.size() > 0) {
1103 f_service_ <<
1104 indent() << "try {" << endl;
1105 indent_up();
1108 // Generate the function call
1109 t_struct* arg_struct = tfunction->get_arglist();
1110 const std::vector<t_field*>& fields = arg_struct->get_members();
1111 vector<t_field*>::const_iterator f_iter;
1113 f_service_ << indent();
1114 if (!tfunction->is_async() && !tfunction->get_returntype()->is_void()) {
1115 f_service_ << "result.success = ";
1117 f_service_ <<
1118 "iface_." << tfunction->get_name() << "(";
1119 bool first = true;
1120 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1121 if (first) {
1122 first = false;
1123 } else {
1124 f_service_ << ", ";
1126 f_service_ << "args." << (*f_iter)->get_name();
1128 f_service_ << ");" << endl;
1130 // Set isset on success field
1131 if (!tfunction->is_async() && !tfunction->get_returntype()->is_void()) {
1132 f_service_ <<
1133 indent() << "result.__isset.success = true;" << endl;
1136 if (!tfunction->is_async() && xceptions.size() > 0) {
1137 indent_down();
1138 f_service_ << indent() << "}";
1139 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
1140 f_service_ << " catch (" << (*x_iter)->get_type()->get_name() << " " << (*x_iter)->get_name() << ") {" << endl;
1141 if (!tfunction->is_async()) {
1142 indent_up();
1143 f_service_ <<
1144 indent() << "result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name() << ";" << endl <<
1145 indent() << "result.__isset." << (*x_iter)->get_name() << " = true;" << endl;
1146 indent_down();
1147 f_service_ << indent() << "}";
1148 } else {
1149 f_service_ << "}";
1152 f_service_ << endl;
1155 // Shortcut out here for async functions
1156 if (tfunction->is_async()) {
1157 f_service_ <<
1158 indent() << "return;" << endl;
1159 scope_down(f_service_);
1161 // Close class
1162 indent_down();
1163 f_service_ <<
1164 indent() << "}" << endl <<
1165 endl;
1166 return;
1169 f_service_ <<
1170 indent() << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name() << "\", TMessageType.REPLY, seqid));" << endl <<
1171 indent() << "result.write(oprot);" << endl <<
1172 indent() << "oprot.writeMessageEnd();" << endl <<
1173 indent() << "oprot.getTransport().flush();" << endl;
1175 // Close function
1176 scope_down(f_service_);
1177 f_service_ << endl;
1179 // Close class
1180 indent_down();
1181 f_service_ <<
1182 indent() << "}" << endl <<
1183 endl;
1187 * Deserializes a field of any type.
1189 * @param tfield The field
1190 * @param prefix The variable name or container for this field
1192 void t_java_generator::generate_deserialize_field(ofstream& out,
1193 t_field* tfield,
1194 string prefix) {
1195 t_type* type = get_true_type(tfield->get_type());
1197 if (type->is_void()) {
1198 throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " +
1199 prefix + tfield->get_name();
1202 string name = prefix + tfield->get_name();
1204 if (type->is_struct() || type->is_xception()) {
1205 generate_deserialize_struct(out,
1206 (t_struct*)type,
1207 name);
1208 } else if (type->is_container()) {
1209 generate_deserialize_container(out, type, name);
1210 } else if (type->is_base_type() || type->is_enum()) {
1212 indent(out) <<
1213 name << " = iprot.";
1215 if (type->is_base_type()) {
1216 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1217 switch (tbase) {
1218 case t_base_type::TYPE_VOID:
1219 throw "compiler error: cannot serialize void field in a struct: " +
1220 name;
1221 break;
1222 case t_base_type::TYPE_STRING:
1223 if (((t_base_type*)type)->is_binary()) {
1224 out << "readBinary();";
1225 } else {
1226 out << "readString();";
1228 break;
1229 case t_base_type::TYPE_BOOL:
1230 out << "readBool();";
1231 break;
1232 case t_base_type::TYPE_BYTE:
1233 out << "readByte();";
1234 break;
1235 case t_base_type::TYPE_I16:
1236 out << "readI16();";
1237 break;
1238 case t_base_type::TYPE_I32:
1239 out << "readI32();";
1240 break;
1241 case t_base_type::TYPE_I64:
1242 out << "readI64();";
1243 break;
1244 case t_base_type::TYPE_DOUBLE:
1245 out << "readDouble();";
1246 break;
1247 default:
1248 throw "compiler error: no Java name for base type " + t_base_type::t_base_name(tbase);
1250 } else if (type->is_enum()) {
1251 out << "readI32();";
1253 out <<
1254 endl;
1255 } else {
1256 printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
1257 tfield->get_name().c_str(), type_name(type).c_str());
1262 * Generates an unserializer for a struct, invokes read()
1264 void t_java_generator::generate_deserialize_struct(ofstream& out,
1265 t_struct* tstruct,
1266 string prefix) {
1267 out <<
1268 indent() << prefix << " = new " << type_name(tstruct) << "();" << endl <<
1269 indent() << prefix << ".read(iprot);" << endl;
1273 * Deserializes a container by reading its size and then iterating
1275 void t_java_generator::generate_deserialize_container(ofstream& out,
1276 t_type* ttype,
1277 string prefix) {
1278 scope_up(out);
1280 string obj;
1282 if (ttype->is_map()) {
1283 obj = tmp("_map");
1284 } else if (ttype->is_set()) {
1285 obj = tmp("_set");
1286 } else if (ttype->is_list()) {
1287 obj = tmp("_list");
1290 // Declare variables, read header
1291 if (ttype->is_map()) {
1292 indent(out) << "TMap " << obj << " = iprot.readMapBegin();" << endl;
1293 } else if (ttype->is_set()) {
1294 indent(out) << "TSet " << obj << " = iprot.readSetBegin();" << endl;
1295 } else if (ttype->is_list()) {
1296 indent(out) << "TList " << obj << " = iprot.readListBegin();" << endl;
1299 indent(out)
1300 << prefix << " = new " << type_name(ttype, false, true)
1301 // size the collection correctly
1302 << "("
1303 << (ttype->is_list() ? "" : "2*" )
1304 << obj << ".size"
1305 << ");" << endl;
1307 // For loop iterates over elements
1308 string i = tmp("_i");
1309 indent(out) <<
1310 "for (int " << i << " = 0; " <<
1311 i << " < " << obj << ".size" << "; " <<
1312 "++" << i << ")" << endl;
1314 scope_up(out);
1316 if (ttype->is_map()) {
1317 generate_deserialize_map_element(out, (t_map*)ttype, prefix);
1318 } else if (ttype->is_set()) {
1319 generate_deserialize_set_element(out, (t_set*)ttype, prefix);
1320 } else if (ttype->is_list()) {
1321 generate_deserialize_list_element(out, (t_list*)ttype, prefix);
1324 scope_down(out);
1326 // Read container end
1327 if (ttype->is_map()) {
1328 indent(out) << "iprot.readMapEnd();" << endl;
1329 } else if (ttype->is_set()) {
1330 indent(out) << "iprot.readSetEnd();" << endl;
1331 } else if (ttype->is_list()) {
1332 indent(out) << "iprot.readListEnd();" << endl;
1335 scope_down(out);
1340 * Generates code to deserialize a map
1342 void t_java_generator::generate_deserialize_map_element(ofstream& out,
1343 t_map* tmap,
1344 string prefix) {
1345 string key = tmp("_key");
1346 string val = tmp("_val");
1347 t_field fkey(tmap->get_key_type(), key);
1348 t_field fval(tmap->get_val_type(), val);
1350 indent(out) <<
1351 declare_field(&fkey) << endl;
1352 indent(out) <<
1353 declare_field(&fval) << endl;
1355 generate_deserialize_field(out, &fkey);
1356 generate_deserialize_field(out, &fval);
1358 indent(out) <<
1359 prefix << ".put(" << key << ", " << val << ");" << endl;
1363 * Deserializes a set element
1365 void t_java_generator::generate_deserialize_set_element(ofstream& out,
1366 t_set* tset,
1367 string prefix) {
1368 string elem = tmp("_elem");
1369 t_field felem(tset->get_elem_type(), elem);
1371 indent(out) <<
1372 declare_field(&felem, true) << endl;
1374 generate_deserialize_field(out, &felem);
1376 indent(out) <<
1377 prefix << ".add(" << elem << ");" << endl;
1381 * Deserializes a list element
1383 void t_java_generator::generate_deserialize_list_element(ofstream& out,
1384 t_list* tlist,
1385 string prefix) {
1386 string elem = tmp("_elem");
1387 t_field felem(tlist->get_elem_type(), elem);
1389 indent(out) <<
1390 declare_field(&felem, true) << endl;
1392 generate_deserialize_field(out, &felem);
1394 indent(out) <<
1395 prefix << ".add(" << elem << ");" << endl;
1400 * Serializes a field of any type.
1402 * @param tfield The field to serialize
1403 * @param prefix Name to prepend to field name
1405 void t_java_generator::generate_serialize_field(ofstream& out,
1406 t_field* tfield,
1407 string prefix) {
1408 t_type* type = get_true_type(tfield->get_type());
1410 // Do nothing for void types
1411 if (type->is_void()) {
1412 throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " +
1413 prefix + tfield->get_name();
1416 if (type->is_struct() || type->is_xception()) {
1417 generate_serialize_struct(out,
1418 (t_struct*)type,
1419 prefix + tfield->get_name());
1420 } else if (type->is_container()) {
1421 generate_serialize_container(out,
1422 type,
1423 prefix + tfield->get_name());
1424 } else if (type->is_base_type() || type->is_enum()) {
1426 string name = prefix + tfield->get_name();
1427 indent(out) <<
1428 "oprot.";
1430 if (type->is_base_type()) {
1431 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1432 switch (tbase) {
1433 case t_base_type::TYPE_VOID:
1434 throw
1435 "compiler error: cannot serialize void field in a struct: " + name;
1436 break;
1437 case t_base_type::TYPE_STRING:
1438 if (((t_base_type*)type)->is_binary()) {
1439 out << "writeBinary(" << name << ");";
1440 } else {
1441 out << "writeString(" << name << ");";
1443 break;
1444 case t_base_type::TYPE_BOOL:
1445 out << "writeBool(" << name << ");";
1446 break;
1447 case t_base_type::TYPE_BYTE:
1448 out << "writeByte(" << name << ");";
1449 break;
1450 case t_base_type::TYPE_I16:
1451 out << "writeI16(" << name << ");";
1452 break;
1453 case t_base_type::TYPE_I32:
1454 out << "writeI32(" << name << ");";
1455 break;
1456 case t_base_type::TYPE_I64:
1457 out << "writeI64(" << name << ");";
1458 break;
1459 case t_base_type::TYPE_DOUBLE:
1460 out << "writeDouble(" << name << ");";
1461 break;
1462 default:
1463 throw "compiler error: no Java name for base type " + t_base_type::t_base_name(tbase);
1465 } else if (type->is_enum()) {
1466 out << "writeI32(" << name << ");";
1468 out << endl;
1469 } else {
1470 printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
1471 prefix.c_str(),
1472 tfield->get_name().c_str(),
1473 type_name(type).c_str());
1478 * Serializes all the members of a struct.
1480 * @param tstruct The struct to serialize
1481 * @param prefix String prefix to attach to all fields
1483 void t_java_generator::generate_serialize_struct(ofstream& out,
1484 t_struct* tstruct,
1485 string prefix) {
1486 out <<
1487 indent() << prefix << ".write(oprot);" << endl;
1491 * Serializes a container by writing its size then the elements.
1493 * @param ttype The type of container
1494 * @param prefix String prefix for fields
1496 void t_java_generator::generate_serialize_container(ofstream& out,
1497 t_type* ttype,
1498 string prefix) {
1499 scope_up(out);
1501 if (ttype->is_map()) {
1502 indent(out) <<
1503 "oprot.writeMapBegin(new TMap(" <<
1504 type_to_enum(((t_map*)ttype)->get_key_type()) << ", " <<
1505 type_to_enum(((t_map*)ttype)->get_val_type()) << ", " <<
1506 prefix << ".size()));" << endl;
1507 } else if (ttype->is_set()) {
1508 indent(out) <<
1509 "oprot.writeSetBegin(new TSet(" <<
1510 type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " <<
1511 prefix << ".size()));" << endl;
1512 } else if (ttype->is_list()) {
1513 indent(out) <<
1514 "oprot.writeListBegin(new TList(" <<
1515 type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
1516 prefix << ".size()));" << endl;
1519 string iter = tmp("_iter");
1520 if (ttype->is_map()) {
1521 indent(out) <<
1522 "for (" <<
1523 type_name(((t_map*)ttype)->get_key_type()) << " " << iter <<
1524 " : " <<
1525 prefix << ".keySet())";
1526 } else if (ttype->is_set()) {
1527 indent(out) <<
1528 "for (" <<
1529 type_name(((t_set*)ttype)->get_elem_type()) << " " << iter <<
1530 " : " <<
1531 prefix << ")";
1532 } else if (ttype->is_list()) {
1533 indent(out) <<
1534 "for (" <<
1535 type_name(((t_list*)ttype)->get_elem_type()) << " " << iter <<
1536 " : " <<
1537 prefix << ")";
1540 scope_up(out);
1542 if (ttype->is_map()) {
1543 generate_serialize_map_element(out, (t_map*)ttype, iter, prefix);
1544 } else if (ttype->is_set()) {
1545 generate_serialize_set_element(out, (t_set*)ttype, iter);
1546 } else if (ttype->is_list()) {
1547 generate_serialize_list_element(out, (t_list*)ttype, iter);
1550 if (ttype->is_map()) {
1551 indent(out) <<
1552 "oprot.writeMapEnd();" << endl;
1553 } else if (ttype->is_set()) {
1554 indent(out) <<
1555 "oprot.writeSetEnd();" << endl;
1556 } else if (ttype->is_list()) {
1557 indent(out) <<
1558 "oprot.writeListEnd();" << endl;
1561 scope_down(out);
1563 scope_down(out);
1567 * Serializes the members of a map.
1569 void t_java_generator::generate_serialize_map_element(ofstream& out,
1570 t_map* tmap,
1571 string iter,
1572 string map) {
1573 t_field kfield(tmap->get_key_type(), iter);
1574 generate_serialize_field(out, &kfield, "");
1575 t_field vfield(tmap->get_val_type(), map + ".get(" + iter + ")");
1576 generate_serialize_field(out, &vfield, "");
1580 * Serializes the members of a set.
1582 void t_java_generator::generate_serialize_set_element(ofstream& out,
1583 t_set* tset,
1584 string iter) {
1585 t_field efield(tset->get_elem_type(), iter);
1586 generate_serialize_field(out, &efield, "");
1590 * Serializes the members of a list.
1592 void t_java_generator::generate_serialize_list_element(ofstream& out,
1593 t_list* tlist,
1594 string iter) {
1595 t_field efield(tlist->get_elem_type(), iter);
1596 generate_serialize_field(out, &efield, "");
1600 * Returns a Java type name
1602 * @param ttype The type
1603 * @param container Is the type going inside a container?
1604 * @return Java type name, i.e. HashMap<Key,Value>
1606 string t_java_generator::type_name(t_type* ttype, bool in_container, bool in_init) {
1607 // In Java typedefs are just resolved to their real type
1608 ttype = get_true_type(ttype);
1610 if (ttype->is_base_type()) {
1611 return base_type_name((t_base_type*)ttype, in_container);
1612 } else if (ttype->is_enum()) {
1613 return (in_container ? "Integer" : "int");
1614 } else if (ttype->is_map()) {
1615 t_map* tmap = (t_map*) ttype;
1616 string prefix;
1617 if (in_init) {
1618 prefix = "HashMap";
1619 } else {
1620 prefix = "AbstractMap";
1622 return prefix + "<" +
1623 type_name(tmap->get_key_type(), true) + "," +
1624 type_name(tmap->get_val_type(), true) + ">";
1625 } else if (ttype->is_set()) {
1626 t_set* tset = (t_set*) ttype;
1627 return "HashSet<" + type_name(tset->get_elem_type(), true) + ">";
1628 } else if (ttype->is_list()) {
1629 t_list* tlist = (t_list*) ttype;
1630 return "ArrayList<" + type_name(tlist->get_elem_type(), true) + ">";
1633 // Check for namespacing
1634 t_program* program = ttype->get_program();
1635 if (program != NULL && program != program_) {
1636 string package = program->get_java_package();
1637 if (!package.empty()) {
1638 return package + "." + ttype->get_name();
1642 return ttype->get_name();
1646 * Returns the C++ type that corresponds to the thrift type.
1648 * @param tbase The base type
1649 * @param container Is it going in a Java container?
1651 string t_java_generator::base_type_name(t_base_type* type,
1652 bool in_container) {
1653 t_base_type::t_base tbase = type->get_base();
1655 switch (tbase) {
1656 case t_base_type::TYPE_VOID:
1657 return "void";
1658 case t_base_type::TYPE_STRING:
1659 if (type->is_binary()) {
1660 return "byte[]";
1661 } else {
1662 return "String";
1664 case t_base_type::TYPE_BOOL:
1665 return "boolean";
1666 case t_base_type::TYPE_BYTE:
1667 return "byte";
1668 case t_base_type::TYPE_I16:
1669 return (in_container ? "Short" : "short");
1670 case t_base_type::TYPE_I32:
1671 return (in_container ? "Integer" : "int");
1672 case t_base_type::TYPE_I64:
1673 return (in_container ? "Long" : "long");
1674 case t_base_type::TYPE_DOUBLE:
1675 return (in_container ? "Double" : "double");
1676 default:
1677 throw "compiler error: no C++ name for base type " + t_base_type::t_base_name(tbase);
1682 * Declares a field, which may include initialization as necessary.
1684 * @param ttype The type
1686 string t_java_generator::declare_field(t_field* tfield, bool init) {
1687 // TODO(mcslee): do we ever need to initialize the field?
1688 string result = type_name(tfield->get_type()) + " " + tfield->get_name();
1689 if (init) {
1690 t_type* ttype = get_true_type(tfield->get_type());
1691 if (ttype->is_base_type() && tfield->get_value() != NULL) {
1692 ofstream dummy;
1693 result += " = " + render_const_value(dummy, tfield->get_name(), ttype, tfield->get_value());
1694 } else if (ttype->is_base_type()) {
1695 t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
1696 switch (tbase) {
1697 case t_base_type::TYPE_VOID:
1698 throw "NO T_VOID CONSTRUCT";
1699 case t_base_type::TYPE_STRING:
1700 result += " = null";
1701 break;
1702 case t_base_type::TYPE_BOOL:
1703 result += " = false";
1704 break;
1705 case t_base_type::TYPE_BYTE:
1706 case t_base_type::TYPE_I16:
1707 case t_base_type::TYPE_I32:
1708 case t_base_type::TYPE_I64:
1709 result += " = 0";
1710 break;
1711 case t_base_type::TYPE_DOUBLE:
1712 result += " = (double)0";
1713 break;
1716 } else if (ttype->is_enum()) {
1717 result += " = 0";
1718 } else if (ttype->is_container()) {
1719 result += " = new " + type_name(ttype, false, true) + "()";
1720 } else {
1721 result += " = new " + type_name(ttype, false, true) + "()";;
1724 return result + ";";
1728 * Renders a function signature of the form 'type name(args)'
1730 * @param tfunction Function definition
1731 * @return String of rendered function definition
1733 string t_java_generator::function_signature(t_function* tfunction,
1734 string prefix) {
1735 t_type* ttype = tfunction->get_returntype();
1736 std::string result =
1737 type_name(ttype) + " " + prefix + tfunction->get_name() + "(" + argument_list(tfunction->get_arglist()) + ") throws ";
1738 t_struct* xs = tfunction->get_xceptions();
1739 const std::vector<t_field*>& xceptions = xs->get_members();
1740 vector<t_field*>::const_iterator x_iter;
1741 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
1742 result += (*x_iter)->get_type()->get_name() + ", ";
1744 result += "TException";
1745 return result;
1749 * Renders a comma separated field list, with type names
1751 string t_java_generator::argument_list(t_struct* tstruct) {
1752 string result = "";
1754 const vector<t_field*>& fields = tstruct->get_members();
1755 vector<t_field*>::const_iterator f_iter;
1756 bool first = true;
1757 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1758 if (first) {
1759 first = false;
1760 } else {
1761 result += ", ";
1763 result += type_name((*f_iter)->get_type()) + " " + (*f_iter)->get_name();
1765 return result;
1769 * Converts the parse type to a C++ enum string for the given type.
1771 string t_java_generator::type_to_enum(t_type* type) {
1772 type = get_true_type(type);
1774 if (type->is_base_type()) {
1775 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1776 switch (tbase) {
1777 case t_base_type::TYPE_VOID:
1778 throw "NO T_VOID CONSTRUCT";
1779 case t_base_type::TYPE_STRING:
1780 return "TType.STRING";
1781 case t_base_type::TYPE_BOOL:
1782 return "TType.BOOL";
1783 case t_base_type::TYPE_BYTE:
1784 return "TType.BYTE";
1785 case t_base_type::TYPE_I16:
1786 return "TType.I16";
1787 case t_base_type::TYPE_I32:
1788 return "TType.I32";
1789 case t_base_type::TYPE_I64:
1790 return "TType.I64";
1791 case t_base_type::TYPE_DOUBLE:
1792 return "TType.DOUBLE";
1794 } else if (type->is_enum()) {
1795 return "TType.I32";
1796 } else if (type->is_struct() || type->is_xception()) {
1797 return "TType.STRUCT";
1798 } else if (type->is_map()) {
1799 return "TType.MAP";
1800 } else if (type->is_set()) {
1801 return "TType.SET";
1802 } else if (type->is_list()) {
1803 return "TType.LIST";
1806 throw "INVALID TYPE IN type_to_enum: " + type->get_name();