playframework - Reload后在WebSocket Iteratee中 Play Morphia MappingException

标签 playframework websocket playframework-2.0 akka morphia

我正在使用 Play 2.3 和 Akka 通过网络套接字设置一个简单的发布订阅协议(protocol)。作为该协议(protocol)的一部分,在客户端订阅后,服务器从数据库发送初始状态。

我当前的代码最初可以工作,但是在开发过程中,Iteratee 套接字内的 Morphia 查询在重新加载开发后停止工作。常规请求,即使是发出完全相同查询的请求,也可以继续正常工作。

我正在使用分布式发布子中介 Akka 插件。以下是代表网络套接字监听器的参与者的相关代码:

object Subscriber {
  def props(channel: Concurrent.Channel[JsValue]): Props = Props(new Subscriber(channel))
}

class Subscriber(channel: Concurrent.Channel[JsValue]) extends Actor {
  def receive = {
    case StatusUpdate(...) =>
      channel.push(...)
  }
}

对于主视图 Controller :

object SocketController extends Controller {
  val mediator = DistributedPubSubExtension.get(Akka.system).mediator

  def index = WebSocket.using[JsValue] { implicit request =>
    val (out, channel) = Concurrent.broadcast[JsValue]

    val ws = Akka.system.actorOf(Subscriber.props(channel))

    val in = Iteratee.foreach[JsValue] { msg =>
      (msg \ "type").as[String] match {
        case "Subscribe" =>
          val target = (msg \ "value").as[String]

          // Query database with Morphia
          val current = MyObj.findByName(target)

          // Notify of current state
          ws ! StatusUpdate(target, current)

          // Subscribe for further updates
          mediator ! DistributedPubSubMediator.Subscribe(target, ws)
      }
    }

    (in, out)
  }
}

问题出在Iterattee中的查询语句。重新加载后,Morphia 会抛出 org.mongodb.morphia.mapping.MappingException:无法映射 models.MyObj ID:5507a3653004b8a9e8f3d3b2。这是完整的跟踪:

org.mongodb.morphia.mapping.MappingException: Could not map models.MyObj with ID: 5507a3653004b8a9e8f3d3b2
    at org.mongodb.morphia.mapping.Mapper.fromDb(Mapper.java:594)
    at org.mongodb.morphia.mapping.Mapper.fromDBObject(Mapper.java:299)
    at org.mongodb.morphia.query.MorphiaIterator.convertItem(MorphiaIterator.java:79)
    at org.mongodb.morphia.query.MorphiaIterator.processItem(MorphiaIterator.java:65)
    at org.mongodb.morphia.query.MorphiaIterator.next(MorphiaIterator.java:60)
    at org.mongodb.morphia.query.QueryImpl.get(QueryImpl.java:402)
    at models.MyObj$.findByName(MyObj.scala:99)
    at controllers.MyObj$$anonfun$MyObj$1$$anonfun$4.apply(MyObj.scala:99)
    at controllers.MyObj$$anonfun$MyObj$1$$anonfun$4.apply(MyObj.scala:93)
    at play.api.libs.iteratee.Iteratee$$anonfun$foreach$1.apply(Iteratee.scala:201)
    at play.api.libs.iteratee.Iteratee$$anonfun$foreach$1.apply(Iteratee.scala:201)
    at play.api.libs.iteratee.Iteratee$$anonfun$fold$1$$anonfun$apply$1.apply(Iteratee.scala:41)
    at play.api.libs.iteratee.internal$.eagerFuture(package.scala:30)
    at play.api.libs.iteratee.Iteratee$$anonfun$fold$1.apply(Iteratee.scala:41)
    at play.api.libs.iteratee.Iteratee$$anonfun$fold$1.apply(Iteratee.scala:41)
    at play.api.libs.iteratee.Iteratee$$anonfun$1.apply(Iteratee.scala:60)
    at play.api.libs.iteratee.Iteratee$$anonfun$1.apply(Iteratee.scala:60)
    at scala.concurrent.impl.Future$PromiseCompletingRunnable.liftedTree1$1(Future.scala:24)
    at scala.concurrent.impl.Future$PromiseCompletingRunnable.run(Future.scala:24)
    at akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:41)
    at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(AbstractDispatcher.scala:393)
    at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
    at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
    at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
    at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
Caused by: org.mongodb.morphia.mapping.MappingException: Error setting value from converter (ObjectIdConverter) for models.MyObj.id to 5507a3653004b8a9e8f3d3b2
    at org.mongodb.morphia.converters.DefaultConverters.fromDBObject(DefaultConverters.java:137)
    at org.mongodb.morphia.mapping.ValueMapper.fromDBObject(ValueMapper.java:27)
    at org.mongodb.morphia.mapping.Mapper.readMappedField(Mapper.java:608)
    at org.mongodb.morphia.mapping.Mapper.fromDb(Mapper.java:589)
    ... 24 more
Caused by: java.lang.IllegalArgumentException: Can not set org.bson.types.ObjectId field models.MyObj.id to models.MyObj
    at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
    at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
    at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:58)
    at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:75)
    at java.lang.reflect.Field.set(Field.java:758)
    at org.mongodb.morphia.mapping.MappedField.setFieldValue(MappedField.java:508)
    at org.mongodb.morphia.converters.DefaultConverters.fromDBObject(DefaultConverters.java:135)
    ... 27 more

这个异常只发生在web socket handler中,常规请求可以使查询正常。完全重启开发服务器可以解决问题,直到下一次重新加载。

这是启动和一次重启的控制台日志:http://pastebin.com/xsstw4ki

对这里可能发生的事情有什么想法吗?我发现此错误的其他引用似乎是 unrelatedold .

更新 - 2015 年 7 月 4 日

也发生在 Play 2.4.2 上。

最佳答案

您可以使用以下代码片段来解决此问题。通过添加以下代码(Scala 代码)修改您的吗啡创建

if (Play.isDev)
    morphia.getMapper.getOptions.setObjectFactory(new PlayCreator)

PlayCreator类的定义是(Java代码)

public class PlayCreator extends DefaultCreator {

@Override
protected ClassLoader getClassLoaderForClass() {
    return Play.application().classloader();
}
}

请添加相关导入,您的热重载应该工作得很好:)

关于playframework - Reload后在WebSocket Iteratee中 Play Morphia MappingException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29179396/

相关文章:

java - 为什么我的 Play 框架模型作为空白记录保存到数据库中?

java - 带有 Maven 和子项目的 Playframework 2.0

scala - 了解 SBT、Scala、SBT-Idea 和 Play 框架如何协同工作

node.js - Websocket 连接错误 : Does not return a 101 changing protocal when using from different path

Javascript客户端无法连接到java服务器

Scala,Play2.0 - 预期为 ';' 但找到了 ')'

scala - 检查 Play 当前模式会发生错误

php - 使用 PHP Ratchet Web 套接字服务器获取真实用户 IP

scala - 方法映射的参数太多 : (apply: (String, models.Address) => R)(unapply : R => Option[(String, models.Address)])play.api.data.Mapping[R]

scala - 使用 specs2 和 FakeApplication() 测试数据库失败的进化插入