0

How do I instantiate an object from this class? I have another class where I would like to use the MongoUtils class as defined below. This class is from reactivemongo

package controllers

import javax.inject.Inject

import scala.concurrent.Future

import play.api.Logger
import play.api.mvc.{ Action, Controller }
import play.api.libs.concurrent.Execution.Implicits.defaultContext
import play.api.libs.functional.syntax._
import play.api.libs.json._

// Reactive Mongo imports
import reactivemongo.api.Cursor

import play.modules.reactivemongo.{ // ReactiveMongo Play2 plugin
MongoController,
ReactiveMongoApi,
ReactiveMongoComponents
}

// BSON-JSON conversions/collection
import reactivemongo.play.json._
import play.modules.reactivemongo.json.collection._

/*
 * Example using ReactiveMongo + Play JSON library.
 *
 * There are two approaches demonstrated in this controller:
 * - using JsObjects directly
 * - using case classes that can be turned into JSON using Reads and Writes.
 *
 * This controller uses JsObjects directly.
 *
 * Instead of using the default Collection implementation (which interacts with
 * BSON structures + BSONReader/BSONWriter), we use a specialized
 * implementation that works with JsObject + Reads/Writes.
 *
 * Of course, you can still use the default Collection implementation
 * (BSONCollection.) See ReactiveMongo examples to learn how to use it.
 */
class MongoUtils @Inject() (val reactiveMongoApi: ReactiveMongoApi)
  extends Controller with MongoController with ReactiveMongoComponents {

  /*
   * Get a JSONCollection (a Collection implementation that is designed to work
   * with JsObject, Reads and Writes.)
   * Note that the `collection` is not a `val`, but a `def`. We do _not_ store
   * the collection reference to avoid potential problems in development with
   * Play hot-reloading.
   */
  def collection: JSONCollection = db.collection[JSONCollection]("persons")

  def index = Action { Ok("works") }

  def create(name: String, age: Int) = Action.async {
    val json = Json.obj(
      "name" -> name,
      "age" -> age,
      "created" -> new java.util.Date().getTime())

    collection.insert(json).map(lastError =>
      Ok("Mongo LastError: %s".format(lastError)))
  }

  def createFromJson = Action.async(parse.json) { request =>
    import play.api.libs.json.Reads._
    /*
     * request.body is a JsValue.
     * There is an implicit Writes that turns this JsValue as a JsObject,
     * so you can call insert() with this JsValue.
     * (insert() takes a JsObject as parameter, or anything that can be
     * turned into a JsObject using a Writes.)
     */
    val transformer: Reads[JsObject] =
      Reads.jsPickBranch[JsString](__ \ "firstName") and
        Reads.jsPickBranch[JsString](__ \ "lastName") and
        Reads.jsPickBranch[JsNumber](__ \ "age") reduce

    request.body.transform(transformer).map { result =>
      collection.insert(result).map { lastError =>
        Logger.debug(s"Successfully inserted with LastError: $lastError")
        Created
      }
    }.getOrElse(Future.successful(BadRequest("invalid json")))
  }

  def findByName(name: String) = Action.async {
    // let's do our query
    val cursor: Cursor[JsObject] = collection.
      // find all people with name `name`
      find(Json.obj("name" -> name)).
      // sort them by creation date
      sort(Json.obj("created" -> -1)).
      // perform the query and get a cursor of JsObject
      cursor[JsObject]()

    // gather all the JsObjects in a list
    val futurePersonsList: Future[List[JsObject]] = cursor.collect[List]()

    // transform the list into a JsArray
    val futurePersonsJsonArray: Future[JsArray] =
      futurePersonsList.map { persons => Json.arr(persons) }

    // everything's ok! Let's reply with the array
    futurePersonsJsonArray.map { persons =>
      Ok(persons)
    }
  }
}

So far I have tried val mongoutil = new MongoUtils(reactiveMongoApi = play.modules.reactivemongo) but apparently it does not work.

summerNight
  • 1,446
  • 3
  • 25
  • 52
  • You won't need to manually instantiate the class. Just let the DI framework handle that for you. Also, that `MongoUtils` class looks really confusing. Is it a controller that you want to inject at other places? – marcospereira Jan 19 '16 at 01:55
  • You can have a look at the doc: http://reactivemongo.org/releases/0.11/documentation/tutorial/play2.html – cchantep Jan 26 '16 at 08:16

2 Answers2

0

If you're using this class from a controller, you should annotate your controller as follows to have play inject an instance into it:

class MyController @Inject() (mongoUtils: MongoUtils) extends Controller {}

If you are not using the injected controllers, you can access it via the injector:

Play.current.injector.instanceOf(classOf[MongoUtils])

Read more about dependency injection in play here: https://www.playframework.com/documentation/2.4.x/ScalaDependencyInjection

rethab
  • 7,170
  • 29
  • 46
0

You can use Play’s dependency injection mechanism to resolve instance of ReactiveMongoApi which is the interface to MongoDB. The steps could be:

Add the lines below to application.conf

play.modules.enabled += "play.modules.reactivemongo.ReactiveMongoModule"
play.modules.enabled += "modules.CommonModule"

modules.CommonModule is the place you define your bindings, so that Guice, a DI framework integrated with Play 2.4, knows which implementation to be used for a particular interface. For example,

package modules

import com.google.inject.AbstractModule
import dao.impl.UserDaoMongo
import dao.UserDao
import play.api.{Configuration, Environment}
import services.{UserService, UserServiceImpl}
case class CommonModule(environment: Environment, configuration: Configuration) extends AbstractModule {

  def configure() {
    bindDAOs()
    bindServices()
  }

  private def bindDAOs(): Unit = {
    bind(classOf[UserDao]).to(classOf[UserDaoMongo])
  }

  def bindServices(): Unit = {
    bind(classOf[UserService]).to(classOf[UserServiceImpl])
  }
}

In addition, it is a good practice to make controllers singleton. For example:

import javax.inject.{Singleton, Inject}

@Singleton    
class UserController @Inject()(userService: UserService) extends Controller {

Please read this to know how to use Reactivemongo with Play framework. On the other hand, this is a complete example: https://github.com/luongbalinh/play-mongo

Luong Ba Linh
  • 802
  • 5
  • 20
  • By default, Guice will create a new object whenever a dependency is injected. Marking a controller, which depends on some services, @Singleton will create only one object for the controller, and reuse the exact same object on all injections. – Luong Ba Linh Jan 19 '16 at 07:57
  • 1
    I know plain guice does that, however play will make controllers singletons by default (https://www.playframework.com/documentation/2.1.x/ScalaDependencyInjection, also supported by this answer: http://stackoverflow.com/a/34867199/1080523). I was more interested in the reasoning behing it. – rethab Jan 19 '16 at 08:37
  • oh I did not know controllers are singletons by default. Thanks. – Luong Ba Linh Jan 20 '16 at 00:31