Index: test/DebugProtoTest.thrift
===================================================================
--- test/DebugProtoTest.thrift	(revision 765026)
+++ test/DebugProtoTest.thrift	(working copy)
@@ -250,4 +250,12 @@
 
 service ReverseOrderService {
   void myMethod(4: string first, 3: i16 second, 2: i32 third, 1: i64 fourth);
+}
+
+union TestUnion {
+  1: string string_field;
+  2: i32 i32_field;
+  3: OneOfEach struct_field;
+  4: list<RandomStuff> struct_list;
+  5: i32 other_i32_field;
 }
\ No newline at end of file
Index: lib/java/test/org/apache/thrift/test/UnionTest.java
===================================================================
--- lib/java/test/org/apache/thrift/test/UnionTest.java	(revision 0)
+++ lib/java/test/org/apache/thrift/test/UnionTest.java	(revision 0)
@@ -0,0 +1,94 @@
+package org.apache.thrift.test;
+
+import org.apache.thrift.TUnion;
+import org.apache.thrift.protocol.TBinaryProtocol;
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.transport.TMemoryBuffer;
+
+import thrift.test.TestUnion;
+
+public class UnionTest {
+
+  /**
+   * @param args
+   */
+  public static void main(String[] args) throws Exception {
+    testBasic();
+    testEquality();    
+    testSerialization();
+  }
+  
+  public static void testBasic() throws Exception {
+    TestUnion union = new TestUnion();
+
+    if (union.isSet()) {
+      throw new RuntimeException("new union with default constructor counts as set!");
+    }
+    
+    if (union.getFieldValue() != null) {
+      throw new RuntimeException("unset union didn't return null for value");
+    }
+    
+    union = new TestUnion(TestUnion.I32_FIELD, 25);
+    
+    if ((Integer)union.getFieldValue() != 25) {
+      throw new RuntimeException("set i32 field didn't come out as planned");
+    }
+    
+    if ((Integer)union.getFieldValue(TestUnion.I32_FIELD) != 25) {
+      throw new RuntimeException("set i32 field didn't come out of TBase getFieldValue");
+    }
+    
+    try {
+      union.getFieldValue(TestUnion.STRING_FIELD);
+      throw new RuntimeException("was expecting an exception around wrong set field");
+    } catch (IllegalArgumentException e) {
+      // cool!
+    }
+    
+    System.out.println(union);
+    
+    // TODO: test field-named getters and setters
+  }
+ 
+  
+  public static void testEquality() throws Exception {
+    TestUnion union = new TestUnion(TestUnion.I32_FIELD, 25);
+    
+    TestUnion otherUnion = new TestUnion(TestUnion.STRING_FIELD, "blah!!!");
+    
+    if (union.equals(otherUnion)) {
+      throw new RuntimeException("shouldn't be equal");
+    }
+    
+    otherUnion = new TestUnion(TestUnion.I32_FIELD, 400);
+    
+    if (union.equals(otherUnion)) {
+      throw new RuntimeException("shouldn't be equal");
+    }
+    
+    otherUnion = new TestUnion(TestUnion.OTHER_I32_FIELD, 25);
+    
+    if (union.equals(otherUnion)) {
+      throw new RuntimeException("shouldn't be equal");
+    }
+  }
+
+
+  public static void testSerialization() throws Exception {
+    TestUnion union = new TestUnion(TestUnion.I32_FIELD, 25);
+    
+    TMemoryBuffer buf = new TMemoryBuffer(0);
+    TProtocol proto = new TBinaryProtocol(buf);
+    
+    union.write(proto);
+    
+    TestUnion u2 = new TestUnion();
+    
+    u2.read(proto);
+    
+    if (!u2.equals(union)) {
+      throw new RuntimeException("serialization fails!");
+    }    
+  }
+}
Index: lib/java/src/org/apache/thrift/TUnion.java
===================================================================
--- lib/java/src/org/apache/thrift/TUnion.java	(revision 0)
+++ lib/java/src/org/apache/thrift/TUnion.java	(revision 0)
@@ -0,0 +1,105 @@
+package org.apache.thrift;
+
+import org.apache.thrift.protocol.TField;
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.protocol.TStruct;
+
+public abstract class TUnion implements TBase {
+
+  protected Object value_;
+  protected short setField_;
+  
+  protected TUnion() {
+    setField_ = 0;
+    value_ = null;
+  }
+  
+  protected TUnion(int setField, Object value) {
+    checkType((short)setField, value);
+    setField_ = (short)setField;
+    value_ = value;
+  }
+  
+  public short getSetField() {
+    return setField_;
+  }
+  
+  public Object getFieldValue() {
+    return value_;
+  }
+  
+  public Object getFieldValue(int fieldId) {
+    if (fieldId != setField_) {
+      throw new IllegalArgumentException("Cannot get the value of field " + fieldId + " because union's set field is " + setField_);
+    }
+    
+    return getFieldValue();
+  }
+
+  public boolean isSet() {
+    return setField_ != 0;
+  }
+  
+  public boolean isSet(int fieldId) {
+    return setField_ == fieldId;
+  }
+
+  public void read(TProtocol iprot) throws TException {
+    setField_ = 0;
+    value_ = null;
+
+    iprot.readStructBegin();
+
+    TField field = iprot.readFieldBegin();
+
+    value_ = readValue(iprot, field);
+    if (value_ != null) {
+      setField_ = field.id;
+    }    
+
+    iprot.readFieldEnd();
+    iprot.readStructEnd();    
+  }
+
+  public void setFieldValue(int fieldId, Object value) {
+    checkType((short)fieldId, value);
+    setField_ = (short)fieldId;
+    value_ = value;
+  }
+
+  // TODO: throw exception when trying to write an "unset" union
+  public void write(TProtocol oprot) throws TException {
+    oprot.writeStructBegin(getStructDesc());
+    oprot.writeFieldBegin(getFieldDesc(setField_));
+    writeValue(oprot, setField_, value_);
+    oprot.writeFieldEnd();
+    oprot.writeStructEnd();
+  }
+
+  /**
+   * Implementation should be generated so that we can efficiently type check 
+   * various values.
+   * @param setField
+   * @param value
+   */
+  protected abstract void checkType(short setField, Object value) throws ClassCastException;
+  
+  /**
+   * Implementation should be generated to read the right stuff from the wire 
+   * based on the field header. 
+   * @param field
+   * @return
+   */
+  protected abstract Object readValue(TProtocol iprot, TField field) throws TException;
+  
+  protected abstract void writeValue(TProtocol oprot, short setField, Object value) throws TException;
+  
+  protected abstract TStruct getStructDesc();
+  
+  protected abstract TField getFieldDesc(short setField);
+  
+  @Override
+  public String toString() {
+    return "<" + this.getClass().getSimpleName() + " " + getFieldDesc(getSetField()).name + ":" + getFieldValue().toString() + ">";
+  }
+}
Index: lib/java/src/org/apache/thrift/TBase.java
===================================================================
--- lib/java/src/org/apache/thrift/TBase.java	(revision 765026)
+++ lib/java/src/org/apache/thrift/TBase.java	(working copy)
@@ -19,13 +19,15 @@
 
 package org.apache.thrift;
 
