add Metadata.hashCode
diff --git a/src/com/google/enterprise/adaptor/Metadata.java b/src/com/google/enterprise/adaptor/Metadata.java
index bd17db2..f0d154f 100644
--- a/src/com/google/enterprise/adaptor/Metadata.java
+++ b/src/com/google/enterprise/adaptor/Metadata.java
@@ -192,6 +192,7 @@
   }
 
   /** True if exactly the same key-values are represented. */
+  @Override
   public boolean equals(Object o) {
     if (!(o instanceof Metadata)) {
       return false;
@@ -203,6 +204,11 @@
     return mappings.equals(other.mappings);
   }
 
+  @Override
+  public int hashCode() {
+    return mappings.hashCode();
+  }
+
   /** True with 0 entries. */
   public boolean isEmpty() {
     return mappings.isEmpty();
diff --git a/test/com/google/enterprise/adaptor/MetadataTest.java b/test/com/google/enterprise/adaptor/MetadataTest.java
index f915c7f..fd3fcea 100644
--- a/test/com/google/enterprise/adaptor/MetadataTest.java
+++ b/test/com/google/enterprise/adaptor/MetadataTest.java
@@ -360,6 +360,35 @@
   }
 
   @Test
+  public void testHashCode() {
+    Metadata m1 = new Metadata();
+    m1.add("foo", "home");
+    Metadata m2 = new Metadata();
+    m2.add("foo", "home");
+    assertEquals(m1.hashCode(), m2.hashCode());
+
+    m1.add("foo", "bar");
+    m2.add("foo", "bar");
+    assertEquals(m1.hashCode(), m2.hashCode());
+
+    m1.set("foo", "high");
+    m2.set("foo", "low");
+    assertFalse(m1.hashCode() == m2.hashCode());
+
+    m2.set("foo", "high");
+    assertEquals(m1.hashCode(), m2.hashCode());
+
+    m1.set("bar", makeSet("floor", "door"));
+    m2.set("bar", makeSet("floor", "door"));
+    assertEquals(m1.hashCode(), m2.hashCode());
+
+    m1.set("bar", makeSet("near", "far"));
+    assertFalse(m1.hashCode() == m2.hashCode());
+    m2.set("bar", makeSet("near", "far"));
+    assertEquals(m1.hashCode(), m2.hashCode());
+  }
+
+  @Test
   public void testUnmodifiableSetSingle() {
     Metadata m = new Metadata().unmodifiableView();
     thrown.expect(UnsupportedOperationException.class);