2016-05-09 24 views
3

Ich benutze scala play 2.5 und ich habe den folgenden Fehler beim Versuch, ein Objekt in einen meiner Controller zu injizieren. Ich verwende das Standard-Injection-Framework, das mit play angegeben wurde, nämlich Guice. HierScala spielen Guice Injektion

ProvisionException: Unable to provision, see the following errors: 
    1) No implementation for services.MyService was bound. 
    while locating services.MyService for parameter 0 at controllers.MyController.<init>(MyController.scala:12) 
    while locating controllers.MyController for parameter 3 at router.Routes.<init>(Routes.scala:55) 
    while locating router.Routes 
    while locating play.api.inject.RoutesProvider while locating play.api.routing.Router for parameter 0 at play.api.http.JavaCompatibleHttpRequestHandler.<init>(HttpRequestHandler.scala:200) 
    while locating play.api.http.JavaCompatibleHttpRequestHandler 
    while locating play.api.http.HttpRequestHandler for parameter 4 at play.api.DefaultApplication.<init>(Application.scala:221) at play.api.DefaultApplication.class(Application.scala:221) 
while locating play.api.DefaultApplication 
    while locating play.api.Application 

ist die Steuerung:

package controllers 

import services.MyService 

class MyController @Inject()(myService: MyService, val messagesApi: MessagesApi) extends Controller with I18nSupport { 

    def someFunctionThatUsesMyService(url: String) = Action {} 
} 

Hier ist der Service Ich mag würde injizieren:

package services 

import javax.inject._ 

trait MyService { 
    def op(param1: String, param2: String): Boolean 
} 

@Singleton 
class BasicMyService extends MyService { 
    override def op(param1: String, param2: String): Boolean = true 
} 

Das ist, wie ich es bin mit:

@Singleton 
class HomeController @Inject() extends Controller { 

    /** 
    * Create an Action to render an HTML page with a welcome message. 
    * The configuration in the `routes` file means that this method 
    * will be called when the application receives a `GET` request with 
    * a path of `/`. 
    */ 
    def index = Action { 
    //Ok(views.html.index("Your new application is ready.")) 
    Redirect(routes.MyController.someFunctionThatUsesMyService(Some(routes.OtherController.welcomePage().url))) 
    } 

} 

Antwort

5

Sie sollten ImplementedBy Annotatio hinzufügen n zu Service Merkmal

package services 

import javax.inject._ 

@ImplementedBy(classOf[BasicMyService]) 
trait MyService { 
    def op(param1: String, param2: String): Boolean 
} 

@Singleton 
class BasicMyService extends MyService { 
    override def op(param1: String, param2: String): Boolean = true 
} 
+0

Wie Sie dies für einen MockedMyService erstreckt MyService zum Testen Zwecke ?. Würde das Laden der Datei den BasicMyService nicht automatisch binden? – dlite922

+0

Warum brauchen Sie eine weitere Abstraktionsschicht? Warum injizieren Sie nicht einfach konkrete Implementierungen in den Controller und machen sie bei Bedarf in Tests lustig? – Sergey

0

Können Sie versuchen, Dienstleistungen direkt zu injizieren, warum brauchen Sie diese Schicht von Dummy-Traits? Alles muss ohne zusätzliche Programmierung funktionieren. Sie können Ihre externen Deps immer feinabstimmen. Siehe Beispiel unten. Hier

ist ein Code

Controller:

class MyController @Inject()(service: SomeConcreteService) extends Controller { /** just use service.anyMethod here */ } 

Service:

@Singleton 
class SomeConcreteService @Inject()(otherStuff: OtherStuffConcrete){ 
/** otherStuff will be also injected */ 
    def mySuperServiceMethod:={ "Hey!" } 
} 

Test:

class MyControllerTest extends PlaySpec with OneAppPerSuite with MockitoSugar { 

    // do it this way if you want framework to provide controller instance 
    private val myController = app.injector.instanceOf[MyController] 

    // or mock external deps and build controller on your own 
    val externalService = mock[SomeConcreteService] 
    val handMadeController = new MyController(externalService) 

    "My controller" should{ 
     "do its best " in { 
      val response = call(handMadeController.doStuff, FakeRequest()) 

      status(response) mustBe OK 

      contentAsString(response) must include("Best controller") 

    } 
}