有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

json使用Scala、Jackson和java对泛型类型进行奇怪的反序列化问题。整型或scala。Int

我们都知道,在Java和Scala下,泛型类型会受到类型擦除的影响。但是我们在使用Jackson和Scala-Jackson模块时遇到了一个奇怪的问题

我创建了一个小测试来说明这个问题

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模块


共 (2) 个答案

  1. # 1 楼答案

    这似乎是因为java.lang.Integer有一个接受字符串的constructor,它允许反序列化程序将该字符串用于Integer,而Int的情况并非如此

  2. # 2 楼答案

    这是一个非常普遍的问题,我为此写了一篇FAQ

    [A]ll primitive type parameters are represented as Object to the JVM. ... The Scala module has informed Jackson that Option is effectively a container type, but it relies on Java reflection to determine the contained type, and comes up with Object.

    The current workaround for this use case is to add the @JsonDeserialize annotation to the member being targeted. Specifically, this annotation has a set of parameters that can be used for different situations:

    • contentAs for collections or map values (supported)
    • keyAs for Map keys (currently unsupported)

    Examples of how to use this annotation can be found in the tests directory.

    对于好奇的人来说,FAQ中有更多的细节