带有播放的Scala:尝试通过WebSocket发送数据时发生类强制转换异常

时间:2019-02-21 10:33:33

标签: scala playframework akka

我正在尝试使用Scala,Play和Akka设置基于websocket的基本通知系统。 websocket可以正常工作,我可以发送内容,将其回显,使用新创建的案例类进行响应等。我已经定义了一个密封的特征,其中包含案例类以表示各种输入和输出,并按顺序进行自定义写入和读取管理输入/输出JSON对象并添加/删除“类型”字段。

但是,当我尝试通过外部操作通过websocket发送数据时,出现了这个奇怪的运行时错误:java.lang.ClassCastException: v1.socket.SocketEvent$ cannot be cast to v1.socket.SocketEvent

以下是操作的调用:

WebSocketActor.send(ConnectionRequest("test", "test", "test"), "test")

这是我的WebSocketActor:

object WebSocketActor {
  def props(out: ActorRef) = Props(new WebSocketActor(out))
  var sessions: Map[String, Map[String, ActorRef]] = Map()

  /** Send data to a specified user. 
    * Response with false if the user does not have a session 
    */
  def send(socketEvent: SocketEvent, userId: String): Boolean = {
    if (sessions contains userId) {
      val userSessions = sessions(userId)
      userSessions.foreach(user => user._2 ! SocketEvent)
      return true
    }
    false
  }
}

class WebSocketActor(out: ActorRef) extends Actor {

  /** Authenticate the user and add device to session
    * (note that authentication is stripped out for brevity) 
    */

  def auth: Receive = {
    case init: Init => {
      var session: Map[String, ActorRef] = Map(init.deviceId -> out)
      if (sessions contains init.userId) {
        session = session ++ sessions(init.userId)
      }
      sessions = sessions + (init.userId -> session)

      context become await
    }
  }

  def await: Receive = {
    case conReq: ConnectionRequest => {
      out ! conReq
    }

  }
  override def receive: Receive = auth

}

这是SocketEvent Seale特性,伴随对象和案例类:

sealed trait SocketEvent

object SocketEvent {

  implicit val socketEventFmt: Format[SocketEvent] = new Format[SocketEvent] {

    override def writes(event: SocketEvent): JsValue = event match {
      case e: ConnectionRequest => Json.toJson(e)(Json.format[ConnectionRequest])
      case e: Init => Json.toJson(e)(Json.format[Init])
    }
    override def reads(json: JsValue): JsResult[SocketEvent] = (json \ "type").as[String] match {
      case "connectionRequest" =>
        Json.fromJson[ConnectionRequest](json.as[JsObject] - "type")(Json.format[ConnectionRequest])
      case "init" =>
        Json.fromJson[Init](json.as[JsObject] - "type")(Json.format[Init])
    }
  }
}

case class ConnectionRequest(userId: String, publicKey: String, signature: String) extends SocketEvent
object ConnectionRequest {
  implicit val format: OWrites[ConnectionRequest] = Json.format[ConnectionRequest]
    .withConstant("type", "connectionRequest")
}

case class Init(userId: String, deviceId: String) extends SocketEvent
object Init{
  implicit val initFmt: OWrites[Init] = Json.format[Init]
    .withConstant("type", "Init")
}

最后,一个OWritesExtra类,用于将字段添加到输出的Json:

object OWritesExtra {

  implicit class OWritesExt[A](owrites: OWrites[A]) {

    /** Add a (key, value) pair to the JSON object,
      * where the value is constant.
      */
    def withConstant[B: Writes](key: String, value: B): OWrites[A] =
      withValue(key, _ => value)

    /** Add a key, value pair to the JSON object that is written, where
      * the value depends on the original object.
      */
    def withValue[B: Writes](key: String, value: A => B): OWrites[A] =
      new OWrites[A] {
        def writes(a: A): JsObject = owrites.writes(a) ++ Json.obj(key -> value(a))
      }

  }

}

1 个答案:

答案 0 :(得分:0)

问题是我在SocketEvent方法中发送类型socketEvent而不是实例send