diff options
author | Brendan Ribera <brendan.ribera@gmail.com> | 2016-09-20 11:07:42 -0700 |
---|---|---|
committer | Brendan Ribera <brendan.ribera@gmail.com> | 2016-09-20 11:07:42 -0700 |
commit | 05aa0df532b263bdfca1ac3f8493db7022950239 (patch) | |
tree | d6d4948e6a219ded90acd026045bec379bd2eb85 /ruby | |
parent | 7b00595ddf8622ae429ef37de8ea2f44b6333ad0 (diff) |
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')
-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)); + } } /* |