Scala使用ToolBox动态生成case class时Json4s反序列化失败问题咨询
异常原因
该异常本质是泛型参数的编译期类型和运行期实际类型不匹配导致的:
Json4s的extract[T]是依赖编译期泛型参数T的类型信息做反序列化的泛型方法。你写js.extract[person.type]时,person是你代码里一个类型为Class[_]的变量,这里的person.type是Scala里的单例类型,指代的是「person这个变量本身的类型」也就是Class[_],而不是person运行时指向的动态生成的Person类。Json4s收到的类型信息是Class,自然找不到对应的构造方法来反序列化JSON,就抛出了MappingException。
而你创建dummy实例后用dummy.type作为泛型参数时,dummy是动态生成的Person类的实例,编译期dummy.type会绑定到实际的Person类类型,Json4s能拿到正确的构造信息,所以可以反序列化成功。
无需dummy实例的解决方案
Json4s提供了不依赖编译期泛型参数的反序列化API,你只需要把动态拿到的Class对象包装成Manifest传入即可,不需要创建任何临时实例:
import org.json4s._ import scala.reflect.runtime._ import scala.tools.reflect.ToolBox import scala.reflect.ManifestFactory implicit val formats = DefaultFormats val cm = universe.runtimeMirror(getClass.getClassLoader) val toolBox = cm.mkToolBox() val parse = toolBox.parse( s""" | case class Person( name:String, age:String) | scala.reflect.classTag[ Person].runtimeClass """.stripMargin) val person = toolBox.compile(parse)().asInstanceOf[Class[_]] val js = JsonMethods.parse("""{ "name":"Tom","age" : "28"}""") // 直接传入Class构造Manifest调用非泛型extract方法 val jv = Extraction.extract(js, formats, ManifestFactory.classType(person)) println(jv) // 输出 Person(Tom,28)
这里使用的Extraction.extract是Json4s的非泛型重载方法,直接接收运行时构造的Manifest作为类型依据,不需要编译期确定泛型参数,也不会产生额外的实例开销。
内容的提问来源于stack exchange,提问作者Bum Su Kim
相关产品推荐
相关产品推荐