+import java.io.Serializable;
+
 import org.apache.thrift.protocol.TProtocol;
 
 /**
  * Generic base interface for generated Thrift objects.
  *
  */
-public interface TBase extends Cloneable {
+public interface TBase extends Cloneable, Serializable {
 
   /**
    * Reads the TObject from the given input protocol.
Index: lib/java/build.xml
===================================================================
--- lib/java/build.xml	(revision 765026)
+++ lib/java/build.xml	(working copy)
@@ -107,6 +107,8 @@
       classpath="${cpath}:${build.test}" failonerror="true" />
     <java classname="org.apache.thrift.test.JavaBeansTest"
       classpath="${cpath}:${build.test}" failonerror="true" />
+    <java classname="org.apache.thrift.test.UnionTest"
+      classpath="${cpath}:${build.test}" failonerror="true" />
   </target>
 
   <target name="generate">
Index: compiler/cpp/src/thriftl.ll
===================================================================
--- compiler/cpp/src/thriftl.ll	(revision 765026)
+++ compiler/cpp/src/thriftl.ll	(working copy)
@@ -119,6 +119,7 @@
 "oneway"             { return tok_oneway;               }
 "typedef"            { return tok_typedef;              }
 "struct"             { return tok_struct;               }
+"union"              { return tok_union;                }
 "exception"          { return tok_xception;             }
 "extends"            { return tok_extends;              }
 "throws"             { return tok_throws;               }
@@ -196,7 +197,6 @@
 "volatile"           { thrift_reserved_keyword(yytext); }
 "while"              { thrift_reserved_keyword(yytext); }
 "with"               { thrift_reserved_keyword(yytext); }
-"union"              { thrift_reserved_keyword(yytext); }
 "yield"              { thrift_reserved_keyword(yytext); }
 
 {intconstant} {
Index: compiler/cpp/src/thrifty.yy
===================================================================
--- compiler/cpp/src/thrifty.yy	(revision 765026)
+++ compiler/cpp/src/thrifty.yy	(working copy)
@@ -148,6 +148,7 @@
 %token tok_const
 %token tok_required
 %token tok_optional
+%token tok_union
 
 /**
  * Grammar nodes
@@ -195,6 +196,7 @@
 %type<tstruct>   Struct
 %type<tstruct>   Xception
 %type<tservice>  Service
+%type<tstruct>   Union
 
 %type<tfunction> Function
 %type<ttype>     FunctionType
@@ -469,6 +471,13 @@
         g_program->add_struct($1);
       }
     }
+| Union
+    {
+      pdebug("TypeDefinition -> Union");
+      if (g_parse_mode == PROGRAM) {
+        g_program->add_union($1);
+      }
+    }
 | Xception
     {
       pdebug("TypeDefinition -> Xception");
@@ -691,6 +700,20 @@
       }
     }
 
+Union:
+  tok_union tok_identifier XsdAll '{' FieldList '}' TypeAnnotations
+    {
+      pdebug("Union -> tok_union tok_identifier { FieldList }");
+      $5->set_xsd_all($3);
+      $5->set_union(true);
+      $$ = $5;
+      $$->set_name($2);
+      if ($7 != NULL) {
+        $$->annotations_ = $7->annotations_;
+        delete $7;
+      }
+    }
+    
 XsdAll:
   tok_xsd_all
     {
Index: compiler/cpp/src/generate/t_generator.cc
===================================================================
--- compiler/cpp/src/generate/t_generator.cc	(revision 765026)
+++ compiler/cpp/src/generate/t_generator.cc	(working copy)
@@ -49,12 +49,14 @@
   vector<t_const*> consts = program_->get_consts();
   generate_consts(consts);
 
-  // Generate structs and exceptions in declared order
+  // Generate structs, exceptions, and unions in declared order
   vector<t_struct*> objects = program_->get_objects();
   vector<t_struct*>::iterator o_iter;
   for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) {
     if ((*o_iter)->is_xception()) {
       generate_xception(*o_iter);
+    } else if ((*o_iter)->is_union()) {
+      generate_union(*o_iter);
     } else {
       generate_struct(*o_iter);
     }
Index: compiler/cpp/src/generate/t_java_generator.cc
===================================================================
--- compiler/cpp/src/generate/t_java_generator.cc	(revision 765026)
+++ compiler/cpp/src/generate/t_java_generator.cc	(working copy)
@@ -74,6 +74,7 @@
   void generate_typedef (t_typedef*  ttypedef);
   void generate_enum    (t_enum*     tenum);
   void generate_struct  (t_struct*   tstruct);
+  void generate_union   (t_struct*   tunion);
   void generate_xception(t_struct*   txception);
   void generate_service (t_service*  tservice);
 
@@ -114,6 +115,19 @@
   void generate_service_server    (t_service* tservice);
   void generate_process_function  (t_service* tservice, t_function* tfunction);
 
+  void generate_java_union(t_struct* tstruct);
+  void generate_union_constructor(ofstream& out, t_struct* tstruct);
+  void generate_union_getters_and_setters(ofstream& out, t_struct* tstruct);
+  void generate_union_abstract_methods(ofstream& out, t_struct* tstruct);
+  void generate_check_type(ofstream& out, t_struct* tstruct);
+  void generate_read_value(ofstream& out, t_struct* tstruct);
+  void generate_write_value(ofstream& out, t_struct* tstruct);
+  void generate_get_field_desc(ofstream& out, t_struct* tstruct);
+  void generate_get_struct_desc(ofstream& out, t_struct* tstruct);
+  void generate_get_field_name(ofstream& out, t_struct* tstruct);
+
+  void generate_union_comparisons(ofstream& out, t_struct* tstruct);
+
   /**
    * Serialization constructs
    */
@@ -183,14 +197,17 @@
   std::string java_package();
   std::string java_type_imports();
   std::string java_thrift_imports();
-  std::string type_name(t_type* ttype, bool in_container=false, bool in_init=false);
+  std::string type_name(t_type* ttype, bool in_container=false, bool in_init=false, bool skip_generic=false);
   std::string base_type_name(t_base_type* tbase, bool in_container=false);
   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);
   std::string get_enum_class_name(t_type* type);
-
+  void generate_struct_desc(ofstream& out, t_struct* tstruct);
+  void generate_field_descs(ofstream& out, t_struct* tstruct);
+  void generate_field_name_constants(ofstream& out, t_struct* tstruct);
+  
   bool type_can_be_null(t_type* ttype) {
     ttype = get_true_type(ttype);
 
@@ -565,8 +582,8 @@
 }
 
 /**
- * Generates a struct definition for a thrift data type. This is a class
- * with data members, read(), write(), and an inner Isset class.
+ * Generates a struct definition for a thrift data type. This will be a TBase 
+ * implementor.
  *
  * @param tstruct The struct definition
  */
@@ -575,6 +592,16 @@
 }
 
 /**
+ * Generates a union definition for a thrift data type. The class will inherit
+ * from TUnion.
+ *
+ * @param tstruct The struct definition
+ */
+void t_java_generator::generate_union(t_struct* tstruct) {
+  generate_java_union(tstruct);
+}
+
+/**
  * Exceptions are structs, but they inherit from Exception
  *
  * @param tstruct The struct definition
@@ -609,6 +636,288 @@
 }
 
 /**
+ * Java union definition.
+ *
+ * @param tstruct The struct definition
+ */
+void t_java_generator::generate_java_union(t_struct* tstruct) {
+  // Make output file
+  string f_struct_name = package_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() <<
+    java_thrift_imports();
+
+  generate_java_doc(f_struct, tstruct);
+
+  bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end());
+
+  indent(f_struct) <<
+    "public " << (is_final ? "final " : "") << "class " << tstruct->get_name() 
+    << " extends TUnion ";
+
+  scope_up(f_struct);
+
+  generate_struct_desc(f_struct, tstruct);
+  generate_field_descs(f_struct, tstruct);
+
+  f_struct << endl;
+
+  generate_field_name_constants(f_struct, tstruct);
+
+  f_struct << endl;
+
+  generate_union_constructor(f_struct, tstruct);
+
+  f_struct << endl;
+
+  generate_union_abstract_methods(f_struct, tstruct);
+
+  f_struct << endl;
+
+  generate_union_getters_and_setters(f_struct, tstruct);
+  
+  f_struct << endl;
+
+  generate_union_comparisons(f_struct, tstruct);
+
+  scope_down(f_struct);
+
+  f_struct.close();
+}
+
+void t_java_generator::generate_union_constructor(ofstream& out, t_struct* tstruct) {
+  indent(out) << "public " << type_name(tstruct) << "() {" << endl;
+  indent(out) << "  super();" << endl;
+  indent(out) << "}" << endl << endl;
+  
+  indent(out) << "public " << type_name(tstruct) << "(int setField, Object value) {" << endl;
+  indent(out) << "  super(setField, value);" << endl;
+  indent(out) << "}" << endl;
+}
+
+void t_java_generator::generate_union_getters_and_setters(ofstream& out, t_struct* tstruct) {
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+  
+  bool first = true;
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    if (first) {
+      first = false;
+    } else {
+      out << endl;
+    }
+
+    t_field* field = (*m_iter);
+
+    indent(out) << "public " << type_name(field->get_type()) << " get" << get_cap_name(field->get_name()) << "() {" << endl;
+    indent(out) << "  if (getSetField() == " << upcase_string(field->get_name()) << ") {" << endl;
+    indent(out) << "    return (" << type_name(field->get_type(), true) << ")getFieldValue();" << endl;
+    indent(out) << "  } else {" << endl;
+    indent(out) << "    throw new RuntimeException(\"Cannot get field '" << field->get_name() 
+      << "' because union is currently set to \" + getFieldDesc(getSetField()).name);" << endl;
+    indent(out) << "  }" << endl;
+    indent(out) << "}" << endl;
+    
+    out << endl;
+    
+    indent(out) << "public void set" << get_cap_name(field->get_name()) << "(" << type_name(field->get_type()) << " value) {" << endl;
+    if (type_can_be_null(field->get_type())) {
+      indent(out) << "  if (value == null) throw new NullPointerException();" << endl;
+    }
+    indent(out) << "  setField_ = (short)" << field->get_key() << ";" << endl;
+    indent(out) << "  value_ = value;" << endl;
+    indent(out) << "}";
+    
+  }
+}
+
+void t_java_generator::generate_union_abstract_methods(ofstream& out, t_struct* tstruct) {
+  generate_check_type(out, tstruct);
+  out << endl;
+  generate_read_value(out, tstruct);
+  out << endl;
+  generate_write_value(out, tstruct);
+  out << endl;
+  generate_get_field_desc(out, tstruct);
+  out << endl;
+  generate_get_struct_desc(out, tstruct);
+}
+
+void t_java_generator::generate_check_type(ofstream& out, t_struct* tstruct) {
+  indent(out) << "@Override" << endl;
+  indent(out) << "protected void checkType(short setField, Object value) throws ClassCastException {" << endl;
+  indent_up();
+
+  indent(out) << "switch (setField) {" << endl;
+  indent_up();
+
+  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) {
+    t_field* field = (*m_iter);
+    
+    indent(out) << "case " << upcase_string(field->get_name()) << ":" << endl;
+    indent(out) << "  if (value instanceof " << type_name(field->get_type(), true, false, true) << ") {" << endl;
+    indent(out) << "    break;" << endl;
+    indent(out) << "  }" << endl;
+    indent(out) << "  throw new ClassCastException(\"Was expecting value of type " 
+      << type_name(field->get_type(), true, false) << " for field '" << field->get_name() 
+      << "', but got \" + value.getClass().getSimpleName());" << endl;
+    // do the real check here
+  }
+  
+  indent(out) << "default:" << endl;
+  indent(out) << "  throw new IllegalArgumentException(\"Unknown field id \" + setField);" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl;
+  
+  indent_down();
+  indent(out) << "}" << endl;
+}
+
+void t_java_generator::generate_read_value(ofstream& out, t_struct* tstruct) {
+  indent(out) << "@Override" << endl;
+  indent(out) << "protected Object readValue(TProtocol iprot, TField field) throws TException {" << endl;
+
+  indent_up();
+
+  indent(out) << "switch (field.id) {" << endl;
+  indent_up();
+
+  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) {
+    t_field* field = (*m_iter);
+    
+    indent(out) << "case " << upcase_string(field->get_name()) << ":" << endl;
+    indent_up();
+    indent(out) << "if (field.type == " << upcase_string(field->get_name()) << "_FIELD_DESC.type) {" << endl;
+    indent_up();
+    indent(out) << type_name(field->get_type(), true, false) << " " << field->get_name() << ";" << endl;
+    generate_deserialize_field(out, field, "");
+    indent(out) << "return " << field->get_name() << ";" << endl;
+    indent_down();
+    indent(out) << "} else {" << endl;
+    indent(out) << "  TProtocolUtil.skip(iprot, field.type);" << endl;
+    indent(out) << "  return null;" << endl;
+    indent(out) << "}" << endl;
+    indent_down();
+  }
+  
+  indent(out) << "default:" << endl;
+  indent(out) << "  TProtocolUtil.skip(iprot, field.type);" << endl;
+  indent(out) << "  return null;" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl;
+}
+
+void t_java_generator::generate_write_value(ofstream& out, t_struct* tstruct) {
+  indent(out) << "@Override" << endl;
+  indent(out) << "protected void writeValue(TProtocol oprot, short setField, Object value) throws TException {" << endl;
+
+  indent_up();
+
+  indent(out) << "switch (setField) {" << endl;
+  indent_up();
+
+  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) {
+    t_field* field = (*m_iter);
+    
+    indent(out) << "case " << upcase_string(field->get_name()) << ":" << endl;
+    indent_up();
+    indent(out) << type_name(field->get_type(), true, false) << " " << field->get_name() 
+      << " = (" <<  type_name(field->get_type(), true, false) << ")getFieldValue();" << endl;
+    generate_serialize_field(out, field, "");
+    indent(out) << "return;" << endl;
+    indent_down();
+  }
+  
+  indent(out) << "default:" << endl;
+  indent(out) << "  throw new IllegalStateException(\"Cannot write union with unknown field \" + setField);" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl;
+
+  indent_down();
+
+
+
+  indent(out) << "}" << endl;
+}
+
+void t_java_generator::generate_get_field_desc(ofstream& out, t_struct* tstruct) {
+  indent(out) << "@Override" << endl;
+  indent(out) << "protected TField getFieldDesc(short setField) {" << endl;
+  indent_up();
+  
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  indent(out) << "switch (setField) {" << endl;
+  indent_up();
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_field* field = (*m_iter);
+    indent(out) << "case " << upcase_string(field->get_name()) << ":" << endl;
+    indent(out) << "  return " << upcase_string(field->get_name()) << "_FIELD_DESC;" << endl;
+  }
+
+  indent(out) << "default:" << endl;
+  indent(out) << "  throw new IllegalArgumentException(\"Unknown field id \" + setField);" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl;
+}
+
+void t_java_generator::generate_get_struct_desc(ofstream& out, t_struct* tstruct) {
+  indent(out) << "@Override" << endl;
+  indent(out) << "protected TStruct getStructDesc() {" << endl;
+  indent(out) << "  return STRUCT_DESC;" << endl;
+  indent(out) << "}" << endl;
+}
+
+void t_java_generator::generate_union_comparisons(ofstream& out, t_struct* tstruct) {
+  // equality
+  indent(out) << "public boolean equals(Object other) {" << endl;
+  indent(out) << "  if (other instanceof " << tstruct->get_name() << ") {" << endl;
+  indent(out) << "    return equals((" << tstruct->get_name() << ")other);" << endl;
+  indent(out) << "  } else {" << endl;
+  indent(out) << "    return false;" << endl;
+  indent(out) << "  }" << endl;
+  indent(out) << "}" << endl;
+  out << endl;
+  
+  indent(out) << "public boolean equals(" << tstruct->get_name() << " other) {" << endl;
+  indent(out) << "  return getSetField() == other.getSetField() && getFieldValue() == other.getFieldValue();" << endl;
+  indent(out) << "}" << endl;
+  out << endl;
+  
+  // compareto - currently not needed
+  // indent(out) << "public int compareTo(Object other) {" << endl;
+  // indent(out) << "  return 0;" << endl;
+  // indent(out) << "}" << endl;
+  out << endl;
+}
+
+/**
  * Java struct definition. This has various parameters, as it could be
  * generated standalone or inside another class as a helper. If it
  * is a helper than it is a static class.
@@ -638,21 +947,14 @@
 
   scope_up(out);
 
-  indent(out) <<
-    "private static final TStruct STRUCT_DESC = new TStruct(\"" << tstruct->get_name() << "\");" << endl;
+  generate_struct_desc(out, tstruct);
 
   // Members are public for -java, private for -javabean
   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(out) <<
-      "private static final TField " << constant_name((*m_iter)->get_name()) <<
-      "_FIELD_DESC = new TField(\"" << (*m_iter)->get_name() << "\", " <<
-      type_to_enum((*m_iter)->get_type()) << ", " <<
-      "(short)" << (*m_iter)->get_key() << ");" << endl;
-  }
-
+  generate_field_descs(out, tstruct);
+  
   out << endl;
 
   for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
@@ -663,9 +965,9 @@
       indent(out) << "public ";
     }
     out << declare_field(*m_iter, false) << endl;
+  }
 
-    indent(out) << "public static final int " << upcase_string((*m_iter)->get_name()) << " = " << (*m_iter)->get_key() << ";" << endl;
-  }
+  generate_field_name_constants(out, tstruct);
   
   // Inner Isset class
   if (members.size() > 0) {
@@ -2584,7 +2886,7 @@
  * @param container Is the type going inside a container?
  * @return Java type name, i.e. HashMap<Key,Value>
  */
