r1459@opsdev009 (orig r77477): dreiss | 2008-01-11 12:59:03 -0800
[amiethrift.git] / compiler / cpp / src / generate / t_java_generator.cc
blobcd4b873df9d3d231fe2e230d2188a5471e2b4057
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 #include "platform.h"
12 using namespace std;
14 /**
15 * Prepares for file generation by opening up the necessary file output
16 * streams.
18 * @param tprogram The program to generate
20 void t_java_generator::init_generator() {
21 // Make output directory
22 MKDIR(get_out_dir().c_str());
23 package_name_ = program_->get_java_package();
25 string dir = package_name_;
26 string subdir = get_out_dir();
27 string::size_type loc;
28 while ((loc = dir.find(".")) != string::npos) {
29 subdir = subdir + "/" + dir.substr(0, loc);
30 MKDIR(subdir.c_str());
31 dir = dir.substr(loc+1);
33 if (dir.size() > 0) {
34 subdir = subdir + "/" + dir;
35 MKDIR(subdir.c_str());
38 package_dir_ = subdir;
41 /**
42 * Packages the generated file
44 * @return String of the package, i.e. "package com.facebook.thriftdemo;"
46 string t_java_generator::java_package() {
47 if (!package_name_.empty()) {
48 return string("package ") + package_name_ + ";\n\n";
50 return "";
53 /**
54 * Prints standard java imports
56 * @return List of imports for Java types that are used in here
58 string t_java_generator::java_type_imports() {
59 return
60 string() +
61 "import java.util.ArrayList;\n" +
62 "import java.util.AbstractMap;\n" +
63 "import java.util.HashMap;\n" +
64 "import java.util.HashSet;\n" +
65 "import com.facebook.thrift.*;\n\n";
68 /**
69 * Prints standard java imports
71 * @return List of imports necessary for thrift
73 string t_java_generator::java_thrift_imports() {
74 return
75 string() +
76 "import com.facebook.thrift.protocol.*;\n" +
77 "import com.facebook.thrift.transport.*;\n\n";
80 /**
81 * Nothing in Java
83 void t_java_generator::close_generator() {}
85 /**
86 * Generates a typedef. This is not done in Java, since it does
87 * not support arbitrary name replacements, and it'd be a wacky waste
88 * of overhead to make wrapper classes.
90 * @param ttypedef The type definition
92 void t_java_generator::generate_typedef(t_typedef* ttypedef) {}
94 /**
95 * Enums are a class with a set of static constants.
97 * @param tenum The enumeration
99 void t_java_generator::generate_enum(t_enum* tenum) {
100 // Make output file
101 string f_enum_name = package_dir_+"/"+(tenum->get_name())+".java";
102 ofstream f_enum;
103 f_enum.open(f_enum_name.c_str());
105 // Comment and package it
106 f_enum <<
107 autogen_comment() <<
108 java_package() << endl;
110 f_enum <<
111 "public class " << tenum->get_name() << " ";
112 scope_up(f_enum);
114 vector<t_enum_value*> constants = tenum->get_constants();
115 vector<t_enum_value*>::iterator c_iter;
116 int value = -1;
117 for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
118 if ((*c_iter)->has_value()) {
119 value = (*c_iter)->get_value();
120 } else {
121 ++value;
124 indent(f_enum) <<
125 "public static final int " << (*c_iter)->get_name() <<
126 " = " << value << ";" << endl;
129 scope_down(f_enum);
130 f_enum.close();
134 * Generates a class that holds all the constants.
136 void t_java_generator::generate_consts(std::vector<t_const*> consts) {
137 string f_consts_name = package_dir_+"/Constants.java";
138 ofstream f_consts;
139 f_consts.open(f_consts_name.c_str());
141 // Print header
142 f_consts <<
143 autogen_comment() <<
144 java_package() <<
145 java_type_imports();
147 f_consts <<
148 "public class Constants {" << endl <<
149 endl;
150 indent_up();
151 vector<t_const*>::iterator c_iter;
152 for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
153 print_const_value(f_consts,
154 (*c_iter)->get_name(),
155 (*c_iter)->get_type(),
156 (*c_iter)->get_value(),
157 false);
159 indent_down();
160 indent(f_consts) <<
161 "}" << endl;
162 f_consts.close();
167 * Prints the value of a constant with the given type. Note that type checking
168 * is NOT performed in this function as it is always run beforehand using the
169 * validate_types method in main.cc
171 void t_java_generator::print_const_value(std::ofstream& out, string name, t_type* type, t_const_value* value, bool in_static, bool defval) {
173 indent(out);
174 if (!defval) {
175 out <<
176 (in_static ? "" : "public static final ") <<
177 type_name(type) << " ";
179 if (type->is_base_type()) {
180 string v2 = render_const_value(out, name, type, value);
181 out << name << " = " << v2 << ";" << endl << endl;
182 } else if (type->is_enum()) {
183 out << name << " = " << value->get_integer() << ";" << endl << endl;
184 } else if (type->is_struct() || type->is_xception()) {
185 const vector<t_field*>& fields = ((t_struct*)type)->get_members();
186 vector<t_field*>::const_iterator f_iter;
187 const map<t_const_value*, t_const_value*>& val = value->get_map();
188 map<t_const_value*, t_const_value*>::const_iterator v_iter;
189 out << name << " = new " << type_name(type) << "();" << endl;
190 if (!in_static) {
191 indent(out) << "static {" << endl;
192 indent_up();
194 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
195 t_type* field_type = NULL;
196 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
197 if ((*f_iter)->get_name() == v_iter->first->get_string()) {
198 field_type = (*f_iter)->get_type();
201 if (field_type == NULL) {
202 throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
204 string val = render_const_value(out, name, field_type, v_iter->second);
205 indent(out) << name << "." << v_iter->first->get_string() << " = " << val << ";" << endl;
206 indent(out) << name << ".__isset." << v_iter->first->get_string() << " = true;" << endl;
208 if (!in_static) {
209 indent_down();
210 indent(out) << "}" << endl;
212 out << endl;
213 } else if (type->is_map()) {
214 out << name << " = new " << type_name(type, true, true) << "();" << endl;
215 if (!in_static) {
216 indent(out) << "static {" << endl;
217 indent_up();
219 t_type* ktype = ((t_map*)type)->get_key_type();
220 t_type* vtype = ((t_map*)type)->get_val_type();
221 const map<t_const_value*, t_const_value*>& val = value->get_map();
222 map<t_const_value*, t_const_value*>::const_iterator v_iter;
223 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
224 string key = render_const_value(out, name, ktype, v_iter->first);
225 string val = render_const_value(out, name, vtype, v_iter->second);
226 indent(out) << name << ".put(" << key << ", " << val << ");" << endl;
228 if (!in_static) {
229 indent_down();
230 indent(out) << "}" << endl;
232 out << endl;
233 } else if (type->is_list() || type->is_set()) {
234 out << name << " = new " << type_name(type) << "();" << endl;
235 if (!in_static) {
236 indent(out) << "static {" << endl;
237 indent_up();
239 t_type* etype;
240 if (type->is_list()) {
241 etype = ((t_list*)type)->get_elem_type();
242 } else {
243 etype = ((t_set*)type)->get_elem_type();
245 const vector<t_const_value*>& val = value->get_list();
246 vector<t_const_value*>::const_iterator v_iter;
247 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
248 string val = render_const_value(out, name, etype, *v_iter);
249 indent(out) << name << ".add(" << val << ");" << endl;
251 if (!in_static) {
252 indent_down();
253 indent(out) << "}" << endl;
255 out << endl;
259 string t_java_generator::render_const_value(ofstream& out, string name, t_type* type, t_const_value* value) {
260 std::ostringstream render;
262 if (type->is_base_type()) {
263 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
264 switch (tbase) {
265 case t_base_type::TYPE_STRING:
266 render << "\"" + value->get_string() + "\"";
267 break;
268 case t_base_type::TYPE_BOOL:
269 render << ((value->get_integer() > 0) ? "true" : "false");
270 break;
271 case t_base_type::TYPE_BYTE:
272 case t_base_type::TYPE_I16:
273 case t_base_type::TYPE_I32:
274 case t_base_type::TYPE_I64:
275 render << value->get_integer();
276 break;
277 case t_base_type::TYPE_DOUBLE:
278 if (value->get_type() == t_const_value::CV_INTEGER) {
279 render << value->get_integer();
280 } else {
281 render << value->get_double();
283 break;
284 default:
285 throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
287 } else if (type->is_enum()) {
288 render << value->get_integer();
289 } else {
290 string t = tmp("tmp");
291 print_const_value(out, t, type, value, true);
292 render << t;
295 return render.str();
299 * Generates a struct definition for a thrift data type. This is a class
300 * with data members, read(), write(), and an inner Isset class.
302 * @param tstruct The struct definition
304 void t_java_generator::generate_struct(t_struct* tstruct) {
305 generate_java_struct(tstruct, false);
309 * Exceptions are structs, but they inherit from Exception
311 * @param tstruct The struct definition
313 void t_java_generator::generate_xception(t_struct* txception) {
314 generate_java_struct(txception, true);
319 * Java struct definition.
321 * @param tstruct The struct definition
323 void t_java_generator::generate_java_struct(t_struct* tstruct,
324 bool is_exception) {
325 // Make output file
326 string f_struct_name = package_dir_+"/"+(tstruct->get_name())+".java";
327 ofstream f_struct;
328 f_struct.open(f_struct_name.c_str());
330 f_struct <<
331 autogen_comment() <<
332 java_package() <<
333 java_type_imports() <<
334 java_thrift_imports();
336 generate_java_struct_definition(f_struct,
337 tstruct,
338 is_exception);
339 f_struct.close();
343 * Java struct definition. This has various parameters, as it could be
344 * generated standalone or inside another class as a helper. If it
345 * is a helper than it is a static class.
347 * @param tstruct The struct definition
348 * @param is_exception Is this an exception?
349 * @param in_class If inside a class, needs to be static class
350 * @param is_result If this is a result it needs a different writer
352 void t_java_generator::generate_java_struct_definition(ofstream &out,
353 t_struct* tstruct,
354 bool is_exception,
355 bool in_class,
356 bool is_result) {
357 generate_java_doc(out, tstruct);
359 indent(out) <<
360 "public " << (in_class ? "static " : "") << "class " << tstruct->get_name() << " ";
362 if (is_exception) {
363 out << "extends Exception ";
365 out << "implements TBase, java.io.Serializable ";
367 scope_up(out);
369 // Members are public for -java, private for -javabean
370 const vector<t_field*>& members = tstruct->get_members();
371 vector<t_field*>::const_iterator m_iter;
372 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
373 if (bean_style_) {
374 indent(out) << "private ";
375 } else {
376 indent(out) << "public ";
378 out << declare_field(*m_iter, false) << endl;
381 // Inner Isset class
382 if (members.size() > 0) {
383 out <<
384 endl <<
385 indent() << "public final Isset __isset = new Isset();" << endl <<
386 indent() << "public static final class Isset {" << endl;
387 indent_up();
388 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
389 indent(out) <<
390 "public boolean " << (*m_iter)->get_name() << " = false;" << endl;
392 indent_down();
393 out <<
394 indent() << "}" << endl <<
395 endl;
398 // Default constructor
399 indent(out) <<
400 "public " << tstruct->get_name() << "() {" << endl;
401 indent_up();
402 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
403 t_type* t = get_true_type((*m_iter)->get_type());
404 if ((*m_iter)->get_value() != NULL) {
405 print_const_value(out, "this." + (*m_iter)->get_name(), t, (*m_iter)->get_value(), true, true);
408 indent_down();
409 indent(out) << "}" << endl << endl;
412 // Full constructor for all fields
413 if (!members.empty()) {
414 indent(out) <<
415 "public " << tstruct->get_name() << "(" << endl;
416 indent_up();
417 for (m_iter = members.begin(); m_iter != members.end(); ) {
418 indent(out) << type_name((*m_iter)->get_type()) << " " <<
419 (*m_iter)->get_name();
420 ++m_iter;
421 if (m_iter != members.end()) {
422 out << "," << endl;
425 out << ")" << endl;
426 indent_down();
427 indent(out) << "{" << endl;
428 indent_up();
429 indent(out) << "this();" << endl;
430 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
431 indent(out) << "this." << (*m_iter)->get_name() << " = " <<
432 (*m_iter)->get_name() << ";" << endl;
433 indent(out) << "this.__isset." << (*m_iter)->get_name() << " = true;" << endl;
435 indent_down();
436 indent(out) << "}" << endl << endl;
439 if (bean_style_) {
440 generate_java_bean_boilerplate(out, tstruct);
442 generate_java_struct_reader(out, tstruct);
443 if (is_result) {
444 generate_java_struct_result_writer(out, tstruct);
445 } else {
446 generate_java_struct_writer(out, tstruct);
448 generate_java_struct_tostring(out, tstruct);
449 scope_down(out);
450 out << endl;
454 * Generates a function to read all the fields of the struct.
456 * @param tstruct The struct definition
458 void t_java_generator::generate_java_struct_reader(ofstream& out,
459 t_struct* tstruct) {
460 out <<
461 indent() << "public void read(TProtocol iprot) throws TException {" << endl;
462 indent_up();
464 const vector<t_field*>& fields = tstruct->get_members();
465 vector<t_field*>::const_iterator f_iter;
467 // Declare stack tmp variables and read struct header
468 out <<
469 indent() << "TField field;" << endl <<
470 indent() << "iprot.readStructBegin();" << endl;
472 // Loop over reading in fields
473 indent(out) <<
474 "while (true)" << endl;
475 scope_up(out);
477 // Read beginning field marker
478 indent(out) <<
479 "field = iprot.readFieldBegin();" << endl;
481 // Check for field STOP marker and break
482 indent(out) <<
483 "if (field.type == TType.STOP) { " << endl;
484 indent_up();
485 indent(out) <<
486 "break;" << endl;
487 indent_down();
488 indent(out) <<
489 "}" << endl;
491 // Switch statement on the field we are reading
492 indent(out) <<
493 "switch (field.id)" << endl;
495 scope_up(out);
497 // Generate deserialization code for known cases
498 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
499 indent(out) <<
500 "case " << (*f_iter)->get_key() << ":" << endl;
501 indent_up();
502 indent(out) <<
503 "if (field.type == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
504 indent_up();
506 generate_deserialize_field(out, *f_iter, "this.");
507 out <<
508 indent() << "this.__isset." << (*f_iter)->get_name() << " = true;" << endl;
509 indent_down();
510 out <<
511 indent() << "} else { " << endl <<
512 indent() << " TProtocolUtil.skip(iprot, field.type);" << endl <<
513 indent() << "}" << endl <<
514 indent() << "break;" << endl;
515 indent_down();
518 // In the default case we skip the field
519 out <<
520 indent() << "default:" << endl <<
521 indent() << " TProtocolUtil.skip(iprot, field.type);" << endl <<
522 indent() << " break;" << endl;
524 scope_down(out);
526 // Read field end marker
527 indent(out) <<
528 "iprot.readFieldEnd();" << endl;
530 scope_down(out);
532 out <<
533 indent() << "iprot.readStructEnd();" << endl;
535 indent_down();
536 out <<
537 indent() << "}" << endl <<
538 endl;
542 * Generates a function to write all the fields of the struct
544 * @param tstruct The struct definition
546 void t_java_generator::generate_java_struct_writer(ofstream& out,
547 t_struct* tstruct) {
548 out <<
549 indent() << "public void write(TProtocol oprot) throws TException {" << endl;
550 indent_up();
552 string name = tstruct->get_name();
553 const vector<t_field*>& fields = tstruct->get_members();
554 vector<t_field*>::const_iterator f_iter;
556 indent(out) << "TStruct struct = new TStruct(\"" << name << "\");" << endl;
557 indent(out) << "oprot.writeStructBegin(struct);" << endl;
559 if (!fields.empty()) {
560 indent(out) << "TField field = new TField();" << endl;
562 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
563 bool null_allowed = type_can_be_null((*f_iter)->get_type());
564 if (null_allowed) {
565 out <<
566 indent() << "if (this." << (*f_iter)->get_name() << " != null) {" << endl;
567 indent_up();
569 bool optional = bean_style_ && (*f_iter)->get_req() == t_field::T_OPTIONAL;
570 if (optional) {
571 out <<
572 indent() << "if (this.__isset." << (*f_iter)->get_name() << ") {" << endl;
575 out <<
576 indent() << "field.name = \"" << (*f_iter)->get_name() << "\";" << endl <<
577 indent() << "field.type = " << type_to_enum((*f_iter)->get_type()) << ";" << endl <<
578 indent() << "field.id = " << (*f_iter)->get_key() << ";" << endl <<
579 indent() << "oprot.writeFieldBegin(field);" << endl;
581 // Write field contents
582 generate_serialize_field(out, *f_iter, "this.");
584 // Write field closer
585 indent(out) <<
586 "oprot.writeFieldEnd();" << endl;
588 if (optional) {
589 indent_down();
590 indent(out) << "}" << endl;
592 if (null_allowed) {
593 indent_down();
594 indent(out) << "}" << endl;
597 // Write the struct map
598 out <<
599 indent() << "oprot.writeFieldStop();" << endl <<
600 indent() << "oprot.writeStructEnd();" << endl;
602 indent_down();
603 out <<
604 indent() << "}" << endl <<
605 endl;
609 * Generates a function to write all the fields of the struct,
610 * which is a function result. These fields are only written
611 * if they are set in the Isset array, and only one of them
612 * can be set at a time.
614 * @param tstruct The struct definition
616 void t_java_generator::generate_java_struct_result_writer(ofstream& out,
617 t_struct* tstruct) {
618 out <<
619 indent() << "public void write(TProtocol oprot) throws TException {" << endl;
620 indent_up();
622 string name = tstruct->get_name();
623 const vector<t_field*>& fields = tstruct->get_members();
624 vector<t_field*>::const_iterator f_iter;
626 indent(out) << "TStruct struct = new TStruct(\"" << name << "\");" << endl;
627 indent(out) << "oprot.writeStructBegin(struct);" << endl;
629 if (!fields.empty()) {
630 indent(out) << "TField field = new TField();" << endl;
632 bool first = true;
633 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
634 if (first) {
635 first = false;
636 out <<
637 endl <<
638 indent() << "if ";
639 } else {
640 out <<
641 " else if ";
644 out <<
645 "(this.__isset." << (*f_iter)->get_name() << ") {" << endl;
646 indent_up();
648 bool null_allowed = type_can_be_null((*f_iter)->get_type());
649 if (null_allowed) {
650 out <<
651 indent() << "if (this." << (*f_iter)->get_name() << " != null) {" << endl;
652 indent_up();
655 out <<
656 indent() << "field.name = \"" << (*f_iter)->get_name() << "\";" << endl <<
657 indent() << "field.type = " << type_to_enum((*f_iter)->get_type()) << ";" << endl <<
658 indent() << "field.id = " << (*f_iter)->get_key() << ";" << endl <<
659 indent() << "oprot.writeFieldBegin(field);" << endl;
661 // Write field contents
662 generate_serialize_field(out, *f_iter, "this.");
664 // Write field closer
665 indent(out) <<
666 "oprot.writeFieldEnd();" << endl;
668 if (null_allowed) {
669 indent_down();
670 indent(out) << "}" << endl;
673 indent_down();
674 indent(out) << "}";
676 // Write the struct map
677 out <<
678 endl <<
679 indent() << "oprot.writeFieldStop();" << endl <<
680 indent() << "oprot.writeStructEnd();" << endl;
682 indent_down();
683 out <<
684 indent() << "}" << endl <<
685 endl;
689 * Generates a set of Java Bean boilerplate functions (setters, getters, etc.)
690 * for the given struct.
692 * @param tstruct The struct definition
694 void t_java_generator::generate_java_bean_boilerplate(ofstream& out,
695 t_struct* tstruct) {
696 const vector<t_field*>& fields = tstruct->get_members();
697 vector<t_field*>::const_iterator f_iter;
698 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
699 t_field* field = *f_iter;
700 t_type* type = get_true_type(field->get_type());
701 std::string field_name = field->get_name();
702 std::string cap_name = field_name;
703 cap_name[0] = toupper(cap_name[0]);
705 if (type->is_container()) {
706 // Method to return the size of the collection
707 indent(out) << "public int get" << cap_name << "Size() {" << endl;
708 indent_up();
709 indent(out) << "return (this." << field_name << " == null) ? 0 : " <<
710 "this." << field_name << ".size();" << endl;
711 indent_down();
712 indent(out) << "}" << endl << endl;
715 if (type->is_set() || type->is_list()) {
717 t_type* element_type;
718 if (type->is_set()) {
719 element_type = ((t_set*)type)->get_elem_type();
720 } else {
721 element_type = ((t_list*)type)->get_elem_type();
724 // Iterator getter for sets and lists
725 indent(out) << "public java.util.Iterator<" <<
726 type_name(element_type) << "> get" << cap_name << "Iterator() {" << endl;
727 indent_up();
728 indent(out) << "return (this." << field_name << " == null) ? null : " <<
729 "this." << field_name << ".iterator();" << endl;
730 indent_down();
731 indent(out) << "}" << endl << endl;
733 // Add to set or list, create if the set/list is null
734 indent(out) << "public void addTo" << cap_name << "(" <<
735 type_name(element_type) <<
736 " elem) {" << endl;
737 indent_up();
738 indent(out) << "if (this." << field_name << " == null) {" << endl;
739 indent_up();
740 indent(out) << "this." << field_name << " = new " << type_name(type) <<
741 "();" << endl;
742 indent_down();
743 indent(out) << "}" << endl;
744 indent(out) << "this." << field_name << ".add(elem);" << endl;
745 indent(out) << "this.__isset." << field_name << " = true;" << endl;
746 indent_down();
747 indent(out) << "}" << endl << endl;
749 } else if (type->is_map()) {
750 // Put to map
751 t_type* key_type = ((t_map*)type)->get_key_type();
752 t_type* val_type = ((t_map*)type)->get_val_type();
753 indent(out) << "public void putTo" << cap_name << "(" <<
754 type_name(key_type) << " key, " <<
755 type_name(val_type) << " val) {" << endl;
756 indent_up();
757 indent(out) << "if (this." << field_name << " == null) {" << endl;
758 indent_up();
759 indent(out) << "this." << field_name << " = new " <<
760 type_name(type, false, true) << "();" << endl;
761 indent_down();
762 indent(out) << "}" << endl;
763 indent(out) << "this." << field_name << ".put(key, val);" << endl;
764 indent(out) << "this.__isset." << field_name << " = true;" << endl;
765 indent_down();
766 indent(out) << "}" << endl << endl;
769 // Simple getter
770 indent(out) << "public " << type_name(type);
771 if (type->is_base_type() &&
772 ((t_base_type*)type)->get_base() == t_base_type::TYPE_BOOL) {
773 out << " is";
774 } else {
775 out << " get";
777 out << cap_name << "() {" << endl;
778 indent_up();
779 indent(out) << "return this." << field_name << ";" << endl;
780 indent_down();
781 indent(out) << "}" << endl << endl;
783 // Simple setter
784 indent(out) << "public void set" << cap_name << "(" << type_name(type) <<
785 " " << field_name << ") {" << endl;
786 indent_up();
787 indent(out) << "this." << field_name << " = " << field_name << ";" <<
788 endl;
789 indent(out) << "this.__isset." << field_name << " = true;" << endl;
790 indent_down();
791 indent(out) << "}" << endl << endl;
793 // Unsetter
794 indent(out) << "public void unset" << cap_name << "() {" << endl;
795 indent_up();
796 if (type->is_container() || type->is_struct() || type->is_xception()) {
797 indent(out) << "this." << field_name << " = null;" << endl;
799 indent(out) << "this.__isset." << field_name << " = false;" << endl;
800 indent_down();
801 indent(out) << "}" << endl << endl;
806 * Generates a toString() method for the given struct
808 * @param tstruct The struct definition
810 void t_java_generator::generate_java_struct_tostring(ofstream& out,
811 t_struct* tstruct) {
812 out <<
813 indent() << "public String toString() {" << endl;
814 indent_up();
816 out <<
817 indent() << "StringBuilder sb = new StringBuilder(\"" << tstruct->get_name() << "(\");" << endl;
819 const vector<t_field*>& fields = tstruct->get_members();
820 vector<t_field*>::const_iterator f_iter;
821 bool first = true;
822 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
823 if (first) {
824 first = false;
825 indent(out) << "sb.append(\"" << (*f_iter)->get_name() << ":\");" << endl;
826 } else {
827 indent(out) << "sb.append(\"," << (*f_iter)->get_name() << ":\");" << endl;
829 t_type* ttype = (*f_iter)->get_type();
830 if (ttype->is_xception() || ttype->is_struct()) {
831 indent(out) << "sb.append(this." << (*f_iter)->get_name() << ".toString());" << endl;
832 } else {
833 indent(out) << "sb.append(this." << (*f_iter)->get_name() << ");" << endl;
836 out <<
837 indent() << "sb.append(\")\");" << endl <<
838 indent() << "return sb.toString();" << endl;
840 indent_down();
841 indent(out) << "}" << endl <<
842 endl;
847 * Generates a thrift service. In C++, this comprises an entirely separate
848 * header and source file. The header file defines the methods and includes
849 * the data types defined in the main header file, and the implementation
850 * file contains implementations of the basic printer and default interfaces.
852 * @param tservice The service definition
854 void t_java_generator::generate_service(t_service* tservice) {
855 // Make output file
856 string f_service_name = package_dir_+"/"+service_name_+".java";
857 f_service_.open(f_service_name.c_str());
859 f_service_ <<
860 autogen_comment() <<
861 java_package() <<
862 java_type_imports() <<
863 java_thrift_imports();
865 f_service_ <<
866 "public class " << service_name_ << " {" << endl <<
867 endl;
868 indent_up();
870 // Generate the three main parts of the service
871 generate_service_interface(tservice);
872 generate_service_client(tservice);
873 generate_service_server(tservice);
874 generate_service_helpers(tservice);
876 indent_down();
877 f_service_ <<
878 "}" << endl;
879 f_service_.close();
883 * Generates a service interface definition.
885 * @param tservice The service to generate a header definition for
887 void t_java_generator::generate_service_interface(t_service* tservice) {
888 string extends = "";
889 string extends_iface = "";
890 if (tservice->get_extends() != NULL) {
891 extends = type_name(tservice->get_extends());
892 extends_iface = " extends " + extends + ".Iface";
895 generate_java_doc(f_service_, tservice);
896 f_service_ << indent() << "public interface Iface" << extends_iface <<
897 " {" << endl << endl;
898 indent_up();
899 vector<t_function*> functions = tservice->get_functions();
900 vector<t_function*>::iterator f_iter;
901 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
902 generate_java_doc(f_service_, *f_iter);
903 indent(f_service_) << "public " << function_signature(*f_iter) << ";" <<
904 endl << endl;
906 indent_down();
907 f_service_ <<
908 indent() << "}" << endl <<
909 endl;
913 * Generates structs for all the service args and return types
915 * @param tservice The service
917 void t_java_generator::generate_service_helpers(t_service* tservice) {
918 vector<t_function*> functions = tservice->get_functions();
919 vector<t_function*>::iterator f_iter;
920 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
921 t_struct* ts = (*f_iter)->get_arglist();
922 generate_java_struct_definition(f_service_, ts, false, true);
923 generate_function_helpers(*f_iter);
928 * Generates a service client definition.
930 * @param tservice The service to generate a server for.
932 void t_java_generator::generate_service_client(t_service* tservice) {
933 string extends = "";
934 string extends_client = "";
935 if (tservice->get_extends() != NULL) {
936 extends = type_name(tservice->get_extends());
937 extends_client = " extends " + extends + ".Client";
940 indent(f_service_) <<
941 "public static class Client" << extends_client << " implements Iface {" << endl;
942 indent_up();
944 indent(f_service_) <<
945 "public Client(TProtocol prot)" << endl;
946 scope_up(f_service_);
947 indent(f_service_) <<
948 "this(prot, prot);" << endl;
949 scope_down(f_service_);
950 f_service_ << endl;
952 indent(f_service_) <<
953 "public Client(TProtocol iprot, TProtocol oprot)" << endl;
954 scope_up(f_service_);
955 if (extends.empty()) {
956 f_service_ <<
957 indent() << "iprot_ = iprot;" << endl <<
958 indent() << "oprot_ = oprot;" << endl;
959 } else {
960 f_service_ <<
961 indent() << "super(iprot, oprot);" << endl;
963 scope_down(f_service_);
964 f_service_ << endl;
966 if (extends.empty()) {
967 f_service_ <<
968 indent() << "protected TProtocol iprot_;" << endl <<
969 indent() << "protected TProtocol oprot_;" << endl <<
970 endl <<
971 indent() << "protected int seqid_;" << endl <<
972 endl;
975 // Generate client method implementations
976 vector<t_function*> functions = tservice->get_functions();
977 vector<t_function*>::const_iterator f_iter;
978 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
979 string funname = (*f_iter)->get_name();
981 // Open function
982 indent(f_service_) <<
983 "public " << function_signature(*f_iter) << endl;
984 scope_up(f_service_);
985 indent(f_service_) <<
986 "send_" << funname << "(";
988 // Get the struct of function call params
989 t_struct* arg_struct = (*f_iter)->get_arglist();
991 // Declare the function arguments
992 const vector<t_field*>& fields = arg_struct->get_members();
993 vector<t_field*>::const_iterator fld_iter;
994 bool first = true;
995 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
996 if (first) {
997 first = false;
998 } else {
999 f_service_ << ", ";
1001 f_service_ << (*fld_iter)->get_name();
1003 f_service_ << ");" << endl;
1005 if (!(*f_iter)->is_async()) {
1006 f_service_ << indent();
1007 if (!(*f_iter)->get_returntype()->is_void()) {
1008 f_service_ << "return ";
1010 f_service_ <<
1011 "recv_" << funname << "();" << endl;
1013 scope_down(f_service_);
1014 f_service_ << endl;
1016 t_function send_function(g_type_void,
1017 string("send_") + (*f_iter)->get_name(),
1018 (*f_iter)->get_arglist());
1020 string argsname = (*f_iter)->get_name() + "_args";
1022 // Open function
1023 indent(f_service_) <<
1024 "public " << function_signature(&send_function) << endl;
1025 scope_up(f_service_);
1027 // Serialize the request
1028 f_service_ <<
1029 indent() << "oprot_.writeMessageBegin(new TMessage(\"" << funname << "\", TMessageType.CALL, seqid_));" << endl <<
1030 indent() << argsname << " args = new " << argsname << "();" << endl;
1032 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
1033 f_service_ <<
1034 indent() << "args." << (*fld_iter)->get_name() << " = " << (*fld_iter)->get_name() << ";" << endl;
1037 f_service_ <<
1038 indent() << "args.write(oprot_);" << endl <<
1039 indent() << "oprot_.writeMessageEnd();" << endl <<
1040 indent() << "oprot_.getTransport().flush();" << endl;
1042 scope_down(f_service_);
1043 f_service_ << endl;
1045 if (!(*f_iter)->is_async()) {
1046 string resultname = (*f_iter)->get_name() + "_result";
1048 t_struct noargs(program_);
1049 t_function recv_function((*f_iter)->get_returntype(),
1050 string("recv_") + (*f_iter)->get_name(),
1051 &noargs,
1052 (*f_iter)->get_xceptions());
1053 // Open function
1054 indent(f_service_) <<
1055 "public " << function_signature(&recv_function) << endl;
1056 scope_up(f_service_);
1058 // TODO(mcslee): Message validation here, was the seqid etc ok?
1060 f_service_ <<
1061 indent() << "TMessage msg = iprot_.readMessageBegin();" << endl <<
1062 indent() << "if (msg.type == TMessageType.EXCEPTION) {" << endl <<
1063 indent() << " TApplicationException x = TApplicationException.read(iprot_);" << endl <<
1064 indent() << " iprot_.readMessageEnd();" << endl <<
1065 indent() << " throw x;" << endl <<
1066 indent() << "}" << endl <<
1067 indent() << resultname << " result = new " << resultname << "();" << endl <<
1068 indent() << "result.read(iprot_);" << endl <<
1069 indent() << "iprot_.readMessageEnd();" << endl;
1071 // Careful, only return _result if not a void function
1072 if (!(*f_iter)->get_returntype()->is_void()) {
1073 f_service_ <<
1074 indent() << "if (result.__isset.success) {" << endl <<
1075 indent() << " return result.success;" << endl <<
1076 indent() << "}" << endl;
1079 t_struct* xs = (*f_iter)->get_xceptions();
1080 const std::vector<t_field*>& xceptions = xs->get_members();
1081 vector<t_field*>::const_iterator x_iter;
1082 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
1083 f_service_ <<
1084 indent() << "if (result.__isset." << (*x_iter)->get_name() << ") {" << endl <<
1085 indent() << " throw result." << (*x_iter)->get_name() << ";" << endl <<
1086 indent() << "}" << endl;
1089 // If you get here it's an exception, unless a void function
1090 if ((*f_iter)->get_returntype()->is_void()) {
1091 indent(f_service_) <<
1092 "return;" << endl;
1093 } else {
1094 f_service_ <<
1095 indent() << "throw new TApplicationException(TApplicationException.MISSING_RESULT, \"" << (*f_iter)->get_name() << " failed: unknown result\");" << endl;
1098 // Close function
1099 scope_down(f_service_);
1100 f_service_ << endl;
1104 indent_down();
1105 indent(f_service_) <<
1106 "}" << endl;
1110 * Generates a service server definition.
1112 * @param tservice The service to generate a server for.
1114 void t_java_generator::generate_service_server(t_service* tservice) {
1115 // Generate the dispatch methods
1116 vector<t_function*> functions = tservice->get_functions();
1117 vector<t_function*>::iterator f_iter;
1119 // Extends stuff
1120 string extends = "";
1121 string extends_processor = "";
1122 if (tservice->get_extends() != NULL) {
1123 extends = type_name(tservice->get_extends());
1124 extends_processor = " extends " + extends + ".Processor";
1127 // Generate the header portion
1128 indent(f_service_) <<
1129 "public static class Processor" << extends_processor << " implements TProcessor {" << endl;
1130 indent_up();
1132 indent(f_service_) <<
1133 "public Processor(Iface iface)" << endl;
1134 scope_up(f_service_);
1135 if (!extends.empty()) {
1136 f_service_ <<
1137 indent() << "super(iface);" << endl;
1139 f_service_ <<
1140 indent() << "iface_ = iface;" << endl;
1142 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1143 f_service_ <<
1144 indent() << "processMap_.put(\"" << (*f_iter)->get_name() << "\", new " << (*f_iter)->get_name() << "());" << endl;
1147 scope_down(f_service_);
1148 f_service_ << endl;
1150 if (extends.empty()) {
1151 f_service_ <<
1152 indent() << "protected static interface ProcessFunction {" << endl <<
1153 indent() << " public void process(int seqid, TProtocol iprot, TProtocol oprot) throws TException;" << endl <<
1154 indent() << "}" << endl <<
1155 endl;
1158 f_service_ <<
1159 indent() << "private Iface iface_;" << endl;
1161 if (extends.empty()) {
1162 f_service_ <<
1163 indent() << "protected final HashMap<String,ProcessFunction> processMap_ = new HashMap<String,ProcessFunction>();" << endl;
1166 f_service_ << endl;
1168 // Generate the server implementation
1169 indent(f_service_) <<
1170 "public boolean process(TProtocol iprot, TProtocol oprot) throws TException" << endl;
1171 scope_up(f_service_);
1173 f_service_ <<
1174 indent() << "TMessage msg = iprot.readMessageBegin();" << endl;
1176 // TODO(mcslee): validate message, was the seqid etc. legit?
1178 f_service_ <<
1179 indent() << "ProcessFunction fn = processMap_.get(msg.name);" << endl <<
1180 indent() << "if (fn == null) {" << endl <<
1181 indent() << " TProtocolUtil.skip(iprot, TType.STRUCT);" << endl <<
1182 indent() << " iprot.readMessageEnd();" << endl <<
1183 indent() << " TApplicationException x = new TApplicationException(TApplicationException.UNKNOWN_METHOD, \"Invalid method name: '\"+msg.name+\"'\");" << endl <<
1184 indent() << " oprot.writeMessageBegin(new TMessage(msg.name, TMessageType.EXCEPTION, msg.seqid));" << endl <<
1185 indent() << " x.write(oprot);" << endl <<
1186 indent() << " oprot.writeMessageEnd();" << endl <<
1187 indent() << " oprot.getTransport().flush();" << endl <<
1188 indent() << " return true;" << endl <<
1189 indent() << "}" << endl <<
1190 indent() << "fn.process(msg.seqid, iprot, oprot);" << endl;
1192 f_service_ <<
1193 indent() << "return true;" << endl;
1195 scope_down(f_service_);
1196 f_service_ << endl;
1198 // Generate the process subfunctions
1199 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1200 generate_process_function(tservice, *f_iter);
1203 indent_down();
1204 indent(f_service_) <<
1205 "}" << endl <<
1206 endl;
1210 * Generates a struct and helpers for a function.
1212 * @param tfunction The function
1214 void t_java_generator::generate_function_helpers(t_function* tfunction) {
1215 if (tfunction->is_async()) {
1216 return;
1219 t_struct result(program_, tfunction->get_name() + "_result");
1220 t_field success(tfunction->get_returntype(), "success", 0);
1221 if (!tfunction->get_returntype()->is_void()) {
1222 result.append(&success);
1225 t_struct* xs = tfunction->get_xceptions();
1226 const vector<t_field*>& fields = xs->get_members();
1227 vector<t_field*>::const_iterator f_iter;
1228 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1229 result.append(*f_iter);
1232 generate_java_struct_definition(f_service_, &result, false, true, true);
1236 * Generates a process function definition.
1238 * @param tfunction The function to write a dispatcher for
1240 void t_java_generator::generate_process_function(t_service* tservice,
1241 t_function* tfunction) {
1242 // Open class
1243 indent(f_service_) <<
1244 "private class " << tfunction->get_name() << " implements ProcessFunction {" << endl;
1245 indent_up();
1247 // Open function
1248 indent(f_service_) <<
1249 "public void process(int seqid, TProtocol iprot, TProtocol oprot) throws TException" << endl;
1250 scope_up(f_service_);
1252 string argsname = tfunction->get_name() + "_args";
1253 string resultname = tfunction->get_name() + "_result";
1255 f_service_ <<
1256 indent() << argsname << " args = new " << argsname << "();" << endl <<
1257 indent() << "args.read(iprot);" << endl <<
1258 indent() << "iprot.readMessageEnd();" << endl;
1260 t_struct* xs = tfunction->get_xceptions();
1261 const std::vector<t_field*>& xceptions = xs->get_members();
1262 vector<t_field*>::const_iterator x_iter;
1264 // Declare result for non async function
1265 if (!tfunction->is_async()) {
1266 f_service_ <<
1267 indent() << resultname << " result = new " << resultname << "();" << endl;
1270 // Try block for a function with exceptions
1271 if (xceptions.size() > 0) {
1272 f_service_ <<
1273 indent() << "try {" << endl;
1274 indent_up();
1277 // Generate the function call
1278 t_struct* arg_struct = tfunction->get_arglist();
1279 const std::vector<t_field*>& fields = arg_struct->get_members();
1280 vector<t_field*>::const_iterator f_iter;
1282 f_service_ << indent();
1283 if (!tfunction->is_async() && !tfunction->get_returntype()->is_void()) {
1284 f_service_ << "result.success = ";
1286 f_service_ <<
1287 "iface_." << tfunction->get_name() << "(";
1288 bool first = true;
1289 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1290 if (first) {
1291 first = false;
1292 } else {
1293 f_service_ << ", ";
1295 f_service_ << "args." << (*f_iter)->get_name();
1297 f_service_ << ");" << endl;
1299 // Set isset on success field
1300 if (!tfunction->is_async() && !tfunction->get_returntype()->is_void()) {
1301 f_service_ <<
1302 indent() << "result.__isset.success = true;" << endl;
1305 if (!tfunction->is_async() && xceptions.size() > 0) {
1306 indent_down();
1307 f_service_ << indent() << "}";
1308 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
1309 f_service_ << " catch (" << type_name((*x_iter)->get_type(), false, false) << " " << (*x_iter)->get_name() << ") {" << endl;
1310 if (!tfunction->is_async()) {
1311 indent_up();
1312 f_service_ <<
1313 indent() << "result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name() << ";" << endl <<
1314 indent() << "result.__isset." << (*x_iter)->get_name() << " = true;" << endl;
1315 indent_down();
1316 f_service_ << indent() << "}";
1317 } else {
1318 f_service_ << "}";
1321 f_service_ << endl;
1324 // Shortcut out here for async functions
1325 if (tfunction->is_async()) {
1326 f_service_ <<
1327 indent() << "return;" << endl;
1328 scope_down(f_service_);
1330 // Close class
1331 indent_down();
1332 f_service_ <<
1333 indent() << "}" << endl <<
1334 endl;
1335 return;
1338 f_service_ <<
1339 indent() << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name() << "\", TMessageType.REPLY, seqid));" << endl <<
1340 indent() << "result.write(oprot);" << endl <<
1341 indent() << "oprot.writeMessageEnd();" << endl <<
1342 indent() << "oprot.getTransport().flush();" << endl;
1344 // Close function
1345 scope_down(f_service_);
1346 f_service_ << endl;
1348 // Close class
1349 indent_down();
1350 f_service_ <<
1351 indent() << "}" << endl <<
1352 endl;
1356 * Deserializes a field of any type.
1358 * @param tfield The field
1359 * @param prefix The variable name or container for this field
1361 void t_java_generator::generate_deserialize_field(ofstream& out,
1362 t_field* tfield,
1363 string prefix) {
1364 t_type* type = get_true_type(tfield->get_type());
1366 if (type->is_void()) {
1367 throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " +
1368 prefix + tfield->get_name();
1371 string name = prefix + tfield->get_name();
1373 if (type->is_struct() || type->is_xception()) {
1374 generate_deserialize_struct(out,
1375 (t_struct*)type,
1376 name);
1377 } else if (type->is_container()) {
1378 generate_deserialize_container(out, type, name);
1379 } else if (type->is_base_type() || type->is_enum()) {
1381 indent(out) <<
1382 name << " = iprot.";
1384 if (type->is_base_type()) {
1385 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1386 switch (tbase) {
1387 case t_base_type::TYPE_VOID:
1388 throw "compiler error: cannot serialize void field in a struct: " +
1389 name;
1390 break;
1391 case t_base_type::TYPE_STRING:
1392 if (((t_base_type*)type)->is_binary()) {
1393 out << "readBinary();";
1394 } else {
1395 out << "readString();";
1397 break;
1398 case t_base_type::TYPE_BOOL:
1399 out << "readBool();";
1400 break;
1401 case t_base_type::TYPE_BYTE:
1402 out << "readByte();";
1403 break;
1404 case t_base_type::TYPE_I16:
1405 out << "readI16();";
1406 break;
1407 case t_base_type::TYPE_I32:
1408 out << "readI32();";
1409 break;
1410 case t_base_type::TYPE_I64:
1411 out << "readI64();";
1412 break;
1413 case t_base_type::TYPE_DOUBLE:
1414 out << "readDouble();";
1415 break;
1416 default:
1417 throw "compiler error: no Java name for base type " + t_base_type::t_base_name(tbase);
1419 } else if (type->is_enum()) {
1420 out << "readI32();";
1422 out <<
1423 endl;
1424 } else {
1425 printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
1426 tfield->get_name().c_str(), type_name(type).c_str());
1431 * Generates an unserializer for a struct, invokes read()
1433 void t_java_generator::generate_deserialize_struct(ofstream& out,
1434 t_struct* tstruct,
1435 string prefix) {
1436 out <<
1437 indent() << prefix << " = new " << type_name(tstruct) << "();" << endl <<
1438 indent() << prefix << ".read(iprot);" << endl;
1442 * Deserializes a container by reading its size and then iterating
1444 void t_java_generator::generate_deserialize_container(ofstream& out,
1445 t_type* ttype,
1446 string prefix) {
1447 scope_up(out);
1449 string obj;
1451 if (ttype->is_map()) {
1452 obj = tmp("_map");
1453 } else if (ttype->is_set()) {
1454 obj = tmp("_set");
1455 } else if (ttype->is_list()) {
1456 obj = tmp("_list");
1459 // Declare variables, read header
1460 if (ttype->is_map()) {
1461 indent(out) << "TMap " << obj << " = iprot.readMapBegin();" << endl;
1462 } else if (ttype->is_set()) {
1463 indent(out) << "TSet " << obj << " = iprot.readSetBegin();" << endl;
1464 } else if (ttype->is_list()) {
1465 indent(out) << "TList " << obj << " = iprot.readListBegin();" << endl;
1468 indent(out)
1469 << prefix << " = new " << type_name(ttype, false, true)
1470 // size the collection correctly
1471 << "("
1472 << (ttype->is_list() ? "" : "2*" )
1473 << obj << ".size"
1474 << ");" << endl;
1476 // For loop iterates over elements
1477 string i = tmp("_i");
1478 indent(out) <<
1479 "for (int " << i << " = 0; " <<
1480 i << " < " << obj << ".size" << "; " <<
1481 "++" << i << ")" << endl;
1483 scope_up(out);
1485 if (ttype->is_map()) {
1486 generate_deserialize_map_element(out, (t_map*)ttype, prefix);
1487 } else if (ttype->is_set()) {
1488 generate_deserialize_set_element(out, (t_set*)ttype, prefix);
1489 } else if (ttype->is_list()) {
1490 generate_deserialize_list_element(out, (t_list*)ttype, prefix);
1493 scope_down(out);
1495 // Read container end
1496 if (ttype->is_map()) {
1497 indent(out) << "iprot.readMapEnd();" << endl;
1498 } else if (ttype->is_set()) {
1499 indent(out) << "iprot.readSetEnd();" << endl;
1500 } else if (ttype->is_list()) {
1501 indent(out) << "iprot.readListEnd();" << endl;
1504 scope_down(out);
1509 * Generates code to deserialize a map
1511 void t_java_generator::generate_deserialize_map_element(ofstream& out,
1512 t_map* tmap,
1513 string prefix) {
1514 string key = tmp("_key");
1515 string val = tmp("_val");
1516 t_field fkey(tmap->get_key_type(), key);
1517 t_field fval(tmap->get_val_type(), val);
1519 indent(out) <<
1520 declare_field(&fkey) << endl;
1521 indent(out) <<
1522 declare_field(&fval) << endl;
1524 generate_deserialize_field(out, &fkey);
1525 generate_deserialize_field(out, &fval);
1527 indent(out) <<
1528 prefix << ".put(" << key << ", " << val << ");" << endl;
1532 * Deserializes a set element
1534 void t_java_generator::generate_deserialize_set_element(ofstream& out,
1535 t_set* tset,
1536 string prefix) {
1537 string elem = tmp("_elem");
1538 t_field felem(tset->get_elem_type(), elem);
1540 indent(out) <<
1541 declare_field(&felem) << endl;
1543 generate_deserialize_field(out, &felem);
1545 indent(out) <<
1546 prefix << ".add(" << elem << ");" << endl;
1550 * Deserializes a list element
1552 void t_java_generator::generate_deserialize_list_element(ofstream& out,
1553 t_list* tlist,
1554 string prefix) {
1555 string elem = tmp("_elem");
1556 t_field felem(tlist->get_elem_type(), elem);
1558 indent(out) <<
1559 declare_field(&felem, true) << endl;
1561 generate_deserialize_field(out, &felem);
1563 indent(out) <<
1564 prefix << ".add(" << elem << ");" << endl;
1569 * Serializes a field of any type.
1571 * @param tfield The field to serialize
1572 * @param prefix Name to prepend to field name
1574 void t_java_generator::generate_serialize_field(ofstream& out,
1575 t_field* tfield,
1576 string prefix) {
1577 t_type* type = get_true_type(tfield->get_type());
1579 // Do nothing for void types
1580 if (type->is_void()) {
1581 throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " +
1582 prefix + tfield->get_name();
1585 if (type->is_struct() || type->is_xception()) {
1586 generate_serialize_struct(out,
1587 (t_struct*)type,
1588 prefix + tfield->get_name());
1589 } else if (type->is_container()) {
1590 generate_serialize_container(out,
1591 type,
1592 prefix + tfield->get_name());
1593 } else if (type->is_base_type() || type->is_enum()) {
1595 string name = prefix + tfield->get_name();
1596 indent(out) <<
1597 "oprot.";
1599 if (type->is_base_type()) {
1600 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1601 switch (tbase) {
1602 case t_base_type::TYPE_VOID:
1603 throw
1604 "compiler error: cannot serialize void field in a struct: " + name;
1605 break;
1606 case t_base_type::TYPE_STRING:
1607 if (((t_base_type*)type)->is_binary()) {
1608 out << "writeBinary(" << name << ");";
1609 } else {
1610 out << "writeString(" << name << ");";
1612 break;
1613 case t_base_type::TYPE_BOOL:
1614 out << "writeBool(" << name << ");";
1615 break;
1616 case t_base_type::TYPE_BYTE:
1617 out << "writeByte(" << name << ");";
1618 break;
1619 case t_base_type::TYPE_I16:
1620 out << "writeI16(" << name << ");";
1621 break;
1622 case t_base_type::TYPE_I32:
1623 out << "writeI32(" << name << ");";
1624 break;
1625 case t_base_type::TYPE_I64:
1626 out << "writeI64(" << name << ");";
1627 break;
1628 case t_base_type::TYPE_DOUBLE:
1629 out << "writeDouble(" << name << ");";
1630 break;
1631 default:
1632 throw "compiler error: no Java name for base type " + t_base_type::t_base_name(tbase);
1634 } else if (type->is_enum()) {
1635 out << "writeI32(" << name << ");";
1637 out << endl;
1638 } else {
1639 printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
1640 prefix.c_str(),
1641 tfield->get_name().c_str(),
1642 type_name(type).c_str());
1647 * Serializes all the members of a struct.
1649 * @param tstruct The struct to serialize
1650 * @param prefix String prefix to attach to all fields
1652 void t_java_generator::generate_serialize_struct(ofstream& out,
1653 t_struct* tstruct,
1654 string prefix) {
1655 out <<
1656 indent() << prefix << ".write(oprot);" << endl;
1660 * Serializes a container by writing its size then the elements.
1662 * @param ttype The type of container
1663 * @param prefix String prefix for fields
1665 void t_java_generator::generate_serialize_container(ofstream& out,
1666 t_type* ttype,
1667 string prefix) {
1668 scope_up(out);
1670 if (ttype->is_map()) {
1671 indent(out) <<
1672 "oprot.writeMapBegin(new TMap(" <<
1673 type_to_enum(((t_map*)ttype)->get_key_type()) << ", " <<
1674 type_to_enum(((t_map*)ttype)->get_val_type()) << ", " <<
1675 prefix << ".size()));" << endl;
1676 } else if (ttype->is_set()) {
1677 indent(out) <<
1678 "oprot.writeSetBegin(new TSet(" <<
1679 type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " <<
1680 prefix << ".size()));" << endl;
1681 } else if (ttype->is_list()) {
1682 indent(out) <<
1683 "oprot.writeListBegin(new TList(" <<
1684 type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
1685 prefix << ".size()));" << endl;
1688 string iter = tmp("_iter");
1689 if (ttype->is_map()) {
1690 indent(out) <<
1691 "for (" <<
1692 type_name(((t_map*)ttype)->get_key_type()) << " " << iter <<
1693 " : " <<
1694 prefix << ".keySet())";
1695 } else if (ttype->is_set()) {
1696 indent(out) <<
1697 "for (" <<
1698 type_name(((t_set*)ttype)->get_elem_type()) << " " << iter <<
1699 " : " <<
1700 prefix << ")";
1701 } else if (ttype->is_list()) {
1702 indent(out) <<
1703 "for (" <<
1704 type_name(((t_list*)ttype)->get_elem_type()) << " " << iter <<
1705 " : " <<
1706 prefix << ")";
1709 scope_up(out);
1711 if (ttype->is_map()) {
1712 generate_serialize_map_element(out, (t_map*)ttype, iter, prefix);
1713 } else if (ttype->is_set()) {
1714 generate_serialize_set_element(out, (t_set*)ttype, iter);
1715 } else if (ttype->is_list()) {
1716 generate_serialize_list_element(out, (t_list*)ttype, iter);
1719 scope_down(out);
1721 if (ttype->is_map()) {
1722 indent(out) <<
1723 "oprot.writeMapEnd();" << endl;
1724 } else if (ttype->is_set()) {
1725 indent(out) <<
1726 "oprot.writeSetEnd();" << endl;
1727 } else if (ttype->is_list()) {
1728 indent(out) <<
1729 "oprot.writeListEnd();" << endl;
1732 scope_down(out);
1736 * Serializes the members of a map.
1738 void t_java_generator::generate_serialize_map_element(ofstream& out,
1739 t_map* tmap,
1740 string iter,
1741 string map) {
1742 t_field kfield(tmap->get_key_type(), iter);
1743 generate_serialize_field(out, &kfield, "");
1744 t_field vfield(tmap->get_val_type(), map + ".get(" + iter + ")");
1745 generate_serialize_field(out, &vfield, "");
1749 * Serializes the members of a set.
1751 void t_java_generator::generate_serialize_set_element(ofstream& out,
1752 t_set* tset,
1753 string iter) {
1754 t_field efield(tset->get_elem_type(), iter);
1755 generate_serialize_field(out, &efield, "");
1759 * Serializes the members of a list.
1761 void t_java_generator::generate_serialize_list_element(ofstream& out,
1762 t_list* tlist,
1763 string iter) {
1764 t_field efield(tlist->get_elem_type(), iter);
1765 generate_serialize_field(out, &efield, "");
1769 * Returns a Java type name
1771 * @param ttype The type
1772 * @param container Is the type going inside a container?
1773 * @return Java type name, i.e. HashMap<Key,Value>
1775 string t_java_generator::type_name(t_type* ttype, bool in_container, bool in_init) {
1776 // In Java typedefs are just resolved to their real type
1777 ttype = get_true_type(ttype);
1779 if (ttype->is_base_type()) {
1780 return base_type_name((t_base_type*)ttype, in_container);
1781 } else if (ttype->is_enum()) {
1782 return (in_container ? "Integer" : "int");
1783 } else if (ttype->is_map()) {
1784 t_map* tmap = (t_map*) ttype;
1785 string prefix;
1786 if (in_init) {
1787 prefix = "HashMap";
1788 } else {
1789 prefix = "AbstractMap";
1791 return prefix + "<" +
1792 type_name(tmap->get_key_type(), true) + "," +
1793 type_name(tmap->get_val_type(), true) + ">";
1794 } else if (ttype->is_set()) {
1795 t_set* tset = (t_set*) ttype;
1796 return "HashSet<" + type_name(tset->get_elem_type(), true) + ">";
1797 } else if (ttype->is_list()) {
1798 t_list* tlist = (t_list*) ttype;
1799 return "ArrayList<" + type_name(tlist->get_elem_type(), true) + ">";
1802 // Check for namespacing
1803 t_program* program = ttype->get_program();
1804 if (program != NULL && program != program_) {
1805 string package = program->get_java_package();
1806 if (!package.empty()) {
1807 return package + "." + ttype->get_name();
1811 return ttype->get_name();
1815 * Returns the C++ type that corresponds to the thrift type.
1817 * @param tbase The base type
1818 * @param container Is it going in a Java container?
1820 string t_java_generator::base_type_name(t_base_type* type,
1821 bool in_container) {
1822 t_base_type::t_base tbase = type->get_base();
1824 switch (tbase) {
1825 case t_base_type::TYPE_VOID:
1826 return "void";
1827 case t_base_type::TYPE_STRING:
1828 if (type->is_binary()) {
1829 return "byte[]";
1830 } else {
1831 return "String";
1833 case t_base_type::TYPE_BOOL:
1834 return (in_container ? "Boolean" : "boolean");
1835 case t_base_type::TYPE_BYTE:
1836 return (in_container ? "Byte" : "byte");
1837 case t_base_type::TYPE_I16:
1838 return (in_container ? "Short" : "short");
1839 case t_base_type::TYPE_I32:
1840 return (in_container ? "Integer" : "int");
1841 case t_base_type::TYPE_I64:
1842 return (in_container ? "Long" : "long");
1843 case t_base_type::TYPE_DOUBLE:
1844 return (in_container ? "Double" : "double");
1845 default:
1846 throw "compiler error: no C++ name for base type " + t_base_type::t_base_name(tbase);
1851 * Declares a field, which may include initialization as necessary.
1853 * @param ttype The type
1855 string t_java_generator::declare_field(t_field* tfield, bool init) {
1856 // TODO(mcslee): do we ever need to initialize the field?
1857 string result = type_name(tfield->get_type()) + " " + tfield->get_name();
1858 if (init) {
1859 t_type* ttype = get_true_type(tfield->get_type());
1860 if (ttype->is_base_type() && tfield->get_value() != NULL) {
1861 ofstream dummy;
1862 result += " = " + render_const_value(dummy, tfield->get_name(), ttype, tfield->get_value());
1863 } else if (ttype->is_base_type()) {
1864 t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
1865 switch (tbase) {
1866 case t_base_type::TYPE_VOID:
1867 throw "NO T_VOID CONSTRUCT";
1868 case t_base_type::TYPE_STRING:
1869 result += " = null";
1870 break;
1871 case t_base_type::TYPE_BOOL:
1872 result += " = false";
1873 break;
1874 case t_base_type::TYPE_BYTE:
1875 case t_base_type::TYPE_I16:
1876 case t_base_type::TYPE_I32:
1877 case t_base_type::TYPE_I64:
1878 result += " = 0";
1879 break;
1880 case t_base_type::TYPE_DOUBLE:
1881 result += " = (double)0";
1882 break;
1885 } else if (ttype->is_enum()) {
1886 result += " = 0";
1887 } else if (ttype->is_container()) {
1888 result += " = new " + type_name(ttype, false, true) + "()";
1889 } else {
1890 result += " = new " + type_name(ttype, false, true) + "()";;
1893 return result + ";";
1897 * Renders a function signature of the form 'type name(args)'
1899 * @param tfunction Function definition
1900 * @return String of rendered function definition
1902 string t_java_generator::function_signature(t_function* tfunction,
1903 string prefix) {
1904 t_type* ttype = tfunction->get_returntype();
1905 std::string result =
1906 type_name(ttype) + " " + prefix + tfunction->get_name() + "(" + argument_list(tfunction->get_arglist()) + ") throws ";
1907 t_struct* xs = tfunction->get_xceptions();
1908 const std::vector<t_field*>& xceptions = xs->get_members();
1909 vector<t_field*>::const_iterator x_iter;
1910 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
1911 result += type_name((*x_iter)->get_type(), false, false) + ", ";
1913 result += "TException";
1914 return result;
1918 * Renders a comma separated field list, with type names
1920 string t_java_generator::argument_list(t_struct* tstruct) {
1921 string result = "";
1923 const vector<t_field*>& fields = tstruct->get_members();
1924 vector<t_field*>::const_iterator f_iter;
1925 bool first = true;
1926 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1927 if (first) {
1928 first = false;
1929 } else {
1930 result += ", ";
1932 result += type_name((*f_iter)->get_type()) + " " + (*f_iter)->get_name();
1934 return result;
1938 * Converts the parse type to a C++ enum string for the given type.
1940 string t_java_generator::type_to_enum(t_type* type) {
1941 type = get_true_type(type);
1943 if (type->is_base_type()) {
1944 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1945 switch (tbase) {
1946 case t_base_type::TYPE_VOID:
1947 throw "NO T_VOID CONSTRUCT";
1948 case t_base_type::TYPE_STRING:
1949 return "TType.STRING";
1950 case t_base_type::TYPE_BOOL:
1951 return "TType.BOOL";
1952 case t_base_type::TYPE_BYTE:
1953 return "TType.BYTE";
1954 case t_base_type::TYPE_I16:
1955 return "TType.I16";
1956 case t_base_type::TYPE_I32:
1957 return "TType.I32";
1958 case t_base_type::TYPE_I64:
1959 return "TType.I64";
1960 case t_base_type::TYPE_DOUBLE:
1961 return "TType.DOUBLE";
1963 } else if (type->is_enum()) {
1964 return "TType.I32";
1965 } else if (type->is_struct() || type->is_xception()) {
1966 return "TType.STRUCT";
1967 } else if (type->is_map()) {
1968 return "TType.MAP";
1969 } else if (type->is_set()) {
1970 return "TType.SET";
1971 } else if (type->is_list()) {
1972 return "TType.LIST";
1975 throw "INVALID TYPE IN type_to_enum: " + type->get_name();
1979 * Emits a JavaDoc comment if the provided object has a doc in Thrift
1981 void t_java_generator::generate_java_doc(ofstream &out,
1982 t_doc* tdoc) {
1983 if (tdoc->has_doc()) {
1984 indent(out) << "/**" << endl;
1985 stringstream docs(tdoc->get_doc(), ios_base::in);
1986 while (!docs.eof()) {
1987 char line[1024];
1988 docs.getline(line, 1024);
1989 if (strlen(line) > 0 || !docs.eof()) { // skip the empty last line
1990 indent(out) << " * " << line << endl;
1993 indent(out) << " */" << endl;