Vikas Pandya
Vikas Pandya

Reputation: 1988

No Json formatter found Scala, Play framework error

I have following two implicits.

implicit val readObjectIdFormat = new Reads[ObjectId] {
def reads(jv: JsValue): JsResult[ObjectId] = {
  JsSuccess(new ObjectId(jv.as[String]))
 }
}

implicit val visitorFormat = (
(__ \ "_id").formatOpt[ObjectId] and
(__ \ "visitorId").format[String] and
(__ \ "referralUrl").formatOpt[String] and
(__ \ "ipAddress").formatOpt[String] and
(__ \ "promotionId").format[String])(Visitor)  

Though readObjectIdFormat is defined at compile time it keeps complaining following on "(__ \ "_id").formatOpt[ObjectId]" line

No Json formatter found for type org.bson.types.ObjectId. Try to implement an implicit Format for this type.

versions : Play 2.1-RC2, Scala 2.10

Any idea why it's not recognizing readObjectIdFormat ?

Upvotes: 6

Views: 1849

Answers (3)

Sebastien Lorber
Sebastien Lorber

Reputation: 92210

Others gave the good answer, use Format instead. By the way, you could handle parse errors.

This implementation is working fine for me:

  implicit val objectIdFormat: Format[ObjectId] = new Format[ObjectId] {

    def reads(json: JsValue) = {
      json match {
        case jsString: JsString => {
          if ( ObjectId.isValid(jsString.value) ) JsSuccess(new ObjectId(jsString.value))
          else JsError("Invalid ObjectId")
        }
        case other => JsError("Can't parse json path as an ObjectId. Json content = " + other.toString())
      }
    }

    def writes(oId: ObjectId): JsValue = {
      JsString(oId.toString)
    }

  }

Upvotes: 3

user425367
user425367

Reputation:

From documentation: Format[T] extends Reads[T] with Writes[T]
Format is a read + write.

Write an implicit writeObjectIdFormat then

implicit val formatObjectIdFormat = 
   Format(readObjectIdFormat, writeObjectIdFormat)

Upvotes: 0

Ivan Meredith
Ivan Meredith

Reputation: 2222

You are implementing Reads and you need implement Format instead.

implicit val readObjectIdFormat = new Format[ObjectId] {
 def reads(jv: JsValue): JsResult[ObjectId] = {
  JsSuccess(new ObjectId(jv.as[String]))
 }

 def writes(o: A): JsValue = JsString(...)
}

Or you need to use the read instead of format (note I assume this works for read, haven't tested it).

implicit val visitorRead = (
(__ \ "_id").readOpt[ObjectId] and
(__ \ "visitorId").read[String] and
(__ \ "referralUrl").readOpt[String] and
(__ \ "ipAddress").readOpt[String] and
(__ \ "promotionId").read[String])(Visitor)  

Upvotes: 2

Related Questions