2014.04.23 追記
scala.util.parsing.json.JSONを使わずに他のライブラリを使おう!
Json4s を使ってみた - kakakakakku blog
背景
Scala で JSON をパースするときに標準で入ってる scala.util.parsing.json.JSON オブジェクトの parseFull を使うと,Int値が自動的にDouble値になるみたいなので調べてみたところ,仕様だったって話.
デフォルトで使ってみる
Int値とDouble値をもった JSON をパースすると Option[Any] で返ってきて,Int値が 10000.0 になってしまう.
import scala.util.parsing.json.JSON object MyJsonParser extends App { val json = """{"name": "kakakakakku", "intval": 10000, "doubleval": 1234.5}""" println(JSON.parseFull(json)) }
Some(Map(name -> kakakakakku, intval -> 10000.0, doubleval -> 1234.5))
Scaladoc を見てみた
Scala Standard Library API (Scaladoc) 2.10.4 を見てみると,
The default conversion for numerics is into a double. と書いてあって,カスタマイズしたかったら globalNumberParser をオーバライドしてと書いてあった.
This object provides a simple interface to the JSON parser class. The default conversion for numerics is into a double. If you wish to override this behavior at the global level, you can set the globalNumberParser property to your own (String => Any) function. If you only want to override at the per-thread level then you can set the perThreadNumberParser property to your function.
globalNumberParser をオーバライドする
globalNumberParser をオーバライドして実行してみると,同じく Option[Any] で返ってきて,Int値は 10000 になる.これで使える感じになった.
import scala.util.parsing.json.JSON object MyJsonParser extends App { val json = """{"name": "kakakakakku", "intval": 10000, "doubleval": 1234.5}""" JSON.globalNumberParser = { input => try { input.toInt } catch { case e => input.toDouble } } println(JSON.parseFull(json)) }
Some(Map(name -> kakakakakku, intval -> 10000, doubleval -> 1234.5))
ちなみに,JSON にDouble値が入らないことが前提になってるような場合であれば,以下の書き方でも良いけど,もしDouble値が入ってると java.lang.NumberFormatException が出るので注意すること.
JSON.globalNumberParser = { input => Integer.parseInt(input) }
関連エントリー
Usage of globalNumberParser of scala.util.parsing.json.JSON
Is it possible to make Scala's JSON.parseFull() not to treat Integers as Decimals? - Stack Overflow
xawa雑記帳: [Scala] JSON の扱い
xawa雑記帳: [Scala] JSON の標準パーサーで数値型が Double になる問題への対処方法