From: Mark Slee Date: Sat, 2 Sep 2006 04:17:07 +0000 (+0000) Subject: Thrift generation for Java X-Git-Tag: 0.2.0~1697 X-Git-Url: https://source.supwisdom.com/gerrit/gitweb?a=commitdiff_plain;h=78f58e25595f704c3b1e05c911b2821c824dd595;p=common%2Fthrift.git Thrift generation for Java Summary: Java works, benchmark roundtrip at around 3ms, so right in between C++ and PHP git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@664775 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/compiler/cpp/Makefile b/compiler/cpp/Makefile index 6b12853f..b857e8c6 100644 --- a/compiler/cpp/Makefile +++ b/compiler/cpp/Makefile @@ -35,9 +35,9 @@ BIN_DIR = bin/ # Source files SRC_FILES = main.cc \ generate/t_generator.cc \ + generate/t_java_generator.cc \ generate/t_php_generator.cc \ - generate/t_cpp_generator.cc \ - generate/t_java_generator.cc + generate/t_cpp_generator.cc # Autogenerated files GEN_FILES = thrift.tab.hh \ diff --git a/compiler/cpp/src/generate/t_cpp_generator.cc b/compiler/cpp/src/generate/t_cpp_generator.cc index 43f80213..72132e5c 100644 --- a/compiler/cpp/src/generate/t_cpp_generator.cc +++ b/compiler/cpp/src/generate/t_cpp_generator.cc @@ -667,15 +667,10 @@ void t_cpp_generator::generate_service_client(t_service* tservice) { f_service_ << indent() << "throw facebook::thrift::Exception(\"Unexpected message type, name, or id\");" << endl; indent_down(); - f_service_ << - indent() << "}" << endl; - - f_service_ << - endl << - indent() << resultname << " __result;" << endl; - // Add a field to the return struct if non void f_service_ << + indent() << "}" << endl << + indent() << resultname << " __result;" << endl << indent() << "read_struct_" << resultname << "(_iprot, _itrans, __result);" << endl << indent() << "_iprot->readMessageEnd(_itrans);" << endl << endl; @@ -727,21 +722,21 @@ void t_cpp_generator::generate_service_server(t_service* tservice) { // Generate the header portion f_header_ << - "class " << service_name_ << "ServerIf : " << + "class " << service_name_ << "Server : " << "public " << service_name_ << "If, " << "public facebook::thrift::TProcessor {" << endl << " public: " << endl; indent_up(); f_header_ << indent() << - service_name_ << "ServerIf(boost::shared_ptr protocol) : " << + service_name_ << "Server(boost::shared_ptr protocol) : " << "_iprot(protocol), _oprot(protocol) {}" << endl << indent() << - service_name_ << "ServerIf(boost::shared_ptr iprot, boost::shared_ptr oprot) : " << + service_name_ << "Server(boost::shared_ptr iprot, boost::shared_ptr oprot) : " << "_iprot(iprot), _oprot(oprot) {}" << endl << indent() << "bool process(boost::shared_ptr _itrans, " << "boost::shared_ptr _otrans);" << endl << - indent() << "virtual ~" << service_name_ << "ServerIf() {}" << endl; + indent() << "virtual ~" << service_name_ << "Server() {}" << endl; indent_down(); // Protected data members @@ -768,7 +763,7 @@ void t_cpp_generator::generate_service_server(t_service* tservice) { // Generate the server implementation f_service_ << - "bool " << service_name_ << "ServerIf::" << + "bool " << service_name_ << "Server::" << "process(boost::shared_ptr itrans, boost::shared_ptr otrans) {" << endl; indent_up(); @@ -832,6 +827,10 @@ void t_cpp_generator::generate_service_server(t_service* tservice) { * @param tfunction The function */ void t_cpp_generator::generate_function_helpers(t_function* tfunction) { + if (tfunction->is_async()) { + return; + } + t_struct result(tfunction->get_name() + "_result"); t_field success(tfunction->get_returntype(), "success", 0); if (!tfunction->get_returntype()->is_void()) { @@ -859,7 +858,7 @@ void t_cpp_generator::generate_process_function(t_service* tservice, t_function* tfunction) { // Open function f_service_ << - "void " << tservice->get_name() << "ServerIf::" << + "void " << tservice->get_name() << "Server::" << "process_" << tfunction->get_name() << "(int32_t seqid, boost::shared_ptr itrans, boost::shared_ptr otrans)" << endl; scope_up(f_service_); @@ -871,13 +870,19 @@ void t_cpp_generator::generate_process_function(t_service* tservice, indent() << argsname << " __args;" << endl << indent() << "read_struct_" << argsname << "(_iprot, itrans, __args);" << endl << indent() << "_iprot->readMessageEnd(itrans);" << endl << - endl << - indent() << resultname << " __result;" << endl; - + endl; + t_struct* xs = tfunction->get_xceptions(); const std::vector& xceptions = xs->get_members(); vector::const_iterator x_iter; + // Declare result + if (!tfunction->is_async()) { + f_service_ << + indent() << resultname << " __result;" << endl; + } + + // Try block for functions with exceptions if (xceptions.size() > 0) { f_service_ << indent() << "try {" << endl; @@ -890,7 +895,7 @@ void t_cpp_generator::generate_process_function(t_service* tservice, vector::const_iterator f_iter; f_service_ << indent(); - if (!tfunction->get_returntype()->is_void()) { + if (!tfunction->is_async() && !tfunction->get_returntype()->is_void()) { f_service_ << "__result.success = "; } f_service_ << @@ -907,26 +912,39 @@ void t_cpp_generator::generate_process_function(t_service* tservice, f_service_ << ");" << endl; // Set isset on success field - if (!tfunction->get_returntype()->is_void()) { + if (!tfunction->is_async() && !tfunction->get_returntype()->is_void()) { f_service_ << indent() << "__result.__isset.success = true;" << endl; } - if (xceptions.size() > 0) { + if (!tfunction->is_async() && xceptions.size() > 0) { indent_down(); f_service_ << indent() << "}"; for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { f_service_ << " catch (" << (*x_iter)->get_type()->get_name() << " &" << (*x_iter)->get_name() << ") {" << endl; - indent_up(); - f_service_ << - indent() << "__result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name() << ";" << endl << - indent() << "__result.__isset." << (*x_iter)->get_name() << " = true;" << endl; - indent_down(); - f_service_ << indent() << "}"; + if (!tfunction->is_async()) { + indent_up(); + f_service_ << + indent() << "__result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name() << ";" << endl << + indent() << "__result.__isset." << (*x_iter)->get_name() << " = true;" << endl; + indent_down(); + f_service_ << indent() << "}"; + } else { + f_service_ << "}"; + } } f_service_ << endl; } + // Shortcut out here for async functions + if (tfunction->is_async()) { + f_service_ << + indent() << "return;" << endl; + indent_down(); + f_service_ << "}" << endl << + endl; + return; + } // Serialize the result into a struct f_service_ << @@ -977,6 +995,9 @@ void t_cpp_generator::generate_deserialize_field(t_field* tfield, case t_base_type::TYPE_STRING: f_service_ << "readString(itrans, " << name << ");"; break; + case t_base_type::TYPE_BOOL: + f_service_ << "readBool(itrans, " << name << ");"; + break; case t_base_type::TYPE_BYTE: f_service_ << "readByte(itrans, " << name << ");"; break; @@ -1172,6 +1193,9 @@ void t_cpp_generator::generate_serialize_field(t_field* tfield, case t_base_type::TYPE_STRING: f_service_ << "writeString(otrans, " << name << ");"; break; + case t_base_type::TYPE_BOOL: + f_service_ << "writeBool(otrans, " << name << ");"; + break; case t_base_type::TYPE_BYTE: f_service_ << "writeByte(otrans, " << name << ");"; break; @@ -1378,6 +1402,8 @@ string t_cpp_generator::base_type_name(t_base_type::t_base tbase) { return "void"; case t_base_type::TYPE_STRING: return "std::string"; + case t_base_type::TYPE_BOOL: + return "bool"; case t_base_type::TYPE_BYTE: return "int8_t"; case t_base_type::TYPE_I16: @@ -1413,6 +1439,9 @@ string t_cpp_generator::declare_field(t_field* tfield, bool init) { case t_base_type::TYPE_STRING: result += " = \"\""; break; + case t_base_type::TYPE_BOOL: + result += " = false"; + break; case t_base_type::TYPE_BYTE: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: @@ -1478,6 +1507,8 @@ string t_cpp_generator::type_to_enum(t_type* type) { throw "NO T_VOID CONSTRUCT"; case t_base_type::TYPE_STRING: return "facebook::thrift::protocol::T_STRING"; + case t_base_type::TYPE_BOOL: + return "facebook::thrift::protocol::T_BOOL"; case t_base_type::TYPE_BYTE: return "facebook::thrift::protocol::T_BYTE"; case t_base_type::TYPE_I16: diff --git a/compiler/cpp/src/generate/t_java_generator.cc b/compiler/cpp/src/generate/t_java_generator.cc index f1124079..1b466f70 100644 --- a/compiler/cpp/src/generate/t_java_generator.cc +++ b/compiler/cpp/src/generate/t_java_generator.cc @@ -13,6 +13,7 @@ using namespace std; void t_java_generator::init_generator(t_program* tprogram) { // Make output directory mkdir(T_JAVA_DIR, S_IREAD | S_IWRITE | S_IEXEC); + package_name_ = tprogram->get_namespace(); } /** @@ -20,7 +21,7 @@ void t_java_generator::init_generator(t_program* tprogram) { */ string t_java_generator::java_package() { // TODO(mcslee): Allow destination package to be specified in .thrift file - return string("package ") + program_name_ + ";\n\n"; + return string("package ") + package_name_ + ";\n\n"; } /** @@ -32,8 +33,7 @@ string t_java_generator::java_type_imports() { "import java.util.ArrayList;\n" + "import java.util.HashMap;\n" + "import java.util.HashSet;\n" + - "import com.facebook.thrift.*;\n" + - "import com.facebook.thrift.protocol.TString;\n\n"; + "import com.facebook.thrift.*;\n\n"; } /** @@ -104,6 +104,15 @@ void t_java_generator::generate_enum(t_enum* tenum) { * @param tstruct The struct definition */ void t_java_generator::generate_struct(t_struct* tstruct) { + generate_java_struct(tstruct, false); +} + +void t_java_generator::generate_xception(t_struct* txception) { + generate_java_struct(txception, true); +} + +void t_java_generator::generate_java_struct(t_struct* tstruct, + bool is_exception) { // Make output file string f_struct_name = string(T_JAVA_DIR)+"/"+(tstruct->get_name())+".java"; ofstream f_struct; @@ -112,23 +121,239 @@ void t_java_generator::generate_struct(t_struct* tstruct) { f_struct << autogen_comment() << java_package() << - java_type_imports(); + java_type_imports() << + java_thrift_imports(); - f_struct << - "public class " << tstruct->get_name() << " "; + generate_java_struct_definition(f_struct, + tstruct, + is_exception); + f_struct.close(); +} + +void t_java_generator::generate_java_struct_definition(ofstream &out, + t_struct* tstruct, + bool is_exception, + bool in_class, + bool is_result) { + out << + "public " << (in_class ? "static " : "") << "class " << tstruct->get_name() << " "; - scope_up(f_struct); + if (is_exception) { + out << "extends Exception "; + } + + scope_up(out); const vector& members = tstruct->get_members(); vector::const_iterator m_iter; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { - indent(f_struct) << + indent(out) << "public " << declare_field(*m_iter, true) << endl; } + + if (members.size() > 0) { + out << + endl << + indent() << "Isset __isset = new Isset();" << endl << + indent() << "public final class Isset {" << endl; + indent_up(); + for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + indent(out) << + "public boolean " << (*m_iter)->get_name() << " = false;" << endl; + } + indent_down(); + out << + indent() << "}" << endl << + endl; + } + + generate_java_struct_reader(out, tstruct); + if (is_result) { + generate_java_struct_result_writer(out, tstruct); + } else { + generate_java_struct_writer(out, tstruct); + } + scope_down(out); +} + +void t_java_generator::generate_java_struct_reader(ofstream& out, + t_struct* tstruct) { + out << + indent() << "public static " << tstruct->get_name() << " read(TProtocol _iprot, TTransport _itrans) throws TException {" << endl; + indent_up(); + + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + // Declare stack tmp variables + out << + indent() << tstruct->get_name() << " _value = new " << tstruct->get_name() << "();" << endl << + indent() << "TField _field;" << endl << + indent() << "TStruct _struct = _iprot.readStructBegin(_itrans);" << endl; - scope_down(f_struct); + // Loop over reading in fields + indent(out) << + "while (true)" << endl; + + scope_up(out); + + // Read beginning field marker + indent(out) << + "_field = _iprot.readFieldBegin(_itrans);" << endl; + + // Check for field STOP marker and break + indent(out) << + "if (_field.type == TType.STOP) { " << endl; + indent_up(); + indent(out) << + "break;" << endl; + indent_down(); + indent(out) << + "}" << endl; + + // Switch statement on the field we are reading + indent(out) << + "switch (_field.id)" << endl; + + scope_up(out); + + // Generate deserialization code for known cases + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + indent(out) << + "case " << (*f_iter)->get_key() << ":" << endl; + indent_up(); + generate_deserialize_field(out, *f_iter, "_value."); + out << + indent() << "_value.__isset." << (*f_iter)->get_name() << " = true;" << endl; + indent(out) << + "break;" << endl; + indent_down(); + } + + // In the default case we skip the field + out << + indent() << "default:" << endl << + indent() << " TProtocolUtil.skip(_iprot, _itrans, _field.type);" << endl << + indent() << " break;" << endl; + + scope_down(out); + + // Read field end marker + indent(out) << + "_iprot.readFieldEnd(_itrans);" << endl; + + scope_down(out); + + out << + indent() << "_iprot.readStructEnd(_itrans);" << endl << + indent() << "return _value;" << endl; + + indent_down(); + out << + indent() << "}" << endl << + endl; +} + +void t_java_generator::generate_java_struct_writer(ofstream& out, + t_struct* tstruct) { + out << + indent() << "public void write(TProtocol _oprot, TTransport _otrans) throws TException {" << endl; + indent_up(); + + string name = tstruct->get_name(); + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + out << + indent() << "TStruct _struct = new TStruct(\"" << name << "\");" << endl << + indent() << "TField _field = new TField();" << endl << + indent() << "_oprot.writeStructBegin(_otrans, _struct);" << endl; + + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + out << + indent() << "_field.name = \"" << (*f_iter)->get_name() << "\";" << endl << + indent() << "_field.type = " << type_to_enum((*f_iter)->get_type()) << ";" << endl << + indent() << "_field.id = " << (*f_iter)->get_key() << ";" << endl << + indent() << "_oprot.writeFieldBegin(_otrans, _field);" << endl; + + // Write field contents + generate_serialize_field(out, *f_iter, "this."); + + // Write field closer + indent(out) << + "_oprot.writeFieldEnd(_otrans);" << endl; + } + // Write the struct map + out << + indent() << "_oprot.writeFieldStop(_otrans);" << endl << + indent() << "_oprot.writeStructEnd(_otrans);" << endl; + + indent_down(); + out << + indent() << "}" << endl << + endl; +} + +void t_java_generator::generate_java_struct_result_writer(ofstream& out, + t_struct* tstruct) { + out << + indent() << "public void write(TProtocol _oprot, TTransport _otrans) throws TException {" << endl; + indent_up(); + + string name = tstruct->get_name(); + const vector& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + out << + indent() << "TStruct _struct = new TStruct(\"" << name << "\");" << endl << + indent() << "TField _field = new TField();" << endl << + indent() << "_oprot.writeStructBegin(_otrans, _struct);" << endl; + + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + out << + endl << + indent() << "if "; + } else { + out << + " else if "; + } + + out << + "(this.__isset." << (*f_iter)->get_name() << ") {" << endl; + indent_up(); + + out << + indent() << "_field.name = \"" << (*f_iter)->get_name() << "\";" << endl << + indent() << "_field.type = " << type_to_enum((*f_iter)->get_type()) << ";" << endl << + indent() << "_field.id = " << (*f_iter)->get_key() << ";" << endl << + indent() << "_oprot.writeFieldBegin(_otrans, _field);" << endl; + + // Write field contents + generate_serialize_field(out, *f_iter, "this."); + + // Write field closer + indent(out) << + "_oprot.writeFieldEnd(_otrans);" << endl; + + indent_down(); + indent(out) << "}"; + } + // Write the struct map + out << + endl << + indent() << "_oprot.writeFieldStop(_otrans);" << endl << + indent() << "_oprot.writeStructEnd(_otrans);" << endl; + + indent_down(); + out << + indent() << "}" << endl << + endl; } + /** * Generates a thrift service. In C++, this comprises an entirely separate * header and source file. The header file defines the methods and includes @@ -138,10 +363,29 @@ void t_java_generator::generate_struct(t_struct* tstruct) { * @param tservice The service definition */ void t_java_generator::generate_service(t_service* tservice) { + // Make output file + string f_service_name = string(T_JAVA_DIR)+"/"+service_name_+".java"; + f_service_.open(f_service_name.c_str()); + + f_service_ << + autogen_comment() << + java_package() << + java_type_imports() << + java_thrift_imports(); + + f_service_ << + "public class " << service_name_ << " {" << endl << + endl; + // Generate the three main parts of the service generate_service_interface(tservice); - generate_service_server(tservice); generate_service_client(tservice); + generate_service_server(tservice); + generate_service_helpers(tservice); + + f_service_ << + "}" << endl; + f_service_.close(); } /** @@ -150,30 +394,29 @@ void t_java_generator::generate_service(t_service* tservice) { * @param tservice The service to generate a header definition for */ void t_java_generator::generate_service_interface(t_service* tservice) { - // Make output file - string f_interface_name = string(T_JAVA_DIR)+"/"+service_name_+"If.java"; - ofstream f_interface; - f_interface.open(f_interface_name.c_str()); - - f_interface << - autogen_comment() << - java_package() << - java_type_imports(); - - f_interface << - "public abstract class " << service_name_ << "If {" << endl; + f_service_ << + indent() << "public interface Iface {" << endl; indent_up(); vector functions = tservice->get_functions(); vector::iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { - indent(f_interface) << - "public abstract " << function_signature(*f_iter) << - " throws TException;" << endl; + indent(f_service_) << + "public " << function_signature(*f_iter) << ";" << endl; } indent_down(); - f_interface << - "}" << endl; - f_interface.close(); + f_service_ << + indent() << "}" << endl << + endl; +} + +void t_java_generator::generate_service_helpers(t_service* tservice) { + vector functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + t_struct* ts = (*f_iter)->get_arglist(); + generate_java_struct_definition(f_service_, ts, false, true); + generate_function_helpers(*f_iter); + } } /** @@ -182,23 +425,12 @@ void t_java_generator::generate_service_interface(t_service* tservice) { * @param tservice The service to generate a server for. */ void t_java_generator::generate_service_client(t_service* tservice) { - string f_client_name = string(T_JAVA_DIR)+"/"+service_name_+"Client.java"; - f_service_.open(f_client_name.c_str()); - f_service_ << - autogen_comment() << - java_package() << - java_type_imports() << - java_thrift_imports(); - - f_service_ << - "public class " << service_name_ << "Client " << - "extends " << service_name_ << "If {" << endl; + "public static class Client implements Iface {" << endl; indent_up(); indent(f_service_) << - "public " << service_name_ << "Client" << - "(TTransport trans, TProtocol prot)" << endl; + "public Client(TTransport trans, TProtocol prot)" << endl; scope_up(f_service_); indent(f_service_) << "this(trans, trans, prot, prot);" << endl; @@ -206,8 +438,7 @@ void t_java_generator::generate_service_client(t_service* tservice) { f_service_ << endl; indent(f_service_) << - "public " << service_name_ << "Client" << - "(TTransport itrans, TTransport otrans," << + "public Client(TTransport itrans, TTransport otrans," << " TProtocol iprot, TProtocol oprot)" << endl; scope_up(f_service_); f_service_ << @@ -222,7 +453,10 @@ void t_java_generator::generate_service_client(t_service* tservice) { indent() << "private TTransport _itrans;" << endl << indent() << "private TTransport _otrans;" << endl << indent() << "private TProtocol _iprot;" << endl << - indent() << "private TProtocol _oprot;" << endl << endl; + indent() << "private TProtocol _oprot;" << endl << + endl << + indent() << "private int _seqid;" << endl << + endl; // Generate client method implementations vector functions = tservice->get_functions(); @@ -232,7 +466,7 @@ void t_java_generator::generate_service_client(t_service* tservice) { // Open function indent(f_service_) << - "public " << function_signature(*f_iter) << " throws TException" << endl; + "public " << function_signature(*f_iter) << endl; scope_up(f_service_); indent(f_service_) << "send_" << funname << "("; @@ -269,74 +503,77 @@ void t_java_generator::generate_service_client(t_service* tservice) { string("send_") + (*f_iter)->get_name(), (*f_iter)->get_arglist()); + string argsname = (*f_iter)->get_name() + "_args"; + // Open function indent(f_service_) << - "public " << function_signature(&send_function) << " throws TException" << endl; + "public " << function_signature(&send_function) << endl; scope_up(f_service_); // Serialize the request f_service_ << - indent() << - "_oprot.writeStructBegin(_otrans, " << - "new TStruct(\"function\"));" << endl << - indent() << - "_oprot.writeFieldBegin(_otrans, " << - "new TField(\"name\", TType.STRING, 0));" << endl << - indent() << - "_oprot.writeString(_otrans, " << - "\"" << funname << "\");" << endl << - indent() << - "_oprot.writeFieldEnd(_otrans);" << endl << - indent() << - "_oprot.writeFieldBegin(_otrans, " << - "new TField(\"args\", TType.STRUCT, 1));" << endl; - generate_serialize_struct((*f_iter)->get_arglist()); + indent() << "_oprot.writeMessageBegin(_otrans, new TMessage(\"" << funname << "\", TMessageType.CALL, _seqid));" << endl << + indent() << argsname << " __args = new " << argsname << "();" << endl; + + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + f_service_ << + indent() << "__args." << (*fld_iter)->get_name() << " = " << (*fld_iter)->get_name() << ";" << endl; + } + f_service_ << - indent() << - "_oprot.writeFieldEnd(_otrans);" << endl << - indent() << - "_oprot.writeFieldStop(_otrans);" << endl << - indent() << - "_oprot.writeStructEnd(_otrans);" << endl; - - // Flush the request - indent(f_service_) << - "_otrans.flush();" << endl; + indent() << "__args.write(_oprot, _otrans);" << endl << + indent() << "_oprot.writeMessageEnd(_otrans);" << endl << + indent() << "_otrans.flush();" << endl; scope_down(f_service_); f_service_ << endl; if (!(*f_iter)->is_async()) { + string resultname = (*f_iter)->get_name() + "_result"; + t_struct noargs; t_function recv_function((*f_iter)->get_returntype(), string("recv_") + (*f_iter)->get_name(), - &noargs); + &noargs, + (*f_iter)->get_xceptions()); // Open function indent(f_service_) << - "public " << function_signature(&recv_function) << " throws TException" << endl; + "public " << function_signature(&recv_function) << endl; scope_up(f_service_); - - // Read the response - t_struct result_struct((*f_iter)->get_name() + "_result"); - t_field result_field((*f_iter)->get_returntype(), "_result"); - - // Add a field to the return struct if non void + + // TODO(mcslee): Message validation here + + f_service_ << + indent() << "TMessage _msg = _iprot.readMessageBegin(_itrans);" << endl << + indent() << resultname << " __result = " << resultname << ".read(_iprot, _itrans);" << endl << + indent() << "_iprot.readMessageEnd(_itrans);" << endl << + endl; + + // Careful, only return _result if not a void function if (!(*f_iter)->get_returntype()->is_void()) { - indent(f_service_) << - declare_field(&result_field, true) << endl; - result_struct.append(&result_field); + f_service_ << + indent() << "if (__result.__isset.success) {" << endl << + indent() << " return __result.success;" << endl << + indent() << "}" << endl; } - - // Deserialize response struct - generate_deserialize_struct(&result_struct); - + + t_struct* xs = (*f_iter)->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + f_service_ << + indent() << "if (__result.__isset." << (*x_iter)->get_name() << ") {" << endl << + indent() << " throw __result." << (*x_iter)->get_name() << ";" << endl << + indent() << "}" << endl; + } + // Careful, only return _result if not a void function - if (!(*f_iter)->get_returntype()->is_void()) { - indent(f_service_) << - "return _result;" << endl; - } else { + if ((*f_iter)->get_returntype()->is_void()) { indent(f_service_) << "return;" << endl; + } else { + f_service_ << + indent() << "throw new TException(\"" << (*f_iter)->get_name() << " failed: unknown result\");" << endl; } // Close function @@ -348,7 +585,6 @@ void t_java_generator::generate_service_client(t_service* tservice) { indent_down(); f_service_ << "}" << endl; - f_service_.close(); } /** @@ -357,28 +593,17 @@ void t_java_generator::generate_service_client(t_service* tservice) { * @param tservice The service to generate a server for. */ void t_java_generator::generate_service_server(t_service* tservice) { - string f_server_name = string(T_JAVA_DIR)+"/"+service_name_+"ServerIf.java"; - f_service_.open(f_server_name.c_str()); - - f_service_ << - autogen_comment() << - java_package() << - java_type_imports() << - java_thrift_imports(); - // Generate the dispatch methods vector functions = tservice->get_functions(); vector::iterator f_iter; // Generate the header portion f_service_ << - "public abstract class " << service_name_ << "ServerIf " << - "extends " << service_name_ << "If implements TProcessor {" << endl; + "public abstract static class Server implements Iface, TProcessor {" << endl; indent_up(); indent(f_service_) << - "public " << service_name_ << "ServerIf" << - "(TProtocol prot)" << endl; + "public Server(TProtocol prot)" << endl; scope_up(f_service_); indent(f_service_) << "this(prot, prot);" << endl; @@ -386,8 +611,7 @@ void t_java_generator::generate_service_server(t_service* tservice) { f_service_ << endl; indent(f_service_) << - "public " << service_name_ << "ServerIf" << - "(TProtocol iprot, TProtocol oprot)" << endl; + "public Server(TProtocol iprot, TProtocol oprot)" << endl; scope_up(f_service_); f_service_ << indent() << "_iprot = iprot;" << endl << @@ -406,22 +630,9 @@ void t_java_generator::generate_service_server(t_service* tservice) { scope_up(f_service_); f_service_ << - indent() << - "String _fname;" << endl << - indent() << - "TStruct _struct;" << endl << - indent() << - "TField _field;" << endl << - indent() << - "_struct = _iprot.readStructBegin(_itrans);" << endl << - indent() << - "_field = _iprot.readFieldBegin(_itrans);" << endl << - indent() << - "_fname = _iprot.readString(_itrans);" << endl << - indent() << - "_iprot.readFieldEnd(_itrans);" << endl << - indent() << - "_field = _iprot.readFieldBegin(_itrans);" << endl; + indent() << "TMessage _msg = _iprot.readMessageBegin(_itrans);" << endl; + + // TODO(mcslee): validate message bool first = true; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { @@ -432,11 +643,11 @@ void t_java_generator::generate_service_server(t_service* tservice) { first = false; } f_service_ << - "if (_fname.equals(\"" << (*f_iter)->get_name() <<"\")) {" << endl; + "if (_msg.name.equals(\"" << (*f_iter)->get_name() <<"\")) {" << endl; indent_up(); indent(f_service_) << "process_" << (*f_iter)->get_name() << - "(_itrans, _otrans);" << endl; + "(_msg.seqid, _itrans, _otrans);" << endl; indent_down(); indent(f_service_) << "}"; } @@ -445,21 +656,14 @@ void t_java_generator::generate_service_server(t_service* tservice) { indent_up(); indent(f_service_) << "System.err.println" << - "(\"Unknown function: '\" + _field.name + \"'\");" << endl; + "(\"Unknown function: '\" + _msg.name + \"'\");" << endl; indent_down(); indent(f_service_) << "}" << endl; - + // Read end of args field, the T_STOP, and the struct close f_service_ << - indent() << - "_iprot.readFieldEnd(_itrans);" << endl << - indent() << - "_field = _iprot.readFieldBegin(_itrans);" << endl << - indent() << - "_iprot.readStructEnd(_itrans);" << endl << - indent() << - "return true;" << endl; + indent() << "return true;" << endl; scope_down(f_service_); f_service_ << endl; @@ -473,8 +677,32 @@ void t_java_generator::generate_service_server(t_service* tservice) { f_service_ << "}" << endl << endl; +} - f_service_.close(); +/** + * Generates a struct and helpers for a function. + * + * @param tfunction The function + */ +void t_java_generator::generate_function_helpers(t_function* tfunction) { + if (tfunction->is_async()) { + return; + } + + t_struct result(tfunction->get_name() + "_result"); + t_field success(tfunction->get_returntype(), "success", 0); + if (!tfunction->get_returntype()->is_void()) { + result.append(&success); + } + + t_struct* xs = tfunction->get_xceptions(); + const vector& fields = xs->get_members(); + vector::const_iterator f_iter; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + result.append(*f_iter); + } + + generate_java_struct_definition(f_service_, &result, false, true, true); } /** @@ -487,28 +715,42 @@ void t_java_generator::generate_process_function(t_service* tservice, // Open function indent(f_service_) << "private void process_" << tfunction->get_name() << - "(TTransport _itrans, TTransport _otrans) throws TException" << endl; + "(int seqid, TTransport _itrans, TTransport _otrans) throws TException" << endl; scope_up(f_service_); - // Get the struct of function call params - t_struct* arg_struct = tfunction->get_arglist(); + string argsname = tfunction->get_name() + "_args"; + string resultname = tfunction->get_name() + "_result"; - // Declare the function arguments - const vector& fields = arg_struct->get_members(); - vector::const_iterator f_iter; - for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { - indent(f_service_) << - declare_field(*f_iter, true) << endl; + f_service_ << + indent() << argsname << " __args = " << argsname << ".read(_iprot, _itrans);" << endl << + indent() << "_iprot.readMessageEnd(_itrans);" << endl; + + t_struct* xs = tfunction->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + + // Declare result for non async function + if (!tfunction->is_async()) { + f_service_ << + indent() << resultname << " __result = new " << resultname << "();" << endl << + endl; } - // Deserialize the function arguments as a struct - generate_deserialize_struct(arg_struct); - + // Try block for a function with exceptions + if (xceptions.size() > 0) { + f_service_ << + indent() << "try {" << endl; + indent_up(); + } + // Generate the function call + t_struct* arg_struct = tfunction->get_arglist(); + const std::vector& fields = arg_struct->get_members(); + vector::const_iterator f_iter; + f_service_ << indent(); - if (!tfunction->get_returntype()->is_void()) { - f_service_ << - type_name(tfunction->get_returntype()) << " _result = "; + if (!tfunction->is_async() && !tfunction->get_returntype()->is_void()) { + f_service_ << "__result.success = "; } f_service_ << tfunction->get_name() << "("; @@ -519,21 +761,51 @@ void t_java_generator::generate_process_function(t_service* tservice, } else { f_service_ << ", "; } - f_service_ << (*f_iter)->get_name(); + f_service_ << "__args." << (*f_iter)->get_name(); } f_service_ << ");" << endl; - // Serialize the result into a struct - t_struct result_struct(tfunction->get_name() + "_result"); - t_field result_field(tfunction->get_returntype(), "_result"); + // Set isset on success field + if (!tfunction->is_async() && !tfunction->get_returntype()->is_void()) { + f_service_ << + indent() << "__result.__isset.success = true;" << endl; + } - // Only append the field if non-void - if (!tfunction->get_returntype()->is_void()) { - result_struct.append(&result_field); + if (!tfunction->is_async() && xceptions.size() > 0) { + indent_down(); + f_service_ << indent() << "}"; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + f_service_ << " catch (" << (*x_iter)->get_type()->get_name() << " " << (*x_iter)->get_name() << ") {" << endl; + if (!tfunction->is_async()) { + indent_up(); + f_service_ << + indent() << "__result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name() << ";" << endl << + indent() << "__result.__isset." << (*x_iter)->get_name() << " = true;" << endl; + indent_down(); + f_service_ << indent() << "}"; + } else { + f_service_ << "}"; + } + } + f_service_ << endl; } - generate_serialize_struct(&result_struct); - indent(f_service_) << - "_otrans.flush();" << endl; + + // Shortcut out here for async functions + if (tfunction->is_async()) { + f_service_ << + indent() << "return;" << endl; + indent_down(); + f_service_ << "}" << endl << + endl; + return; + } + + f_service_ << + endl << + indent() << "_oprot.writeMessageBegin(_otrans, new TMessage(\"" << tfunction->get_name() << "\", TMessageType.REPLY, seqid));" << endl << + indent() << "__result.write(_oprot, _otrans);" << endl << + indent() << "_oprot.writeMessageEnd(_otrans);" << endl << + indent() << "_otrans.flush();" << endl; // Close function scope_down(f_service_); @@ -543,8 +815,9 @@ void t_java_generator::generate_process_function(t_service* tservice, /** * Deserializes a field of any type. */ -void t_java_generator::generate_deserialize_field(t_field* tfield, - string prefix) { +void t_java_generator::generate_deserialize_field(ofstream& out, + t_field* tfield, + string prefix) { t_type* type = tfield->get_type(); while (type->is_typedef()) { type = ((t_typedef*)type)->get_type(); @@ -557,14 +830,15 @@ void t_java_generator::generate_deserialize_field(t_field* tfield, string name = prefix + tfield->get_name(); - if (type->is_struct()) { - generate_deserialize_struct((t_struct*)(tfield->get_type()), - name + "."); + if (type->is_struct() || type->is_xception()) { + generate_deserialize_struct(out, + (t_struct*)(tfield->get_type()), + name); } else if (type->is_container()) { - generate_deserialize_container(tfield->get_type(), name); + generate_deserialize_container(out, tfield->get_type(), name); } else if (type->is_base_type() || type->is_enum()) { - indent(f_service_) << + indent(out) << name << " = _iprot."; if (type->is_base_type()) { @@ -575,24 +849,30 @@ void t_java_generator::generate_deserialize_field(t_field* tfield, name; break; case t_base_type::TYPE_STRING: - f_service_ << "readString(_itrans);"; + out << "readString(_itrans);"; + break; + case t_base_type::TYPE_BOOL: + out << "readBool(_itrans);"; break; case t_base_type::TYPE_BYTE: - f_service_ << "readByte(_itrans);"; + out << "readByte(_itrans);"; + break; + case t_base_type::TYPE_I16: + out << "readI16(_itrans);"; break; case t_base_type::TYPE_I32: - f_service_ << "readI32(_itrans);"; + out << "readI32(_itrans);"; break; case t_base_type::TYPE_I64: - f_service_ << "readI64(_itrans);"; + out << "readI64(_itrans);"; break; default: - throw "compiler error: no C++ name for base type " + tbase; + throw "compiler error: no Java name for base type " + tbase; } } else if (type->is_enum()) { - f_service_ << "readI32(_itrans);"; + out << "readI32(_itrans);"; } - f_service_ << + out << endl; } else { printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", @@ -606,86 +886,17 @@ void t_java_generator::generate_deserialize_field(t_field* tfield, * buffer for deserialization, and that there is a variable protocol which * is a reference to a TProtocol serialization object. */ -void t_java_generator::generate_deserialize_struct(t_struct* tstruct, - string prefix) { - const vector& fields = tstruct->get_members(); - vector::const_iterator f_iter; - - scope_up(f_service_); - - // Read the struct fields from the protocol - string _struct = tmp("_struct"); - string _field = tmp("_field"); - - // Declare stack tmp variables - f_service_ << - indent() << "TField " << _field << ";" << endl << - indent() << "TStruct " << _struct << " = _iprot.readStructBegin(_itrans);" << endl; - - // Loop over reading in fields - indent(f_service_) << - "while (true)" << endl; - - scope_up(f_service_); - - // Read beginning field marker - indent(f_service_) << - _field << " = _iprot.readFieldBegin(_itrans);" << endl; - - // Check for field STOP marker and break - indent(f_service_) << - "if (" << _field << ".type == TType.STOP) { " << endl; - indent_up(); - indent(f_service_) << - "break;" << endl; - indent_down(); - indent(f_service_) << - "}" << endl; - - // Switch statement on the field we are reading - indent(f_service_) << - "switch ((int)" << _field << ".id)" << endl; - - scope_up(f_service_); - - // Generate deserialization code for known cases - for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { - indent(f_service_) << - "case " << (*f_iter)->get_key() << ":" << endl; - indent_up(); - generate_deserialize_field(*f_iter, prefix); - indent(f_service_) << - "break;" << endl; - indent_down(); - } - - // In the default case we skip the field - f_service_ << - indent() << - "default:" << endl << - indent() << - " TProtocolUtil.skip(_iprot, _itrans, " << - _field << ".type);" << endl << - indent() << - " break;" << endl; - - scope_down(f_service_); - - // Read field end marker - indent(f_service_) << - "_iprot.readFieldEnd(_itrans);" << endl; - - scope_down(f_service_); - - indent(f_service_) << - "_iprot.readStructEnd(_itrans);" << endl; - - scope_down(f_service_); +void t_java_generator::generate_deserialize_struct(ofstream& out, + t_struct* tstruct, + string prefix) { + out << + indent() << prefix << " = " << tstruct->get_name() << ".read(_iprot, _itrans);" << endl; } -void t_java_generator::generate_deserialize_container(t_type* ttype, - string prefix) { - scope_up(f_service_); +void t_java_generator::generate_deserialize_container(ofstream& out, + t_type* ttype, + string prefix) { + scope_up(out); string obj; @@ -699,96 +910,99 @@ void t_java_generator::generate_deserialize_container(t_type* ttype, // Declare variables, read header if (ttype->is_map()) { - f_service_ << + out << indent() << "TMap " << obj << " = _iprot.readMapBegin(_itrans);" << endl; } else if (ttype->is_set()) { - f_service_ << + out << indent() << "TSet " << obj << " = _iprot.readSetBegin(_itrans);" << endl; } else if (ttype->is_list()) { - f_service_ << + out << indent() << "TList " << obj << " = _iprot.readListBegin(_itrans);" << endl; } // For loop iterates over elements string i = tmp("_i"); - indent(f_service_) << + indent(out) << "for (int " << i << " = 0; " << i << " < " << obj << ".size" << "; " << "++" << i << ")" << endl; - scope_up(f_service_); + scope_up(out); if (ttype->is_map()) { - generate_deserialize_map_element((t_map*)ttype, prefix); + generate_deserialize_map_element(out, (t_map*)ttype, prefix); } else if (ttype->is_set()) { - generate_deserialize_set_element((t_set*)ttype, prefix); + generate_deserialize_set_element(out, (t_set*)ttype, prefix); } else if (ttype->is_list()) { - generate_deserialize_list_element((t_list*)ttype, prefix); + generate_deserialize_list_element(out, (t_list*)ttype, prefix); } - scope_down(f_service_); + scope_down(out); // Read container end if (ttype->is_map()) { - indent(f_service_) << "_iprot.readMapEnd(_itrans);" << endl; + indent(out) << "_iprot.readMapEnd(_itrans);" << endl; } else if (ttype->is_set()) { - indent(f_service_) << "_iprot.readSetEnd(_itrans);" << endl; + indent(out) << "_iprot.readSetEnd(_itrans);" << endl; } else if (ttype->is_list()) { - indent(f_service_) << "_iprot.readListEnd(_itrans);" << endl; + indent(out) << "_iprot.readListEnd(_itrans);" << endl; } - scope_down(f_service_); + scope_down(out); } /** * Generates code to deserialize a map */ -void t_java_generator::generate_deserialize_map_element(t_map* tmap, +void t_java_generator::generate_deserialize_map_element(ofstream& out, + t_map* tmap, string prefix) { string key = tmp("_key"); string val = tmp("_val"); t_field fkey(tmap->get_key_type(), key); t_field fval(tmap->get_val_type(), val); - indent(f_service_) << + indent(out) << declare_field(&fkey, true) << endl; - indent(f_service_) << + indent(out) << declare_field(&fval, true) << endl; - generate_deserialize_field(&fkey); - generate_deserialize_field(&fval); + generate_deserialize_field(out, &fkey); + generate_deserialize_field(out, &fval); - indent(f_service_) << + indent(out) << prefix << ".put(" << key << ", " << val << ");" << endl; } -void t_java_generator::generate_deserialize_set_element(t_set* tset, +void t_java_generator::generate_deserialize_set_element(ofstream& out, + t_set* tset, string prefix) { string elem = tmp("_elem"); t_field felem(tset->get_elem_type(), elem); - indent(f_service_) << + indent(out) << declare_field(&felem, true) << endl; - generate_deserialize_field(&felem); + generate_deserialize_field(out, &felem); - indent(f_service_) << + indent(out) << prefix << ".add(" << elem << ");" << endl; } -void t_java_generator::generate_deserialize_list_element(t_list* tlist, +void t_java_generator::generate_deserialize_list_element(ofstream& out, + t_list* tlist, string prefix) { string elem = tmp("_elem"); t_field felem(tlist->get_elem_type(), elem); - indent(f_service_) << + indent(out) << declare_field(&felem, true) << endl; - generate_deserialize_field(&felem); + generate_deserialize_field(out, &felem); - indent(f_service_) << + indent(out) << prefix << ".add(" << elem << ");" << endl; } @@ -799,8 +1013,9 @@ void t_java_generator::generate_deserialize_list_element(t_list* tlist, * @param tfield The field to serialize * @param prefix Name to prepend to field name */ -void t_java_generator::generate_serialize_field(t_field* tfield, - string prefix) { +void t_java_generator::generate_serialize_field(ofstream& out, + t_field* tfield, + string prefix) { t_type* type = tfield->get_type(); while (type->is_typedef()) { type = ((t_typedef*)type)->get_type(); @@ -812,16 +1027,18 @@ void t_java_generator::generate_serialize_field(t_field* tfield, prefix + tfield->get_name(); } - if (type->is_struct()) { - generate_serialize_struct((t_struct*)(tfield->get_type()), - prefix + tfield->get_name() + "."); + if (type->is_struct() || type->is_xception()) { + generate_serialize_struct(out, + (t_struct*)(tfield->get_type()), + prefix + tfield->get_name()); } else if (type->is_container()) { - generate_serialize_container(tfield->get_type(), + generate_serialize_container(out, + tfield->get_type(), prefix + tfield->get_name()); } else if (type->is_base_type() || type->is_enum()) { string name = prefix + tfield->get_name(); - indent(f_service_) << + indent(out) << "_oprot."; if (type->is_base_type()) { @@ -832,24 +1049,30 @@ void t_java_generator::generate_serialize_field(t_field* tfield, "compiler error: cannot serialize void field in a struct: " + name; break; case t_base_type::TYPE_STRING: - f_service_ << "writeString(_otrans, " << name << ");"; + out << "writeString(_otrans, " << name << ");"; + break; + case t_base_type::TYPE_BOOL: + out << "writeBool(_otrans, " << name << ");"; break; case t_base_type::TYPE_BYTE: - f_service_ << "writeByte(_otrans, " << name << ");"; + out << "writeByte(_otrans, " << name << ");"; + break; + case t_base_type::TYPE_I16: + out << "writeI16(_otrans, " << name << ");"; break; case t_base_type::TYPE_I32: - f_service_ << "writeI32(_otrans, " << name << ");"; + out << "writeI32(_otrans, " << name << ");"; break; case t_base_type::TYPE_I64: - f_service_ << "writeI64(_otrans, " << name << ");"; + out << "writeI64(_otrans, " << name << ");"; break; default: - throw "compiler error: no C++ name for base type " + tbase; + throw "compiler error: no Java name for base type " + tbase; } } else if (type->is_enum()) { - f_service_ << "writeI32(_otrans, " << name << ");"; + out << "writeI32(_otrans, " << name << ");"; } - f_service_ << endl; + out << endl; } else { printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n", prefix.c_str(), @@ -864,64 +1087,31 @@ void t_java_generator::generate_serialize_field(t_field* tfield, * @param tstruct The struct to serialize * @param prefix String prefix to attach to all fields */ -void t_java_generator::generate_serialize_struct(t_struct* tstruct, +void t_java_generator::generate_serialize_struct(ofstream& out, + t_struct* tstruct, string prefix) { - string name = tstruct->get_name(); - const vector& fields = tstruct->get_members(); - vector::const_iterator f_iter; - - scope_up(f_service_); - string _struct = tmp("_struct"); - string _field = tmp("_field"); - - f_service_ << - indent() << - "TStruct " << _struct << " = new TStruct(\"" << name << "\");" << endl << - indent() << - "TField " << _field << " = new TField();" << endl << - indent() << - "_oprot.writeStructBegin(_otrans, " << _struct << ");" << endl; - for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { - f_service_ << - indent() << - _field << ".name = \"" << (*f_iter)->get_name() << "\";" << endl << - indent() << - _field << ".type = " << type_to_enum((*f_iter)->get_type()) << ";" << endl << - indent() << - _field << ".id = " << (*f_iter)->get_key() << ";" << endl << - indent() << - "_oprot.writeFieldBegin(_otrans, " << _field << ");" << endl; - // Write field contents - generate_serialize_field(*f_iter, prefix); - // Write field closer - indent(f_service_) << - "_oprot.writeFieldEnd(_otrans);" << endl; - } - // Write the struct map - f_service_ << - indent() << "_oprot.writeFieldStop(_otrans);" << endl << - indent() << "_oprot.writeStructEnd(_otrans);" << endl; - - scope_down(f_service_); + out << + indent() << prefix << ".write(_oprot, _otrans);" << endl; } -void t_java_generator::generate_serialize_container(t_type* ttype, +void t_java_generator::generate_serialize_container(ofstream& out, + t_type* ttype, string prefix) { - scope_up(f_service_); + scope_up(out); if (ttype->is_map()) { - indent(f_service_) << + indent(out) << "_oprot.writeMapBegin(_otrans, new TMap(" << type_to_enum(((t_map*)ttype)->get_key_type()) << ", " << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " << prefix << ".size()));" << endl; } else if (ttype->is_set()) { - indent(f_service_) << + indent(out) << "_oprot.writeSetBegin(_otrans, new TSet(" << type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " << prefix << ".size()));" << endl; } else if (ttype->is_list()) { - indent(f_service_) << + indent(out) << "_oprot.writeListBegin(_otrans, new TList(" << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " << prefix << ".size()));" << endl; @@ -929,81 +1119,84 @@ void t_java_generator::generate_serialize_container(t_type* ttype, string iter = tmp("_iter"); if (ttype->is_map()) { - indent(f_service_) << + indent(out) << "for (" << type_name(((t_map*)ttype)->get_key_type()) << " " << iter << " : " << prefix << ".keySet())"; } else if (ttype->is_set()) { - indent(f_service_) << + indent(out) << "for (" << type_name(((t_set*)ttype)->get_elem_type()) << " " << iter << " : " << prefix << ")"; } else if (ttype->is_list()) { - indent(f_service_) << + indent(out) << "for (" << type_name(((t_list*)ttype)->get_elem_type()) << " " << iter << " : " << prefix << ")"; } - scope_up(f_service_); + scope_up(out); if (ttype->is_map()) { - generate_serialize_map_element((t_map*)ttype, iter, prefix); + generate_serialize_map_element(out, (t_map*)ttype, iter, prefix); } else if (ttype->is_set()) { - generate_serialize_set_element((t_set*)ttype, iter); + generate_serialize_set_element(out, (t_set*)ttype, iter); } else if (ttype->is_list()) { - generate_serialize_list_element((t_list*)ttype, iter); + generate_serialize_list_element(out, (t_list*)ttype, iter); } if (ttype->is_map()) { - indent(f_service_) << + indent(out) << "_oprot.writeMapEnd(_otrans);" << endl; } else if (ttype->is_set()) { - indent(f_service_) << + indent(out) << "_oprot.writeSetEnd(_otrans);" << endl; } else if (ttype->is_list()) { - indent(f_service_) << + indent(out) << "_oprot.writeListEnd(_otrans);" << endl; } - scope_down(f_service_); + scope_down(out); - scope_down(f_service_); + scope_down(out); } /** * Serializes the members of a map. * - */ -void t_java_generator::generate_serialize_map_element(t_map* tmap, + */ +void t_java_generator::generate_serialize_map_element(ofstream& out, + t_map* tmap, string iter, string map) { t_field kfield(tmap->get_key_type(), iter); - generate_serialize_field(&kfield, ""); + generate_serialize_field(out, &kfield, ""); t_field vfield(tmap->get_val_type(), map + ".get(" + iter + ")"); - generate_serialize_field(&vfield, ""); + generate_serialize_field(out, &vfield, ""); } /** * Serializes the members of a set. */ -void t_java_generator::generate_serialize_set_element(t_set* tset, +void t_java_generator::generate_serialize_set_element(ofstream& out, + t_set* tset, string iter) { t_field efield(tset->get_elem_type(), iter); - generate_serialize_field(&efield, ""); + generate_serialize_field(out, &efield, ""); } /** * Serializes the members of a list. */ -void t_java_generator::generate_serialize_list_element(t_list* tlist, - string iter) { +void t_java_generator::generate_serialize_list_element(ofstream& out, + t_list* tlist, + string iter) { t_field efield(tlist->get_elem_type(), iter); - generate_serialize_field(&efield, ""); + generate_serialize_field(out, &efield, ""); } /** @@ -1051,8 +1244,12 @@ string t_java_generator::base_type_name(t_base_type::t_base tbase, return "void"; case t_base_type::TYPE_STRING: return "String"; + case t_base_type::TYPE_BOOL: + return "boolean"; case t_base_type::TYPE_BYTE: return "byte"; + case t_base_type::TYPE_I16: + return (in_container ? "Short" : "short"); case t_base_type::TYPE_I32: return (in_container ? "Integer" : "int"); case t_base_type::TYPE_I64: @@ -1081,9 +1278,14 @@ string t_java_generator::declare_field(t_field* tfield, bool init) { case t_base_type::TYPE_VOID: throw "NO T_VOID CONSTRUCT"; case t_base_type::TYPE_STRING: - result += " = \"\""; + // result += " = \"\""; + result += " = null"; + break; + case t_base_type::TYPE_BOOL: + result += " = false"; break; case t_base_type::TYPE_BYTE: + case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: result += " = 0"; @@ -1106,11 +1308,19 @@ string t_java_generator::declare_field(t_field* tfield, bool init) { * @return String of rendered function definition */ string t_java_generator::function_signature(t_function* tfunction, - string prefix) { + string prefix) { t_type* ttype = tfunction->get_returntype(); - return + std::string result = type_name(ttype) + " " + prefix + tfunction->get_name() + - "(" + argument_list(tfunction->get_arglist()) + ")"; + "(" + argument_list(tfunction->get_arglist()) + ") throws "; + t_struct* xs = tfunction->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + result += (*x_iter)->get_type()->get_name() + ", "; + } + result += "TException"; + return result; } /** @@ -1148,8 +1358,12 @@ string t_java_generator::type_to_enum(t_type* type) { throw "NO T_VOID CONSTRUCT"; case t_base_type::TYPE_STRING: return "TType.STRING"; + case t_base_type::TYPE_BOOL: + return "TType.BOOL"; case t_base_type::TYPE_BYTE: return "TType.BYTE"; + case t_base_type::TYPE_I16: + return "TType.I16"; case t_base_type::TYPE_I32: return "TType.I32"; case t_base_type::TYPE_I64: @@ -1157,7 +1371,7 @@ string t_java_generator::type_to_enum(t_type* type) { } } else if (type->is_enum()) { return "TType.I32"; - } else if (type->is_struct()) { + } else if (type->is_struct() || type->is_xception()) { return "TType.STRUCT"; } else if (type->is_map()) { return "TType.MAP"; diff --git a/compiler/cpp/src/generate/t_java_generator.h b/compiler/cpp/src/generate/t_java_generator.h index 0fa90741..2c8e2471 100644 --- a/compiler/cpp/src/generate/t_java_generator.h +++ b/compiler/cpp/src/generate/t_java_generator.h @@ -31,52 +31,75 @@ class t_java_generator : public t_oop_generator { void generate_typedef (t_typedef* ttypedef); void generate_enum (t_enum* tenum); void generate_struct (t_struct* tstruct); + void generate_xception(t_struct* txception); void generate_service (t_service* tservice); /** Service-level generation functions */ + void generate_java_struct(t_struct* tstruct, bool is_exception); + + void generate_java_struct_definition(std::ofstream& out, t_struct* tstruct, bool is_xception=false, bool in_class=false, bool is_result=false); + void generate_java_struct_reader(std::ofstream& out, t_struct* tstruct); + void generate_java_struct_result_writer(std::ofstream& out, t_struct* tstruct); + void generate_java_struct_writer(std::ofstream& out, t_struct* tstruct); + + void generate_function_helpers(t_function* tfunction); + void generate_service_interface (t_service* tservice); + void generate_service_helpers (t_service* tservice); void generate_service_client (t_service* tservice); void generate_service_server (t_service* tservice); void generate_process_function (t_service* tservice, t_function* tfunction); /** Serialization constructs */ - void generate_deserialize_field (t_field* tfield, + void generate_deserialize_field (std::ofstream& out, + t_field* tfield, std::string prefix=""); - void generate_deserialize_struct (t_struct* tstruct, + void generate_deserialize_struct (std::ofstream& out, + t_struct* tstruct, std::string prefix=""); - void generate_deserialize_container (t_type* ttype, + void generate_deserialize_container (std::ofstream& out, + t_type* ttype, std::string prefix=""); - void generate_deserialize_set_element (t_set* tset, + void generate_deserialize_set_element (std::ofstream& out, + t_set* tset, std::string prefix=""); - void generate_deserialize_map_element (t_map* tmap, + void generate_deserialize_map_element (std::ofstream& out, + t_map* tmap, std::string prefix=""); - void generate_deserialize_list_element (t_list* tlist, + void generate_deserialize_list_element (std::ofstream& out, + t_list* tlist, std::string prefix=""); - void generate_serialize_field (t_field* tfield, + void generate_serialize_field (std::ofstream& out, + t_field* tfield, std::string prefix=""); - void generate_serialize_struct (t_struct* tstruct, + void generate_serialize_struct (std::ofstream& out, + t_struct* tstruct, std::string prefix=""); - void generate_serialize_container (t_type* ttype, + void generate_serialize_container (std::ofstream& out, + t_type* ttype, std::string prefix=""); - void generate_serialize_map_element (t_map* tmap, + void generate_serialize_map_element (std::ofstream& out, + t_map* tmap, std::string iter, std::string map); - void generate_serialize_set_element (t_set* tmap, + void generate_serialize_set_element (std::ofstream& out, + t_set* tmap, std::string iter); - void generate_serialize_list_element (t_list* tlist, + void generate_serialize_list_element (std::ofstream& out, + t_list* tlist, std::string iter); /** Helper rendering functions */ @@ -94,14 +117,9 @@ class t_java_generator : public t_oop_generator { private: /** File streams */ + std::string package_name_; - std::ofstream f_types_; - std::ofstream f_header_; std::ofstream f_service_; - - std::ofstream f_client_; - std::ofstream f_server_; - }; #endif diff --git a/compiler/cpp/src/generate/t_php_generator.cc b/compiler/cpp/src/generate/t_php_generator.cc index efd24c58..6f4b76ad 100644 --- a/compiler/cpp/src/generate/t_php_generator.cc +++ b/compiler/cpp/src/generate/t_php_generator.cc @@ -687,6 +687,11 @@ void t_php_generator::generate_deserialize_field(ofstream &out, indent() << "}" << endl << indent() << "$" << name << " = " << itrans << "->readAll($_len);" << endl; break; + case t_base_type::TYPE_BOOL: + out << + indent() << "$" << name << " = unpack('c', " << itrans << "->readAll(1));" << endl << + indent() << "$" << name << " = (bool)$" << name << "[1];" << endl; + break; case t_base_type::TYPE_BYTE: out << indent() << "$" << name << " = unpack('c', " << itrans << "->readAll(1));" << endl << @@ -748,6 +753,9 @@ void t_php_generator::generate_deserialize_field(ofstream &out, case t_base_type::TYPE_STRING: out << "readString($itrans, $" << name << ");"; break; + case t_base_type::TYPE_BOOL: + out << "readBool($itrans, $" << name << ");"; + break; case t_base_type::TYPE_BYTE: out << "readByte($itrans, $" << name << ");"; break; @@ -975,6 +983,10 @@ void t_php_generator::generate_serialize_field(ofstream &out, indent() << "$_output .= pack('N', strlen($" << name << "));" << endl << indent() << "$_output .= $" << name << ";" << endl; break; + case t_base_type::TYPE_BOOL: + out << + indent() << "$_output .= pack('c', $" << name << " ? 1 : 0);" << endl; + break; case t_base_type::TYPE_BYTE: out << indent() << "$_output .= pack('c', $" << name << ");" << endl; @@ -1013,6 +1025,9 @@ void t_php_generator::generate_serialize_field(ofstream &out, case t_base_type::TYPE_STRING: out << "writeString($otrans, $" << name << ");"; break; + case t_base_type::TYPE_BOOL: + out << "writeBool($otrans, $" << name << ");"; + break; case t_base_type::TYPE_BYTE: out << "writeByte($otrans, $" << name << ");"; break; @@ -1225,6 +1240,8 @@ string t_php_generator::base_type_name(t_base_type::t_base tbase) { return "void"; case t_base_type::TYPE_STRING: return "TString"; + case t_base_type::TYPE_BOOL: + return "bool"; case t_base_type::TYPE_BYTE: return "UInt8"; case t_base_type::TYPE_I16: @@ -1258,6 +1275,9 @@ string t_php_generator::declare_field(t_field* tfield, bool init, bool obj) { case t_base_type::TYPE_STRING: result += " = ''"; break; + case t_base_type::TYPE_BOOL: + result += " = false"; + break; case t_base_type::TYPE_BYTE: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: @@ -1330,6 +1350,8 @@ string t_php_generator ::type_to_enum(t_type* type) { throw "NO T_VOID CONSTRUCT"; case t_base_type::TYPE_STRING: return "TType::STRING"; + case t_base_type::TYPE_BOOL: + return "TType::BOOL"; case t_base_type::TYPE_BYTE: return "TType::BYTE"; case t_base_type::TYPE_I16: diff --git a/compiler/cpp/src/generate/t_php_generator.h b/compiler/cpp/src/generate/t_php_generator.h index d5bc8e0b..0cc837ff 100644 --- a/compiler/cpp/src/generate/t_php_generator.h +++ b/compiler/cpp/src/generate/t_php_generator.h @@ -41,7 +41,7 @@ class t_php_generator : public t_oop_generator { void generate_php_struct(t_struct* tstruct, bool is_exception); - void generate_php_struct_definition(std::ofstream& out, t_struct* tstruct, bool is_xception); + void generate_php_struct_definition(std::ofstream& out, t_struct* tstruct, bool is_xception=false); void generate_php_struct_reader(std::ofstream& out, t_struct* tstruct); void generate_php_struct_writer(std::ofstream& out, t_struct* tstruct); diff --git a/compiler/cpp/src/parse/t_base_type.h b/compiler/cpp/src/parse/t_base_type.h index 5aebba7a..1429d1c8 100644 --- a/compiler/cpp/src/parse/t_base_type.h +++ b/compiler/cpp/src/parse/t_base_type.h @@ -14,6 +14,7 @@ class t_base_type : public t_type { enum t_base { TYPE_VOID, TYPE_STRING, + TYPE_BOOL, TYPE_BYTE, TYPE_I16, TYPE_I32, diff --git a/compiler/cpp/src/parse/t_program.h b/compiler/cpp/src/parse/t_program.h index 98968ff2..abb368bf 100644 --- a/compiler/cpp/src/parse/t_program.h +++ b/compiler/cpp/src/parse/t_program.h @@ -32,6 +32,7 @@ class t_program { name_(name), namespace_() { type_void = new t_base_type("void", t_base_type::TYPE_VOID); type_string = new t_base_type("string", t_base_type::TYPE_STRING); + type_bool = new t_base_type("bool", t_base_type::TYPE_BOOL); type_byte = new t_base_type("byte", t_base_type::TYPE_BYTE); type_i16 = new t_base_type("i16", t_base_type::TYPE_I16); type_i32 = new t_base_type("i32", t_base_type::TYPE_I32); @@ -40,6 +41,7 @@ class t_program { ~t_program() { delete type_string; + delete type_bool; delete type_byte; delete type_i16; delete type_i32; @@ -62,6 +64,7 @@ class t_program { // Accessors for global types t_type* get_void_type() const { return type_void; } t_type* get_string_type() const { return type_string; } + t_type* get_bool_type() const { return type_byte; } t_type* get_byte_type() const { return type_byte; } t_type* get_i16_type() const { return type_i16; } t_type* get_i32_type() const { return type_i32; } @@ -122,6 +125,7 @@ class t_program { // Global base types t_type* type_void; t_type* type_string; + t_type* type_bool; t_type* type_byte; t_type* type_i16; t_type* type_i32; diff --git a/compiler/cpp/src/thrift.l b/compiler/cpp/src/thrift.l index 1f4d7fe9..1ff7708e 100644 --- a/compiler/cpp/src/thrift.l +++ b/compiler/cpp/src/thrift.l @@ -36,6 +36,7 @@ symbol ([\,\{\}\(\)\=<>]) "namespace" { return tok_namespace; } "void" { return tok_void; } +"bool" { return tok_bool; } "byte" { return tok_byte; } "i16" { return tok_i16; } "i32" { return tok_i32; } diff --git a/compiler/cpp/src/thrift.y b/compiler/cpp/src/thrift.y index 069d6c8b..e7381809 100644 --- a/compiler/cpp/src/thrift.y +++ b/compiler/cpp/src/thrift.y @@ -39,6 +39,7 @@ int y_field_val = -1; %token tok_namespace /** Base datatypes */ +%token tok_bool %token tok_byte %token tok_string %token tok_i16 @@ -368,6 +369,11 @@ BaseType: pdebug("BaseType -> tok_string"); $$ = g_program->get_string_type(); } +| tok_bool + { + pdebug("BaseType -> tok_bool"); + $$ = g_program->get_bool_type(); + } | tok_byte { pdebug("BaseType -> tok_byte"); diff --git a/lib/cpp/src/protocol/TProtocol.h b/lib/cpp/src/protocol/TProtocol.h index 2b3666fa..e9d560c3 100644 --- a/lib/cpp/src/protocol/TProtocol.h +++ b/lib/cpp/src/protocol/TProtocol.h @@ -200,10 +200,15 @@ class TProtocol { */ uint32_t skip(shared_ptr in, TType type) const { switch (type) { + case T_BOOL: + { + bool boolv; + return readBool(in, boolv); + } case T_BYTE: { - int8_t byte; - return readByte(in, byte); + int8_t bytev; + return readByte(in, bytev); } case T_I16: { diff --git a/lib/java/src/protocol/TBinaryProtocol.java b/lib/java/src/protocol/TBinaryProtocol.java index a7590058..d90decef 100644 --- a/lib/java/src/protocol/TBinaryProtocol.java +++ b/lib/java/src/protocol/TBinaryProtocol.java @@ -9,13 +9,23 @@ import com.facebook.thrift.transport.TTransport; * @author Mark Slee */ public class TBinaryProtocol implements TProtocol { + + public void writeMessageBegin(TTransport out, TMessage message) throws TException { + writeString(out, message.name); + writeByte(out, message.type); + writeI32(out, message.seqid); + } + + public void writeMessageEnd(TTransport out) throws TException {} + + public void writeStructBegin(TTransport out, TStruct struct) throws TException {} public void writeStructEnd(TTransport out) throws TException {} public void writeFieldBegin(TTransport out, TField field) throws TException { writeByte(out, field.type); - writeI32(out, field.id); + writeI16(out, field.id); } public void writeFieldEnd(TTransport out) throws TException {} @@ -46,14 +56,21 @@ public class TBinaryProtocol implements TProtocol { public void writeSetEnd(TTransport out) throws TException {} + public void writeBool(TTransport out, boolean b) throws TException { + writeByte(out, b ? (byte)1 : (byte)0); + } + byte[] bout = new byte[1]; public void writeByte(TTransport out, byte b) throws TException { bout[0] = b; out.write(bout, 0, 1); } - public void writeU32(TTransport out, int u32) throws TException { - writeI32(out, u32); + byte[] i16out = new byte[2]; + public void writeI16(TTransport out, short i16) throws TException { + i16out[0] = (byte)(0xff & (i16 >> 8)); + i16out[1] = (byte)(0xff & (i16)); + out.write(i16out, 0, 2); } byte[] i32out = new byte[4]; @@ -65,10 +82,6 @@ public class TBinaryProtocol implements TProtocol { out.write(i32out, 0, 4); } - public void writeU64(TTransport out, long u64) throws TException { - writeI64(out, u64); - } - byte[] i64out = new byte[8]; public void writeI64(TTransport out, long i64) throws TException { i64out[0] = (byte)(0xff & (i64 >> 56)); @@ -92,6 +105,16 @@ public class TBinaryProtocol implements TProtocol { * Reading methods. */ + public TMessage readMessageBegin(TTransport in) throws TException { + TMessage message = new TMessage(); + message.name = readString(in); + message.type = readByte(in); + message.seqid = readI32(in); + return message; + } + + public void readMessageEnd(TTransport in) throws TException {} + public TStruct readStructBegin(TTransport in) throws TException { return new TStruct(); } @@ -102,7 +125,7 @@ public class TBinaryProtocol implements TProtocol { TField field = new TField(); field.type = readByte(in); if (field.type != TType.STOP) { - field.id = readI32(in); + field.id = readI16(in); } return field; } @@ -137,14 +160,23 @@ public class TBinaryProtocol implements TProtocol { public void readSetEnd(TTransport in) throws TException {} + public boolean readBool(TTransport in) throws TException { + return (readByte(in) == 1); + } + byte[] bin = new byte[1]; public byte readByte(TTransport in) throws TException { in.readAll(bin, 0, 1); return bin[0]; } - public int readU32(TTransport in) throws TException { - return readI32(in); + byte[] i16rd = new byte[2]; + public short readI16(TTransport in) throws TException { + in.readAll(i16rd, 0, 2); + return + (short) + (((i16rd[0] & 0xff) << 8) | + ((i16rd[1] & 0xff))); } byte[] i32rd = new byte[4]; @@ -156,11 +188,7 @@ public class TBinaryProtocol implements TProtocol { ((i32rd[2] & 0xff) << 8) | ((i32rd[3] & 0xff)); } - - public long readU64(TTransport in) throws TException { - return readI64(in); - } - + byte[] i64rd = new byte[8]; public long readI64(TTransport in) throws TException { in.readAll(i64rd, 0, 8); diff --git a/lib/java/src/protocol/TField.java b/lib/java/src/protocol/TField.java index 50570fbb..d32d7084 100644 --- a/lib/java/src/protocol/TField.java +++ b/lib/java/src/protocol/TField.java @@ -8,7 +8,7 @@ package com.facebook.thrift.protocol; public class TField { public TField() {} - public TField(String n, byte t, int i) { + public TField(String n, byte t, short i) { name = n; type = t; id = i; @@ -16,5 +16,5 @@ public class TField { public String name = ""; public byte type = TType.STOP; - public int id = 0; + public short id = 0; } diff --git a/lib/java/src/protocol/TMessage.java b/lib/java/src/protocol/TMessage.java new file mode 100644 index 00000000..92f4f8bb --- /dev/null +++ b/lib/java/src/protocol/TMessage.java @@ -0,0 +1,20 @@ +package com.facebook.thrift.protocol; + +/** + * Helper class that encapsulates struct metadata. + * + * @author Mark Slee + */ +public class TMessage { + public TMessage() {} + + public TMessage(String n, byte t, int s) { + name = n; + type = t; + seqid = s; + } + + public String name = ""; + public byte type; + public int seqid; +} diff --git a/lib/java/src/protocol/TMessageType.java b/lib/java/src/protocol/TMessageType.java new file mode 100644 index 00000000..905f99a9 --- /dev/null +++ b/lib/java/src/protocol/TMessageType.java @@ -0,0 +1,11 @@ +package com.facebook.thrift.protocol; + +/** + * Message type constants in the Thrift protocol. + * + * @author Mark Slee + */ +public final class TMessageType { + public static final byte CALL = 1; + public static final byte REPLY = 2; +} diff --git a/lib/java/src/protocol/TProtocol.java b/lib/java/src/protocol/TProtocol.java index a60becbd..69fe885f 100644 --- a/lib/java/src/protocol/TProtocol.java +++ b/lib/java/src/protocol/TProtocol.java @@ -14,6 +14,11 @@ public interface TProtocol { * Writing methods. */ + public void writeMessageBegin(TTransport out, + TMessage message) throws TException; + + public void writeMessageEnd (TTransport out) throws TException; + public void writeStructBegin (TTransport out, TStruct struct) throws TException; @@ -41,18 +46,18 @@ public interface TProtocol { public void writeSetEnd (TTransport out) throws TException; + public void writeBool (TTransport out, + boolean b) throws TException; + public void writeByte (TTransport out, byte b) throws TException; - public void writeU32 (TTransport out, - int u32) throws TException; + public void writeI16 (TTransport out, + short i16) throws TException; public void writeI32 (TTransport out, int i32) throws TException; - public void writeU64 (TTransport out, - long u64) throws TException; - public void writeI64 (TTransport out, long i64) throws TException; @@ -63,36 +68,40 @@ public interface TProtocol { * Reading methods. */ - public TStruct readStructBegin (TTransport in) throws TException; + public TMessage readMessageBegin (TTransport in) throws TException; - public void readStructEnd (TTransport in) throws TException; + public void readMessageEnd (TTransport in) throws TException; - public TField readFieldBegin (TTransport in) throws TException; + public TStruct readStructBegin (TTransport in) throws TException; + + public void readStructEnd (TTransport in) throws TException; + + public TField readFieldBegin (TTransport in) throws TException; - public void readFieldEnd (TTransport in) throws TException; + public void readFieldEnd (TTransport in) throws TException; - public TMap readMapBegin (TTransport in) throws TException; + public TMap readMapBegin (TTransport in) throws TException; - public void readMapEnd (TTransport in) throws TException; + public void readMapEnd (TTransport in) throws TException; - public TList readListBegin (TTransport in) throws TException; + public TList readListBegin (TTransport in) throws TException; - public void readListEnd (TTransport in) throws TException; + public void readListEnd (TTransport in) throws TException; - public TSet readSetBegin (TTransport in) throws TException; + public TSet readSetBegin (TTransport in) throws TException; - public void readSetEnd (TTransport in) throws TException; + public void readSetEnd (TTransport in) throws TException; - public byte readByte (TTransport in) throws TException; + public boolean readBool (TTransport in) throws TException; - public int readU32 (TTransport in) throws TException; + public byte readByte (TTransport in) throws TException; - public int readI32 (TTransport in) throws TException; + public short readI16 (TTransport in) throws TException; - public long readU64 (TTransport in) throws TException; - - public long readI64 (TTransport in) throws TException; + public int readI32 (TTransport in) throws TException; + + public long readI64 (TTransport in) throws TException; - public String readString (TTransport in) throws TException; + public String readString (TTransport in) throws TException; } diff --git a/lib/java/src/protocol/TProtocolUtil.java b/lib/java/src/protocol/TProtocolUtil.java index b8e5afec..52236398 100644 --- a/lib/java/src/protocol/TProtocolUtil.java +++ b/lib/java/src/protocol/TProtocolUtil.java @@ -14,16 +14,22 @@ public class TProtocolUtil { throws TException { switch (type) { + case TType.BOOL: + { + prot.readBool(in); + } case TType.BYTE: { prot.readByte(in); } - case TType.U32: + case TType.I16: + { + prot.readI16(in); + } case TType.I32: { prot.readI32(in); } - case TType.U64: case TType.I64: { prot.readI64(in); diff --git a/lib/java/src/protocol/TString.java b/lib/java/src/protocol/TString.java deleted file mode 100644 index 04fcc1dd..00000000 --- a/lib/java/src/protocol/TString.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.facebook.thrift.protocol; - -/** - * Wrapper around String so that you can pass this object to a function and - * have it set the internal string value. - * - * @author Mark Slee - */ -public class TString { - public TString() {} - - public TString(String v) { - value = v; - } - - public String value = ""; -} diff --git a/lib/java/src/protocol/TType.java b/lib/java/src/protocol/TType.java index 96f06d35..37b53bd9 100644 --- a/lib/java/src/protocol/TType.java +++ b/lib/java/src/protocol/TType.java @@ -6,17 +6,16 @@ package com.facebook.thrift.protocol; * @author Mark Slee */ public final class TType { - public static final byte STOP = 1; - public static final byte BYTE = 2; - public static final byte U16 = 3; - public static final byte I16 = 4; - public static final byte U32 = 5; - public static final byte I32 = 6; - public static final byte U64 = 7; - public static final byte I64 = 8; - public static final byte STRING = 9; - public static final byte STRUCT = 10; - public static final byte MAP = 11; - public static final byte SET = 12; - public static final byte LIST = 13; + public static final byte STOP = 0; + public static final byte VOID = 1; + public static final byte BOOL = 2; + public static final byte BYTE = 3; + public static final byte I16 = 6; + public static final byte I32 = 8; + public static final byte I64 = 10; + public static final byte STRING = 11; + public static final byte STRUCT = 12; + public static final byte MAP = 13; + public static final byte SET = 14; + public static final byte LIST = 15; } diff --git a/lib/php/src/protocol/TProtocol.php b/lib/php/src/protocol/TProtocol.php index 15938dfb..d703bd73 100644 --- a/lib/php/src/protocol/TProtocol.php +++ b/lib/php/src/protocol/TProtocol.php @@ -79,6 +79,8 @@ abstract class TProtocol { public abstract function writeSetEnd($out); + public abstract function writeBool($out, $bool); + public abstract function writeByte($out, $byte); public abstract function writeI16($out, $i16); @@ -127,6 +129,8 @@ abstract class TProtocol { public abstract function readSetEnd($in); + public abstract function readBool($in, &$bool); + public abstract function readByte($in, &$byte); public abstract function readI16($in, &$i16); @@ -146,6 +150,8 @@ abstract class TProtocol { */ public function skip($in, $type) { switch ($type) { + case TType::BOOL: + return $this->readBool($in, $bool); case TType::BYTE: return $this->readByte($in, $byte); case TType::I16; diff --git a/lib/php/src/protocol/TType.php b/lib/php/src/protocol/TType.php index 22c1c3d1..6ef09355 100644 --- a/lib/php/src/protocol/TType.php +++ b/lib/php/src/protocol/TType.php @@ -11,22 +11,22 @@ * Data types that can be sent via Thrift */ class TType { - const STOP = 0; - const VOID = 1; - const BOOL = 2; - const BYTE = 3; - const I08 = 4; - const I16 = 6; - const I32 = 8; - const I64 = 10; + const STOP = 0; + const VOID = 1; + const BOOL = 2; + const BYTE = 3; + const I08 = 4; + const I16 = 6; + const I32 = 8; + const I64 = 10; const STRING = 11; - const UTF7 = 11; + const UTF7 = 11; const STRUCT = 12; - const MAP = 13; - const SET = 14; - const LST = 15; // N.B. cannot use LIST keyword in PHP! - const UTF8 = 16; - const UTF16 = 17; + const MAP = 13; + const SET = 14; + const LST = 15; // N.B. cannot use LIST keyword in PHP! + const UTF8 = 16; + const UTF16 = 17; } /** @@ -34,7 +34,7 @@ class TType { */ class TMessageType { const CALL = 1; - const REPLY = 2; + const REPLY = 2; } ?> diff --git a/test/cpp/src/TestServer.cc b/test/cpp/src/TestServer.cc index baf2ae54..2f2d97d2 100644 --- a/test/cpp/src/TestServer.cc +++ b/test/cpp/src/TestServer.cc @@ -19,10 +19,10 @@ using namespace facebook::thrift::server; using namespace thrift::test; -class TestServer : public ThriftTestServerIf { +class TestServer : public ThriftTestServer { public: TestServer(shared_ptr protocol) : - ThriftTestServerIf(protocol) {} + ThriftTestServer(protocol) {} void testVoid() { printf("testVoid()\n"); diff --git a/test/java/build.xml b/test/java/build.xml index 80a73d75..d7d712aa 100644 --- a/test/java/build.xml +++ b/test/java/build.xml @@ -14,7 +14,7 @@ - + @@ -23,6 +23,11 @@ + + + + + diff --git a/test/java/src/TestClient.java b/test/java/src/TestClient.java index cbcd8021..686920c7 100644 --- a/test/java/src/TestClient.java +++ b/test/java/src/TestClient.java @@ -1,11 +1,11 @@ package com.facebook.thrift.test; -import ThriftTest.*; -import com.facebook.thrift.types.*; +// Generated code +import thrift.test.*; + import com.facebook.thrift.transport.TSocket; import com.facebook.thrift.transport.TTransportException; import com.facebook.thrift.protocol.TBinaryProtocol; -import com.facebook.thrift.protocol.TString; import java.util.HashMap; import java.util.HashSet; @@ -39,8 +39,8 @@ public class TestClient { new TSocket(host, port); TBinaryProtocol binaryProtocol = new TBinaryProtocol(); - ThriftTestClient testClient = - new ThriftTestClient(tSocket, binaryProtocol); + ThriftTest.Client testClient = + new ThriftTest.Client(tSocket, binaryProtocol); for (int test = 0; test < numTests; ++test) { @@ -69,154 +69,154 @@ public class TestClient { * STRING TEST */ System.out.print("testString(\"Test\")"); - TString s = testClient.testString(new TString("Test")); - System.out.print(" = \"" + s.value + "\"\n"); - + String s = testClient.testString("Test"); + System.out.print(" = \"" + s + "\"\n"); + /** * BYTE TEST */ System.out.print("testByte(1)"); - UInt8 u8 = testClient.testByte(new UInt8((short)1)); - System.out.print(" = " + u8.get() + "\n"); + byte i8 = testClient.testByte((byte)1); + System.out.print(" = " + i8 + "\n"); /** * I32 TEST */ System.out.print("testI32(-1)"); - Int32 i32 = testClient.testI32(new Int32(-1)); - System.out.print(" = " + i32.get() + "\n"); + int i32 = testClient.testI32(-1); + System.out.print(" = " + i32 + "\n"); /** * I64 TEST */ System.out.print("testI64(-34359738368)"); - Int64 i64 = testClient.testI64(new Int64(-34359738368L)); - System.out.print(" = " + i64.get() + "\n"); + long i64 = testClient.testI64(-34359738368L); + System.out.print(" = " + i64 + "\n"); /** * STRUCT TEST */ System.out.print("testStruct({\"Zero\", 1, -3, -5})"); Xtruct out = new Xtruct(); - out.string_thing.value = "Zero"; - out.byte_thing.set((short)1); - out.i32_thing.set(-3); - out.i64_thing.set(-5); + out.string_thing = "Zero"; + out.byte_thing = (byte) 1; + out.i32_thing = -3; + out.i64_thing = -5; Xtruct in = testClient.testStruct(out); System.out.print(" = {" + - "\"" + in.string_thing.value + "\", " + - in.byte_thing.get() + ", " + - in.i32_thing.get() + ", " + - in.i64_thing.get() + "}\n"); + "\"" + in.string_thing + "\", " + + in.byte_thing + ", " + + in.i32_thing + ", " + + in.i64_thing + "}\n"); /** * NESTED STRUCT TEST */ System.out.print("testNest({1, {\"Zero\", 1, -3, -5}), 5}"); Xtruct2 out2 = new Xtruct2(); - out2.byte_thing.set((short)1); + out2.byte_thing = (short)1; out2.struct_thing = out; - out2.i32_thing.set(5); + out2.i32_thing = 5; Xtruct2 in2 = testClient.testNest(out2); in = in2.struct_thing; System.out.print(" = {" + - in2.byte_thing.get() + ", {" + - "\"" + in.string_thing.value + "\", " + - in.byte_thing.get() + ", " + - in.i32_thing.get() + ", " + - in.i64_thing.get() + "}, " + - in2.i32_thing.get() + "}\n"); + in2.byte_thing + ", {" + + "\"" + in.string_thing + "\", " + + in.byte_thing + ", " + + in.i32_thing + ", " + + in.i64_thing + "}, " + + in2.i32_thing + "}\n"); /** * MAP TEST */ - HashMap mapout = new HashMap(); + HashMap mapout = new HashMap(); for (int i = 0; i < 5; ++i) { - mapout.put(new Int32(i), new Int32(i-10)); + mapout.put(i, i-10); } System.out.print("testMap({"); boolean first = true; - for (Int32 key : mapout.keySet()) { + for (int key : mapout.keySet()) { if (first) { first = false; } else { System.out.print(", "); } - System.out.print(key.get() + " => " + mapout.get(key).get()); + System.out.print(key + " => " + mapout.get(key)); } System.out.print("})"); - HashMap mapin = testClient.testMap(mapout); + HashMap mapin = testClient.testMap(mapout); System.out.print(" = {"); first = true; - for (Int32 key : mapin.keySet()) { + for (int key : mapin.keySet()) { if (first) { first = false; } else { System.out.print(", "); } - System.out.print(key.get() + " => " + mapout.get(key).get()); + System.out.print(key + " => " + mapout.get(key)); } System.out.print("}\n"); /** * SET TEST */ - HashSet setout = new HashSet(); + HashSet setout = new HashSet(); for (int i = -2; i < 3; ++i) { - setout.add(new Int32(i)); + setout.add(i); } System.out.print("testSet({"); first = true; - for (Int32 elem : setout) { + for (int elem : setout) { if (first) { first = false; } else { System.out.print(", "); } - System.out.print(elem.get()); + System.out.print(elem); } System.out.print("})"); - HashSet setin = testClient.testSet(setout); + HashSet setin = testClient.testSet(setout); System.out.print(" = {"); first = true; - for (Int32 elem : setin) { + for (int elem : setin) { if (first) { first = false; } else { System.out.print(", "); } - System.out.print(elem.get()); + System.out.print(elem); } System.out.print("}\n"); /** * LIST TEST */ - ArrayList listout = new ArrayList(); + ArrayList listout = new ArrayList(); for (int i = -2; i < 3; ++i) { - listout.add(new Int32(i)); + listout.add(i); } System.out.print("testList({"); first = true; - for (Int32 elem : listout) { + for (int elem : listout) { if (first) { first = false; } else { System.out.print(", "); } - System.out.print(elem.get()); + System.out.print(elem); } System.out.print("})"); - ArrayList listin = testClient.testList(listout); + ArrayList listin = testClient.testList(listout); System.out.print(" = {"); first = true; - for (Int32 elem : listin) { + for (int elem : listin) { if (first) { first = false; } else { System.out.print(", "); } - System.out.print(elem.get()); + System.out.print(elem); } System.out.print("}\n"); @@ -224,44 +224,44 @@ public class TestClient { * ENUM TEST */ System.out.print("testEnum(ONE)"); - Int32 ret = testClient.testEnum(Numberz.ONE); - System.out.print(" = " + ret.get() + "\n"); + int ret = testClient.testEnum(Numberz.ONE); + System.out.print(" = " + ret + "\n"); System.out.print("testEnum(TWO)"); ret = testClient.testEnum(Numberz.TWO); - System.out.print(" = " + ret.get() + "\n"); + System.out.print(" = " + ret + "\n"); System.out.print("testEnum(THREE)"); ret = testClient.testEnum(Numberz.THREE); - System.out.print(" = " + ret.get() + "\n"); + System.out.print(" = " + ret + "\n"); System.out.print("testEnum(FIVE)"); ret = testClient.testEnum(Numberz.FIVE); - System.out.print(" = " + ret.get() + "\n"); + System.out.print(" = " + ret + "\n"); System.out.print("testEnum(EIGHT)"); ret = testClient.testEnum(Numberz.EIGHT); - System.out.print(" = " + ret.get() + "\n"); + System.out.print(" = " + ret + "\n"); /** * TYPEDEF TEST */ System.out.print("testTypedef(309858235082523)"); - Int64 uid = testClient.testTypedef(new Int64(309858235082523L)); - System.out.print(" = " + uid.get() + "\n"); + long uid = testClient.testTypedef(309858235082523L); + System.out.print(" = " + uid + "\n"); /** * NESTED MAP TEST */ System.out.print("testMapMap(1)"); - HashMap> mm = - testClient.testMapMap(new Int32(1)); + HashMap> mm = + testClient.testMapMap(1); System.out.print(" = {"); - for (Int32 key : mm.keySet()) { - System.out.print(key.get() + " => {"); - HashMap m2 = mm.get(key); - for (Int32 k2 : m2.keySet()) { - System.out.print(k2.get() + " => " + m2.get(k2).get() + ", "); + for (int key : mm.keySet()) { + System.out.print(key + " => {"); + HashMap m2 = mm.get(key); + for (int k2 : m2.keySet()) { + System.out.print(k2 + " => " + m2.get(k2) + ", "); } System.out.print("}, "); } @@ -271,29 +271,29 @@ public class TestClient { * INSANITY TEST */ Insanity insane = new Insanity(); - insane.userMap.put(Numberz.FIVE, new Int64(5000)); + insane.userMap.put(Numberz.FIVE, (long)5000); Xtruct truck = new Xtruct(); - truck.string_thing.value = "Truck"; - truck.byte_thing.set((short)8); - truck.i32_thing.set(8); - truck.i64_thing.set(8); + truck.string_thing = "Truck"; + truck.byte_thing = (byte)8; + truck.i32_thing = 8; + truck.i64_thing = 8; insane.xtructs.add(truck); System.out.print("testInsanity()"); - HashMap> whoa = + HashMap> whoa = testClient.testInsanity(insane); System.out.print(" = {"); - for (Int64 key : whoa.keySet()) { - HashMap val = whoa.get(key); - System.out.print(key.get() + " => {"); + for (long key : whoa.keySet()) { + HashMap val = whoa.get(key); + System.out.print(key + " => {"); - for (Int32 k2 : val.keySet()) { + for (int k2 : val.keySet()) { Insanity v2 = val.get(k2); - System.out.print(k2.get() + " => {"); - HashMap userMap = v2.userMap; + System.out.print(k2 + " => {"); + HashMap userMap = v2.userMap; System.out.print("{"); - for (Int32 k3 : userMap.keySet()) { - System.out.print(k3.get() + " => " + - userMap.get(k3).get() + ", "); + for (int k3 : userMap.keySet()) { + System.out.print(k3 + " => " + + userMap.get(k3) + ", "); } System.out.print("}, "); @@ -301,10 +301,10 @@ public class TestClient { System.out.print("{"); for (Xtruct x : xtructs) { System.out.print("{" + - "\"" + x.string_thing.value + "\", " + - x.byte_thing.get() + ", " + - x.i32_thing.get() + ", "+ - x.i64_thing.get() + "}, "); + "\"" + x.string_thing + "\", " + + x.byte_thing + ", " + + x.i32_thing + ", "+ + x.i64_thing + "}, "); } System.out.print("}"); diff --git a/test/java/src/TestServer.java b/test/java/src/TestServer.java index 0acc8a21..4e415ae1 100644 --- a/test/java/src/TestServer.java +++ b/test/java/src/TestServer.java @@ -1,22 +1,22 @@ package com.facebook.thrift.test; -import com.facebook.thrift.types.*; +import com.facebook.thrift.TException; import com.facebook.thrift.protocol.TBinaryProtocol; import com.facebook.thrift.protocol.TProtocol; -import com.facebook.thrift.protocol.TString; import com.facebook.thrift.server.TServer; import com.facebook.thrift.server.TSimpleServer; import com.facebook.thrift.transport.TServerSocket; import com.facebook.thrift.transport.TServerTransport; -import ThriftTest.*; +// Generated code +import thrift.test.*; import java.net.ServerSocket; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; -public class TestServer extends ThriftTestServerIf { +public class TestServer extends ThriftTest.Server { public TestServer(TProtocol prot) { super(prot); } @@ -25,159 +25,199 @@ public class TestServer extends ThriftTestServerIf { System.out.print("testVoid()\n"); } - public TString testString(TString thing) { - System.out.print("testString(\"" + thing.value + "\")\n"); + public String testString(String thing) { + System.out.print("testString(\"" + thing + "\")\n"); return thing; } - public UInt8 testByte(UInt8 thing) { - System.out.print("testByte(" + thing.get() + ")\n"); + public byte testByte(byte thing) { + System.out.print("testByte(" + thing + ")\n"); return thing; } - public Int32 testI32(Int32 thing) { - System.out.print("testI32(" + thing.get() + ")\n"); + public int testI32(int thing) { + System.out.print("testI32(" + thing + ")\n"); return thing; } - public Int64 testI64(Int64 thing) { - System.out.print("testI64(" + thing.get() + ")\n"); + public long testI64(long thing) { + System.out.print("testI64(" + thing + ")\n"); return thing; } public Xtruct testStruct(Xtruct thing) { System.out.print("testStruct({" + - "\"" + thing.string_thing.value + "\", " + - thing.byte_thing.get() + ", " + - thing.i32_thing.get() + ", " + - thing.i64_thing.get() + "})\n"); + "\"" + thing.string_thing + "\", " + + thing.byte_thing + ", " + + thing.i32_thing + ", " + + thing.i64_thing + "})\n"); return thing; } public Xtruct2 testNest(Xtruct2 nest) { Xtruct thing = nest.struct_thing; System.out.print("testNest({" + - nest.byte_thing.get() + ", {" + - "\"" + thing.string_thing.value + "\", " + - thing.byte_thing.get() + ", " + - thing.i32_thing.get() + ", " + - thing.i64_thing.get() + "}, " + - nest.i32_thing.get() + "})\n"); + nest.byte_thing + ", {" + + "\"" + thing.string_thing + "\", " + + thing.byte_thing + ", " + + thing.i32_thing + ", " + + thing.i64_thing + "}, " + + nest.i32_thing + "})\n"); return nest; } - public HashMap testMap(HashMap thing) { + public HashMap testMap(HashMap thing) { System.out.print("testMap({"); boolean first = true; - for (Int32 key : thing.keySet()) { + for (int key : thing.keySet()) { if (first) { first = false; } else { System.out.print(", "); } - System.out.print(key.get() + " => " + thing.get(key).get()); + System.out.print(key + " => " + thing.get(key)); } System.out.print("})\n"); return thing; } - public HashSet testSet(HashSet thing) { + public HashSet testSet(HashSet thing) { System.out.print("testSet({"); boolean first = true; - for (Int32 elem : thing) { + for (int elem : thing) { if (first) { first = false; } else { System.out.print(", "); } - System.out.print(elem.get()); + System.out.print(elem); } System.out.print("})\n"); return thing; } - public ArrayList testList(ArrayList thing) { + public ArrayList testList(ArrayList thing) { System.out.print("testList({"); boolean first = true; - for (Int32 elem : thing) { + for (int elem : thing) { if (first) { first = false; } else { System.out.print(", "); } - System.out.print(elem.get()); + System.out.print(elem); } System.out.print("})\n"); return thing; } - public Int32 testEnum(Int32 thing) { - System.out.print("testEnum(" + thing.get() + ")\n"); + public int testEnum(int thing) { + System.out.print("testEnum(" + thing + ")\n"); return thing; } - public Int64 testTypedef(Int64 thing) { - System.out.print("testTypedef(" + thing.get() + ")\n"); + public long testTypedef(long thing) { + System.out.print("testTypedef(" + thing + ")\n"); return thing; } - public HashMap> testMapMap(Int32 hello) { - System.out.print("testMapMap(" + hello.get() + ")\n"); - HashMap> mapmap = - new HashMap>(); + public HashMap> testMapMap(int hello) { + System.out.print("testMapMap(" + hello + ")\n"); + HashMap> mapmap = + new HashMap>(); - HashMap pos = new HashMap(); - HashMap neg = new HashMap(); + HashMap pos = new HashMap(); + HashMap neg = new HashMap(); for (int i = 1; i < 5; i++) { - pos.put(new Int32(i), new Int32(i)); - neg.put(new Int32(-i), new Int32(-i)); + pos.put(i, i); + neg.put(-i, -i); } - mapmap.put(new Int32(4), pos); - mapmap.put(new Int32(-4), neg); + mapmap.put(4, pos); + mapmap.put(-4, neg); return mapmap; } - public HashMap> testInsanity(Insanity argument) { + public HashMap> testInsanity(Insanity argument) { System.out.print("testInsanity()\n"); Xtruct hello = new Xtruct(); - hello.string_thing.value = "Hello2"; - hello.byte_thing.set((short)2); - hello.i32_thing.set(2); - hello.i64_thing.set(2); + hello.string_thing = "Hello2"; + hello.byte_thing = 2; + hello.i32_thing = 2; + hello.i64_thing = 2; Xtruct goodbye = new Xtruct(); - goodbye.string_thing.value = "Goodbye4"; - goodbye.byte_thing.set((short)4); - goodbye.i32_thing.set(4); - goodbye.i64_thing.set(4); + goodbye.string_thing = "Goodbye4"; + goodbye.byte_thing = (byte)4; + goodbye.i32_thing = 4; + goodbye.i64_thing = (long)4; Insanity crazy = new Insanity(); - crazy.userMap.put(Numberz.EIGHT, new Int64(8)); + crazy.userMap.put(Numberz.EIGHT, (long)8); crazy.xtructs.add(goodbye); Insanity looney = new Insanity(); - crazy.userMap.put(Numberz.FIVE, new Int64(5)); + crazy.userMap.put(Numberz.FIVE, (long)5); crazy.xtructs.add(hello); - HashMap first_map = new HashMap(); - HashMap second_map = new HashMap();; + HashMap first_map = new HashMap(); + HashMap second_map = new HashMap();; first_map.put(Numberz.TWO, crazy); first_map.put(Numberz.THREE, crazy); second_map.put(Numberz.SIX, looney); - HashMap> insane = - new HashMap>(); - insane.put(new Int64(1), first_map); - insane.put(new Int64(2), second_map); + HashMap> insane = + new HashMap>(); + insane.put((long)1, first_map); + insane.put((long)2, second_map); return insane; } + public Xtruct testMulti(byte arg0, int arg1, long arg2, HashMap arg3, int arg4, long arg5) { + System.out.print("testMulti()\n"); + + Xtruct hello = new Xtruct();; + hello.string_thing = "Hello2"; + hello.byte_thing = arg0; + hello.i32_thing = arg1; + hello.i64_thing = arg2; + return hello; + } + + public void testException(String arg) throws Xception { + System.out.print("testException("+arg+")\n"); + if (arg.equals("Xception")) { + Xception x = new Xception(); + x.errorCode = 1001; + x.message = "This is an Xception"; + throw x; + } + return; + } + + public Xtruct testMultiException(String arg0, String arg1) throws Xception, Xception2 { + System.out.print("testMultiException(" + arg0 + ", " + arg1 + ")\n"); + if (arg0.equals("Xception")) { + Xception x = new Xception(); + x.errorCode = 1001; + x.message = "This is an Xception"; + } else if (arg0.equals("Xception2")) { + Xception2 x = new Xception2(); + x.errorCode = 2002; + x.struct_thing.string_thing = "This is an Xception2"; + } + + Xtruct result = new Xtruct(); + result.string_thing = arg1; + return result; + } + + public static void main(String [] args) { try { int port = 9090;