-string t_java_generator::type_name(t_type* ttype, bool in_container, bool in_init) {
+string t_java_generator::type_name(t_type* ttype, bool in_container, bool in_init, bool skip_generic) {
   // In Java typedefs are just resolved to their real type
   ttype = get_true_type(ttype);
   string prefix;
@@ -2600,25 +2902,25 @@
     } else {
       prefix = "Map";
     }
-    return prefix + "<" +
+    return prefix + (skip_generic ? "" : "<" +
       type_name(tmap->get_key_type(), true) + "," +
-      type_name(tmap->get_val_type(), true) + ">";
+      type_name(tmap->get_val_type(), true) + ">");
   } else if (ttype->is_set()) {
     t_set* tset = (t_set*) ttype;
     if (in_init) {
-      prefix = "HashSet<";
+      prefix = "HashSet";
     } else {
-      prefix = "Set<";
+      prefix = "Set";
     }
-    return prefix + type_name(tset->get_elem_type(), true) + ">";
+    return prefix + (skip_generic ? "" : "<" + type_name(tset->get_elem_type(), true) + ">");
   } else if (ttype->is_list()) {
     t_list* tlist = (t_list*) ttype;
     if (in_init) {
-      prefix = "ArrayList<";
+      prefix = "ArrayList";
     } else {
-      prefix = "List<";
+      prefix = "List";
     }
-    return prefix + type_name(tlist->get_elem_type(), true) + ">";
+    return prefix + (skip_generic ? "" : "<" + type_name(tlist->get_elem_type(), true) + ">");
   }
 
   // Check for namespacing
