在Json4s中,为什么JSON对象中的整数字段会自动转换为String?

时间:2017-02-02 19:30:03

标签: json scala json4s

如果我有一个JSON对象,如:

{
  "test": 3
}

然后我希望提取"测试"作为字符串的字段将失败,因为类型不排队:

import org.json4s._
import org.json4s.jackson.JsonMethods
import org.json4s.JsonAST.JValue

def getVal[T: Manifest](json: JValue, fieldName: String): Option[T] = {
  val field = json findField {
    case JField(name, _) if name == fieldName => true
    case _ => false
  }

  field.map {
    case (_, value) => value.extract[T]
  }
}

val json = JsonMethods.parse("""{"test":3}""")
val value: Option[String] = getVal[String](json, "test") // Was Some(3) but expected None

这是从JSON数字自动转换为Json4s中预期的字符串吗?如果是这样,是否有任何解决方法,其中提取的字段必须与extract方法的type参数中指定的类型相同?

2 个答案:

答案 0 :(得分:1)

这是大多数(如果不是全部)解析器的默认属性。如果您请求类型为T的值,并且该值可以安全地转换为该特定类型,那么库将为您投射它。例如,看看typesafe配置,其类似性质是将Numeric字段转换为String。

import com.typesafe.config._
val config = ConfigFactory parseString """{ test = 3 }"""
val res1 = config.getString("test")
res1: String = 3

如果你不想自动将Integer / Boolean强制转换为String,你可以手动检查Int / Boolean类型,如下所示。

if(Try(value.extract[Int]).isFailure || Try(value.extract[Boolean]).isFailure) {
    throw RuntimeException(s"not a String field. try Int or Boolean")
} else {
 value.extract[T]
}

答案 1 :(得分:0)

一个简单的解决方法是为需要“严格”行为的情况创建自定义序列化程序。例如:

  import org.json4s._

  val stringSerializer = new CustomSerializer[String](_ => (
    {
      case JString(s) => s
      case JNull      => null
      case x          => throw new MappingException("Can't convert %s to String." format x)
    },
    {
      case s: String => JString(s)
    }
  ))

将此序列化器添加到隐式格式中可确保严格的行为:

  implicit val formats = DefaultFormats + stringSerializer

  val js = JInt(123)
  val str = js.extract[String] // throws MappingException