使用spray-json,Slick和PostgreSQL进行DateTime的Stack Overflow

Mic*_*ech 1 postgresql scala spray-json slick akka-http

希望你能帮我解决这个问题.使用Akka HTTP,Slick和PosgreSQL,我正在尝试实现一个公告板作为练习.您可以在这里找到它的最新版本以获得完整的图片.


我所拥有的,简而言之:

我有这样的表:

final class Posts(tag: Tag) extends Table[Post](tag, "POSTS") with CustomColumnTypes {
  def id = column[Long]("ID", O.PrimaryKey, O.AutoInc)
  def threadId = column[Long]("THREAD_ID")
  def secretId = column[String]("SECRET")
  def pseudonym = column[String]("PSEUDONYM")
  def email = column[String]("EMAIL")
  def content = column[String]("CONTENT")
  def created = column[DateTime]("CREATED")

final class Threads(tag: Tag) extends Table[Thread](tag, "THREADS") {
  def threadId = column[Long]("THREAD_ID", O.PrimaryKey, O.AutoInc)
  def subject = column[String]("SUBJECT")
Run Code Online (Sandbox Code Playgroud)

和域模型:

case class Post(
    postId: Option[Long] = None,
    threadId: Option[Long],
    secretId: String,
    pseudonym: String,
    email: String,
    content: String,
    created: DateTime = DateTime.now)

case class Thread(
    threadId: Option[Long] = None, 
    subject: String

case class NewThreadWithPost(
    postId: Option[Long] = None,
    subject: String,
    secretId: String,
    pseudonym: String,
    email: String,
    content: String)
Run Code Online (Sandbox Code Playgroud)

使用这样写出的自定义协议:

trait TextboardJsonProtocol extends DefaultJsonProtocol with SprayJsonSupport with DateTimeHelper {
  implicit object DateTimeFormat extends RootJsonFormat[DateTime] {
    def read(value: JsValue) = value match {
      case dt: JsValue => value.convertTo[DateTime]
      case _ => deserializationError("DateTime expected")
    }
    def write(c: DateTime) = JsString(c.toString)
  }

  implicit val threadFormat = jsonFormat2(Thread.apply)
  implicit val postFormat = jsonFormat7(Post.apply)
  implicit val newThread = jsonFormat6(NewThread.apply)
}
Run Code Online (Sandbox Code Playgroud)

和这样的路线:

  def route: Route = {
...
          post {
            entity(as[Post]) { post =>
              complete(createPost(Some(threadId), post).toJson) }
...
          post {
            entity(as[NewThread]) { thread =>
              (master ? CreateNewThread(thread)).mapTo[NewThread]
              complete(StatusCodes.Created) }
...
Run Code Online (Sandbox Code Playgroud)

我打算做什么以及失败的地方:

我打算使用这种方法添加新的Thread和new Post,它很有用:

  def createNewThread(nt: NewThread) = {
    exec(threads += Thread(None, nt.subject))
    exec(posts += Post(None, lastId, secretId, nt.pseudonym, nt.email, nt.content, DateTime.now))
  }
Run Code Online (Sandbox Code Playgroud)

什么是不起作用的是这个看似相似的方法我用来创建帖子:

  def createPost(threadId: Option[Long], p: Post) = {
    exec(posts returning posts.map(_.secretId)
      += Post(None, p.threadId, secretId, p.pseudonym, p.email, p.content, DateTime.now))
  }
Run Code Online (Sandbox Code Playgroud)

怎么了?

[error] Uncaught error from thread [default-akka.actor.default-dispatcher-7] shutting down JVM since 'akka.jvm-exit-on-fatal-error' is enabled for ActorSystem[default]
[error] java.lang.StackOverflowError
[error] at main.scala.textboard.TextboardJsonProtocol$DateTimeFromat$.read(Protocol.scala:22)
[info] [ERROR] [SECURITY][12/11/2016 23:03:22.301] [default-akka.actor.default-dispatcher-7] [akka.actor.ActorSystemImpl
(default)] Uncaught error from thread [default-akka.actor.default-dispatcher-7] shutting down JVM since 'akka.jvm-exit-on-fatal-error' is enabled    [error] at spray.json.JsValue.convertTo(JsValue.scala:31) <- repeated tens of times
[error] at main.scala.textboard.TextboardJsonProtocol$DateTimeFormat$.read(Protocol.scala:23) <- repeated tens of times
[error] at main.scala.textboard.TextboardJsonProtocol$DateTimeFormat$.read(Protocol.scala:21) <- repeated tens of times
Java.lang.RuntimeException: Nonzero exit code returned from runner: -1 at scala.sys.package$.error(package.scala:27)
[trace] Stack trace suppressed: run last compile:run for the full output.
[error] (compile:run) Nonzero exit code returned from runner: -1
[error] Total time: 18 s, completed 2016-12-11 23:19:16
Run Code Online (Sandbox Code Playgroud)

我已经尝试过了什么

  • 试图找出当我使用createNewThread()时没有发生这种情况的原因.
  • 使用RootJsonFormat [DateTime]进行修补以修复隐式读者.
  • 使用DSL路由进行修补以启用或避免使用actor.
  • 试图避免将threadId作为Option传递.

Ste*_*tti 5

你让自己无限循环DateTimeFormat.你正在打电话给convertToread,并convertTo打电话read(参见spray-json来源).

使用类似的东西

implicit object DateJsonFormat extends RootJsonFormat[DateTime] {

    private val parser : DateTimeFormatter = ??? // your parser here

    override def write(obj: DateTime) = JsString(parser.print(obj))

    override def read(json: JsValue) : DateTime = json match {
      case JsString(s) => parser.parseDateTime(s)
      case _ => throw new Exception("Malformed datetime")
    }
  }
Run Code Online (Sandbox Code Playgroud)