0.7以降のmsgpack-javaを使って古いフォーマットでシリアライズする方法

こんにちは、chaltosです。

今回は、msgpack-javaのバージョンを0.6.Xから上げたいが0.6.Xと同じフォーマットでシリアライズしたい場合の対処についてです。

MessagePackとは何なのかといった部分は省略させていただきます。

ひとことで

0.8.5以降のバージョンでorg.msgpack.core.MessagePack.PackerConfig.withStr8FormatSupport(false)しましょう。

str8

MessagePackは2013年に仕様が変わったようで、それまでRaw bytesだった文字列のtypeがStringに変わりました。

それに伴いシリアライズのフォーマットもfix raw, raw16, raw32からfixstr, str8, str16, str32に変わりました。

それぞれのフォーマットは以下のようになっています。

* Raw bytes
** fix raw
   +--------+========+
   |101XXXXX|  data  |
   +--------+========+
** raw16
   +--------+--------+--------+========+
   |  0xda  |ZZZZZZZZ|ZZZZZZZZ|  data  |
   +--------+--------+--------+========+
** raw32
   +--------+--------+--------+--------+--------+========+
   |  0xdb  |AAAAAAAA|AAAAAAAA|AAAAAAAA|AAAAAAAA|  data  |
   +--------+--------+--------+--------+--------+========+

* String
** fixstr
   +--------+========+
   |101XXXXX|  data  |
   +--------+========+
** str8
   +--------+--------+========+
   |  0xd9  |YYYYYYYY|  data  |
   +--------+--------+========+
** str16
   +--------+--------+--------+========+
   |  0xda  |ZZZZZZZZ|ZZZZZZZZ|  data  |
   +--------+--------+--------+========+
** str32
   +--------+--------+--------+--------+--------+========+
   |  0xdb  |AAAAAAAA|AAAAAAAA|AAAAAAAA|AAAAAAAA|  data  |
   +--------+--------+--------+--------+--------+========+

# XXXXX is a 5-bit unsigned integer which represents N
# YYYYYYYY is a 8-bit unsigned integer which represents N
# ZZZZZZZZ_ZZZZZZZZ is a 16-bit big-endian unsigned integer which represents N
# AAAAAAAA_AAAAAAAA_AAAAAAAA_AAAAAAAA is a 32-bit big-endian unsigned integer which represents N
# N is the length of data

だいたい同じなんですが、データサイズが32 ~ 255バイトの場合はシリアライズした結果が異なってしまいます。

scala> import org.msgpack.MessagePack
import org.msgpack.MessagePack

scala> val mp = new MessagePack
mp: org.msgpack.MessagePack = org.msgpack.MessagePack@33d4ae0c

scala> mp.write("a"*31)
res0: Array[Byte] = Array(-65, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97)

scala> mp.write("a"*32)
res1: Array[Byte] = Array(-38, 0, 32, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97)

scala> mp.write("a"*255)
res2: Array[Byte] = Array(-38, 0, -1, 97, 97, 97, ..., 97)

scala> mp.write("a"*256)
res3: Array[Byte] = Array(-38, 1, 0, 97, 97, 97, ..., 97, 97)
scala> import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.ObjectMapper

scala> import org.msgpack.jackson.dataformat.MessagePackFactory
import org.msgpack.jackson.dataformat.MessagePackFactory

scala> import org.msgpack.core.MessagePack
import org.msgpack.core.MessagePack

scala> val config = new MessagePack.PackerConfig()
config: org.msgpack.core.MessagePack.PackerConfig = org.msgpack.core.MessagePack$PackerConfig@164be01

scala> val objMapper = new ObjectMapper(new MessagePackFactory(config))
objMapper: com.fasterxml.jackson.databind.ObjectMapper = com.fasterxml.jackson.databind.ObjectMapper@6e5a587a

scala> objMapper.writeValueAsBytes("a"*31)
res0: Array[Byte] = Array(-65, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97)

scala> objMapper.writeValueAsBytes("a"*32)
res1: Array[Byte] = Array(-39, 32, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97)

scala> objMapper.writeValueAsBytes("a"*255)
res2: Array[Byte] = Array(-39, -1, 97, 97, 97, .., 97)

scala> objMapper.writeValueAsBytes("a"*256)
res3: Array[Byte] = Array(-38, 1, 0, 97, 97, 97, ..., 97, 97)

PackerConfig.withStr8FormatSupport

名前のとおり、str8フォーマットについての設定です。0.8.5で追加されました。

これの引数にfalseを渡すとstr8を使用しなくなります。

scala> val configForOldFormat = new MessagePack.PackerConfig().withStr8FormatSupport(false)
configForOldFormat: org.msgpack.core.MessagePack.PackerConfig = org.msgpack.core.MessagePack$PackerConfig@164be00

scala> val objMapperForOldFormat = new ObjectMapper(new MessagePackFactory(configForOldFormat))
objMapperForOldFormat: com.fasterxml.jackson.databind.ObjectMapper = com.fasterxml.jackson.databind.ObjectMapper@3054da79

scala> objMapperForOldFormat.writeValueAsBytes("a"*32)
res4: Array[Byte] = Array(-38, 0, 32, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97)

scala> objMapperForOldFormat.writeValueAsBytes("a"*255)
res5: Array[Byte] = Array(-38, 0, -1, 97, 97, 97, ..., 97)