diff options
Diffstat (limited to 'java/src/main/java/com/google/protobuf/AbstractMessage.java')
-rw-r--r-- | java/src/main/java/com/google/protobuf/AbstractMessage.java | 60 |
1 files changed, 58 insertions, 2 deletions
diff --git a/java/src/main/java/com/google/protobuf/AbstractMessage.java b/java/src/main/java/com/google/protobuf/AbstractMessage.java index fb416bdc..b9d83016 100644 --- a/java/src/main/java/com/google/protobuf/AbstractMessage.java +++ b/java/src/main/java/com/google/protobuf/AbstractMessage.java @@ -32,9 +32,10 @@ package com.google.protobuf; import com.google.protobuf.Descriptors.Descriptor; import com.google.protobuf.Descriptors.FieldDescriptor; +import com.google.protobuf.Internal.EnumLite; -import java.io.InputStream; import java.io.IOException; +import java.io.InputStream; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -167,11 +168,66 @@ public abstract class AbstractMessage extends AbstractMessageLite public int hashCode() { int hash = 41; hash = (19 * hash) + getDescriptorForType().hashCode(); - hash = (53 * hash) + getAllFields().hashCode(); + hash = hashFields(hash, getAllFields()); hash = (29 * hash) + getUnknownFields().hashCode(); return hash; } + /** Get a hash code for given fields and values, using the given seed. */ + @SuppressWarnings("unchecked") + protected int hashFields(int hash, Map<FieldDescriptor, Object> map) { + for (Map.Entry<FieldDescriptor, Object> entry : map.entrySet()) { + FieldDescriptor field = entry.getKey(); + Object value = entry.getValue(); + hash = (37 * hash) + field.getNumber(); + if (field.getType() != FieldDescriptor.Type.ENUM){ + hash = (53 * hash) + value.hashCode(); + } else if (field.isRepeated()) { + List<? extends EnumLite> list = (List<? extends EnumLite>) value; + hash = (53 * hash) + hashEnumList(list); + } else { + hash = (53 * hash) + hashEnum((EnumLite) value); + } + } + return hash; + } + + /** + * Helper method for implementing {@link Message#hashCode()}. + * @see Boolean#hashCode() + */ + protected static int hashLong(long n) { + return (int) (n ^ (n >>> 32)); + } + + /** + * Helper method for implementing {@link Message#hashCode()}. + * @see Boolean#hashCode() + */ + protected static int hashBoolean(boolean b) { + return b ? 1231 : 1237; + } + + /** + * Helper method for implementing {@link Message#hashCode()}. + * <p> + * This is needed because {@link java.lang.Enum#hashCode()} is final, but we + * need to use the field number as the hash code to ensure compatibility + * between statically and dynamically generated enum objects. + */ + protected static int hashEnum(EnumLite e) { + return e.getNumber(); + } + + /** Helper method for implementing {@link Message#hashCode()}. */ + protected static int hashEnumList(List<? extends EnumLite> list) { + int hash = 1; + for (EnumLite e : list) { + hash = 31 * hash + hashEnum(e); + } + return hash; + } + // ================================================================= /** |