Generate quality overrides of hashCode for Thrift structs (in Java).

This feature is turned off by default because it adds a new dependency:
Apache Commons Lang.  This package seems enough like Boost that
I would be open to turning this feature on by default.

Also updated test/java/build.xml to use this new option.
ant test still passes.


git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@665542 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/compiler/cpp/src/generate/t_java_generator.cc b/compiler/cpp/src/generate/t_java_generator.cc
index 4b255b1..8d478ce 100644
--- a/compiler/cpp/src/generate/t_java_generator.cc
+++ b/compiler/cpp/src/generate/t_java_generator.cc
@@ -36,6 +36,9 @@
     iter = parsed_options.find("beans");
     bean_style_ = (iter != parsed_options.end());
 
+    iter = parsed_options.find("hashcode");
+    gen_hash_code_ = (iter != parsed_options.end());
+
     out_dir_base_ = (bean_style_ ? "gen-javabean" : "gen-java");
   }
 
@@ -177,6 +180,7 @@
   std::string package_dir_;
 
   bool bean_style_;
+  bool gen_hash_code_;
 
 };
 
@@ -226,6 +230,11 @@
  * @return List of imports for Java types that are used in here
  */
 string t_java_generator::java_type_imports() {
+  string hash_builder;
+  if (gen_hash_code_) {
+    hash_builder = "import org.apache.commons.lang.builder.HashCodeBuilder;\n";
+  }
+
   return
     string() +
     "import java.util.List;\n" +
@@ -234,6 +243,7 @@
     "import java.util.HashMap;\n" +
     "import java.util.Set;\n" +
     "import java.util.HashSet;\n" +
+    hash_builder +
     "import com.facebook.thrift.*;\n\n";
 }
 
@@ -708,13 +718,54 @@
   scope_down(out);
   out << endl;
 
-  out <<
-    indent() << "public int hashCode() {" << endl;
-  indent_up();
-  out <<
-    indent() << "return 0;" << endl;
-  scope_down(out);
-  out << endl;
+  if (gen_hash_code_) {
+    out <<
+      indent() << "public int hashCode() {" << endl;
+    indent_up();
+
+    out <<
+      indent() << "HashCodeBuilder builder = new HashCodeBuilder();" << endl;
+
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      out << endl;
+
+      t_type* t = get_true_type((*m_iter)->get_type());
+      bool is_optional = (*m_iter)->get_req() == t_field::T_OPTIONAL;
+      bool can_be_null = type_can_be_null(t);
+      string name = (*m_iter)->get_name();
+
+      string present = "true";
+
+      if (is_optional) {
+        present += " && (__isset." + name + ")";
+      }
+      if (can_be_null) {
+        present += " && (" + name + " != null)";
+      }
+
+      out <<
+        indent() << "boolean present_" << name << " = "
+                 << present << ";" << endl <<
+        indent() << "builder.append(present_" << name << ");" << endl <<
+        indent() << "if (present_" << name << ")" << endl <<
+        indent() << "  builder.append(" << name << ");" << endl;
+    }
+
+    out << endl;
+    out <<
+      indent() << "return builder.toHashCode();" << endl;
+    scope_down(out);
+    out << endl;
+
+  } else {
+    out <<
+      indent() << "public int hashCode() {" << endl;
+    indent_up();
+    out <<
+      indent() << "return 0;" << endl;
+    scope_down(out);
+    out << endl;
+  }
 }
 
 /**
@@ -2291,4 +2342,5 @@
 
 THRIFT_REGISTER_GENERATOR(java, "Java",
 "    beans:           Generate bean-style output files.\n"
+" hashcode:           Generate quality hashCode methods.\n"
 );
diff --git a/test/java/build.xml b/test/java/build.xml
index 68d7b98..7eed8c3 100644
--- a/test/java/build.xml
+++ b/test/java/build.xml
@@ -5,7 +5,7 @@
   <property name="src" location="src" />
   <property name="gen" location="gen-java" />
   <property name="build" location="build" />
-  <property name="cpath" location="../../lib/java/libthrift.jar" />
+  <property name="cpath" location="../../lib/java/libthrift.jar:/usr/share/java/commons-lang-2.3.jar" />
 
   <target name="init">
     <tstamp />
@@ -14,13 +14,13 @@
 
   <target name="generate">
     <exec executable="../../compiler/cpp/thrift">
-      <arg line="--gen java ../ThriftTest.thrift" />
+      <arg line="--gen java:hashcode ../ThriftTest.thrift" />
     </exec>
     <exec executable="../../compiler/cpp/thrift">
-      <arg line="--gen java ../DebugProtoTest.thrift" />
+      <arg line="--gen java:hashcode ../DebugProtoTest.thrift" />
     </exec>
     <exec executable="../../compiler/cpp/thrift">
-      <arg line="--gen java ../OptionalRequiredTest.thrift" />
+      <arg line="--gen java:hashcode ../OptionalRequiredTest.thrift" />
     </exec>
   </target>