score:10

Ok. I will assume you have two classes. First we will have your Client class:

@Singleton // this is not necessary, I put it here so you know this is possible
class Client @Inject() (ws:WSClient, baseUrl: String) {

    // Since this controller is not annotated with @Inject
    // it WILL NOT be used when binding components
    def this(ws:WSClient) = this(ws, "<url string>")

    def getResponse() = {
        // do something using ws object
    }
}

Then you have another class that uses Client, per instance, a controller:

class MyController @Inject() (client: Client) extends Controller {

    def someAction = Action {
        // do something with client object
    }

}

The main point here is that the controller did not need to create a Client instance. It was automatically injected by Guice.

Moreover, your client class needs a baseUrl and there is no place telling Play which value is needed there. If this is a configuration, than you can do something like this:

import play.api.Configuration

class Client @Inject() (ws:WSClient, configuration: Configuration) {

    def getResponse() = {
        val baseUrl = configuration.getString("key.to.baseUrl")
        // do something using ws object and baseUrl
    }
}

But, if you really want your Client object to receives a String, then we need to tell Play which String needs to be injected:

package com.acme.modules

import com.google.inject.AbstractModule
import com.google.inject.name.Names

class MyModule extends AbstractModule {
  def configure() = {
    bind(classOf[String])
      .annotatedWith(Names.named("baseUrl")) // attention to the name here. It will be used below
      .toInstance("http://api.example.com/")
  }
}

And then enable this module by adding the following line to your application.conf:

play.modules.enabled += "com.acme.modules.MyModule"

After that, we will change Client to be specific about which String it is expecting:

import play.api.Configuration

// @Named needs to receive the same value defined at the module class.
class Client @Inject() (ws:WSClient, @Named("baseUrl") baseUrl: String) {

    def getResponse() = {
        val baseUrl = configuration.getString("key.to.baseUrl")
        // do something using ws object and baseUrl
    }
}

Update after question edit:

Give the structure you want/need:

Controller Action --> Determine Plugins to Execute --> Execute Plugins ---> Plugin1

Your code can also follow that path with classes like this:

MyController -> PluginResolver -> Plugin
             -> PluginRunner ->

And, then, you can have:

Controller:

class MyController @Inject() (
    pluginResolver: PluginResolver,
    pluginRunner: PluginRunner
) extends Controller {

    def action = Action {
        val plugins = pluginsResolver.resolve(/* give a criteria to select plugins */)
        val someResultFromPluginsExecution = pluginsRunner.run(plugins)

        // map result from plugins execution to a play play.api.mvc.Result
        // return the play.api.mvc.Result
    }
}

Plugin classes:

import play.api.inject.Injector

class PluginResolver @Inject()(injector: Injector) {

    def resolve(/* some criteria to resolve plugins */): Seq[Plugin] = {
        val pluginsClasses = ... // find the necessary plugins based on the criteria
        pluginsClasses.map { pluginClass => injector.instanceOf(pluginClass) }
    }

}

// ExecutionContext is not really necessary, but maybe you want/need
// another thread pool to execute plugins
class PluginRunner @Inject()(implicit executionContext: ExecutionContext) {

    def run(plugins: Seq[Plugin]): Seq[PluginExecutionResult] = {
        // run the plugins
        // return the result
    }
}

trait Plugin {
    def execute(): PluginExecutionResult
}

The real magic here happens at the PluginResolver. It uses a play.api.inject.Injector to create plugins instances and then your plugins can use Dependency Injection. Per instance:

class PluginThatNeedsWSClient @Inject(wsClient: WSClient) extends Plugin {
    def execute(): PluginExecutionResult = {
        // Use wsClient to call a remote service
        // return the execution result
    }
}

Reference:

  1. Scala: Dependency Injection
  2. Scala: Play WS API
  3. play.api.inject.Injector

Related Query