@@ -3001,8 +3303,37 @@
   return package + type->get_name();
 }
 
+void t_java_generator::generate_struct_desc(ofstream& out, t_struct* tstruct) {
+  indent(out) <<
+    "private static final TStruct STRUCT_DESC = new TStruct(\"" << tstruct->get_name() << "\");" << endl;
+}
+
+void t_java_generator::generate_field_descs(ofstream& out, t_struct* tstruct) {
+  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(out) <<
+      "private static final TField " << constant_name((*m_iter)->get_name()) <<
+      "_FIELD_DESC = new TField(\"" << (*m_iter)->get_name() << "\", " <<
+      type_to_enum((*m_iter)->get_type()) << ", " <<
+      "(short)" << (*m_iter)->get_key() << ");" << endl;
+  }
+}
+
+void t_java_generator::generate_field_name_constants(ofstream& out, t_struct* tstruct) {
+  // Members are public for -java, private for -javabean
+  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(out) << "public static final int " << upcase_string((*m_iter)->get_name()) << " = " << (*m_iter)->get_key() << ";" << endl;
+  }
+}
+
 THRIFT_REGISTER_GENERATOR(java, "Java",
 "    beans:           Generate bean-style output files.\n"
 "    nocamel:         Do not use CamelCase field accessors with beans.\n"
 "    hashcode:        Generate quality hashCode methods.\n"
 );
