Implicit JsonFormat not visible for Spray-Json

1,091 views
Skip to first unread message

Daniel Ford

unread,
Aug 23, 2013, 4:38:02 PM8/23/13
to spray...@googlegroups.com
Hello,

I need help with resolving implicit JsonFormat.

Here is my code:

package com.mycompany.rest.spray.tags

import com.mycompany.rest.spray.SpringService
import com.mycompany.domain.{User, Tag}

import spray.routing.Directives._
import spray.http.MediaTypes

import spray.json._
import DefaultJsonProtocol._
import scala.collection.immutable

trait TagsService { this: SpringService =>

  def tagsRoute(implicit owner: User) =
    path("tags") {
      get {
        respondWithMediaType(MediaTypes.`application/json`) {
          complete {

            import scala.collection.JavaConversions.asScalaBuffer

            val tags: immutable.List[Tag] = asScalaBuffer(someService.findBySearchTerm[Tag]("", owner.id)).toList   // #findBySearchTerm() returns java.util.List (Hibernate). For some reason import scala.collection.JavaConversions._ doesn't work :/
//            tags(0).toJson
            tags.toJson
          }
        }
      }
    }
}

object TagsService {

  implicit object TagJsonFormat extends RootJsonFormat[Tag] {
    def write(tag: Tag) =
      JsObject(
        "id" -> JsNumber(tag.id),
        "name" -> JsString(tag.name),
        "desc" -> JsString(tag.description)
      )

    def read(value: JsValue) = {
      value.asJsObject.getFields("id", "name", "desc") match {
        case Seq(JsNumber(id), JsString(name), JsString(desc)) => {
          val t = new Tag()
          t.id = id.toLong
          t.name = name
          t.description = desc
          t
        }
        case _ => throw new DeserializationException("Tag expected")
      }
    }
  }
}


By defining TagJsonFormat in the companion object I think it should be in scope but it seems it is not.
The error I get is:
Cannot find JsonWriter or JsonFormat type class for List#15168[com#9.mycompany#7199.domain#7217.Tag#28124]
            tags.toJson
                 ^

I'm relatively new to Scala and very fresh with Spray-Json.
What I'm doing wrong ?

Thanks!
Daniel

Age Mooij

unread,
Aug 25, 2013, 8:41:43 AM8/25/13
to spray...@googlegroups.com
Hi Daniel

The import that you are missing is the one that bridges spray-httpx and spray-json, i.e. the one that provides a Marshaller[T: RootJsonFormat].

Simply import spray.httpx.SprayJsonSupport._ and you should be set… except that you would still get a compiler error because your complete function should just return tags, not the result of tags.toJson. The conversion to Json is done transparently by the Marshaller.

To recap, you can complete a route with anything that has an implicit Marshaller type class in scope. SprayJsonSupport provides one of those for any class T that has an implicit RootJsonFormat in scope. It's type classes all the way down :)

Hope this helps
Age


--
You received this message because you are subscribed to the Google Groups "spray-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to spray-user+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Daniel Ford

unread,
Aug 26, 2013, 7:45:15 AM8/26/13
to spray...@googlegroups.com

Hi Age,

Thank you for the help!

It worked after making your suggested changes and after moving my implicit object TagJsonFormat to a package object. For some reason it wasn't visible in the companion object.

Age Mooij

unread,
Aug 26, 2013, 8:20:08 AM8/26/13
to spray...@googlegroups.com
Ah, I didn't notice the object names. The companion object of your service is not a place where the compiler will normally look for implicits so you would have to import the object like so:

import TagService._ in order to brig the implicit into scope.

A better place for implicits associated with a case class is in the companion object of that case class. If you put it in the Tag object it will be found automatically because that companion object *is* in implicit scope. More info on implicit resolution can be found here: http://docs.scala-lang.org/tutorials/FAQ/finding-implicits.html

Also, are you aware of the jsonFormatX() utilities in DefaultJsonProtocol? They will save you a lot of time and lines of code as long as you can live with the json properties having the same name as the case class properties. You Tag object would look like this:

object Tag {
  implicit val jsonFormat = jsonFormat3(Tag.apply)
}

See the "Providing JsonFormats for Case Classes" section in the spray-json README (https://github.com/spray/spray-json) for more information about that.

Age

Daniel Ford

unread,
Aug 26, 2013, 8:26:19 AM8/26/13
to spray...@googlegroups.com


26 август 2013, понеделник, 15:20:08 UTC+3, Age Mooij написа:
Ah, I didn't notice the object names. The companion object of your service is not a place where the compiler will normally look for implicits so you would have to import the object like so:

import TagService._ in order to brig the implicit into scope.

A better place for implicits associated with a case class is in the companion object of that case class. If you put it in the Tag object it will be found automatically because that companion object *is* in implicit scope. More info on implicit resolution can be found here: http://docs.scala-lang.org/tutorials/FAQ/finding-implicits.html 

Thanks for this link!
 

Also, are you aware of the jsonFormatX() utilities in DefaultJsonProtocol? They will save you a lot of time and lines of code as long as you can live with the json properties having the same name as the case class properties. You Tag object would look like this:

object Tag {
  implicit val jsonFormat = jsonFormat3(Tag.apply)
}

See the "Providing JsonFormats for Case Classes" section in the spray-json README (https://github.com/spray/spray-json) for more information about that.

My Tag class is not a case class. It is a (legacy) Hibernate entity.
 
Reply all
Reply to author
Forward
0 new messages