No Json deserializer found for type List[(java.util.UUID, String, String, String, Int, Int, Int, Int, java.sql.Timestamp)]

My scala skill is lacking but I've been wrestling with this. But I'm having a problem serializing and deserializing JSON. I've googled and searched StackOverflow but unfortunately I cannot piece it together.

So this is my last resort..

My model is:

package models

import java.util.UUID
import java.sql.Timestamp


import play.api.db._
import play.api.Play.current
import play.api.libs.json._


import slick.driver.PostgresDriver.simple._
import Database.threadLocalSession

case class User(
  id:UUID,
  username: String,
  password: String,
  email: String,
  comment_score_down: Int,
  comment_score_up: Int,
  post_score_down: Int,
  post_score_up: Int,
  created_on: Timestamp)

object Users extends
  Table[(UUID, String, String, String, Int, Int, Int, Int, Timestamp)]("users"){

  implicit object UserFormat extends Format[User] {

    implicit object UUIDFormatter extends Format[UUID] {
      def reads(s: JsString): UUID = java.util.UUID.fromString(s.toString)
      def writes(uuid: UUID) = JsString(uuid.toString)
    }

    implicit object TimestampFormatter extends Format[Timestamp] {
      def reads(s: JsValue): Timestamp = new Timestamp(s.toString.toLong)
      def writes(timestamp: Timestamp) = JsString(timestamp.toString)
    }


    def reads(json: JsValue): User = User(
        (json \ "id").as[UUID],
        (json \ "username").as[String],
        (json \ "password").as[String],
        (json \ "email").as[String],
        (json \ "comment_score_down").as[Int],
        (json \ "comment_score_up").as[Int],
        (json \ "post_score_down").as[Int],
        (json \ "post_score_up").as[Int],
        (json \ "created_on").as[Timestamp]
      )
     def writes(u: User): JsValue = JsObject(List(
         "id" -> JsString(u.id.toString),
         "username" -> JsString(u.username),
         "password" -> JsString(u.password),
         "email" -> JsString(u.email),
         "comment_score_down" -> JsString(u.comment_score_down.toString),
         "comment_score_up" -> JsString(u.comment_score_up.toString),
         "post_score_down" -> JsString(u.post_score_down.toString),
         "post_score_up" -> JsString(u.post_score_up.toString),
         "created_on" -> JsString(u.created_on.toString)
       ))
  }


  def id = column[UUID]("ID", O.PrimaryKey) // This is the primary key column
  def username = column[String]("username")
  def password = column[String]("password")
  def email = column[String]("email")
  def comment_score_down = column[Int]("comment_score_down")
  def comment_score_up = column[Int]("comment_score_up")
  def post_score_down = column[Int]("post_score_down")
  def post_score_up = column[Int]("post_score_up")
  def created_on = column[Timestamp]("created_on")

  def * = id ~ username ~ password ~ email ~ comment_score_down ~
    comment_score_up ~ post_score_down ~ post_score_up ~ created_on

}

My controller:

  def getUsers = Action {
    val json = database withSession {
      val users = for (u <- Users) yield u.*
      Json.toJson(users.list)
    }
    Ok(json).as(JSON)

  }

Thank you for your time!

Answers


Kay, I got it sweet.

Made some edit to my model:

case class User(
  id:UUID,
  username: String,
  password: String,
  email: String,
  comment_score_down: Option[Int],
  comment_score_up: Option[Int],
  post_score_down: Option[Int],
  post_score_up: Option[Int],
  created_on: Timestamp)

object Users extends Table[User]("users"){     

I also changed my object signature so that it can return type User instead of just User's parameters. And I just have to append <> (User, User.unapply _) to my projection method (the *).

But in my controller:

I just needed:

  implicit object UserWrites extends Writes[User] {

    def writes(u: User) = Json.obj(
         "id" -> JsString(u.id.toString),
         "username" -> JsString(u.username),
         "password" -> JsString(u.password),
         "email" -> JsString(u.email),
         "comment_score_down" -> JsNumber(u.comment_score_down.getOrElse(0).toInt),
         "comment_score_up" -> JsNumber(u.comment_score_up.getOrElse(0).toInt),
         "post_score_down" -> JsNumber(u.post_score_down.getOrElse(0).toInt),
         "post_score_up" -> JsNumber(u.post_score_up.getOrElse(0).toInt),
         "created_on" -> JsString(u.created_on.toString)
    ) 


  }

as member of the controller class.

So now my controller action is just:

  def getUsers = Action {

    val json = database withSession {
      val users = for (u <- Users) yield u
      Json.toJson(users.list)
    }
    Ok(json).as(JSON)
  }

Edit:

Alternatively, I've moved the getUsers code to my model as a findAll method and also moved my writable to there too. I didn't like the data logic being in the controller...

So in my controller I only have a method/action:

  def getUsers = Action {
    Ok(Users.findAll).as(JSON)
  }

My model now looks like:

package models

import java.util.UUID
import java.sql.Timestamp


import play.api.db._
import play.api.Play.current
import play.api.libs.json._


import slick.driver.PostgresDriver.simple._
import Database.threadLocalSession

case class User(
  id:UUID,
  username: String,
  password: String,
  email: String,
  comment_score_down: Option[Int],
  comment_score_up: Option[Int],
  post_score_down: Option[Int],
  post_score_up: Option[Int],
  created_on: Timestamp)

object Users extends Table[User]("users") {

  lazy val database = Database.forDataSource(DB.getDataSource())

  def id = column[UUID]("id", O.PrimaryKey) // This is the primary key column
  def username = column[String]("username")
  def password = column[String]("password")
  def email = column[String]("email")
  def comment_score_down = column[Option[Int]]("comment_score_down")
  def comment_score_up = column[Option[Int]]("comment_score_up")
  def post_score_down = column[Option[Int]]("post_score_down")
  def post_score_up = column[Option[Int]]("post_score_up")
  def created_on = column[Timestamp]("created_on")

  implicit object UserWrites extends Writes[User] {

    def writes(u: User) = Json.obj(
         "id" -> JsString(u.id.toString),
         "username" -> JsString(u.username),
         "password" -> JsString(u.password),
         "email" -> JsString(u.email),
         "comment_score_down" -> JsNumber(u.comment_score_down.getOrElse(0).toInt),
         "comment_score_up" -> JsNumber(u.comment_score_up.getOrElse(0).toInt),
         "post_score_down" -> JsNumber(u.post_score_down.getOrElse(0).toInt),
         "post_score_up" -> JsNumber(u.post_score_up.getOrElse(0).toInt),
         "created_on" -> JsString(u.created_on.toString)
    )
  }

  def * = id ~ username ~ password ~ email ~ comment_score_down ~
    comment_score_up ~ post_score_down ~ post_score_up ~ created_on <>
    (User, User.unapply _)

  def findByPK(pk: UUID) =
    for (entity <- Users if entity.id === pk) yield entity

  def findAll = database withSession {
      val users = for (u <- Users) yield u
      Json.toJson(users.list)
    }

}

Need Your Help

jquery works on second click only (but works fine in localhost...)

javascript jquery

The title says it all pretty much. The page loads another one and then refresh. (the 'name' attribute contains the 'id' of the element to like)