+
Index: compiler/cpp/src/generate/t_generator.h
===================================================================
--- compiler/cpp/src/generate/t_generator.h	(revision 765026)
+++ compiler/cpp/src/generate/t_generator.h	(working copy)
@@ -93,6 +93,7 @@
   virtual void generate_enum     (t_enum*     tenum)     = 0;
   virtual void generate_const    (t_const*    tconst) {}
   virtual void generate_struct   (t_struct*   tstruct)   = 0;
+  virtual void generate_union    (t_struct*   tstruct) {printf("Your language generator does not support unions!\n");}
   virtual void generate_service  (t_service*  tservice)  = 0;
   virtual void generate_xception (t_struct*   txception) {
     // By default exceptions are the same as structs
Index: compiler/cpp/src/parse/t_program.h
===================================================================
--- compiler/cpp/src/parse/t_program.h	(revision 765026)
+++ compiler/cpp/src/parse/t_program.h	(working copy)
@@ -90,6 +90,7 @@
   const std::vector<t_enum*>&    get_enums()     const { return enums_;     }
   const std::vector<t_const*>&   get_consts()    const { return consts_;    }
   const std::vector<t_struct*>&  get_structs()   const { return structs_;   }
+  const std::vector<t_struct*>&  get_unions()    const { return unions_;    }
   const std::vector<t_struct*>&  get_xceptions() const { return xceptions_; }
   const std::vector<t_struct*>&  get_objects()   const { return objects_;   }
   const std::vector<t_service*>& get_services()  const { return services_;  }
@@ -100,6 +101,9 @@
   void add_const    (t_const*   tc) { consts_.push_back(tc);    }
   void add_struct   (t_struct*  ts) { objects_.push_back(ts);
                                       structs_.push_back(ts);   }
+  void add_union    (t_struct*  ts) { objects_.push_back(ts);
+                                      unions_.push_back(ts);   }
+  
   void add_xception (t_struct*  tx) { objects_.push_back(tx);
                                       xceptions_.push_back(tx); }
   void add_service  (t_service* ts) { services_.push_back(ts);  }
@@ -208,6 +212,7 @@
   std::vector<t_enum*>    enums_;
   std::vector<t_const*>   consts_;
   std::vector<t_struct*>  objects_;
+  std::vector<t_struct*>  unions_;
   std::vector<t_struct*>  structs_;
   std::vector<t_struct*>  xceptions_;
   std::vector<t_service*> services_;
Index: compiler/cpp/src/parse/t_struct.h
===================================================================
--- compiler/cpp/src/parse/t_struct.h	(revision 765026)
+++ compiler/cpp/src/parse/t_struct.h	(working copy)
@@ -58,6 +58,10 @@
     is_xception_ = is_xception;
   }
 
+  void set_union(bool is_union) {
+    is_union_ = is_union;
+  }
+
   void set_xsd_all(bool xsd_all) {
     xsd_all_ = xsd_all;
   }
@@ -89,12 +93,16 @@
   }
 
   bool is_struct() const {
-    return !is_xception_;
+    return !(is_xception_ || is_union_);
   }
 
   bool is_xception() const {
     return is_xception_;
   }
+  
+  bool is_union() const {
+    return is_union_;
+  }
 
   virtual std::string get_fingerprint_material() const {
     std::string rv = "{";
@@ -120,6 +128,7 @@
   members_type members_;
   members_type members_in_id_order_;
   bool is_xception_;
+  bool is_union_;
 
   bool xsd_all_;
 };
