MessagePack for JavaをJRubyで使う
こんにちは。那由多屋の加藤です。
データシリアライズ形式である「MessagePack」をGAE/JRubyで使いたいのですが、Pure Rubyな実装は存在しないようです。
そこでMessagePack for Javaを使うことを試みたのですが・・・疲れました。
JavaとRubyとのデータ変換が思ったよりも大変そうです。とりあえずスキーマを指定すれば、まあまあ動作するようにはなりました。コードはgistに上げておきます。
誰か続きを作ってくれないかなー。
msgpack-for-java.rb
module MessagePack def self.pack(obj, schema = nil) ostream = java.io.ByteArrayOutputStream.new packer = org.msgpack.Packer.new(ostream) value = self.ruby_to_java(obj) if schema packer.packWithSchema(value, org.msgpack.Schema.parse(schema)) else packer.pack(value) end bytes = ostream.toByteArray return bytes.to_a.pack("c*") end def self.unpack(binary, schema = nil) bytes = binary.unpack("c*").to_java(:byte) istream = java.io.ByteArrayInputStream.new(bytes) unpacker = org.msgpack.Unpacker.new(istream) unpacker.useSchema(org.msgpack.Schema.parse(schema)) if schema iterator = unpacker.iterator value = iterator.next return self.java_to_ruby(value) end def self.ruby_to_java(obj) case obj when Fixnum then return java.lang.Long.new(obj) when Array return java.util.ArrayList.new(obj.map { |item| self.ruby_to_java(item) }) when Hash return obj.inject({}) { |memo, (key, value)| memo[self.ruby_to_java(key)] = self.ruby_to_java(value) memo } else return obj end end def self.java_to_ruby(value) if value.java_kind_of?(java.util.HashMap) return Hash[value.map { |key, value| [self.java_to_ruby(key), self.java_to_ruby(value)] }] else if value.respond_to?(:getClass) case value.getClass.getName when "java.util.Arrays$ArrayList" then return value.to_a else return value end else return value end end end end