Search code examples
scaladependency-injectionguice

Inject object into App in scala main


Here is the code:

import akka.actor.ActorSystem
import akka.stream.ActorMaterializer
import akka.stream.scaladsl.Sink
import com.google.inject.Inject
import org.bytedeco.javacv.{CanvasFrame, Frame}

class WebCamWindow @Inject()(webCam: WebCam) {

  implicit val system = ActorSystem()
  implicit val materializer = ActorMaterializer()

  val canvas = new CanvasFrame("Webcam")
  //  Set Canvas frame to close on exit
  canvas.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE)

  val imageDimensions = Dimensions(width = 640, height = 480)
  val webcamSource = webCam.source

  val graph = webcamSource
    .map(MediaConversion.toMat) // most OpenCV manipulations require a Matrix
    .map(Flip.horizontal)
    .map(MediaConversion.toFrame) // convert back to a frame
    .map(canvas.showImage)
    .to(Sink.ignore)

  def run(): Unit = {
    graph.run()
  }
}

I would like to make this an App object and run it, but I don't know how to deal with the dependency injection here. Could anyone help?

Full project can be found here: https://bitbucket.org/kindlychung/testscalacv


Solution

  • First step is to make it into a trait (just for convenience):

    trait WebCamWindowLike  {
       def webCam: WebCam
    
       implicit val system ...//all the code is here
    
    }
    

    Then you can have old injectable WebCamWindow:

    class WebCamWindow @Inject()(val webCam: WebCam) extends WebCamWindowLike
    

    As well as independent runnable object:

    object WebCamWindowApp extends App with WebCamWindowLike {
       private val injector = Guice.createInjector(new AppInjectory())
       override val webCam = injector.getInstance(classOf[WebCam])
       run()
    }
    

    Where AppInjectory extends AbstractModule is your actual injectory for Guice that takes care of all of your dependencies.

    Another option is (if you want to get rid of Guice) manual "injection":

    object WebCamWindowApp extends App with WebCamWindowLike {
    
       override val webCam = new WebCam(...)
       run()
    
    }