简体   繁体   中英

Scala and Play2: ClassCastException: java.lang.Object cannot be cast to play.api.libs.json.JsValue

This is the second time I've bumped into this. Edit: I discovered it's also the second time I've asked on stack and is the THIRD or FOURTH time I've run into this. Other question is here: Cast Class Exception in Scala: java.lang.Object to Scala CaseClass

Edited heavily... I can simplify the question after much analysis. Appears this is a problem with how I'm using traits and implementing/overriding the toJson method... I'm sure this is something easy but I haven't been able to find what I'm doing wrong.

I get this class cast exception and I can't see any problem with this.

I have this:

package service

import play.api.libs.json.{JsObject, Json, JsValue}

/**
 * author: jason goodwin
 */
trait Jsonable{

  def toJson: JsValue = {null}
}

object Jsonable {
  def renderJsonableListToJson(entities: Iterable[Jsonable]): String = {

    val jsonList = Json.toJson(entities.map(x => x.toJson).toSeq)
    val result = JsObject("meta" -> JsObject(Seq()) :: "data" -> jsonList :: Nil)

    Json.stringify(result)
  }
}

and this which is interfacing with a java library:

trait GraphedArticle extends BaseFramedEntity with Jsonable {

  @Property("articleId")
  def setArticleId (userId: String)

  @Property("articleId")
  def getArticleId:String

  @Property("title")
  def setTitle (title: String)

  @Property("title")
  def getTitle:String

  @Property("preview")
  def setPreview (preview: String)

  @Property("preview")
  def getPreview: String

  @Property("imageUrl")
  def setImageUrl (imageUrl: String)

  @Property("imageUrl")
  def getImageUrl: String

  @Property("articleUrl")
  def setArticleUrl (imageUrl: String)

  @Property("articleUrl")
  def getArticleUrl: String

  override def toJson: JsValue = {
    val ret = JsObject(
      "articleId" -> Json.toJson(getArticleId)
        :: "graphId" -> Json.toJson(asVertex().getId.toString)
        :: "created_time" -> Json.toJson(123123123)
        :: "url" -> Json.toJson(getArticleUrl)
        :: "title" -> Json.toJson(getTitle)
        :: "preview" -> Json.toJson("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut euismod pellentesque facilisis. Morbi odio sem, dapibus eget cursus vel, sodales in diam. Nunc porttitor mauris vitae diam imperdiet nec bibendum magna eleifend. Mauris sapien lectus, sodales et tincidunt at, aliquam a leo. Nullam quis enim vitae ligula condimentum tempus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Aliquam ut facilisis quam. Aenean sed dapibus sapien. Nulla facilisi.")
        :: "image" -> Json.toJson(getImageUrl)
        :: "topics" -> JsArray(Seq(Json.toJson("Tiger Dog"), Json.toJson("Lemon Party")))
        :: "from_user" -> JsArray(
        JsObject(
          "username" -> Json.toJson("fudgeface")
            :: "full_name" -> Json.toJson("Mr. Fudge Face")
            :: "id" -> Json.toJson("#3:27")
            :: "profile_picture" -> Json.toJson("url here")
            :: Nil
        ) :: Nil)
        :: "shares" -> JsArray(
        JsObject(
          "count" -> Json.toJson("100")
            :: Nil
        ) :: Nil)
        :: Nil).asInstanceOf

    println(ret.toString, "here")
    ret

  }
}

If I try to access toJson it dies. The other methods work.

println("\n\n"+getArticleList(defaultPage, defaultPageSize).head.toJson)

error] application - 

! @6dckhec3c - Internal server error, for request [GET /articles] ->

play.core.ActionInvoker$$anonfun$receive$1$$anon$1: Execution exception [[ClassCastException: java.lang.Object cannot be cast to play.api.libs.json.JsValue]]
    at play.core.ActionInvoker$$anonfun$receive$1.apply(Invoker.scala:134) [play_2.9.1.jar:2.0.4]
    at play.core.ActionInvoker$$anonfun$receive$1.apply(Invoker.scala:115) [play_2.9.1.jar:2.0.4]
    at akka.actor.Actor$class.apply(Actor.scala:318) [akka-actor.jar:2.0.2]
    at play.core.ActionInvoker.apply(Invoker.scala:113) [play_2.9.1.jar:2.0.4]
    at akka.actor.ActorCell.invoke(ActorCell.scala:626) [akka-actor.jar:2.0.2]
    at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:197) [akka-actor.jar:2.0.2]
Caused by: java.lang.ClassCastException: java.lang.Object cannot be cast to play.api.libs.json.JsValue
    at $Proxy53.toJson(Unknown Source) ~[na:na]
    at controllers.ArticleController$$anonfun$index$1.apply(ArticleController.scala:111) ~[classes/:2.0.4]
    at controllers.ArticleController$$anonfun$index$1.apply(ArticleController.scala:97) ~[classes/:2.0.4]
    at play.api.mvc.Action$$anon$1.apply(Action.scala:170) ~[play_2.9.1.jar:2.0.4]
    at play.core.ActionInvoker$$anonfun$receive$1$$anonfun$6.apply(Invoker.scala:126) ~[play_2.9.1.jar:2.0.4]
    at play.core.ActionInvoker$$anonfun$receive$1$$anonfun$6.apply(Invoker.scala:126) ~[play_2.9.1.jar:2.0.4]
[debug] application - [securesocial] calling deleteExpiredTokens()

Any idea why? That looks okay to me.

There already is a trait that is similar to Jsonable in the default framework. This trait is called a Writes . It's automatically used by the toJson method.

It would work something like this:

import play.api.libs.json.Json.toJson 

object GraphedArticle {

  implicit object graphedArticleWrites extends Writes[GraphedArticle] {
    def writes(g: GraphedArticle) = 
      toJson(Map(
          "articleId" -> toJson(g.getArticleId),
          "graphId" -> toJson(asVertex().getId.toString)
          "created_time" -> toJson(123123123)))
    }
}

This method would look a bit different:

import play.api.libs.json.Json.toJson

def renderListToJson[T](entities: Iterable[T])(implicit writes:Writes[T]): String = {

  val jsonList = Json.toJson(entities.map(Json.toJson).toSeq)
  val result = Json.toJson(Map(
      "meta" -> Json.toJson(Seq()), 
      "data" -> jsonList))

  Json.stringify(result)
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM