【问题标题】:implicit json converter in scala is null at runtimescala中的隐式json转换器在运行时为空
【发布时间】:2019-01-18 10:08:47
【问题描述】:

使用过的游戏框架我有 案例类 文件(在项目中有聚合任务。这很重要),例如

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

在另一个文件trait中进行转换

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] is null 用于 Task 类(对于 Project 来说一切正常)

我认为这是因为在.as[Map[String, Project] 中仅指定了 Project 类,而不是 Task。但不完全是

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

1) 在 same 文件中用案例类声明所有隐式转换器。但我想将所有转换器放在单独的文件中。这个解决方案不适合我

2) 在trait JsonConverters

中使用 lazy mod 声明 Task 的隐含
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]
}

它工作正常,看起来不错。但是我不明白为什么没有 lazyseparate trait 中不起作用?谁能描述一下?或建议其他解决方案

【问题讨论】:

  • 不同文件不保证初始化顺序

标签: json scala playframework


【解决方案1】:

平凡变量(val)和惰性变量(lazy val)的初始化顺序不同。

val 的初始化顺序在文件中描述。
lazy val 被初始化在首次访问时

在您的情况下,Project 包含Task,因此projectRead 需要初始化taskRead 才能完成。

在您的代码中,如果没有 lazyprojectReadtaskRead 之前声明,所以当 projectRead 需要它时,taskRead 仍然是 null。这就是你得到NPE的原因。

不过,编译器仍然可以找到隐含的 taskRead 并且不会引发错误

您对lazy 的修复有效,因为taskRead 现在在首次访问时初始化。现在,taskReadprojectRead 请求时进行初始化。 NPE 没了。

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

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

【讨论】:

  • 嗨!非常有趣……这是我第一次想到声明的顺序。而且这个修复昨天没有工作О_о但是在你回答之后它工作正常!可能是某些类没有在带有播放框架的“热交换”中重新编译。感谢您的详细描述!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-13
  • 1970-01-01
  • 2019-09-04
  • 1970-01-01
  • 2018-08-06
  • 2018-09-16
相关资源
最近更新 更多