Accessing Singleton values in Play for Scala - scala

I have the following singleton defined in Scala
package main
import javax.inject._
#Singleton
class Properties {
val timeout = 120
}
how do I access it from other programs? I tried main.Properties.timeout but it throws a compilation error saying that a companion object was not found

If you want to access it in the way, that you've mentioned: main.Properties.timeout, then use companion object instead:
class Properties {
// ...
}
object Properties {
val timeout = 120
// ...
}
With #Singleton annotation, you have to inject that service somewhere, to be able to use it. So something like this:
import javax.inject._
import main.Properties
class SomeService #Inject() (props:Properties)() {
println(props.timeout)
}
Here is documentation about DI for PlayFramework: https://www.playframework.com/documentation/2.5.x/ScalaDependencyInjection - for the latest one (not 2.0), but it is a good start point.

Related

Importing object without class

I'm trying to import an object from another .scala file that doesn't exist inside a class. I've found you can import a class like in here Scala, importing class. Is there a way to import an object without having a class around it?
Thanks
Importing a class and importing an object work the same in scala.
If you have a class
package com.package1
class MyClass{}
and an object
package com.package2
object MyObject{}
You import both the exact same way
package com.package3
import com.package1.MyClass
import com.package2.MyObject
import syntax is the same no matter what you are importing, whether it's an object, a class, a trait, a method, or a field
Yes, Scala can do exactly what you ask, and this is used frequently. Here is an example:
object Blah {
val x = 1
val y = "hello"
}
object Main extends App {
import Blah._
println(s"x=$x; y=$y")
}
Output is:
x=1; y=hello
You can also import members of a class instance, which blew my mind the first time I saw it.
If you are talking about companion objects, they are not defined inside a class, but after the class definition:
class AClass {
def sayHello() = {
println(AClass.Hello)
}
}
object AClass {
private val Hello = "hello"
}
You should have no problem importing it.

PlayFramework Scala dependency Injection Javax

I am new to Scala and the PlayFramework and am trying to figure out how I can do a a dependency Injection. I basically want a file that will be a trait and inject that into a controller. My problem is that my Controller class is not seeing my Trait this is my code
ProfileTrait
package traitss
import play.api.mvc._
trait ProfileTrait extends Controller {
def Addone()
}
Then I try to inject that into my controller
import java.nio.file.{Files, Paths}
import traitss.ProfileTrait_
import play.api.mvc.{Action, Controller}
import javax.inject._
class Profiles #Inject() (profileTrait: ProfileTrait) extends Controller
{
}
However my controller is not seeing it, I am trying to follow the example here https://www.playframework.com/documentation/2.5.x/ScalaDependencyInjection .
I am using the play framework version 2.50
You cannot inject a trait directly. You need to specify the implementation of the trait that needs to be injected.
There are two ways to specify the implementation of a trait that is to be injected:
Using #ImplementedBy annotation. Here's a simple example:
package traitss
import play.api.mvc._
import com.google.inject.ImplementedBy
#ImplementedBy(classOf[ProfileTraitImpl])
trait ProfileTrait extends Controller {
def Addone()
}
class ProfileTraitImpl extends ProfileTrait {
// your implementation goes here
}
Using Programmatic Bindings
package traitss
import play.api.mvc._
import com.google.inject.ImplementedBy
#ImplementedBy(classOf[ProfileTraitImpl])
trait ProfileTrait extends Controller {
def Addone()
}
ProfileTraitImpl:
package traitss.impl
class ProfileTraitImpl extends ProfileTrait {
// your implementation goes here
}
Create a module where you can bind the implementation with trait
import com.google.inject.AbstractModule
class Module extends AbstractModule {
def configure() = {
bind(classOf[ProfileTrait])
.to(classOf[ProfileTraitImpl])
}
}
With using the modules approach you get an additional benefit of enabling or disabling the binding. For example, in your application.conf file you can enable/disable a module using play.modules.enabled += module OR play.modules.disabled += module
You can't inject a trait, you have to inject an object that implements that trait.
For dependency injection to work, you have to tell the framework (play uses Guice under the hood) how to resolve the dependency to be injected.
There are many ways to do it and it depends on your case, for more detail you can look at Guice's documentation, the simplest way in play is to create Module.scala into your app directory , if it's not there already, and put something like this:
import com.google.inject.AbstractModule
class Module extends AbstractModule {
override def configure() = {
bind(classOf[ProfileTrait]).toInstance( ... )
}
}
where in ... you put the logic to create the object you want to inject.

Dependency injection with abstract class and object in Play Framework 2.5

