Search code examples
mongodbscalaplayframework-2.3reactivemongoplay-reactivemongo

Cannot invoke the action, eventually got an error: java.lang.IllegalArgumentException: Only JsObjects can be stored in Play framework?


I am new to Reactivemongo database(2.6), as I am trying to upload/insert json object(which is of key/value pairs, I am sending it to store in database after clicking of Submit button from my UI ) from my localsystem to store in Mongodb using Play Framework/Scala(tried with Play 2.2.3 and 2.3.8). I have tried:

import play.api.libs.json.{JsObject, JsValue, OWrites}
import play.api.mvc.{Action, Controller}
import play.modules.reactivemongo.MongoController
import play.modules.reactivemongo.json.collection._

import scala.concurrent.ExecutionContext.Implicits.global

object Application extends Controller with MongoController {
  def jsinfocollection: JSONCollection = db.collection[JSONCollection]("mycollection")

  implicit val jsvalueWrites = new OWrites[JsValue] {
    println("implicit val jsvalueWrites ...")//getting the message on Play console
    override def writes(o: JsValue): JsObject = o match {
      case o : JsObject => o
      case _ => throw new IllegalArgumentException("Only JsObjects can be stored")
    }
  }

  def createJson = Action.async(parse.json) {
    println("createJson calling...")//getting the message on Play console
    request =>
        jsinfocollection.insert(request.body).map{
    println("jsinfocollection.insert...")//getting the message on Play console
        r => Created(s"JsonInfo is Saved with result $r")
      }
  }
}

I created a collection in Mongodb already like: >db.createCollection("mycollection")

{ "ok" : 1 }

but if I give: >db.mycollection.count() - is giving 0, otherwise if I give: db.mycollection.find() - is giving nothing

Please let me know that how can I insert my json data into my required collection("mycollection"). Thanks in advance.

I am getting the following on console:

implicit val jsvalueWrites ...
createJson calling...
jsinfocollection.insert...
[error] play - Cannot invoke the action, eventually got an error: java.lang.IllegalArgumentException: Only JsObjects can be stored

Internal server error, for (POST) [/createJson] 

Solution

  • As you are using Action.async(parse.json) you have a JsValue in the request.body

    jsinfocollection is only able to store JsObjects (JsObjects are only one type of JsValues, other types are JsArray, JsString, ...)

    The following code should do what you are looking for

    import play.api.libs.json.{JsObject, JsValue, OWrites}
    import play.api.mvc.{Action, Controller}
    import play.modules.reactivemongo.MongoController
    import play.modules.reactivemongo.json.collection._
    
    import scala.concurrent.ExecutionContext.Implicits.global
    
    object Application extends Controller with MongoController {
      def jsinfocollection: JSONCollection = db.collection[JSONCollection]("mycollection")
    
      implicit val jsvalueWrites = new OWrites[JsValue] {
        override def writes(o: JsValue): JsObject = o match {
          case o : JsObject => o
          case _ => throw new IllegalArgumentException("Only JsObjects can be stored")
        }
      }
    
      def createJson = Action.async(parse.json) {
        request =>
          jsinfocollection.insert(request.body).map{
            r => Created(s"JsonInfo is Saved with result $r")
          }
      }
    }
    

    Maybe there is a simpler way to create the jsvalueWrites No Json serializer as JsObject found for type play.api.libs.json.JsObject And maybe updating to the latest version helps

    Note: Validation that the string is a valid JsValue will be done by the framework in parse.json, validation that is an object is done in jsvalueWrites if you need total control you could implement OWrites[String] and remove the parse.json