0

I'm trying to create a post request for insert a data to mongoddb using : 1. sbt 0.13.6 2. play 2.10 3. scala 2.11.2 4. play2-reactivamongo 0.10.2 5. mongodb 2.6.4

data post by json, and create a case class for the model, and using JSPath to convert the json to entity class.

this is my sample code :

def inserTransaction = Action(parser.json) { implicit request =>

   val json = request.body
   val data = json.as[Transaction]
   Logger.info(data.toString)
   val future = collection.insert(data.copy(id = Option[BSONObjectID](BSONObjectID.generate)))
   var result = ""

   future.onComplete {
     case Failure(t) => result = "An error has occured: " + t.getMessage
     case Success(post) => result = "success"
   }
   Ok(result)
}

I've seen some sample code that used Action.sync for handling asynchronous in controllers, but when i try to use Action.sync, my Intellij IDE detect an error "cannot resolve Action.sync as signature", i've tried to change the result of function like this

future.onComplete {
    case Failure(t) => Ok("An error has occured: " + t.getMessage)
    case Success(post) => Ok("success")
  }

So I decided to use Action(parser.json) , but the issue that came from activator play is tell me that i should use "import play.api.libs.concurrent.Execution.Implicits._" in my code. But when i import the libraries, it came a new error :

 ! Internal server error, for (POST) [/insertdata] ->

java.lang.ExceptionInInitializerError: null ....

Caused by: play.api.PlayException: ReactiveMongoPlugin Error[The ReactiveMongoPlugin has not been         
initialized! Please edit your conf/play.plugins file and add the following line....

when i tried to reload the request, it showed another error :

! Internal server error, for (POST) [/api/insertdata] ->

java.lang.NoClassDefFoundError: Could not initialize class controllers.TransactionController$

[error] application - Error while rendering default error page
scala.MatchError: java.lang.NoClassDefFoundError: Could not initialize class 
controllers.TransactionController$ (of class java.lang.NoClassDefFoundError)

Anyone have any solution for my problem?

Hendri
  • 45
  • 6

2 Answers2

5

The problem with your code is that you're using a Future callback to manipulate a mutable variable. The function will return long before the Future is completed, so the callback essentially does nothing. Instead, you should use Action.async and map the Future to your desired Result. You can also use recover to handle any failures.

Your code should look more like this:

def inserTransaction = Action(parser.json).async { implicit request =>
   val json = request.body
   val data = json.as[Transaction]
   Logger.info(data.toString)
   val future = collection.insert(data.copy(id = Option[BSONObjectID](BSONObjectID.generate)))

   future.map(result => Ok(result))
       .recover { t: Throwable => Ok("An error has occured: " + t.getMessage) }
}

Or even better:

def inserTransaction = Action(parser.json).async { implicit request =>
   request.body.validate[Transaction].fold(
       error => Future.successful(Ok("json errors...")),
       data => {
           collection.insert(data.copy(id = Option[BSONObjectID](BSONObjectID.generate)))
              .map(result => Ok(result))
              .recover { t: Throwable => Ok("An error has occured: " + t.getMessage) }
       }
   )
}

(May not compile right away, as I don't know what collection.insert does)

Michael Zajac
  • 55,144
  • 7
  • 113
  • 138
0

This question might help: Are there any benefits in using non-async actions in Play Framework 2.2?

Action vs Action.async

If you think of actions at high level that take and input and produce an output then these two do the same thing but slightly different. Both of these take in request and output results. Action.async allows the action code to properly deal with Futures. I am skipping over some details but I hope this helps.

Can you paste your plugins file?

Community
  • 1
  • 1
Barry
  • 1,800
  • 2
  • 25
  • 46
  • you're right, the problem is plugins files It has been resolved. The code was right, and the problem was came from play.plugins, i'm not yet edit play.plugins for reactivemongo package information thanks – Hendri Oct 21 '14 at 15:09
  • 1
    @situkangsayur Using a mutable result and `Future` callback like in your code sample is not right, and **will** cause you problems. It might compile, but you're creating a race condition. Between the function returning, and the future callback changing the result. – Michael Zajac Oct 21 '14 at 20:41
  • @LimbSoup yap, you're right, thanks for reminding and informing me about it – Hendri Oct 27 '14 at 08:21