I'm trying to migrate from Play 2.4 to 2.5 avoiding deprecated stuff.
I had an abstract class Microservice from which I created some objects. Some functions of the Microservice class used play.api.libs.ws.WS to make HTTP requests and also play.Play.application.configuration to read the configuration.
Previously, all I needed was some imports like:
import play.api.libs.ws._
import play.api.Play.current
import play.api.libs.concurrent.Execution.Implicits.defaultContext
But now you should use dependency injection to use WS and also to use access the current Play application.
I have something like this (shortened):
abstract class Microservice(serviceName: String) {
// ...
protected lazy val serviceURL: String = play.Play.application.configuration.getString(s"microservice.$serviceName.url")
// ...and functions using WS.url()...
}
An object looks something like this (shortened):
object HelloWorldService extends Microservice("helloWorld") {
// ...
}
Unfortunately I don't understand how I get all the stuff (WS, configuration, ExecutionContect) into the abstract class to make it work.
I tried to change it to:
abstract class Microservice #Inject() (serviceName: String, ws: WSClient, configuration: play.api.Configuration)(implicit context: scala.concurrent.ExecutionContext) {
// ...
}
But this doesn't solve the problem, because now I have to change the object too, and I can't figure out how.
I tried to turn the object into a #Singleton class, like:
#Singleton
class HelloWorldService #Inject() (implicit ec: scala.concurrent.ExecutionContext) extends Microservice ("helloWorld", ws: WSClient, configuration: play.api.Configuration) { /* ... */ }
I tried all sorts of combinations, but I'm not getting anywhere and I feel I'm not really on the right track here.
Any ideas how I can use things like WS the proper way (not using deprecated methods) without making things so complicated?
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 Injection
Like 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
}
}
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 {
// ...
}

Guice and Play2 Singleton from trait

I am using Play with Scala and I am trying to create a singleton, and i want to inject it from its trait and not directly.
for example:
#ImplementedBy(classOf[S3RepositoryImpl])
trait S3Repository {
}
#Singleton
class S3RepositoryImpl extends S3Repository {
}
But this fails with error:
trait Singleton is abstract; cannot be instantiated
I have tried several combinations and they all produce the same.
I come from Spring background and its very natural there? am i missing something about how Guice handles this type of Injection?
Thanks.
As pointed out by #Tavian-Barnes, the solution is to ensure you have the following import:
import javax.inject.Singleton
I have here a "complete" working example, just hope that I'm not stating the obvious...
package controllers
import play.api._
import play.api.mvc._
import com.google.inject._
class Application #Inject() (s3: S3Repository) extends Controller {
def index = Action {
println(s3.get)
Ok
}
}
#ImplementedBy(classOf[S3RepositoryImpl])
trait S3Repository {
def get: String
}
#Singleton
class S3RepositoryImpl extends S3Repository {
def get: String = "bla"
}
Whenever you mark a class' constructor with #Inject the Guice will manage the injection of the instance itself. So, if you marked your class as #Singleton, Guice will create and will always give you just that one instance. Nobody can stop you from manually instantiating a class in your code... You can explore it in detail at Play.
Use below import, instead of import javax.inject.Singleton
import com.google.inject.{Inject, Singleton}
Import both Inject and Singleton.
import javax.inject.{Inject, Singleton}
Refrain from using:
import com.google.inject.{Inject, Singleton}
as play framework requires the javax import

Instantiating Akka actors in a Play application with Subcut

I have a Play 2.1 application. I am also using Subcut for dependency injection, which is already set up and working for most parts of the application, except for one.
Say I have the following snippet of actor-related code:
import akka.actor._
import com.typesafe.plugin._
import play.api.Play.current
import play.api.libs.concurrent.Akka
class FoobarActor extends Actor {
def receive = {
// do stuff here
}
}
object Foobar {
val actor = Akka.system.actorOf(Props[FoobarActor])
}
Now, say I would like to inject some objects into each instance of the FoobarActor using Subcut. This would require the actor class to extend Injectable, with the BindingModule passed into the constructor, like this:
import akka.actor._
import com.typesafe.plugin._
import play.api.Play.current
import play.api.libs.concurrent.Akka
import com.escalatesoft.subcut.inject.{Injectable, BindingModule}
class FoobarActor(implicit val bindingModule: BindingModule) extends Actor
with Injectable {
val bazProvider = inject[BazProvider]
val quuxProvider = inject[QuuxProvider]
def receive = {
// do stuff here
}
}
The question is: how is such an actor instantiated?
Typically, objects managed by Subcut are constructed in Subcut's configuration objects (i.e., objects that extend NewBindingModule), or in the case of Play's controllers, in the Global object (see play-subcut on github).
What would I replace Akka.system.actorOf(Props[FoobarActor]) with in order to override the instantiation of actors in order to pass in the binding module?
object Foobar {
val actor = /* what goes here? */
}
As Roland mentioned, this should be as simple as just instantiating the actor with a constructor argument. I wasn't sure the implicit would work with Akka's way of doing actor instantiation with constructor args but it seems to work okay. The code should look something like this:
class FoobarActor(implicit val bindingModule: BindingModule) extends Actor
with Injectable {
val bazProvider = inject[BazProvider]
val quuxProvider = inject[QuuxProvider]
def receive = {
// do stuff here
}
}
object FoobarActor {
def apply(implicit bindingModule:BindingModule) = {
Akka.system.actorOf(Props(classOf[FoobarActor], bindingModule))
}
}
Then, if you wanted to instantiate the FoobarActor, as long as you had an implicit BindingModule in scope, you could just do:
val ref = FoobarActor()