Thrift compiler now compiles both native Java and C++ code

Summary: Compiles to both C++ and Java, plus a host of other cool options like command line control over which languages to output code in

Reviewed By: aditya

Test Plan: The unit test checkins are coming momentarily...




git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@664713 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/compiler/Makefile b/compiler/Makefile
index 62ce275..49833cb 100644
--- a/compiler/Makefile
+++ b/compiler/Makefile
@@ -35,7 +35,8 @@
 # Source files
 SRC_FILES = main.cc \
             generate/t_generator.cc \
-            generate/t_cpp_generator.cc
+            generate/t_cpp_generator.cc \
+            generate/t_java_generator.cc
 
 # Autogenerated files
 GEN_FILES = thrift.tab.hh \
@@ -61,21 +62,23 @@
 # Flex library
 LIBS = -lfl
 
+# Build directories
+obj_dirs: $(OBJ_DIR)parse $(OBJ_DIR)generate
+$(OBJ_DIR)parse:
+	$(MKDIR) -p $(OBJ_DIR)parse
+$(OBJ_DIR)generate:
+	$(MKDIR) -p $(OBJ_DIR)generate
+
 # Scanner generation
 $(GEN_DIR)lex.yy.cc: $(SRC_DIR)thrift.l
 	$(LEX) -o$@ $(SRC_DIR)thrift.l
-
-# Parser generation
-$(GEN_DIR)thrift.tab.hh: $(GEN_DIR)thrift.tab.cc
-
-$(GEN_DIR)thrift.tab.cc: $(SRC_DIR)thrift.y
-	$(YACC) -d -o$(GEN_DIR)thrift.tab.cc $(SRC_DIR)thrift.y
-
-# C++ compilation
 $(OBJ_DIR)lex.yy.o: $(GEN_DIR)lex.yy.cc
 	$(CC) $(CFL) -c -o $@ $(GEN_DIR)lex.yy.cc
 
-# C++ compilation
+# Parser generation
+$(GEN_DIR)thrift.tab.hh: $(GEN_DIR)thrift.tab.cc
+$(GEN_DIR)thrift.tab.cc: $(SRC_DIR)thrift.y
+	$(YACC) -d -o$(GEN_DIR)thrift.tab.cc $(SRC_DIR)thrift.y
 $(OBJ_DIR)thrift.tab.o: $(GEN_DIR)thrift.tab.cc
 	$(CC) $(CFL) -c -o $@ $(GEN_DIR)thrift.tab.cc
 
@@ -84,15 +87,10 @@
 	$(CC) $(CFL) -c -o $@ ${subst $(OBJ_DIR),$(SRC_DIR),$*.cc}
 
 # Main build rule
-thrift:	$(OBJS)	$(GOBS)
+thrift:	obj_dirs $(OBJS) $(GOBS)
 	$(LD) $(CFL) -o $(BIN_DIR)thrift $(OBJS) $(GOBS) $(LIBS)
 
-# Build directory
-obj_dirs:	
-	$(MKDIR) -p $(OBJ_DIR)parse
-	$(MKDIR) -p $(OBJ_DIR)generate
-
-# Install it
+# Install
 install: thrift
 	sudo install bin/thrift /usr/local/bin/thrift
 
diff --git a/compiler/src/generate/t_cpp_generator.cc b/compiler/src/generate/t_cpp_generator.cc
index e47c13b..18cfa31 100644
--- a/compiler/src/generate/t_cpp_generator.cc
+++ b/compiler/src/generate/t_cpp_generator.cc
@@ -2,7 +2,6 @@
 #include <sys/stat.h>
 #include <sstream>
 #include "t_cpp_generator.h"
-#include "globals.h"
 using namespace std;
 
 /**
@@ -146,7 +145,8 @@
     "#ifndef " << service_name_ << "_H" << endl <<
     "#define " << service_name_ << "_H" << endl <<
     endl <<
-    "#include \"TDispatcher.h\"" << endl <<
+    "#include \"TProcessor.h\"" << endl <<
+    "#include \"transport/TTransport.h\"" << endl <<
     "#include \"protocol/TProtocol.h\"" << endl <<
     "#include \"" << program_name_ << "Types.h\"" << endl <<
     endl;
@@ -201,16 +201,24 @@
     "class " << service_name_ << "Client : " <<
     "public " << service_name_ << "If {" << endl <<
     " public:" << endl; 
+
   indent_up();
   f_header_ <<
     indent() << service_name_ << "Client" <<
-    "(TDispatcher* dispatcher, TProtocol* protocol) : " <<
-    "_dispatcher(dispatcher), _protocol(protocol) {}" << endl;
+    "(TTransport* trans, TProtocol* prot) : " <<
+    "_itrans(trans), _otrans(trans), " <<
+    "_iprot(prot), _oprot(prot) {}" << endl;
+  f_header_ <<
+    indent() << service_name_ << "Client" <<
+    "(TTransport* itrans, TTransport* otrans," <<
+    " TProtocol* iprot, TProtocol* oprot) : " <<
+    "_itrans(itrans), _otrans(otrans), " <<
+    "_iprot(iprot), _oprot(oprot) {}" << endl;
+
   vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter; 
+  vector<t_function*>::const_iterator f_iter; 
   for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    f_header_ <<
-      indent() << function_signature(*f_iter) << ";" << endl;
+    indent(f_header_) << function_signature(*f_iter) << ";" << endl;
   }
   indent_down();
   
@@ -218,47 +226,78 @@
     " protected:" << endl;
   indent_up();
   f_header_ <<
-    indent() << "TDispatcher* _dispatcher;" << endl <<
-    indent() << "TProtocol* _protocol;" << endl;
+    indent() << "TTransport* _itrans;" << endl <<
+    indent() << "TTransport* _otrans;" << endl <<
+    indent() << "TProtocol*  _iprot;"  << endl <<
+    indent() << "TProtocol*  _oprot;"  << endl;
   indent_down();  
+
   f_header_ <<
     "};" << endl <<
     endl;
   
+  string scope = service_name_ + "Client::";
+
   // Generate client method implementations
   for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    string prefix = service_name_ + "Client::";
+    string funname = (*f_iter)->get_name();
+
+    // Open function
     f_service_ <<
-      function_signature(*f_iter, prefix) << " {" << endl;
-    indent_up();
+      function_signature(*f_iter, scope) << "" << endl;
+    scope_up(f_service_);
 
+    // Serialize the request
+    f_service_ <<
+      indent() <<
+      "_oprot->writeStructBegin(_otrans, \"function\");" << endl <<
+      indent() <<
+      "_oprot->writeFieldBegin(_otrans, \"name\", T_STRING, 0);" << endl <<
+      indent() <<
+      "_oprot->writeString(_otrans, \"" << funname << "\");" << endl <<
+      indent() <<
+      "_oprot->writeFieldEnd(_otrans);" << endl <<
+      indent() <<
+      "_oprot->writeFieldBegin(_otrans, \"args\", T_STRUCT, 1);" << endl;     
+    generate_serialize_struct((*f_iter)->get_arglist());
+    f_service_ <<
+      indent() <<
+      "_oprot->writeFieldEnd(_otrans);" << endl <<
+      indent() <<
+      "_oprot->writeFieldStop(_otrans);" << endl <<
+      indent() <<
+      "_oprot->writeStructEnd(_otrans);" << endl;
+    
+    // Flush the request
     indent(f_service_) <<
-      "std::string _argbuf = \"\";" << endl;
-    generate_serialize_struct("_argbuf", (*f_iter)->get_arglist());
-    indent(f_service_) <<
-      "std::string _sbuf = _protocol->writeFunction(\"" <<
-      (*f_iter)->get_name() << "\", _argbuf);" << endl;
-    indent(f_service_) <<
-      "std::string _rbuf = _dispatcher->dispatch(_sbuf);" << endl;
+      "_otrans->flush();" << endl;
 
+    // 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
     if (!(*f_iter)->get_returntype()->is_void()) {
       indent(f_service_) <<
-        "TBuf _tbuf((uint8_t*)_rbuf.data(), _rbuf.size());" << endl;
-      indent(f_service_) <<
         type_name((*f_iter)->get_returntype()) << " _result;" << endl;
-      t_field result_field((*f_iter)->get_returntype(), "_result", 0);
-      generate_deserialize_field("_tbuf", &result_field);
+      result_struct.append(&result_field);
+    }
+
+    // Deserialize response struct
+    generate_deserialize_struct(&result_struct);
+
+    // Careful, only return _result if not a void function
+    if (!(*f_iter)->get_returntype()->is_void()) {
       indent(f_service_) <<
         "return _result;" << endl;
     } else {
       indent(f_service_) <<
         "return;" << endl;
     }
-   
-    indent_down();
-    f_service_ <<
-      "}" << endl <<
-      endl;
+
+    // Close function
+    scope_down(f_service_);
+    indent(f_service_) << endl;
   }
 }
 
@@ -268,46 +307,76 @@
  * @param tservice The service to generate a server for.
  */
 void t_cpp_generator::generate_service_server(t_service* tservice) {
+  // Generate the dispatch methods
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter; 
+
   // Generate the header portion
   f_header_ <<
     "class " << service_name_ << "ServerIf : " <<
     "public " << service_name_ << "If, " <<
-    "public TDispatcher {" << endl <<
+    "public TProcessor {" << endl <<
     " public: " << endl;
   indent_up();
   f_header_ << 
-    indent() << service_name_ << "ServerIf(TProtocol* protocol) : " <<
-    "_protocol(protocol) {}" << endl <<
-    indent() << "std::string dispatch(const std::string& _in);" << endl <<
+    indent() <<
+    service_name_ << "ServerIf(TProtocol* protocol) : " <<
+                       "_iprot(protocol), _oprot(protocol) {}" << endl <<
+    indent() <<
+    service_name_ << "ServerIf(TProtocol* iprot, TProtocol* oprot) : " <<
+                       "_iprot(iprot), _oprot(oprot) {}" << endl <<
+    indent() << "bool process(TTransport *_itrans, " <<
+                             "TTransport* _otrans);" << endl <<
     indent() << "virtual ~" << service_name_ << "ServerIf() {}" << endl;
   indent_down();
+
+  // Protected data members
   f_header_ <<
     " protected:" << endl;
   indent_up();
   f_header_ <<
-    indent() << "TProtocol* _protocol;" << endl;
-  indent_down();  
+    indent() << "TProtocol* _iprot;" << endl <<
+    indent() << "TProtocol* _oprot;" << endl;
+  indent_down();
+
+  // Process function declarations
+  f_header_ <<
+    " private:" << endl;
+  indent_up();
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    indent(f_header_) <<
+      "void process_" << (*f_iter)->get_name() <<
+      "(TTransport* _itrans, TTransport* _otrans);" << endl;
+  }
+  indent_down();
   f_header_ <<
     "};" << endl << endl;
 
