我正在尝试使用gson反序列化Scala案例类,并且当案例类包含原始类型的集合时遇到问题。
考虑以下代码:
准备gson:
import com.google.gson._
import scala.collection.JavaConverters._
//custom deserialization for Seq
class SeqDeserializer[T] extends JsonDeserializer[scala.collection.Seq[T]] {
override def deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): scala.collection.Seq[T] = {
//this is the `Type` of `T`
val innerType = typeOfT.asInstanceOf[ParameterizedType].getActualTypeArguments.head //there is only one type arg since it a Seq
println(s"json=$json, type=$innerType")
json
.getAsJsonArray
.asScala
.map(j => context.deserialize[T](j, innerType))
.toSeq
}
}
//initiate gson:
val builder = new GsonBuilder().registerTypeAdapter(classOf[scala.collection.Seq[Any]], new SeqDeserializer[Any])
val gson = builder.create()
要反序列化的类:
case class Top(
ints: Seq[Int] = Nil,
items: Seq[Item] = Nil
)
case class Item(i: Int = 0)
重新产生问题的代码:
val json =
"""
|{
| "ints": [1,2,3],
| "items": [
| {
| "i": 1
| },
| {
| "i": 2
| }
| ]
|}
""".stripMargin
val res = gson.fromJson(json, classOf[Top])
println(res) //1
println(res.items.map(_.toString)) //2
println(res.ints.map(_.toString)) //3
第一个println
将打印:
顶部(列表(1.0,2.0,3.0),列表(项目(1),项目(2)))
我们已经看到存在问题,因为ints
中的值是doubles
第二个println
将打印:
列表(Item(1),Item(2))
(符合预期)
在第三个println
上,我遇到了一个例外:
从java.lang.Double无法转换为java.lang.Integer java.lang.ClassCastException:无法将java.lang.Double强制转换为 java.lang.Integer在 scala.runtime.BoxesRunTime.unboxToInt(BoxesRunTime.java:101)
SeqDeserializer
内的印刷品中我们得到:
json = [1,2,3],类型= class java.lang.Object
json = [{“ i”:1},{“ i”:2}],type = class Item
我们可以看到,对于Seq[Item]
,gson
正确地将内部类型标识为Item
,
但对于Seq[Int]
,内部类型标识为Object
,然后解析为Double
而不是Int
我猜想这与Int
如何使gson
在集合内的原始类型上正常工作?