scala中的隐式json转换器在运行时为null

问题描述 投票:1回答:1

使用了play框架我有一个case类的文件(在Project中有聚合Task。很重要)就像

case class Project (var tasks: Map[String, Task])
case class Task (var activities: Map[String, String])

并在另一个文件特征中进行转换

trait JsonConverters {
  implicit val projectWrite: OWrites[Project] = Json.writes[Project]
  implicit val projectRead: Reads[Project] = Json.reads[Project]
  implicit val taskWrite: OWrites[Task] = Json.writes[Task]
  implicit val taskRead: Reads[Task] = Json.reads[Task]
}
object JsonConverters extends JsonConverters

在我的服务类中

import support.JsonConverters._
class Service {
  def someMethod(json: String) = {
    val obj = Json.parse(json).as[Map[String, Project]]
  }
}

在编译时一切都很好。但在json解析中我得到了json库中的NPE(play.api.libs.json.DefaultReads#mapReads

implicit def mapReads[K, V](k: String => JsResult[K])(implicit fmtv: Reads[V]): Reads[Map[K, V]] = Reads[Map[K, V]] {

任务类的implicit fmtv: Reads[V]为null(对于Project都很好)

我认为这是因为在.as[Map[String, Project]中只指定了Project类,而不是Task。但事实并非如此

我找到了两个不同的解决方案来解决这个问题,但两者对我来说都很难看

1)使用case类在同一个文件中声明所有隐式转换器。但我希望将所有转换器都放在分开的文件中。这个解决方案不适合我

2)在qazxsw poi中使用lazy mod声明对Task的隐式

trait JsonConverters

它工作正常,看起来很好。但是我不明白为什么没有单独的特质懒惰它不起作用?谁有人形容?或建议另一种解决方案

json scala playframework
1个回答
2
投票

平凡变量(trait JsonConverter { implicit val projectWrite: OWrites[Project] = Json.writes[Project] implicit val projectRead: Reads[Project] = Json.reads[Project] implicit lazy val taskWrite: OWrites[Task] = Json.writes[Task] implicit lazy val taskRead: Reads[Task] = Json.reads[Task] } )和惰性变量(val)的初始化顺序是不同的。

lazy val按照文件中描述的顺序进行初始化。 val是在首次访问时初始化的。

在你的情况下,lazy val包含一个Project所以Task需要初始化的projectRead完成。

在你的代码中,没有taskReadlazyprojectRead之前宣布,所以当taskRead需要时,taskRead仍然是null。这就是你获得NPE的原因。

仍然,编译器可以找到隐式projectRead并且不会引发错误。

您对taskRead的修复有效,因为lazy现在在首次访问时初始化。现在,当taskRead要求时,taskRead初始化。 NPE消失了。

您可以通过切换声明顺序来实现相同的修复:

projectRead
© www.soinside.com 2019 - 2024. All rights reserved.