Add support for .equals() to Java structs.

- Add a new method to t_java_generator that generates a .equals() method.
- Add a correct but useless implementation of hashCode for structs.
  (This is required by conventino when overriding .equals().)
- Add java_package to DebugProtoTest and OptionalRequiredTest.
- Add a new structure to OptionalRequiredTest to assist testing the behavior
  of .equals() with respect to null and unset fields.
- Clean up test/java/build.xml a bit.  (It still has a ways to go.)
- Add EqualityTest.java to test .equals().
- Add IdentityTest.java to test that writing and reading a structure
  preserves equality.

Tested by runnint atn test.
I also looked at the generated code for OptionalRequiredTest.thrift.


git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@665541 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/test/java/src/IdentityTest.java b/test/java/src/IdentityTest.java
new file mode 100644
index 0000000..3f64ef7
--- /dev/null
+++ b/test/java/src/IdentityTest.java
@@ -0,0 +1,158 @@
+package com.facebook.thrift.test;
+
+// Generated code
+import thrift.test.*;
+
+import com.facebook.thrift.TSerializer;
+import com.facebook.thrift.TDeserializer;
+import com.facebook.thrift.protocol.TBinaryProtocol;
+import com.facebook.thrift.protocol.TSimpleJSONProtocol;
+
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.List;
+import java.util.ArrayList;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+/**
+ *
+ * @author David Reiss <dreiss@facebook.com>
+ */
+public class IdentityTest {
+  public static Object deepCopy(Object oldObj) throws Exception {
+    ObjectOutputStream oos = null;
+    ObjectInputStream ois = null;
+    try {
+      ByteArrayOutputStream bos =
+        new ByteArrayOutputStream();
+      oos = new ObjectOutputStream(bos);
+      oos.writeObject(oldObj);
+      oos.flush();
+      ByteArrayInputStream bis =
+        new ByteArrayInputStream(bos.toByteArray());
+      ois = new ObjectInputStream(bis);
+      return ois.readObject();
+    } finally {
+      oos.close();
+      ois.close();
+    }
+  }
+
+  public static void main(String[] args) throws Exception {
+    TSerializer   binarySerializer   = new   TSerializer(new TBinaryProtocol.Factory());
+    TDeserializer binaryDeserializer = new TDeserializer(new TBinaryProtocol.Factory());
+
+    OneOfEach ooe = new OneOfEach();
+    ooe.im_true   = true;
+    ooe.im_false  = false;
+    ooe.a_bite    = (byte)0xd6;
+    ooe.integer16 = 27000;
+    ooe.integer32 = 1<<24;
+    ooe.integer64 = (long)6000 * 1000 * 1000;
+    ooe.double_precision = Math.PI;
+    ooe.some_characters  = "JSON THIS! \"\u0001";
+    ooe.base64 = new byte[]{1,2,3,(byte)255};
+
+    Nesting n = new Nesting();
+    n.my_ooe = (OneOfEach)deepCopy(ooe);
+    n.my_ooe.integer16 = 16;
+    n.my_ooe.integer32 = 32;
+    n.my_ooe.integer64 = 64;
+    n.my_ooe.double_precision = (Math.sqrt(5)+1)/2;
+    n.my_ooe.some_characters  = ":R (me going \"rrrr\")";
+    n.my_ooe.zomg_unicode     = "\u04c0\u216e\u039d\u0020\u041d\u03bf\u217f"+
+                                "\u043e\u0261\u0433\u0430\u03c1\u210e\u0020"+
+                                "\u0391\u0074\u0074\u03b1\u217d\u03ba\u01c3"+
+                                "\u203c";
+    n.my_bonk = new Bonk();
+    n.my_bonk.type    = 31337;
+    n.my_bonk.message = "I am a bonk... xor!";
+
+    HolyMoley hm = new HolyMoley();
+    hm.big = new ArrayList<OneOfEach>();
+    hm.contain = new HashSet<List<String>>();
+    hm.bonks = new HashMap<String,List<Bonk>>();
+
+    hm.big.add((OneOfEach)deepCopy(ooe));
+    hm.big.add((OneOfEach)deepCopy(n.my_ooe));
+    hm.big.get(0).a_bite = 0x22;
+    hm.big.get(1).a_bite = 0x33;
+
+    List<String> stage1 = new ArrayList<String>();
+    stage1.add("and a one");
+    stage1.add("and a two");
+    hm.contain.add(stage1);
+    stage1 = new ArrayList<String>();
+    stage1.add("then a one, two");
+    stage1.add("three!");
+    stage1.add("FOUR!!");
+    hm.contain.add(stage1);
+    stage1 = new ArrayList<String>();
+    hm.contain.add(stage1);
+
+    List<Bonk> stage2 = new ArrayList<Bonk>();
+    hm.bonks.put("nothing", stage2);
+    stage2.add(new Bonk());
+    stage2.get(0).type = 1;
+    stage2.get(0).message = "Wait.";
+    stage2.add(new Bonk());
+    stage2.get(1).type = 2;
+    stage2.get(1).message = "What?";
+    hm.bonks.put("something", stage2);
+    stage2 = new ArrayList<Bonk>();
+    stage2.add(new Bonk());
+    stage2.get(0).type = 3;
+    stage2.get(0).message = "quoth";
+    stage2.add(new Bonk());
+    stage2.get(1).type = 4;
+    stage2.get(1).message = "the raven";
+    stage2.add(new Bonk());
+    stage2.get(2).type = 5;
+    stage2.get(2).message = "nevermore";
+    hm.bonks.put("poe", stage2);
+
+    OneOfEach ooe2 = new OneOfEach();
+    binaryDeserializer.deserialize(
+        ooe2,
+        binarySerializer.serialize(ooe));
+
+    if (!ooe.equals(ooe2)) {
+      throw new RuntimeException("Failure: ooe (equals)");
+    }
+    if (ooe.hashCode() != ooe2.hashCode()) {
+      throw new RuntimeException("Failure: ooe (hash)");
+    }
+
+
+    Nesting n2 = new Nesting();
+    binaryDeserializer.deserialize(
+        n2,
+        binarySerializer.serialize(n));
+
+    if (!n.equals(n2)) {
+      throw new RuntimeException("Failure: n (equals)");
+    }
+    if (n.hashCode() != n2.hashCode()) {
+      throw new RuntimeException("Failure: n (hash)");
+    }
+
+    HolyMoley hm2 = new HolyMoley();
+    binaryDeserializer.deserialize(
+        hm2,
+        binarySerializer.serialize(hm));
+
+    if (!hm.equals(hm2)) {
+      throw new RuntimeException("Failure: hm (equals)");
+    }
+    if (hm.hashCode() != hm2.hashCode()) {
+      throw new RuntimeException("Failure: hm (hash)");
+    }
+
+  }
+}