使用json4s泛型解析JSON到Case Class遇错的解决方案咨询
解决json4s解析泛型Case Class的问题
这个报错的根源是你在ResultList这个Case Class上添加的[T: Manifest]上下文绑定导致的——Scala会把这个隐式的Manifest参数转换成Case Class的一个普通构造参数(名为evidence$1),而你的JSON里根本没有对应的字段,所以json4s尝试解析这个不存在的字段时就抛出了异常。
修复步骤:
- 移除Case Class上的Manifest绑定:把
ResultList的定义改成不带Manifest上下文绑定的形式,因为Manifest是解析时需要的类型信息,不需要作为Case Class的成员。 - 保持decode方法的Manifest上下文绑定:decode方法需要Manifest来获取泛型类型的信息,这个是必须的。
完整的修复代码:
import org.json4s._ import org.json4s.native.JsonMethods._ implicit val formats = org.json4s.DefaultFormats case class User(name: String) case class Product(id: String) case class Meta(count: Int) // 移除了Manifest上下文绑定 case class ResultList[T](meta: Meta, result: List[T]) // 非泛型版本可以保留,也可以不用 case class ResultListUser(meta: Meta, result: List[User]) case class ResultListProduct(meta: Meta, result: List[Product]) // 保持原有的decode方法,Manifest在这里提供解析所需的类型信息 def decode[T: Manifest](jsonStr: String): T = { parse(jsonStr).extract[T] } // 测试数据 val userJson = """{"meta":{"count":2},"result":[{"name":"Tom"},{"name":"Lucas"}]}""" val productJson = """{"meta":{"count":2},"result":[{"id":"123"},{"id":"456"}]}""" // 测试泛型版本解析 val resultListUser2 = decode[ResultList[User]](userJson) println(resultListUser2) // 输出:ResultList(Meta(2),List(User(Tom), User(Lucas))) val resultListProduct2 = decode[ResultList[Product]](productJson) println(resultListProduct2) // 输出:ResultList(Meta(2),List(Product(123), Product(456)))
为什么原来的写法会报错?
当你写case class ResultList[T: Manifest](meta: Meta, result: List[T])时,Scala编译器会把它转换成等价的:
case class ResultList[T](meta: Meta, result: List[T])(implicit evidence$1: Manifest[T])
而json4s在解析Case Class时,会尝试为所有构造参数寻找对应的JSON字段。因为你的JSON里没有evidence$1这个字段,所以就会抛出No usable value for evidence$1的错误。
把Manifest从Case Class的构造参数中移除,只在需要进行类型提取的方法(比如decode)上保留上下文绑定,就能让json4s正确解析泛型类型了。
内容的提问来源于stack exchange,提问作者Tom Lous
相关产品推荐
相关产品推荐

