我正在尝试使用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")
}
最后,一个Writes Extra类用于向输出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))
}
}
}
问题是我在SocketEvent
方法中发送了类型socketEvent
而不是实例send
。