使用Scala和Jackson以及java.lang.Integer或scala.Int对泛型类型进行奇怪的反序列化问题

时间:2013-10-15 11:21:26

标签: java json scala generics jackson

我们都知道泛型类型在Java和Scala下受类型擦除的影响。但是我们使用Jackson和Scala Jackson Module在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

这种不同的行为来自哪里? Generic Type Erasure,Jackson,Jackson Scala Module?

2 个答案:

答案 0 :(得分:4)

这是一个常见的问题,我为它写了FAQ

  

[A] ll基本类型参​​数表示为JVM的Object。 ...... Scala模块告诉Jackson Option实际上是一个容器类型,但它依赖Java反射来确定包含的类型,并提出Object

     

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

     
      
  • contentAs用于集合或地图值(支持)
  •   
  • keyAs表示地图密钥(目前不支持)
  •   
     

如何使用此注释的示例can be found in the tests directory

好奇心的常见问题解答中有更多细节。

答案 1 :(得分:0)

这似乎是因为java.lang.Integer有一个constructor带有一个String,它允许反序列化器使用Integer,而Int不是这种情况。