6

我们都知道泛型类型在 Java 和 Scala 下会进行类型擦除。但是我们在使用 Jackson 和 Scala Jackson 模块的 Scala 中遇到了一个奇怪的问题。

我创建了一个小测试来显示问题。

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

object GenericTest {

  case class TestWithInt(id: Option[Int])
  case class TestWithInteger(id: Option[Integer])

  def main(args: Array[String]) {

    val mapper = new ObjectMapper()
    mapper.registerModule(DefaultScalaModule)

    // Test with scala's Int
    val test = mapper.readValue[TestWithInt]("""{ "id" : 5 }""", classOf[TestWithInt])
    print("Test 1: ")
    println(test.id.get +  1)

    val test2 = mapper.readValue[TestWithInt]("""{ "id" : "5" }""", classOf[TestWithInt])
    print("Test 2: ")
    try {
      println(test2.id.get + 1)
    } catch {
      case e: ClassCastException => println(e.getMessage)
    }

    // Test with java.lang.Integer
    val test3 = mapper.readValue[TestWithInteger]("""{ "id" : 5 }""", classOf[TestWithInteger])
    print("Test 3: ")
    println(test3.id.get +  1)

    val test4 = mapper.readValue[TestWithInteger]("""{ "id" : "5" }""", classOf[TestWithInteger])
    print("Test 4: ")
    println(test4.id.get + 1)
  }
}

上面的输出是:

Test 1: 6
Test 2: java.lang.String cannot be cast to java.lang.Integer
Test 3: 6
Test 4: 6

这种不同的行为从何而来?通用类型擦除,Jackson,Jackson Scala 模块?

4

2 回答 2

5

这成为一个常见的问题,我为此写了一个常见问题解答

[A]所有原始类型参数都表示为ObjectJVM。... Scala 模块已告知 Jackson 实际上Option是一种容器类型,但它依赖于 Java 反射来确定包含的类型,并提出了Object.

此用例的当前解决方法是将@JsonDeserialize注释添加到目标成员。具体来说,这个注解有一组参数可以用于不同的情况:

  • contentAs用于集合或映射值(支持)
  • keyAs映射键(当前不支持)

可以在测试目录中找到如何使用此注解的示例。

对于好奇的人,FAQ 中有更多详细信息。

于 2013-10-15T19:10:23.070 回答
-1

这似乎是因为java.lang.Integer有一个构造函数接受一个字符串,它允许反序列化器使用它,Integer而情况并非如此Int

于 2013-10-15T11:29:32.590 回答