score:17
This is more related to how Guice handles inheritance and you have to do exactly what you would do if you were not using Guice, which is declaring the parameters to the superclass and calling the super constructor at your child classes. Guice even suggest it at its docs:
Wherever possible, use constructor injection to create immutable objects. Immutable objects are simple, shareable, and can be composed.
Constructor injection has some limitations:
- Subclasses must call super() with all dependencies. This makes constructor injection cumbersome, especially as the injected base class changes.
In pure Java, it will means doing something like this:
public abstract class Base {
private final Dependency dep;
public Base(Dependency dep) {
this.dep = dep;
}
}
public class Child extends Base {
private final AnotherDependency anotherDep;
public Child(Dependency dep, AnotherDependency anotherDep) {
super(dep); // guaranteeing that fields at superclass will be properly configured
this.anotherDep = anotherDep;
}
}
Dependency injection won't change that and you will just have to add the annotations to indicate how to inject the dependencies. In this case, since Base
class is abstract
, and then no instances of Base
can be created, we may skip it and just annotate Child
class:
public abstract class Base {
private final Dependency dep;
public Base(Dependency dep) {
this.dep = dep;
}
}
public class Child extends Base {
private final AnotherDependency anotherDep;
@Inject
public Child(Dependency dep, AnotherDependency anotherDep) {
super(dep); // guaranteeing that fields at superclass will be properly configured
this.anotherDep = anotherDep;
}
}
Translating to Scala, we will have something like this:
abstract class Base(dep: Dependency) {
// something else
}
class Child @Inject() (anotherDep: AnotherDependency, dep: Dependency) extends Base(dep) {
// something else
}
Now, we can rewrite your code to use this knowledge and avoid deprecated APIs:
abstract class Microservice(serviceName: String, configuration: Configuration, ws: WSClient) {
protected lazy val serviceURL: String = configuration.getString(s"microservice.$serviceName.url")
// ...and functions using the injected WSClient...
}
// a class instead of an object
// annotated as a Singleton
@Singleton
class HelloWorldService(configuration: Configuration, ws: WSClient)
extends Microservice("helloWorld", configuration, ws) {
// ...
}
The last point is the implicit
ExecutionContext
and here we have two options:
- Use the default execution context, which will be
play.api.libs.concurrent.Execution.Implicits.defaultContext
- Use other thread pools
This depends on you, but you can easily inject an ActorSystem
to lookup the dispatcher. If you decide to go with a custom thread pool, you can do something like this:
abstract class Microservice(serviceName: String, configuration: Configuration, ws: WSClient, actorSystem: ActorSystem) {
// this will be available here and at the subclass too
implicit val executionContext = actorSystem.dispatchers.lookup("my-context")
protected lazy val serviceURL: String = configuration.getString(s"microservice.$serviceName.url")
// ...and functions using the injected WSClient...
}
// a class instead of an object
// annotated as a Singleton
@Singleton
class HelloWorldService(configuration: Configuration, ws: WSClient, actorSystem: ActorSystem)
extends Microservice("helloWorld", configuration, ws, actorSystem) {
// ...
}
How to use HelloWorldService
?
Now, there are two things you need to understand in order to proper inject an instance of HelloWorldService
where you need it.
From where HelloWorldService
gets its dependencies?
Guice docs has a good explanation about it:
Dependency InjectionLike the factory, dependency injection is just a design pattern. The core principle is to separate behaviour from dependency resolution.
The dependency injection pattern leads to code that's modular and testable, and Guice makes it easy to write. To use Guice, we first need to tell it how to map our interfaces to their implementations. This configuration is done in a Guice module, which is any Java class that implements the Module interface.
And then, Playframework declare modules for WSClient and for Configuration. Both modules gives Guice enough information about how to build these dependencies, and there are modules to describe how to build the dependencies necessary for WSClient
and Configuration
. Again, Guice docs has a good explanation about it:
With dependency injection, objects accept dependencies in their constructors. To construct an object, you first build its dependencies. But to build each dependency, you need its dependencies, and so on. So when you build an object, you really need to build an object graph.
In our case, for HelloWorldService
, we are using constructor injection to enable Guice to set/create our object graph.
How HelloWorldService
is injected?
Just like WSClient
has a module to describe how an implementation is binded to an interface/trait, we can do the same for HelloWorldService
. Play docs has a clear explanation about how to create and configure modules, so I won't repeat it here.
But after creating an module, to inject a HelloWorldService
to your controller, you just declare it as a dependency:
class MyController @Inject() (service: Microservice) extends Controller {
def index = Action {
// access "service" here and do whatever you want
}
}
score:1
In scala,
-> If you do not want to explicitly forward all the injected parameters to the base constructor, you can do it like that :
abstract class Base {
val depOne: DependencyOne
val depTwo: DependencyTwo
// ...
}
case class Child @Inject() (param1: Int,
depOne: DependencyOne,
depTwo: DependencyTwo) extends Base {
// ...
}
Source: stackoverflow.com
Related Query
- Dependency injection with abstract class and object in Play Framework 2.5
- Play Framework dependency injection Object vs @Singleton Class
- ScalaWS in play framework 2.5 and dependency injection of WSClient in custom class
- Using Spring as a dependency injection framework with play 2.4.x?
- Play Framework PathBindable with Dependency Injection
- How to read and write Anorm object with the new JSON API in Play Framework 2.1-RC2?
- how plugin works with inject and object instead of class in play 2.4
- Using Play Framework and case class with greater than 22 parameters
- Play 2.5 scala import class with Dependency Injection
- Scala class method with WSClient call inside an object in play framework
- provide own unapply method in play framework 2 with scala and circumflex-orm class
- how to instantiate a controller class with injection in play framework 2.5.x
- Play framework compile-time dependency injection and singleton
- How to use IntelliJ with Play Framework and Scala
- Which is best data access options available for Play framework with Scala and PostgreSQL?
- Dynamic SQL Parameters with Anorm and Scala Play Framework
- What's the difference between a class with a companion object and a class and object with the same name?
- How do I get Intellij IDEA 12.0 to work with Play Framework 2.1.0 app and Scala 2.10.0?
- Play Framework REST with basic authentication and SSL
- Debug not working with play framework activator, scala and eclipse
- How to set up play framework ApplicationLoader and Macwire to work with custom routes?
- Cannot resolve symbol 'play' error with Play Framework 2.4.x and IntellijIdea 14.x
- @Repeat Form Helper with complex object - Play Framework
- Difference between static controller and non static controller in play framework with Java
- Play framework 2 : How to pass object between routes, views, and controller?
- Trouble with Scala's class and object
- Why does SonarQube find this issue (<static initializer for >() uses a Side Effect Constructor) with case and object class files?
- Play Framework returning 404 with play.http.context and trailing slash
- Play 2.4: Schedule a recurring task at app startup with dependency injection
- How to create an instance of a model with the ebean framework and scala in Play 2.2
More Query from same tag
- How read a csv with quotes using sparkcontext
- merge two different types of RDD
- All possible permutations of values for such a map
- Error of "No implicit ordering defined for U" where a trait which has extended Ordered
- Why do IntelliJ worksheets mess with the class name?
- How to redefine a symbol/character to be interpreted as a """ (triple quotes) symbol in Scala code?
- How to convert a Map to Traverse
- Akka.io: Thread per Actor
- sortByKey in Spark
- Better way to create scala array from lines of a file
- How to set up a local development environment for Scala Spark ETL to run in AWS Glue?
- Is it possible to ignore null values when using lead window function in Spark
- How do you read the HTML content of an Atom feed with Scala and Play framework 2.0?
- Is it possible to make a cycle in an immutable linked list?
- Application not exiting after terminating Actor and ActorSystem
- How to catch Future.failed in Scala?
- Using Jersey Test Framework in Scala
- Scala: return element using if inside map function
- Why is it legal to call a method that takes Any without any argument?
- Play framework 2.0, Eclipse Helios, Scala IDE 2.0 plugin - Getting build errors out of the box
- Creating dataset based on different case classes
- `exception during macro expansion: [error] scala.reflect.macros.TypecheckException` when using quill
- Routing does not recognize modules for my sbt-multimodule project in Play 2 (code and error mesage inside)
- Apache spark taking average by key with python
- How can I replace a string which comes with some pattern and keeping the rest same?
- Replace Asynchronous Anonymous Class with Function
- Lambda calculus: Apply in Scala
- Mix several Enumerations into one
- toBreeze Spark function scala
- With Scala's Set, is there a method analog to the containsAll method in Java's Set?