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 になる問題への対処方法