Emit equals and hashcode for auto-generated Java code.

Test: hidl_test_java
Bug: 32834072

Change-Id: I660852b7d76f79d41b93c9986e4c1188c02ba4a6
diff --git a/CompoundType.cpp b/CompoundType.cpp
index 5f3dd5a..6527f86 100644
--- a/CompoundType.cpp
+++ b/CompoundType.cpp
@@ -16,6 +16,7 @@
 
 #include "CompoundType.h"
 
+#include "ArrayType.h"
 #include "VectorType.h"
 #include <hidl-util/Formatter.h>
 #include <android-base/logging.h>
@@ -489,6 +490,50 @@
         out << "\n";
     }
 
+    ////////////////////////////////////////////////////////////////////////////
+
+    if (canCheckEquality()) {
+        out << "public final boolean equals(" << localName() << " other) ";
+        out.block([&] {
+            for (const auto &field : *mFields) {
+                std::string condition = field->type().isScalar()
+                    ? "this." + field->name() + " != other." + field->name()
+                    : ("!java.util.Objects.deepEquals(this." + field->name()
+                            + ", other." + field->name() + ")");
+                out.sIf(condition, [&] {
+                    out << "return false;\n";
+                }).endl();
+            }
+            out << "return true;\n";
+        }).endl().endl();
+
+        out << "public final int hashCode() ";
+        out.block([&] {
+            out << "return java.util.Objects.hash(";
+            bool first = true;
+            for (const auto &field : *mFields) {
+                if (!first) {
+                    out << ", ";
+                }
+                first = false;
+                if (field->type().isArray()) {
+                    const ArrayType &type = static_cast<const ArrayType &>(field->type());
+                    if (type.countDimensions() == 1 &&
+                        type.getElementType()->resolveToScalarType() != nullptr) {
+                        out << "java.util.Arrays.hashCode(this." << field->name() << ")";
+                    } else {
+                        out << "java.util.Arrays.deepHashCode(this." << field->name() << ")";
+                    }
+                } else {
+                    out << "this." << field->name();
+                }
+            }
+            out << ");\n";
+        }).endl().endl();
+    }
+
+    ////////////////////////////////////////////////////////////////////////////
+
     out << "public final void readFromParcel(android.os.HwParcel parcel) {\n";
     out.indent();
     out << "android.os.HwBlob blob = parcel.readBuffer();\n";