-  // Generate the dispatch methods
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter; 
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    generate_dispatch_function(tservice, *f_iter);
-  }
-
   // Generate the server implementation
   f_service_ <<
-    "std::string " << service_name_ << "ServerIf::" <<
-    "dispatch(const std::string& _in) {" << endl;
+    "bool " << service_name_ << "ServerIf::" <<
+    "process(TTransport* _itrans, TTransport* _otrans) {" << endl;
   indent_up();
 
   f_service_ <<
-    indent() << "TBuf _tbuf((uint8_t*)_in.data(), _in.size());" << endl <<
-    indent() << "std::string _fname = " <<
-                "_protocol->readFunction(_tbuf);" << endl <<
-    indent() << "std::string _result;" << endl;
+    indent() <<
+    "std::string _name;" << endl <<
+    indent() <<
+    "std::string _fname;" << endl <<
+    indent() <<
+    "TType _ftype;" << endl <<
+    indent() <<
+    "uint16_t _fid;" << endl <<
+    indent() <<
+    "_iprot->readStructBegin(_itrans, _name);" << endl <<
+    indent() <<
+    "_iprot->readFieldBegin(_itrans, _name, _ftype, _fid);" << endl <<
+    indent() <<
+    "_iprot->readString(_itrans, _fname);" << endl <<
+    indent() <<
+    "_iprot->readFieldEnd(_itrans);" << endl <<
+    indent() <<
+    "_iprot->readFieldBegin(_itrans, _name, _ftype, _fid);" << endl;
 
   bool first = true;
   for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
@@ -321,44 +390,56 @@
       "if (_fname.compare(\"" << (*f_iter)->get_name() <<"\") == 0) {" << endl;
     indent_up();
     indent(f_service_) <<
-      "_result = dispatch_" << (*f_iter)->get_name() <<
-      "(_tbuf, this, _protocol);" << endl;
+      "process_" << (*f_iter)->get_name() <<
+      "(_itrans, _otrans);" << endl;
     indent_down();
     indent(f_service_) << "}";
   }
   indent(f_service_) <<
     " else {" << endl;
   indent_up();
-  f_service_ <<
-    indent() << "fprintf(stderr, \"Unknown function: '%s'\\n\", " <<
-    "_fname.c_str());" << endl <<
-    indent() << "_result = \"\";" << endl;
+  indent(f_service_) <<
+    "fprintf(stderr, \"Unknown function: '%s'\\n\", " <<
+    "_fname.c_str());" << endl;
   indent_down();
   indent(f_service_) <<
     "}" << endl;
 
-  indent(f_service_) <<
-    "return _result;" << endl;
+  // Read end of args field, the T_STOP, and the struct close
+  f_service_ <<
+    indent() <<
+    "_iprot->readFieldEnd(_itrans);" << endl <<
+    indent() <<
+    "_iprot->readFieldBegin(_itrans, _name, _ftype, _fid);" << endl <<   
+    indent() <<
+    "_iprot->readStructEnd(_itrans);" << endl <<
+    indent() <<
+    "return true;" << endl;
 
   indent_down();
   f_service_ <<
     "}" << endl <<
     endl;
+
+  // Generate the process subfunctions
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_process_function(tservice, *f_iter);
+  }
 }
 
 /**
- * Generates a dispatch function definition.
+ * Generates a process function definition.
  *
  * @param tfunction The function to write a dispatcher for
  */
-void t_cpp_generator::generate_dispatch_function(t_service* tservice,
-                                                 t_function* tfunction) {
+void t_cpp_generator::generate_process_function(t_service* tservice,
+                                                t_function* tfunction) {
+  // Open function
   f_service_ <<
-    "std::string dispatch_" << tfunction->get_name() <<
-    "(TBuf _tbuf, " <<
-    service_name_ << "If *_dispatcher, " <<
-    "const TProtocol *_protocol) {" << endl;
-  indent_up();
+    "void " << tservice->get_name() << "ServerIf::" <<
+    "process_" << tfunction->get_name() <<
+    "(TTransport *_itrans, TTransport *_otrans)" << endl;
+  scope_up(f_service_);
 
   // Get the struct of function call params
   t_struct* arg_struct = tfunction->get_arglist();
@@ -372,7 +453,7 @@
   }
 
   // Deserialize the function arguments as a struct
-  generate_deserialize_struct("_tbuf", arg_struct);
+  generate_deserialize_struct(arg_struct);
   
   // Generate the function call
   f_service_ << indent();
@@ -380,7 +461,7 @@
     f_service_ << type_name(tfunction->get_returntype()) << " _result = ";
   }
   f_service_ <<
-    "_dispatcher->" << tfunction->get_name() << "(";
+    tfunction->get_name() << "(";
   bool first = true;
   for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
     if (first) {
@@ -392,28 +473,27 @@
   }
   f_service_ << ");" << endl;
 
-  // Serialize the result into _sbuf
+  // Serialize the result into a struct
+  t_struct result_struct(tfunction->get_name() + "_result");
+  t_field result_field(tfunction->get_returntype(), "_result");
+
+  // Only append the field if non-void
+  if (!tfunction->get_returntype()->is_void()) {
+    result_struct.append(&result_field);
+  }
+  generate_serialize_struct(&result_struct);
   indent(f_service_) <<
-    "std::string _sbuf = \"\";" << endl;
+    "_otrans->flush();" << endl;
 
-  t_field result_field(tfunction->get_returntype(), "_result", 0);
-  generate_serialize_field("_sbuf", &result_field);
-
-  // Return the serialized buffer
-  indent(f_service_) <<
-    "return _sbuf;" << endl;
-
-  indent_down();
-  f_service_ <<
-    "}" << endl <<
-    endl;
+  // Close function
+  scope_down(f_service_);
+  f_service_ << endl;
 }
 
 /**
  * Deserializes a field of any type.
  */
