発生した問題
JavaScriptでは64bitの整数を扱うことができない。
32bitの範囲を超えた数値は64bitの浮動小数点型に変換されるが、整数として精度を保てるのは53bitまでとなる。
このため整数として53bitを超える精度が必要な場合には何らかの対処が必要となる。
kotlinでGsonを使ってWeb-APIを作成していた際に、この問題に突き当たった。
DBレコードのIDを64bit整数として設計していたためだ。
解決方法
val gson = GsonBuilder().setLongSerializationPolicy(LongSerializationPolicy.SRING)
以下古い情報(コメントで指摘をいただき、実は簡単に設定できました。)
Gsonには型ごとにどのようにJSONとして書くか、または読み取るかを設定する機能がある。
この機能を使い、Long型は無条件で文字列に変換して返すことでこの問題を回避した。
クライアント側で64bit整数に対する計算が発生する場合はこれだけでは済まないが今回は計算は不要であった。
Long型を文字列型に変換できるように設定する例
private val gson = with(GsonBuilder()) {
registerTypeAdapter(Long::class.javaObjectType, object: TypeAdapter<Long>() {
override fun write(out: JsonWriter?, value: Long?) {
out ?: throw IllegalStateException()
out.value(value?.toString() ?: "")
}
override fun read(r: JsonReader?): Long? {
r ?: throw IllegalStateException()
return r.nextLong()
}
})
create()
}
write()関数を改造すれば、53bitの精度に収まる範囲であれば整数型のまま返すことや、逆に53bitを超える場合はエラーにするいったことも可能だ。