【问题标题】:No instance of play.api.libs.json.Format is available for akka.actor.typed.ActorRef[org.knoldus.eventSourcing.UserState.Confirmation]没有可用于 akka.actor.typed.ActorRef[org.knoldus.eventSourcing.UserState.Confirmation] 的 play.api.libs.json.Format 实例
【发布时间】:2021-10-12 08:42:30
【问题描述】:

在隐式范围内没有可用于 akka.actor.typed.ActorRef[org.knoldus.eventSourcing.UserState.Confirmation] 的 play.api.libs.json.Format 实例(提示:如果在同一个文件中声明,确保之前声明过)

[error] 隐式 val userCommand: Format[AddUserCommand] = Json.format

即使我为 AddUserCommand 创建了 Json Format 的隐式实例,我仍然收到此错误。

这是我的代码:

trait UserCommand extends CommandSerializable
    
object AddUserCommand{
  implicit val format: Format[AddUserCommand] = Json.format[AddUserCommand]
}
    
final case class AddUserCommand(user:User, reply: ActorRef[Confirmation]) extends UserCommand

谁能帮我解决这个错误以及如何解决它?

【问题讨论】:

    标签: scala playframework akka play-json


    【解决方案1】:

    正如 Gael 所说,您需要为 ActorRef[Confirmation] 提供一个 Format。与此相关的复杂情况是,使用 the ActorRefResolver 的自然序列化要求存在 ExtendedActorSystem,这意味着在伴随对象中定义 Format 的常用方法将不太有效。

    请注意,由于 Lagom 进行依赖注入的方式,this approach doesn't really work in Lagom: commands in Lagom basically can't use Play JSON

    import akka.actor.typed.scaladsl.adapter.ClassicActorSystemOps
    import play.api.libs.json._
    
    class PlayJsonActorRefFormat(system: ExtendedActorSystem) {
      def reads[A] = new Reads[ActorRef[A]] {
        def reads(jsv: JsValue): JsResult[ActorRef[A]] =
          jsv match {
            case JsString(s) => JsSuccess(ActorRefResolver(system.toTyped).resolveActorRef(s))
            case _ => JsError(Seq(JsPath() -> Seq(JsonValidationError(Seq("ActorRefs are strings"))))) // hopefully parenthesized that right...
          }
      }
    
      def writes[A] = new Writes[ActorRef[A]] {
        def writes(a: ActorRef[A]): JsValue = JsString(ActorRefResolver(system.toTyped).toSerializationFormat(a))
      }
    
      def format[A] = Format[ActorRef[A]](reads, writes)
    }
    

    然后您可以将AddUserCommand 的格式定义为

    object AddUserCommand {
      def format(arf: PlayJsonActorRefFormat): Format[AddUserCommand] = {
        implicit def arfmt[A]: Format[ActorRef[A]] = arf.format
    
        Json.format[AddUserCommand]
      }
    }
    

    由于您大概使用 JSON 来序列化围绕集群发送的消息(否则,ActorRef 不应该像这样泄漏),然后您将在 Akka 序列化器实现中构造该格式的实例。

    (注意:我只用 Circe 做过这个,而不是 Play JSON,但基本方法很常见)

    【讨论】:

    • 是的,我现在了解流程,感谢您的努力。但我得到了这个: - 类型不匹配。必需:读取[ActorRef[A]],找到:JsValue => JsResult[ActorRef[A]]。 in def format[A] = Format[ActorRef[A]](读取,写入)
    • 错过了{...在 SO 文本框中编码的乐趣...现在编辑
    【解决方案2】:

    错误表示它无法为AddUserCommand 构造Format,因为ActorRef[Confirmation] 没有Format

    使用Json.format[X]时,案例类X的所有成员都必须定义一个Format

    在您的情况下,您可能不想为此案例类定义格式化程序(序列化 ActorRef 没有多大意义),而是仅使用数据构建另一个案例类。

    编辑:如果您真的想向那里发送演员参考,请参阅 Levi 的回答,了解如何为 ActorRef 提供格式化程序。

    【讨论】:

    • 好的,我明白你在说什么,但是如果我提供 ActorRef[Confirmation] 的序列化可以解决这个问题吗?
    • 是的,但这不是你应该做的。你将如何(反)序列化它?
    • ActorRef 是为序列化而设计的(Akka 提供了一些内置方法来将 ActorRef 表示为不透明的字符串)
    • 哦,好吧,不知道。即使您的答案更完整,也会相应地编辑我的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-24
    • 1970-01-01
    相关资源
    最近更新 更多