Search code examples
ruby-on-railsrubyjruby

Using Java's MessageDigest class with JRuby


I am trying to use Java's message digest class to calculate an md5 hash for a large amount of files, inside of my rails application. I have written some code in a ruby script with JRuby, but the call to Files.readAllBytes() gives me "undefined method `getFileSystem' for #". Here is the method I've written in ruby:

def calculate_md5_java(zip)
  require 'java'
  import java.security.MessageDigest
  import java.nio.file.Files
  import javax.xml.bind.DatatypeConverter
  import java.nio.file.FileSystems

  md = MessageDigest.getInstance("MD5")

  FileUtils.cp(zip, "GODPLEASELETTHISWORK.zip")

  Zip::File.open("GODPLEASELETTHISWORK.zip") do |z|
    z.each do |entry|
      md.update(Files.readAllBytes(entry.get_input_stream))
    end
  end

  digest = md.digest()
  DatatypeConverter.printHexBinary(digest).toLowerCase()
end

I've also tried changing my argument to

 md.update(entry.get_input_stream.read.bytes.to_a)

Which gives me:

no method 'update' for arguments (org.jruby.RubyArray) on Java::JavaSecurity::MessageDigest::Delegate available overloads: (byte) (java.nio.ByteBuffer) (byte[])

Solution

  • I created a java File object based off of the files being passed into here and then passed File.toPath into readAllBytes. readAllBytes doesn't want a string path, but the Path object.

    def calculate_md5_java(xmls)
      require 'java'
      import java.security.MessageDigest
      import java.nio.file.Files
      import javax.xml.bind.DatatypeConverter
      import java.nio.file.FileSystems
      import java.io.ByteArrayOutputStream
      import java.io.DataOutputStream
    
      md = MessageDigest.getInstance("MD5")
      baos = ByteArrayOutputStream.new
      out = DataOutputStream.new(baos)
    
      xmls = Hash[xmls.sort_by { |k,v| k.tr(':', '-').to_s }]
      xmls.values.each do |xml|
        xml_file = java.io.File.new(xml.path)
        md.update(Files.readAllBytes(xml_file.toPath()))
      end
    
      digest = md.digest()
      md5 = DatatypeConverter.printHexBinary(digest)
      md5.downcase!
    end