我只是通过使用 Jackson JSON 反序列化破坏了 JAVA 类型安全吗?

Did I just break JVM type safety by using Jackson JSON deserialisation?

这是我得到的:

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.scala.DefaultScalaModuleobject 

AppStart extends App {
  val mapper = new ObjectMapper()
  mapper.registerModule(DefaultScalaModule)

  val json = """{"id":"AB","stuff":"whatever"}"""
  val obj = mapper.readValue(json, classOf[TestClass])

  println(obj.id.get) // prints AB !!!
}

case class TestClass(id: Option[Int] = None, stuff: Option[String] = None)

同时,这连构建都没有:

val bad: Option[Int] = "AB"

这里显然有问题。我在项目中使用的版本:

scalaVersion := "2.11.6"

libraryDependencies += "com.fasterxml.jackson.module" % "jackson-module-scala_2.11" % "2.7.3"

您需要查看 class Scala 生成的字节码。

我的猜测是反射仍然有效,但是该字段的运行时类型不是它在 Scala 中出现的类型,因此 JVM 不会阻止这种情况的发生。

不,这不会破坏 JVM 类型安全。 JVM 不支持泛型,就其而言id 的类型是Option,而不是Option[Int]。要破坏类型安全,你必须得到一个 TestClassid 不是 Option.

反射和转换肯定会破坏 Java 和 Scala 的类型安全,而且它们应该会。

要在 Jackson 中正确反序列化泛型,您需要提供额外信息(参见 http://wiki.fasterxml.com/JacksonFAQ#Deserializing_Generic_types)并且 jackson-module-scala 允许 Scala 编译器提供它:

You can also mixin ScalaObjectMapper (experimental) to get rich wrappers that automatically convert scala manifests directly into TypeReferences for Jackson to use:

val mapper = new ObjectMapper() with ScalaObjectMapper
mapper.registerModule(DefaultScalaModule)
val myMap = mapper.readValue[Map[String,Tuple2[Int,Int]]](src)

我不知道它是否会自动阻止您遇到的问题。