-void t_cpp_generator::generate_deserialize_field(string src,
-                                                 t_field* tfield,
+void t_cpp_generator::generate_deserialize_field(t_field* tfield,
                                                  string prefix) {
   t_type* type = tfield->get_type();
   while (type->is_typedef()) {
@@ -421,59 +501,53 @@
   }
 
   if (type->is_void()) {
-    return;
+    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " +
+      prefix + tfield->get_name();
   }
 
+  string name = prefix + tfield->get_name();
+
   if (type->is_struct()) {
-    generate_deserialize_struct(src,
-                                (t_struct*)(tfield->get_type()),
-                                prefix + tfield->get_name() + ".");
+    generate_deserialize_struct((t_struct*)(tfield->get_type()),
+                                 name + ".");
   } else if (type->is_container()) {
-    generate_deserialize_container(src,
-                                   tfield->get_type(),
-                                   prefix + tfield->get_name());
+    generate_deserialize_container(tfield->get_type(), name);
   } else if (type->is_base_type() || type->is_enum()) {
 
     indent(f_service_) <<
-      prefix << tfield->get_name() << " = ";
-    if (type->is_enum()) {
-      f_service_ << "(" << type_name(type) << ")";
-    }
-    f_service_ <<
-      "_protocol->";
+      "_iprot->";
     
     if (type->is_base_type()) {
       t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
       switch (tbase) {
       case t_base_type::TYPE_VOID:
         throw "compiler error: cannot serialize void field in a struct: " +
-          src + ":" + tfield->get_name() + ":" + prefix;
+          name;
         break;
       case t_base_type::TYPE_STRING:
-        f_service_ << "readString(" << src << ");";
+        f_service_ << "readString(_itrans, " << name << ");";
         break;
       case t_base_type::TYPE_BYTE:
-        f_service_ << "readByte(" << src << ");";
+        f_service_ << "readByte(_itrans, " << name << ");";
         break;
       case t_base_type::TYPE_I32:
-        f_service_ << "readI32(" << src << ");";
+        f_service_ << "readI32(_itrans, " << name << ");";
         break;
       case t_base_type::TYPE_U32:
-        f_service_ << "readU32(" << src << ");";
+        f_service_ << "readU32(_itrans, " << name << ");";
         break;
       case t_base_type::TYPE_I64:
-        f_service_ << "readI64(" << src << ");";
+        f_service_ << "readI64(_itrans, " << name << ");";
         break;
       case t_base_type::TYPE_U64:
-        f_service_ << "readU64(" << src << ");";
+        f_service_ << "readU64(_itrans, " << name << ");";
         break;
       default:
         throw "compiler error: no C++ name for base type " + tbase;
       }
     } else if (type->is_enum()) {
-      f_service_ << "readI32(" << src << ");";
+      f_service_ << "readI32(_itrans, (int32_t&)" << name << ");";
     }
-    
     f_service_ <<
       endl;
   } else {
@@ -488,83 +562,139 @@
  * buffer for deserialization, and that there is a variable protocol which
  * is a reference to a TProtocol serialization object.
  */
-void t_cpp_generator::generate_deserialize_struct(string src,
-                                                  t_struct* tstruct,
+void t_cpp_generator::generate_deserialize_struct(t_struct* tstruct,
                                                   string prefix) {
   const vector<t_field*>& fields = tstruct->get_members();
   vector<t_field*>::const_iterator f_iter;
 
-  // Ensure that there are some fields
-  if (fields.size() == 0) {
-    return;
-  }
-
   scope_up(f_service_);
 
   // Read the struct fields from the protocol
-  string _struct = tmp("_struct");
+  string fid   = tmp("_fid");
+  string ftype = tmp("_ftype");
+  string fname = tmp("_name");
+  
+  // Declare stack tmp variables
+  f_service_ <<
+    indent() << "std::string " << fname << ";" << endl <<
+    indent() << "TType " << ftype << ";" << endl <<
+    indent() << "uint16_t " << fid << ";" << endl <<
+    indent() << "_iprot->readStructBegin(_itrans, " << fname << ");" << endl;
+  
+  // Loop over reading in fields
   indent(f_service_) <<
-    "std::map<uint32_t,TBuf> " << _struct <<
-    " = _protocol->readStruct(" << src << ");" << endl;
+    "while (true)" << endl;
+
+    scope_up(f_service_);
+    
+    // Read beginning field marker
+    indent(f_service_) <<
+      "_iprot->readFieldBegin(_itrans, " <<
+      fname << ", " << ftype << ", " << fid << ");" << endl;
+    
+    // Check for field STOP marker
+    indent(f_service_) <<
+      "if (" << ftype << " == T_STOP) { break; }" << endl;
+    
+    // Switch statement on the field we are reading
+    indent(f_service_) <<
+      "switch (" << fid << ")" << 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() << "  _iprot->skip(_itrans, " << ftype << ");" << 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_) <<
-    "std::map<uint32_t,TBuf>::iterator _field;" << endl;
-
-  // Decleare a temp buffer for working with fields
-  string fbuf = tmp("_fbuf");
-
-  // Iterate over the fields and extract them
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    // Check for existence of the field
-    indent(f_service_) <<
-      "if ((_field = " << _struct << ".find(" << (*f_iter)->get_key() <<
-      ")) != " << _struct << ".end()) {" <<
-      endl;
-    indent_up();
-
-    // Copy the field buffer into temp buffer
-    indent(f_service_) <<
-      "TBuf& " << fbuf << " = _field->second;" << endl;
-
-    // Deserialize from the field's buffer
-    generate_deserialize_field(fbuf, *f_iter, prefix);
-
-    indent_down();
-    indent(f_service_) <<
-      "}" << endl;
-  }
+    "_iprot->readStructEnd(_itrans);" << endl;
 
   scope_down(f_service_);
 }
 
-void t_cpp_generator::generate_deserialize_container(string src,
-                                                     t_type* ttype,
+void t_cpp_generator::generate_deserialize_container(t_type* ttype,
                                                      string prefix) {
   scope_up(f_service_);
   
   string size = tmp("_size");
+  string ktype = tmp("_ktype");
+  string vtype = tmp("_vtype");
+  string etype = tmp("_etype");
+  
   indent(f_service_) <<
-    "uint32_t " << size << " = _protocol->readU32(" << src << ");" << endl;
+    "uint32_t " << size << ";" << endl;
+  
 
+  // Declare variables, read header
+  if (ttype->is_map()) {
+    f_service_ <<
+      indent() << "TType " << ktype << ";" << endl <<
+      indent() << "TType " << vtype << ";" << endl <<
+      indent() << "_iprot->readMapBegin(_itrans, " <<
+                   ktype << ", " << vtype << ", " << size << ");" << endl;
+  } else if (ttype->is_set()) {
+    f_service_ <<
+      indent() << "TType " << etype << ";" << endl <<
+      indent() << "_iprot->readSetBegin(_itrans, " <<
+                   etype << ", " << size << ");" << endl;
+  } else if (ttype->is_list()) {
+    f_service_ <<
+      indent() << "TType " << etype << ";" << endl <<
+      indent() << "_iprot->readListBegin(_itrans, " <<
+                   etype << ", " << size << ");" << endl;
+  }
+
+
+  // For loop iterates over elements
   string i = tmp("_i");
   indent(f_service_) <<
     "uint32_t " << i << ";" << endl;
   indent(f_service_) <<
     "for (" <<
-    i << " = 0; " << i << " < " << size << "; ++" << i << ") {" << endl;
-  indent_up();
+    i << " = 0; " << i << " < " << size << "; ++" << i << ")" << endl;
+  
+    scope_up(f_service_);
+    
+    if (ttype->is_map()) {
+      generate_deserialize_map_element((t_map*)ttype, prefix);
+    } else if (ttype->is_set()) {
+      generate_deserialize_set_element((t_set*)ttype, prefix);
+    } else if (ttype->is_list()) {
+      generate_deserialize_list_element((t_list*)ttype, prefix);
+    }
+    
+    scope_down(f_service_);
 
+  // Read container end
   if (ttype->is_map()) {
-    generate_deserialize_map_element(src, (t_map*)ttype, prefix);
+    indent(f_service_) << "_iprot->readMapEnd(_itrans);" << endl;
   } else if (ttype->is_set()) {
-    generate_deserialize_set_element(src, (t_set*)ttype, prefix);
+    indent(f_service_) << "_iprot->readSetEnd(_itrans);" << endl;
   } else if (ttype->is_list()) {
-    generate_deserialize_list_element(src, (t_list*)ttype, prefix);
+    indent(f_service_) << "_iprot->readListEnd(_itrans);" << endl;
   }
 
-  indent_down();
-  indent(f_service_) <<
-    "}" << endl;
-
   scope_down(f_service_);
 }
 
@@ -572,51 +702,48 @@
 /**
  * Generates code to deserialize a map
  */
-void t_cpp_generator::generate_deserialize_map_element(string src,
-                                                       t_map* tmap,
+void t_cpp_generator::generate_deserialize_map_element(t_map* tmap,
                                                        string prefix) {
   string key = tmp("_key");
   string val = tmp("_val");
-  t_field fkey(tmap->get_key_type(), key, 0);
-  t_field fval(tmap->get_val_type(), val, 0);
+  t_field fkey(tmap->get_key_type(), key);
+  t_field fval(tmap->get_val_type(), val);
 
   indent(f_service_) <<
     declare_field(&fkey) << endl;
   indent(f_service_) <<
     declare_field(&fval) << endl;
 
-  generate_deserialize_field(src, &fkey, "");
-  generate_deserialize_field(src, &fval, "");
+  generate_deserialize_field(&fkey);
+  generate_deserialize_field(&fval);
 
   indent(f_service_) <<
     prefix << ".insert(std::make_pair(" << key << ", " << val << "));" << endl;
 }
 
-void t_cpp_generator::generate_deserialize_set_element(string src,
-                                                       t_set* tset,
+void t_cpp_generator::generate_deserialize_set_element(t_set* tset,
                                                        string prefix) {
   string elem = tmp("_elem");
-  t_field felem(tset->get_elem_type(), elem, 0);
+  t_field felem(tset->get_elem_type(), elem);
 
   indent(f_service_) <<
     declare_field(&felem) << endl;
 
-  generate_deserialize_field(src, &felem, "");
+  generate_deserialize_field(&felem);
 
   indent(f_service_) <<
     prefix << ".insert(" << elem << ");" << endl;
 }
 
-void t_cpp_generator::generate_deserialize_list_element(string src,
-                                                        t_list* tlist,
+void t_cpp_generator::generate_deserialize_list_element(t_list* tlist,
                                                         string prefix) {
   string elem = tmp("_elem");
-  t_field felem(tlist->get_elem_type(), elem, 0);
+  t_field felem(tlist->get_elem_type(), elem);
 
   indent(f_service_) <<
     declare_field(&felem) << endl;
 
-  generate_deserialize_field(src, &felem, "");
+  generate_deserialize_field(&felem);
 
   indent(f_service_) <<
     prefix << ".push_back(" << elem << ");" << endl;
@@ -629,66 +756,68 @@
  * @param tfield The field to serialize
  * @param prefix Name to prepend to field name
  */
-void t_cpp_generator::generate_serialize_field(string dest,
-                                               t_field* tfield,
+void t_cpp_generator::generate_serialize_field(t_field* tfield,
                                                string prefix) {
   t_type* type = tfield->get_type();
   while (type->is_typedef()) {
     type = ((t_typedef*)type)->get_type();
   }
-  
+
   // Do nothing for void types
   if (type->is_void()) {
-    return;
+    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " +
+      prefix + tfield->get_name();
   }
-
+  
   if (type->is_struct()) {
-    generate_serialize_struct(dest,
-                              (t_struct*)(tfield->get_type()),
+    generate_serialize_struct((t_struct*)(tfield->get_type()),
                               prefix + tfield->get_name() + ".");
   } else if (type->is_container()) {
-    generate_serialize_container(dest,
-                                 tfield->get_type(),
+    generate_serialize_container(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_) <<
-      dest << " += _protocol->";
+      "_oprot->";
     
     if (type->is_base_type()) {
       t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
       switch (tbase) {
       case t_base_type::TYPE_VOID:
-        throw "compiler error: cannot serialize void field in a struct: " +
-          dest + ":" + tfield->get_name() + ":" + prefix;
+        throw
+          "compiler error: cannot serialize void field in a struct: " + name;
         break;
       case t_base_type::TYPE_STRING:
-        f_service_ << "writeString(" << prefix << tfield->get_name() << ");";
+        f_service_ << "writeString(_otrans, " << name << ");";
         break;
       case t_base_type::TYPE_BYTE:
-        f_service_ << "writeByte(" << prefix << tfield->get_name() << ");";
+        f_service_ << "writeByte(_otrans, " << name << ");";
         break;
       case t_base_type::TYPE_I32:
-        f_service_ << "writeI32(" << prefix << tfield->get_name() << ");";
+        f_service_ << "writeI32(_otrans, " << name << ");";
         break;
       case t_base_type::TYPE_U32:
-        f_service_ << "writeU32(" << prefix << tfield->get_name() << ");";
+        f_service_ << "writeU32(_otrans, " << name << ");";
         break;
       case t_base_type::TYPE_I64:
-        f_service_ << "writeI64(" << prefix << tfield->get_name() << ");";
+        f_service_ << "writeI64(_otrans, " << name << ");";
         break;
       case t_base_type::TYPE_U64:
-        f_service_ << "writeU64(" << prefix << tfield->get_name() << ");";
+        f_service_ << "writeU64(_otrans, " << name << ");";
         break;
       default:
         throw "compiler error: no C++ name for base type " + tbase;
       }
     } else if (type->is_enum()) {
-      f_service_ << "writeI32(" << prefix << tfield->get_name() << ");";
-    } 
+      f_service_ << "writeI32(_otrans, (int32_t)" << name << ");";
+    }
     f_service_ << endl;
   } else {
-    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s' TYPE '%s'\n",
-           tfield->get_name().c_str(), type_name(type).c_str());
+    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
+           prefix.c_str(),
+           tfield->get_name().c_str(),
+           type_name(type).c_str());
   }
 }
 
@@ -698,44 +827,57 @@
  * @param tstruct The struct to serialize
  * @param prefix  String prefix to attach to all fields
  */
-void t_cpp_generator::generate_serialize_struct(string dest,
-                                                t_struct* tstruct,
+void t_cpp_generator::generate_serialize_struct(t_struct* tstruct,
                                                 string prefix) {
+  string name = tstruct->get_name();
   const vector<t_field*>& fields = tstruct->get_members();
   vector<t_field*>::const_iterator f_iter;
 
-  // Ensure that there are some fields
-  if (fields.size() == 0) {
-    return;
-  }
-
   scope_up(f_service_);
-  string _struct = tmp("_struct");
-
   indent(f_service_) <<
-    "std::map<uint32_t,std::string> " << _struct << ";" << endl;
-
-  // Serialize each of the fields into the map
+    "_oprot->writeStructBegin(_otrans, \"" << name << "\");" << endl;
   for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    ostringstream fdest;
-    fdest << _struct << "[" << (*f_iter)->get_key() << "]";
-    generate_serialize_field(fdest.str(), *f_iter, prefix);
+    // Write field header
+    indent(f_service_) <<
+      "_oprot->writeFieldBegin(_otrans, " <<
+      "\"" << (*f_iter)->get_name() << "\", " <<
+      type_to_enum((*f_iter)->get_type()) << ", " <<
+      (*f_iter)->get_key() << ");" << endl;
+    // Write field contents
+    generate_serialize_field(*f_iter, prefix);
+    // Write field closer
+    indent(f_service_) <<
+      "_oprot->writeFieldEnd(_otrans);" << endl;
   }
-
   // Write the struct map
-  indent(f_service_) <<
-    dest << " += _protocol->writeStruct(" << _struct << ");" << endl;
+  f_service_ <<
+    indent() << "_oprot->writeFieldStop(_otrans);" << endl <<
+    indent() << "_oprot->writeStructEnd(_otrans);" << endl;
 
   scope_down(f_service_);
 }
 
-void t_cpp_generator::generate_serialize_container(string dest,
-                                                   t_type* ttype,
+void t_cpp_generator::generate_serialize_container(t_type* ttype,
                                                    string prefix) {
   scope_up(f_service_);
   
-  indent(f_service_) <<
-    dest << " += _protocol->writeU32(" << prefix << ".size());" << endl;
+  if (ttype->is_map()) {
+    indent(f_service_) <<
+      "_oprot->writeMapBegin(_otrans, " <<
+      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_) <<
+      "_oprot->writeSetBegin(_otrans, " <<
+      type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " <<
+      prefix << ".size());" << endl;
+  } else if (ttype->is_list()) {
+    indent(f_service_) <<
+      "_oprot->writeListBegin(_otrans, " <<
+      type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
+      prefix << ".size());" << endl;
+  }
 
   string iter = tmp("_iter");
   indent(f_service_) <<
@@ -743,21 +885,31 @@
   indent(f_service_) <<
     "for (" << iter << " = " << prefix  << ".begin(); " <<
     iter << " != " << prefix << ".end(); " <<
-    "++" << iter << ") {" << endl;
-  indent_up();
-  
-  if (ttype->is_map()) {
-    generate_serialize_map_element(dest, (t_map*)ttype, iter);
-  } else if (ttype->is_set()) {
-    generate_serialize_set_element(dest, (t_set*)ttype, iter);
-  } else if (ttype->is_list()) {
-    generate_serialize_list_element(dest, (t_list*)ttype, iter);
-  }
+    "++" << iter << ")" << endl;
 
-  indent_down();
-  indent(f_service_) <<
-    "}" << endl;  
-  
+    scope_up(f_service_);
+
+    if (ttype->is_map()) {
+      generate_serialize_map_element((t_map*)ttype, iter);
+    } else if (ttype->is_set()) {
+      generate_serialize_set_element((t_set*)ttype, iter);
+    } else if (ttype->is_list()) {
+      generate_serialize_list_element((t_list*)ttype, iter);
+    }
+    
+    if (ttype->is_map()) {
+      indent(f_service_) <<
+        "_oprot->writeMapEnd(_otrans);" << endl;
+    } else if (ttype->is_set()) {
+      indent(f_service_) <<
+        "_oprot->writeSetEnd(_otrans);" << endl;
+    } else if (ttype->is_list()) {
+      indent(f_service_) <<
+        "_oprot->writeListEnd(_otrans);" << endl;
+    }
+    
+    scope_down(f_service_);
+ 
   scope_down(f_service_);  
 }
 
@@ -765,51 +917,31 @@
  * Serializes the members of a map.
  *
  */
-void t_cpp_generator::generate_serialize_map_element(string dest,
-                                                     t_map* tmap,
+void t_cpp_generator::generate_serialize_map_element(t_map* tmap,
                                                      string iter) {
-  t_field kfield(tmap->get_key_type(), iter + "->first", 0);
-  generate_serialize_field(dest, &kfield, "");
+  t_field kfield(tmap->get_key_type(), iter + "->first");
+  generate_serialize_field(&kfield, "");
 
-  t_field vfield(tmap->get_val_type(), iter + "->second", 0);
-  generate_serialize_field(dest, &vfield, "");
+  t_field vfield(tmap->get_val_type(), iter + "->second");
+  generate_serialize_field(&vfield, "");
 }
 
 /**
  * Serializes the members of a set.
  */
-void t_cpp_generator::generate_serialize_set_element(string dest,
-                                                     t_set* tset,
+void t_cpp_generator::generate_serialize_set_element(t_set* tset,
                                                      string iter) {
-  t_field efield(tset->get_elem_type(), "(*" + iter + ")", 0);
-  generate_serialize_field(dest, &efield, "");
+  t_field efield(tset->get_elem_type(), "(*" + iter + ")");
+  generate_serialize_field(&efield, "");
 }
 
 /**
  * Serializes the members of a list.
  */
-void t_cpp_generator::generate_serialize_list_element(string dest,
-                                                      t_list* tlist,
+void t_cpp_generator::generate_serialize_list_element(t_list* tlist,
                                                       string iter) {
-  t_field efield(tlist->get_elem_type(), "(*" + iter + ")", 0);
-  generate_serialize_field(dest, &efield, "");
-}
-
-/**
- * Generates a comment about this code being autogenerated.
- *
- * @return C-style comment mentioning that this file is autogenerated.
- */
-string t_cpp_generator::autogen_comment() {
-  string result = "";
-  return
-    result +
-    "/**\n" +
-    " * Autogenerated by Thrift\n" +
-    " * " + g_time_str +
-    " *\n" +
-    " * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" +
-    " */\n";
+  t_field efield(tlist->get_elem_type(), "(*" + iter + ")");
+  generate_serialize_field(&efield, "");
 }
 
 /**
@@ -934,3 +1066,44 @@
   }
   return result;
 }
+
+/**
+ * Converts the parse type to a C++ enum string for the given type.
+ */
+string t_cpp_generator::type_to_enum(t_type* type) {
+  while (type->is_typedef()) {
+    type = ((t_typedef*)type)->get_type();
+  }
+  
+  if (type->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_VOID:
+      throw "NO T_VOID CONSTRUCT";
+    case t_base_type::TYPE_STRING:
+      return "T_STRING";
+    case t_base_type::TYPE_BYTE:
+      return "T_BYTE";
+    case t_base_type::TYPE_I32:
+      return "T_I32";
+    case t_base_type::TYPE_U32:
+      return "T_U32";
+    case t_base_type::TYPE_I64:
+      return "T_I64";
+    case t_base_type::TYPE_U64:
+      return "T_U64";
+    }
+  } else if (type->is_enum()) {
+    return "T_I32";
+  } else if (type->is_struct()) {
+    return "T_STRUCT";
+  } else if (type->is_map()) {
+    return "T_MAP";
+  } else if (type->is_set()) {
+    return "T_SET";
+  } else if (type->is_list()) {
+    return "T_LIST";
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
diff --git a/compiler/src/generate/t_cpp_generator.h b/compiler/src/generate/t_cpp_generator.h
index 079a26d..801c06c 100644
--- a/compiler/src/generate/t_cpp_generator.h
+++ b/compiler/src/generate/t_cpp_generator.h
@@ -6,16 +6,17 @@
 #include <iostream>
 #include <vector>
 
-#include "t_generator.h"
+#include "t_oop_generator.h"
 
+// TODO(mcslee: Paramaterize the output dir
 #define T_CPP_DIR "gen-cpp"
 
 /**
- * C++ code generator.
+ * C++ code generator. This is legitimacy incarnate.
  *
  * @author Mark Slee <mcslee@facebook.com>
  */
-class t_cpp_generator : public t_generator {
+class t_cpp_generator : public t_oop_generator {
  public:
   t_cpp_generator() {}
   ~t_cpp_generator() {}
@@ -37,80 +38,57 @@
   void generate_service_interface (t_service* tservice);
   void generate_service_client    (t_service* tservice);
   void generate_service_server    (t_service* tservice);
-  void generate_dispatch_function (t_service* tservice, t_function* tfunction);
+  void generate_process_function  (t_service* tservice, t_function* tfunction);
 
   /** Serialization constructs */
 
-  void generate_deserialize_field        (std::string src,
-                                          t_field*    tfield, 
+  void generate_deserialize_field        (t_field*    tfield, 
                                           std::string prefix="");
   
-  void generate_deserialize_struct       (std::string src,
-                                          t_struct*   tstruct,
+  void generate_deserialize_struct       (t_struct*   tstruct,
                                           std::string prefix="");
   
-  void generate_deserialize_container    (std::string src,
-                                          t_type*     ttype,
+  void generate_deserialize_container    (t_type*     ttype,
                                           std::string prefix="");
   
-  void generate_deserialize_set_element  (std::string src,
-                                          t_set*      tset,
+  void generate_deserialize_set_element  (t_set*      tset,
                                           std::string prefix="");
 
-  void generate_deserialize_map_element  (std::string src,
-                                          t_map*      tmap,
+  void generate_deserialize_map_element  (t_map*      tmap,
                                           std::string prefix="");
 
-  void generate_deserialize_list_element (std::string src,
-                                          t_list*     tlist,
+  void generate_deserialize_list_element (t_list*     tlist,
                                           std::string prefix="");
 
-  void generate_serialize_field          (std::string dest,
-                                          t_field*    tfield,
+  void generate_serialize_field          (t_field*    tfield,
                                           std::string prefix="");
 
-  void generate_serialize_struct         (std::string dest,
-                                          t_struct*   tstruct,
+  void generate_serialize_struct         (t_struct*   tstruct,
                                           std::string prefix="");
 
-  void generate_serialize_container      (std::string dest,
-                                          t_type*     ttype,
+  void generate_serialize_container      (t_type*     ttype,
                                           std::string prefix="");
 
-  void generate_serialize_map_element    (std::string dest,
-                                          t_map*      tmap,
+  void generate_serialize_map_element    (t_map*      tmap,
                                           std::string iter);
 
-  void generate_serialize_set_element    (std::string dest,
-                                          t_set*      tmap,
+  void generate_serialize_set_element    (t_set*      tmap,
                                           std::string iter);
 
-  void generate_serialize_list_element   (std::string dest,
-                                          t_list*     tlist,
+  void generate_serialize_list_element   (t_list*     tlist,
                                           std::string iter);
 
-  /** Scoping */
-
-  void scope_up(std::ostream& out) {
-    indent(out) << "{" << std::endl;
-    indent_up();
-  }
-
-  void scope_down(std::ostream& out) {
-    indent_down();
-    indent(out) << "}" << std::endl;
-  }
-
   /** Helper rendering functions */
 
-  std::string autogen_comment();
   std::string type_name(t_type* ttype);
   std::string base_type_name(t_base_type::t_base tbase);
   std::string declare_field(t_field* tfield, bool init=false);
   std::string function_signature(t_function* tfunction, std::string prefix="");
   std::string argument_list(t_struct* tstruct);
-  
+  std::string type_to_enum(t_type* ttype);
+
  private:
+
   /** File streams */
 
   std::ofstream f_types_;
diff --git a/compiler/src/generate/t_java_generator.cc b/compiler/src/generate/t_java_generator.cc
new file mode 100644
index 0000000..e4236fc
--- /dev/null
+++ b/compiler/src/generate/t_java_generator.cc
@@ -0,0 +1,1118 @@
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sstream>
+#include "t_java_generator.h"
+using namespace std;
+
+/**
+ * Prepares for file generation by opening up the necessary file output
+ * streams.
+ *
+ * @param tprogram The program to generate
+ */
+void t_java_generator::init_generator(t_program* tprogram) {
+  // Make output directory
+  mkdir(T_JAVA_DIR, S_IREAD | S_IWRITE | S_IEXEC);
+}
+
+/**
+ * Packages the generated file
+ */
+string t_java_generator::java_package() {
+  // TODO(mcslee): Allow destination package to be specified in .thrift file
+  return string("package ") + program_name_ + ";\n\n";
+}
+
+/**
+ * Prints standard java imports
+ */
+string t_java_generator::java_type_imports() {
+  return
+    string() +
+    "import java.util.ArrayList;\n" +
+    "import java.util.HashMap;\n" +
+    "import java.util.HashSet;\n" +
+    "import com.facebook.thrift.*;\n" +
+    "import com.facebook.thrift.types.*;\n" +
+    "import com.facebook.thrift.protocol.TString;\n\n";
+}
+
+/**
+ * Prints standard java imports
+ */
+string t_java_generator::java_thrift_imports() {
+  return
+    string() +
+    "import com.facebook.thrift.protocol.*;\n" +
+    "import com.facebook.thrift.transport.*;\n\n";
+}
+
+/**
+ * Does nothing in Java
+ */
+void t_java_generator::close_generator() {}
+
+/**
+ * Generates a typedef. This is not done in Java.
+ *
+ * @param ttypedef The type definition
+ */
+void t_java_generator::generate_typedef(t_typedef* ttypedef) {}
+
+/**
+ * Generates code for an enumerated type. In C++, this is essentially the same
+ * as the thrift definition itself, using the enum keyword in C++.
+ *
+ * @param tenum The enumeration
+ */
+void t_java_generator::generate_enum(t_enum* tenum) {
+  // Make output file
+  string f_enum_name = string(T_JAVA_DIR)+"/"+(tenum->get_name())+".java";
+  ofstream f_enum;
+  f_enum.open(f_enum_name.c_str());
+
+  f_enum <<
+    autogen_comment() <<
+    java_package() <<
+    "import com.facebook.thrift.types.Int32;" << endl << endl;
+
+  f_enum <<
+    "public class " << tenum->get_name() << " ";
+  scope_up(f_enum);
+
+  vector<t_constant*> constants = tenum->get_constants();
+  vector<t_constant*>::iterator c_iter;
+  int value = -1;
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    if ((*c_iter)->has_value()) {
+      value = (*c_iter)->get_value();
+    } else {
+      ++value;
+    }
+
+    indent(f_enum) <<
+      "public static final Int32 " << (*c_iter)->get_name() <<
+      " = new Int32(" << value << ");" << endl;
+  }
+
+  scope_down(f_enum);
+}
+
+/**
+ * Generates a struct definition for a thrift data type. In C++, this is just
+ * simple C struct with basic data members. There are no constructors,
+ * initializers, etc.
+ *
+ * @param tstruct The struct definition
+ */
+void t_java_generator::generate_struct(t_struct* tstruct) {
+  // Make output file
+  string f_struct_name = string(T_JAVA_DIR)+"/"+(tstruct->get_name())+".java";
+  ofstream f_struct;
+  f_struct.open(f_struct_name.c_str());
+
+  f_struct <<
+    autogen_comment() <<
+    java_package() <<
+    java_type_imports();
+
+  f_struct <<
+    "public class " << tstruct->get_name() << " ";
+  
+  scope_up(f_struct);
+
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter; 
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    indent(f_struct) <<
+      "public " << declare_field(*m_iter, true) << endl;
+  }
+  
+  scope_down(f_struct);
+}
+
+/**
+ * Generates a thrift service. In C++, this comprises an entirely separate
+ * header and source file. The header file defines the methods and includes
+ * the data types defined in the main header file, and the implementation
+ * file contains implementations of the basic printer and default interfaces.
+ *
+ * @param tservice The service definition
+ */
+void t_java_generator::generate_service(t_service* tservice) {
+  // Generate the three main parts of the service
+  generate_service_interface(tservice);
+  generate_service_server(tservice);
+  generate_service_client(tservice);
+}
+
+/**
+ * Generates a service interface definition.
+ *
+ * @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;
+  indent_up();
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::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_down();
+  f_interface <<
+    "}" << endl;
+  f_interface.close();
+}
+
+/**
+ * Generates a service client definition.
+ *
+ * @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;
+  indent_up();
+
+  indent(f_service_) <<
+    "public " << service_name_ << "Client" <<
+    "(TTransport trans, TProtocol prot)" << endl;
+  scope_up(f_service_);
+  indent(f_service_) << 
+    "this(trans, trans, prot, prot);" << endl;
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  indent(f_service_) <<
+    "public " << service_name_ << "Client" <<
+    "(TTransport itrans, TTransport otrans," <<
+    " TProtocol iprot, TProtocol oprot)" << endl;
+  scope_up(f_service_);
+  f_service_ <<
+    indent() << "_itrans = itrans;" << endl <<
+    indent() << "_otrans = otrans;" << endl <<
+    indent() << "_iprot = iprot;" << endl <<
+    indent() << "_oprot = oprot;" << endl;
+  scope_down(f_service_);
+  f_service_ << endl;
+ 
+  f_service_ <<
+    indent() << "private TTransport _itrans;" << endl <<
+    indent() << "private TTransport _otrans;" << endl <<
+    indent() << "private TProtocol  _iprot;"  << endl <<
+    indent() << "private TProtocol  _oprot;"  << endl << endl;
+
+  // Generate client method implementations
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::const_iterator f_iter; 
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    string funname = (*f_iter)->get_name();
+
+    // Open function
+    indent(f_service_) <<
+      "public " << function_signature(*f_iter) << " throws TException" << 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, " <<
+      "new TString(\"" << 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());
+    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;
+
+    // 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
+    if (!(*f_iter)->get_returntype()->is_void()) {
+      indent(f_service_) <<
+        declare_field(&result_field, true) << endl;
+      result_struct.append(&result_field);
+    }
+
+    // Deserialize response struct
+    generate_deserialize_struct(&result_struct);
+
+    // Careful, only return _result if not a void function
+    if (!(*f_iter)->get_returntype()->is_void()) {
+      indent(f_service_) <<
+        "return _result;" << endl;
+    } else {
+      indent(f_service_) <<
+        "return;" << endl;
+    }
+
+    // Close function
+    scope_down(f_service_);
+    f_service_ << endl;
+  }
+
+  indent_down();
+  f_service_ <<
+    "}" << endl;
+  f_service_.close();
+}
+
+/**
+ * Generates a service server definition.
+ *
+ * @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<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter; 
+
+  // Generate the header portion
+  f_service_ <<
+    "public abstract class " << service_name_ << "ServerIf " <<
+    "extends " << service_name_ << "If implements TProcessor {" << endl;
+  indent_up();
+
+  indent(f_service_) <<
+    "public " << service_name_ << "ServerIf" <<
+    "(TProtocol prot)" << endl;
+  scope_up(f_service_);
+  indent(f_service_) << 
+    "this(prot, prot);" << endl;
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  indent(f_service_) <<
+    "public " << service_name_ << "ServerIf" <<
+    "(TProtocol iprot, TProtocol oprot)" << endl;
+  scope_up(f_service_);
+  f_service_ <<
+    indent() << "_iprot = iprot;" << endl <<
+    indent() << "_oprot = oprot;" << endl;
+  scope_down(f_service_);
+  f_service_ << endl;
+ 
+  f_service_ <<
+    indent() << "private TProtocol _iprot;" << endl <<
+    indent() << "private TProtocol _oprot;" << endl << endl;
+  
+  // Generate the server implementation
+  indent(f_service_) <<
+    "public boolean process(TTransport _itrans, TTransport _otrans) " <<
+    "throws TException" << endl;
+  scope_up(f_service_);
+
+  f_service_ <<
+    indent() <<
+    "TString _fname = new TString();" << endl <<
+    indent() <<
+    "TStruct _struct = new TStruct();" << endl <<
+    indent() <<
+    "TField _field = new TField();" << endl <<
+    indent() <<
+    "_iprot.readStructBegin(_itrans, _struct);" << endl <<
+    indent() <<
+    "_iprot.readFieldBegin(_itrans, _field);" << endl <<
+    indent() <<
+    "_iprot.readString(_itrans, _fname);" << endl <<
+    indent() <<
+    "_iprot.readFieldEnd(_itrans);" << endl <<
+    indent() <<
+    "_iprot.readFieldBegin(_itrans, _field);" << endl;
+
+  bool first = true;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    if (!first) {
+      f_service_ << " else ";
+    } else {
+      f_service_ << indent();
+      first = false;
+    }
+    f_service_ <<
+      "if (_fname.value.equals(\"" << (*f_iter)->get_name() <<"\")) {" << endl;
+    indent_up();
+    indent(f_service_) <<
+      "process_" << (*f_iter)->get_name() <<
+      "(_itrans, _otrans);" << endl;
+    indent_down();
+    indent(f_service_) << "}";
+  }
+  f_service_ <<
+    " else {" << endl;
+  indent_up();
+  indent(f_service_) <<
+    "System.err.println" <<
+    "(\"Unknown function: '\" + _field.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() <<
+    "_iprot.readFieldBegin(_itrans, _field);" << endl <<   
+    indent() <<
+    "_iprot.readStructEnd(_itrans);" << endl <<
+    indent() <<
+    "return true;" << endl;
+
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  // Generate the process subfunctions
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_process_function(tservice, *f_iter);
+  }
+
+  indent_down();
+  f_service_ <<
+    "}" << endl <<
+    endl;
+
+  f_service_.close();
+}
+
+/**
+ * Generates a process function definition.
+ *
+ * @param tfunction The function to write a dispatcher for
+ */
+void t_java_generator::generate_process_function(t_service* tservice,
+                                                 t_function* tfunction) {
+  // Open function
+  indent(f_service_) <<
+    "private void process_" << tfunction->get_name() <<
+    "(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();
+
+  // Declare the function arguments
+  const vector<t_field*>& fields = arg_struct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    indent(f_service_) <<
+      declare_field(*f_iter, true) << endl;
+  }
+
+  // Deserialize the function arguments as a struct
+  generate_deserialize_struct(arg_struct);
+  
+  // Generate the function call
+  f_service_ << indent();
+  if (!tfunction->get_returntype()->is_void()) {
+    f_service_ <<
+      type_name(tfunction->get_returntype()) << " _result = ";
+  }
+  f_service_ <<
+    tfunction->get_name() << "(";
+  bool first = true;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+    } else {
+      f_service_ << ", ";
+    }
+    f_service_ << (*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");
+
+  // Only append the field if non-void
+  if (!tfunction->get_returntype()->is_void()) {
+    result_struct.append(&result_field);
+  }
+  generate_serialize_struct(&result_struct);
+  indent(f_service_) <<
+    "_otrans.flush();" << endl;
+
+  // Close function
+  scope_down(f_service_);
+  f_service_ << endl;
+}
+
+/**
+ * Deserializes a field of any type.
+ */
+void t_java_generator::generate_deserialize_field(t_field* tfield,
+                                                 string prefix) {
+  t_type* type = tfield->get_type();
+  while (type->is_typedef()) {
+    type = ((t_typedef*)type)->get_type();
+  }
+
+  if (type->is_void()) {
+    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " +
+      prefix + tfield->get_name();
+  }
+
+  string name = prefix + tfield->get_name();
+
+  if (type->is_struct()) {
+    generate_deserialize_struct((t_struct*)(tfield->get_type()),
+                                 name + ".");
+  } else if (type->is_container()) {
+    generate_deserialize_container(tfield->get_type(), name);
+  } else if (type->is_base_type() || type->is_enum()) {
+
+    indent(f_service_) <<
+      "_iprot.";
+    
+    if (type->is_base_type()) {
+      t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+      switch (tbase) {
+      case t_base_type::TYPE_VOID:
+        throw "compiler error: cannot serialize void field in a struct: " +
+          name;
+        break;
+      case t_base_type::TYPE_STRING:        
+        f_service_ << "readString(_itrans, " << name << ");";
+        break;
+      case t_base_type::TYPE_BYTE:
+        f_service_ << "readByte(_itrans, " << name << ");";
+        break;
+      case t_base_type::TYPE_I32:
+        f_service_ << "readI32(_itrans, " << name << ");";
+        break;
+      case t_base_type::TYPE_U32:
+        f_service_ << "readU32(_itrans, " << name << ");";
+        break;
+      case t_base_type::TYPE_I64:
+        f_service_ << "readI64(_itrans, " << name << ");";
+        break;
+      case t_base_type::TYPE_U64:
+        f_service_ << "readU64(_itrans, " << name << ");";
+        break;
+      default:
+        throw "compiler error: no C++ name for base type " + tbase;
+      }
+    } else if (type->is_enum()) {
+      f_service_ << "readI32(_itrans, " << name << ");";
+    }
+    f_service_ <<
+      endl;
+  } else {
+    printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
+           tfield->get_name().c_str(), type_name(type).c_str());
+  }
+}
+
+/**
+ * Generates an unserializer for a variable. This makes two key assumptions,
+ * first that there is a const char* variable named data that points to the
+ * 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<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::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() << "TStruct " << _struct << " = new TStruct();" << endl <<
+    indent() << "TField " << _field << " = new TField();" << endl <<
+    indent() << "_iprot.readStructBegin(_itrans, " << _struct << ");" << endl;
+  
+  // Loop over reading in fields
+  indent(f_service_) <<
+    "while (true)" << endl;
+
+    scope_up(f_service_);
+    
+    // Read beginning field marker
+    indent(f_service_) <<
+      "_iprot.readFieldBegin(_itrans, " << _field << ");" << endl;
+    
+    // Check for field STOP marker and break
+    indent(f_service_) <<
+      "if (" << _field << ".type.equals(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.get())" << 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_container(t_type* ttype,
+                                                     string prefix) {
+  scope_up(f_service_);
+  
+  string obj;
+
+  if (ttype->is_map()) {
+    obj = tmp("_map");
+  } else if (ttype->is_set()) {
+    obj = tmp("_set");
+  } else if (ttype->is_list()) {
+    obj = tmp("_list");
+  }
+
+  // Declare variables, read header
+  if (ttype->is_map()) {
+    f_service_ <<
+      indent() << "TMap " << obj << " = new TMap();" << endl <<
+      indent() << "_iprot.readMapBegin(_itrans, " << obj << ");" << endl;
+  } else if (ttype->is_set()) {
+    f_service_ <<
+      indent() << "TSet " << obj << " = new TSet();" << endl <<
+      indent() << "_iprot.readSetBegin(_itrans, " << obj << ");" << endl;
+  } else if (ttype->is_list()) {
+    f_service_ <<
+      indent() << "TList " << obj << " = new TList();" << endl <<
+      indent() << "_iprot.readListBegin(_itrans, " << obj << ");" << endl;
+  }
+
+
+  // For loop iterates over elements
+  string i = tmp("_i");
+  indent(f_service_) <<
+    "for (int " << i << " = 0; " <<
+    i << " < " << obj << ".size.get()" << "; " <<
+    "++" << i << ")" << endl;
+  
+    scope_up(f_service_);
+    
+    if (ttype->is_map()) {
+      generate_deserialize_map_element((t_map*)ttype, prefix);
+    } else if (ttype->is_set()) {
+      generate_deserialize_set_element((t_set*)ttype, prefix);
+    } else if (ttype->is_list()) {
+      generate_deserialize_list_element((t_list*)ttype, prefix);
+    }
+    
+    scope_down(f_service_);
+
+  // Read container end
+  if (ttype->is_map()) {
+    indent(f_service_) << "_iprot.readMapEnd(_itrans);" << endl;
+  } else if (ttype->is_set()) {
+    indent(f_service_) << "_iprot.readSetEnd(_itrans);" << endl;
+  } else if (ttype->is_list()) {
+    indent(f_service_) << "_iprot.readListEnd(_itrans);" << endl;
+  }
+
+  scope_down(f_service_);
+}
+
+
+/**
+ * Generates code to deserialize a map
+ */
+void t_java_generator::generate_deserialize_map_element(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_) <<
+    declare_field(&fkey, true) << endl;
+  indent(f_service_) <<
+    declare_field(&fval, true) << endl;
+
+  generate_deserialize_field(&fkey);
+  generate_deserialize_field(&fval);
+
+  indent(f_service_) <<
+    prefix << ".put(" << key << ", " << val << ");" << endl;
+}
+
+void t_java_generator::generate_deserialize_set_element(t_set* tset,
+                                                        string prefix) {
+  string elem = tmp("_elem");
+  t_field felem(tset->get_elem_type(), elem);
+
+  indent(f_service_) <<
+    declare_field(&felem, true) << endl;
+
+  generate_deserialize_field(&felem);
+
+  indent(f_service_) <<
+    prefix << ".add(" << elem << ");" << endl;
+}
+
+void t_java_generator::generate_deserialize_list_element(t_list* tlist,
+                                                         string prefix) {
+  string elem = tmp("_elem");
+  t_field felem(tlist->get_elem_type(), elem);
+
+  indent(f_service_) <<
+    declare_field(&felem, true) << endl;
+
+  generate_deserialize_field(&felem);
+
+  indent(f_service_) <<
+    prefix << ".add(" << elem << ");" << endl;
+}
+
+
+/**
+ * Serializes a field of any type.
+ *
+ * @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) {
+  t_type* type = tfield->get_type();
+  while (type->is_typedef()) {
+    type = ((t_typedef*)type)->get_type();
+  }
+
+  // Do nothing for void types
+  if (type->is_void()) {
+    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " +
+      prefix + tfield->get_name();
+  }
+  
+  if (type->is_struct()) {
+    generate_serialize_struct((t_struct*)(tfield->get_type()),
+                              prefix + tfield->get_name() + ".");
+  } else if (type->is_container()) {
+    generate_serialize_container(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_) <<
+      "_oprot.";
+    
+    if (type->is_base_type()) {
+      t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+      switch (tbase) {
+      case t_base_type::TYPE_VOID:
+        throw
+          "compiler error: cannot serialize void field in a struct: " + name;
+        break;
+      case t_base_type::TYPE_STRING:
+        f_service_ << "writeString(_otrans, " << name << ");";
+        break;
+      case t_base_type::TYPE_BYTE:
+        f_service_ << "writeByte(_otrans, " << name << ");";
+        break;
+      case t_base_type::TYPE_I32:
+        f_service_ << "writeI32(_otrans, " << name << ");";
+        break;
+      case t_base_type::TYPE_U32:
+        f_service_ << "writeU32(_otrans, " << name << ");";
+        break;
+      case t_base_type::TYPE_I64:
+        f_service_ << "writeI64(_otrans, " << name << ");";
+        break;
+      case t_base_type::TYPE_U64:
+        f_service_ << "writeU64(_otrans, " << name << ");";
+        break;
+      default:
+        throw "compiler error: no C++ name for base type " + tbase;
+      }
+    } else if (type->is_enum()) {
+      f_service_ << "writeI32(_otrans, " << name << ");";
+    }
+    f_service_ << endl;
+  } else {
+    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
+           prefix.c_str(),
+           tfield->get_name().c_str(),
+           type_name(type).c_str());
+  }
+}
+
+/**
+ * Serializes all the members of a struct.
+ *
+ * @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,
+                                                 string prefix) {
+  string name = tstruct->get_name();
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::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.set(" << (*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_);
+}
+
+void t_java_generator::generate_serialize_container(t_type* ttype,
+                                                    string prefix) {
+  scope_up(f_service_);
+  
+  if (ttype->is_map()) {
+    indent(f_service_) <<
+      "_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_) <<
+      "_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_) <<
+      "_oprot.writeListBegin(_otrans, new TList(" <<
+      type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
+      prefix << ".size()));" << endl;
+  }
+
+  string iter = tmp("_iter");
+  if (ttype->is_map()) {
+    indent(f_service_) <<
+      "for (" <<
+      type_name(((t_map*)ttype)->get_key_type()) << " " << iter <<
+      " : " <<
+      prefix << ".keySet())";
+  } else if (ttype->is_set()) {
+    indent(f_service_) <<
+      "for (" <<
+      type_name(((t_set*)ttype)->get_elem_type()) << " " << iter <<
+      " : " <<
+      prefix << ")";
+  } else if (ttype->is_list()) {
+    indent(f_service_) <<
+      "for (" <<
+      type_name(((t_list*)ttype)->get_elem_type()) << " " << iter <<
+      " : " <<
+      prefix << ")";
+  }
+
+    scope_up(f_service_);
+
+    if (ttype->is_map()) {
+      generate_serialize_map_element((t_map*)ttype, iter, prefix);
+    } else if (ttype->is_set()) {
+      generate_serialize_set_element((t_set*)ttype, iter);
+    } else if (ttype->is_list()) {
+      generate_serialize_list_element((t_list*)ttype, iter);
+    }
+    
+    if (ttype->is_map()) {
+      indent(f_service_) <<
+        "_oprot.writeMapEnd(_otrans);" << endl;
+    } else if (ttype->is_set()) {
+      indent(f_service_) <<
+        "_oprot.writeSetEnd(_otrans);" << endl;
+    } else if (ttype->is_list()) {
+      indent(f_service_) <<
+        "_oprot.writeListEnd(_otrans);" << endl;
+    }
+    
+    scope_down(f_service_);
+ 
+  scope_down(f_service_);  
+}
+
+/**
+ * Serializes the members of a map.
+ *
+ */
+void t_java_generator::generate_serialize_map_element(t_map* tmap,
+                                                      string iter,
+                                                      string map) {
+  t_field kfield(tmap->get_key_type(), iter);
+  generate_serialize_field(&kfield, "");
+
+  t_field vfield(tmap->get_val_type(), map + ".get(" + iter + ")");
+  generate_serialize_field(&vfield, "");
+}
+
+/**
+ * Serializes the members of a set.
+ */
+void t_java_generator::generate_serialize_set_element(t_set* tset,
+                                                      string iter) {
+  t_field efield(tset->get_elem_type(), iter);
+  generate_serialize_field(&efield, "");
+}
+
+/**
+ * Serializes the members of a list.
+ */
+void t_java_generator::generate_serialize_list_element(t_list* tlist,
+                                                      string iter) {
+  t_field efield(tlist->get_elem_type(), iter);
+  generate_serialize_field(&efield, "");
+}
+
+/**
+ * Returns a Java type name
+ *
+ * @param ttype The type
+ */
+string t_java_generator::type_name(t_type* ttype) {
+  // In Java typedefs are just resolved to their real type
+  while (ttype->is_typedef()) {
+    ttype = ((t_typedef*)ttype)->get_type();
+  }
+
+  if (ttype->is_base_type()) {
+    return base_type_name(((t_base_type*)ttype)->get_base());
+  } else if (ttype->is_enum()) {
+    return "Int32";
+  } else if (ttype->is_map()) {
+    t_map* tmap = (t_map*) ttype;
+    return "HashMap<" +
+      type_name(tmap->get_key_type()) + "," +
+      type_name(tmap->get_val_type()) + ">";
+  } else if (ttype->is_set()) {
+    t_set* tset = (t_set*) ttype;
+    return "HashSet<" + type_name(tset->get_elem_type()) + ">";
+  } else if (ttype->is_list()) {
+    t_list* tlist = (t_list*) ttype;
+    return "ArrayList<" + type_name(tlist->get_elem_type()) + ">";
+  } else {
+    return ttype->get_name();
+  }
+}
+
+/**
+ * Returns the C++ type that corresponds to the thrift type.
+ *
+ * @param tbase The base type
+ */
+string t_java_generator::base_type_name(t_base_type::t_base tbase) {
+  switch (tbase) {
+  case t_base_type::TYPE_VOID:
+    return "void";
+  case t_base_type::TYPE_STRING:
+    return "TString";
+  case t_base_type::TYPE_BYTE:
+    return "UInt8";
+  case t_base_type::TYPE_I32:
+    return "Int32";
+  case t_base_type::TYPE_U32:
+    return "UInt32";
+  case t_base_type::TYPE_I64:
+    return "Int64";
+  case t_base_type::TYPE_U64:
+    return "UInt64";
+  default:
+    throw "compiler error: no C++ name for base type " + tbase;
+  }
+}
+
+/**
+ * Declares a field, which may include initialization as necessary.
+ *
+ * @param ttype The type
+ */
+string t_java_generator::declare_field(t_field* tfield, bool init) {
+  // TODO(mcslee): do we ever need to initialize the field?
+  string result = type_name(tfield->get_type()) + " " + tfield->get_name();
+  if (init) {
+    result += " = new " + type_name(tfield->get_type()) + "()";
+  }
+  return result + ";";
+}
+
+/**
+ * Renders a function signature of the form 'type name(args)'
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_java_generator::function_signature(t_function* tfunction,
+                                           string prefix) {
+  t_type* ttype = tfunction->get_returntype();
+  return
+    type_name(ttype) + " " + prefix + tfunction->get_name() +
+    "(" + argument_list(tfunction->get_arglist()) + ")";
+}
+
+/**
+ * Renders a field list
+ */
+string t_java_generator::argument_list(t_struct* tstruct) {
+  string result = "";
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  bool first = true;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+    } else {
+      result += ", ";
+    }
+    result += type_name((*f_iter)->get_type()) + " " + (*f_iter)->get_name();
+  }
+  return result;
+}
+
+/**
+ * Converts the parse type to a C++ enum string for the given type.
+ */
+string t_java_generator::type_to_enum(t_type* type) {
+  while (type->is_typedef()) {
+    type = ((t_typedef*)type)->get_type();
+  }
+  
+  if (type->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_VOID:
+      throw "NO T_VOID CONSTRUCT";
+    case t_base_type::TYPE_STRING:
+      return "TType.STRING";
+    case t_base_type::TYPE_BYTE:
+      return "TType.BYTE";
+    case t_base_type::TYPE_I32:
+      return "TType.I32";
+    case t_base_type::TYPE_U32:
+      return "TType.U32";
+    case t_base_type::TYPE_I64:
+      return "TType.I64";
+    case t_base_type::TYPE_U64:
+      return "TType.U64";
+    }
+  } else if (type->is_enum()) {
+    return "TType.I32";
+  } else if (type->is_struct()) {
+    return "TType.STRUCT";
+  } else if (type->is_map()) {
+    return "TType.MAP";
+  } else if (type->is_set()) {
+    return "TType.SET";
+  } else if (type->is_list()) {
+    return "TType.LIST";
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
diff --git a/compiler/src/generate/t_java_generator.h b/compiler/src/generate/t_java_generator.h
new file mode 100644
index 0000000..ae96252
--- /dev/null
+++ b/compiler/src/generate/t_java_generator.h
@@ -0,0 +1,107 @@
+#ifndef T_JAVA_GENERATOR_H
+#define T_JAVA_GENERATOR_H
+
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+
+#include "t_oop_generator.h"
+
+// TODO(mcslee: Paramaterize the output dir
+#define T_JAVA_DIR "gen-java"
+
+/**
+ * Java code generator.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+class t_java_generator : public t_oop_generator {
+ public:
+  t_java_generator() {}
+  ~t_java_generator() {}
+
+  /** Init and close methods */
+
+  void init_generator(t_program *tprogram);
+  void close_generator();
+
+  /** Program-level generation functions */
+
+  void generate_typedef (t_typedef*  ttypedef);
+  void generate_enum    (t_enum*     tenum);
+  void generate_struct  (t_struct*   tstruct);
+  void generate_service (t_service*  tservice);
+
+  /** Service-level generation functions */
+
+  void generate_service_interface (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, 
+                                          std::string prefix="");
+  
+  void generate_deserialize_struct       (t_struct*   tstruct,
+                                          std::string prefix="");
+  
+  void generate_deserialize_container    (t_type*     ttype,
+                                          std::string prefix="");
+  
+  void generate_deserialize_set_element  (t_set*      tset,
+                                          std::string prefix="");
+
+  void generate_deserialize_map_element  (t_map*      tmap,
+                                          std::string prefix="");
+
+  void generate_deserialize_list_element (t_list*     tlist,
+                                          std::string prefix="");
+
+  void generate_serialize_field          (t_field*    tfield,
+                                          std::string prefix="");
+
+  void generate_serialize_struct         (t_struct*   tstruct,
+                                          std::string prefix="");
+
+  void generate_serialize_container      (t_type*     ttype,
+                                          std::string prefix="");
+
+  void generate_serialize_map_element    (t_map*      tmap,
+                                          std::string iter,
+                                          std::string map);
+
+  void generate_serialize_set_element    (t_set*      tmap,
+                                          std::string iter);
+
+  void generate_serialize_list_element   (t_list*     tlist,
+                                          std::string iter);
+
+  /** Helper rendering functions */
+
+  std::string java_package();
+  std::string java_type_imports();
+  std::string java_thrift_imports();
+  std::string type_name(t_type* ttype);
+  std::string base_type_name(t_base_type::t_base tbase);
+  std::string declare_field(t_field* tfield, bool init=false);
+  std::string function_signature(t_function* tfunction, std::string prefix="");
+  std::string argument_list(t_struct* tstruct);
+  std::string type_to_enum(t_type* ttype);
+
+ private:
+
+  /** File streams */
+
+  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/src/generate/t_oop_generator.h b/compiler/src/generate/t_oop_generator.h
new file mode 100644
index 0000000..7b7ada1
--- /dev/null
+++ b/compiler/src/generate/t_oop_generator.h
@@ -0,0 +1,44 @@
+#ifndef T_OOP_GENERATOR_H
+#define T_OOP_GENERATOR_H
+
+#include "globals.h"
+#include "t_generator.h"
+
+/**
+ * Class with utility methods shared across common object oriented languages.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+class t_oop_generator : public t_generator {
+ public:
+
+  /** Scoping */
+
+  void scope_up(std::ostream& out) {
+    indent(out) << "{" << std::endl;
+    indent_up();
+  }
+
+  void scope_down(std::ostream& out) {
+    indent_down();
+    indent(out) << "}" << std::endl;
+  }
+
+  /**
+   * Generates a comment about this code being autogenerated.
+   *
+   * @return C-style comment mentioning that this file is autogenerated.
+   */
+  std::string autogen_comment() {
+    return
+      std::string("/**\n") +
+      " * Autogenerated by Thrift\n" +
+      " * " + g_time_str +
+      " *\n" +
+      " * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" +
+      " */\n";
+  }
+};
+
+#endif
+
diff --git a/compiler/src/main.cc b/compiler/src/main.cc
index 8d8263c..7f87368 100644
--- a/compiler/src/main.cc
+++ b/compiler/src/main.cc
@@ -19,6 +19,7 @@
 #include "main.h"
 #include "parse/t_program.h"
 #include "generate/t_cpp_generator.h"
+#include "generate/t_java_generator.h"
 
 using namespace std;
 
@@ -91,7 +92,13 @@
  * Diplays the usage message and then exits with an error code.
  */
 void usage() {
-  fprintf(stderr, "Usage: thrift [-d] <filename>\n");
+  fprintf(stderr, "Usage: thrift [options] file\n");
+  fprintf(stderr, "Options:\n");
+  fprintf(stderr, "  -cpp    Generate C++ output files\n");
+  fprintf(stderr, "  -java   Generate Java output files\n");
+  //fprintf(stderr, "  -php    Generate PHP output files\n");
+  //fprintf(stderr, "  -python Generate Python output files\n");
+  fprintf(stderr, "  -d      Print parse debugging to standard output\n");
   exit(1);
 }
 
@@ -100,23 +107,36 @@
  */
 int main(int argc, char** argv) {
   int i;
+  bool gen_cpp = false;
+  bool gen_java = false;
+
+  // Setup time string
+  time_t now = time(NULL);
+  g_time_str = ctime(&now);
 
   // Check for necessary arguments
-  if (argc < 2) usage();
+  if (argc < 2) {
+    usage();
+  }
 
   for (i = 1; i < argc-1; i++) {
     if (strcmp(argv[i], "-d") == 0) {
       g_debug = 1;
+    } else if (strcmp(argv[i], "-cpp") == 0) {
+      gen_cpp = true;
+    } else if (strcmp(argv[i], "-java") == 0) {
+      gen_java = true;
     } else {
       fprintf(stderr, "!!! Unrecognized option: %s\n", argv[i]);
       usage();
     }
   }
   
-  // Setup time string
-  time_t now = time(NULL);
-  g_time_str = ctime(&now);
-
+  if (!gen_cpp && !gen_java) {
+    fprintf(stderr, "!!! No output language(s) specified\n\n");
+    usage();
+  }
+  
   // Open input file
   char* input_file = argv[i];
   yyin = fopen(input_file, "r");
@@ -144,9 +164,18 @@
 
   // Generate code
   try {
-    t_cpp_generator* cpp = new t_cpp_generator();
-    cpp->generate_program(g_program);
-    delete cpp;
+    if (gen_cpp) {
+      t_cpp_generator* cpp = new t_cpp_generator();
+      cpp->generate_program(g_program);
+      delete cpp;
+    }
+
+    if (gen_java) {
+      t_java_generator* java = new t_java_generator();
+      java->generate_program(g_program);
+      delete java;
+    }
+
   } catch (string s) {
     printf("Error: %s\n", s.c_str());
   } catch (const char* exc) {
@@ -157,6 +186,5 @@
   delete g_program;
 
   // Finished
-  printf("\nDone!\n");
   return 0;
 }
diff --git a/compiler/src/parse/t_field.h b/compiler/src/parse/t_field.h
index 304bb16..fc38456 100644
--- a/compiler/src/parse/t_field.h
+++ b/compiler/src/parse/t_field.h
@@ -11,6 +11,9 @@
  */
 class t_field {
  public:
+  t_field(t_type* type, std::string name) :
+    type_(type), name_(name), key_(0) {}
+
   t_field(t_type* type, std::string name, uint32_t key) :
     type_(type), name_(name), key_(key) {}
 
diff --git a/compiler/src/parse/t_function.h b/compiler/src/parse/t_function.h
index 1caf54a..b248db7 100644
--- a/compiler/src/parse/t_function.h
+++ b/compiler/src/parse/t_function.h
@@ -19,29 +19,10 @@
 
   ~t_function() {}
 
-  /**
-   * Implementation of the Fowler / Noll / Vo (FNV) Hash 
-   *	http://www.isthe.com/chongo/tech/comp/fnv/
-   */
-  static uint32_t fnv32(const char *s) {
-    uint32_t hash = (uint32_t)216613626;
-    while (*s) {
-      hash +=
-        (hash << 1) +
-        (hash << 4) +
-        (hash << 7) +
-        (hash << 8) +
-        (hash << 24);
-      hash ^= *s++;
-    }
-    return hash;
-  }
-
   t_type*      get_returntype() const { return returntype_; }
   const std::string& get_name() const { return name_; }
   t_struct*    get_arglist()    const { return arglist_; }
-  uint32_t     get_hash()       const { return fnv32(name_.c_str()); }
- 
+
  private:
   t_type* returntype_;
   std::string name_;
diff --git a/compiler/src/parse/t_struct.h b/compiler/src/parse/t_struct.h
index 38eb750..6e87c8c 100644
--- a/compiler/src/parse/t_struct.h
+++ b/compiler/src/parse/t_struct.h
@@ -10,6 +10,8 @@
 class t_struct : public t_type {
  public:
   t_struct() {}
+  t_struct(const std::string& name) : t_type(name) {}
+
   ~t_struct() {}
 
   /** Set the struct name */
diff --git a/compiler/src/thrift.l b/compiler/src/thrift.l
index 61a0ce3..33cbda8 100644
--- a/compiler/src/thrift.l
+++ b/compiler/src/thrift.l
@@ -49,7 +49,6 @@
 
 "typedef"     { return tok_typedef;  }
 "struct"      { return tok_struct;   }
-"function"    { return tok_function; }
 "service"     { return tok_service;  }
 "enum"        { return tok_enum;     }
 
diff --git a/compiler/src/thrift.y b/compiler/src/thrift.y
index a406c8e..269d163 100644
--- a/compiler/src/thrift.y
+++ b/compiler/src/thrift.y
@@ -56,7 +56,6 @@
 /** Thrift actions */
 %token tok_typedef
 %token tok_struct
-%token tok_function
 %token tok_service
 %token tok_enum
 
@@ -213,6 +212,7 @@
 Function:
   FunctionType FunctionModifiers tok_identifier '(' FieldList ')'
     {
+      $5->set_name(std::string($3) + "_args");
       $$ = new t_function($1, $3, $5);
       y_field_val = 0;
     }