diff options
author | Brendan Ribera <brendan.ribera@gmail.com> | 2016-09-20 11:07:42 -0700 |
---|---|---|
committer | Bo Yang <teboring@google.com> | 2016-09-22 00:18:12 +0000 |
commit | 525c6327ab45c60bcd7804804eb0dd74c0ba86fe (patch) | |
tree | 627e8798224149cb9640f84c79e7b46df6e5fff0 /ruby/src | |
parent | b8e7e892c805c0e3b41238549af2d94a4c2403d3 (diff) | |
download | protobuf-525c6327ab45c60bcd7804804eb0dd74c0ba86fe.tar.gz protobuf-525c6327ab45c60bcd7804804eb0dd74c0ba86fe.tar.bz2 protobuf-525c6327ab45c60bcd7804804eb0dd74c0ba86fe.zip |
Fix hash computation for JRuby's RubyMessage
`System.identityHashCode` returns a hash that does not consider a
Message's values. This means two Messages with identical values will not
have identical hashCodes.
This patch uses the pattern from RubyMap to combine the hashCodes from
all values in a given message and produce a unique, consistent,
value-based hash.
Diffstat (limited to 'ruby/src')
-rw-r--r-- | ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java | 19 |
1 files changed, 17 insertions, 2 deletions
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java index 462f8a69..733ccfbc 100644 --- a/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java +++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java @@ -41,6 +41,8 @@ import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import org.jruby.util.ByteList; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.HashMap; import java.util.Map; @@ -164,8 +166,21 @@ public class RubyMessage extends RubyObject { */ @JRubyMethod public IRubyObject hash(ThreadContext context) { - int hashCode = System.identityHashCode(this); - return context.runtime.newFixnum(hashCode); + try { + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + for (RubyMap map : maps.values()) { + digest.update((byte) map.hashCode()); + } + for (RubyRepeatedField repeatedField : repeatedFields.values()) { + digest.update((byte) repeatedFields.hashCode()); + } + for (IRubyObject field : fields.values()) { + digest.update((byte) field.hashCode()); + } + return context.runtime.newString(new ByteList(digest.digest())); + } catch (NoSuchAlgorithmException ignore) { + return context.runtime.newFixnum(System.identityHashCode(this)); + } } /* |