Search code examples
jsonscalaplayframeworkreactivemongoplay-reactivemongo

RuntimeException on validation of JsonReaders - Scala - ReactiveMongo


I have a case classe to store my userOption that I insert into my User. The structure of my user is as such:

{  
   "_id":ObjectId("55d54d05ece39a6cf774c3e4"),
"main":{  
  "providerId":"userpass",
  "userId":"[email protected]",
  "firstName":"test",
  "lastName":"one",
  "fullName":"Test One",
  "email":"[email protected]",
  "authMethod":{  
     "method":"userPassword"
  },
  "passwordInfo":{  
     "hasher":"bcrypt",
     "password":"aslkdjfasdjh"
    }
},
"userOption":{  
  "hotLeadNotification":{  
     "f":"IMMEDIATE"
  }
 }
   }

now, I'd like to add an additional option: favoriteNotification. I changed my case class adding favoriteNotification:

    case class UserOption (
      hotLeadNotification: Frequency = Frequency("IMMEDIATE"),
    favoriteNotification: Frequency = Frequency("IMMEDIATE")
    )
    object UserOption{
  implicit val userOptionFormat = Json.format[UserOption]
implicit object BSONObjectIDFormat extends Format[BSONObjectID] {
    def writes(objectId: BSONObjectID): JsValue = JsString(objectId.toString())
    def reads(json: JsValue): JsResult[BSONObjectID] = json match {
      case JsString(x) => {
        val maybeOID: Try[BSONObjectID] = BSONObjectID.parse(x)
        if(maybeOID.isSuccess) JsSuccess(maybeOID.get) else {
          JsError("Expected BSONObjectID as JsString")
        }
      }
      case _ => JsError("Expected BSONObjectID as JsString")
    }
  }
val userOptionForm = Form(
  mapping(
        "hotLeadNotification" -> text, 
        "favoriteNotification" -> text
   )((hotLeadNotification: String, favoriteNotification: String) =>
   UserOption( 
   hotLeadNotification = Frequency(hotLeadNotification), 
   favoriteNotification = Frequency(favoriteNotification)
   )  
   )((u:UserOption) => Some(u.hotLeadNotification.f, u.favoriteNotification.f))
)  
 implicit object UserOptionBSONReader extends BSONDocumentReader[UserOption] {
    def read(doc: BSONDocument): UserOption = 
      UserOption(
      doc.getAs[Frequency]("hotLeadNotification").getOrElse(Frequency("IMMEDIATE")), 
      doc.getAs[Frequency]("favoriteNotification").getOrElse(Frequency("IMMEDIATE"))
      )

  }
  implicit object UserOptionBSONWriter extends BSONDocumentWriter[UserOption]{
    def write(userOption: UserOption): BSONDocument = 
      BSONDocument(
          "hotLeadNotification" -> userOption.hotLeadNotification, 
          "favoriteNotification" -> userOption.favoriteNotification

      )
  }

}

Since I added favoriteNotification, I get a RuntimeException:

java.lang.RuntimeException: (/userOption/favoriteNotification,List(ValidationError(error.path.missing,WrappedArray())))
    at scala.sys.package$.error(package.scala:27) ~[scala-library-2.11.6.jar:na]
    at play.api.libs.iteratee.Iteratee$$anonfun$run$1.apply(Iteratee.scala:355) ~[play-iteratees_2.11-2.3.9.jar:2.3.9]
    at play.api.libs.iteratee.Iteratee$$anonfun$run$1.apply(Iteratee.scala:348) ~[play-iteratees_2.11-2.3.9.jar:2.3.9]
    at play.api.libs.iteratee.StepIteratee$$anonfun$fold$2.apply(Iteratee.scala:670) ~[play-iteratees_2.11-2.3.9.jar:2.3.9]
    at play.api.libs.iteratee.StepIteratee$$anonfun$fold$2.apply(Iteratee.scala:670) ~[play-iteratees_2.11-2.3.9.jar:2.3.9]

But there's not list in my code. What am I doing wrong?

Thanks for your help


Solution

  • The issue was that UserOption was an Option, but not it parameters. As I added only the new option is the case class and not in the database, it was throwing this error. I changed the case class as adding options:

       case class UserOption (
              hotLeadNotification: Option[Frequency] = Some(Frequency("IMMEDIATE")),
              favoriteNotification: Option[Frequency] = Some(Frequency("IMMEDIATE"))  
            )